aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/CMakeLists.txt884
-rw-r--r--src/qml/Qt5QmlConfigExtras.cmake.in5
-rw-r--r--src/qml/Qt6AndroidQmlMacros.cmake139
-rw-r--r--src/qml/Qt6QmlBuildInternals.cmake470
-rw-r--r--src/qml/Qt6QmlConfigExtras.cmake.in16
-rw-r--r--src/qml/Qt6QmlDeploySupport.cmake331
-rw-r--r--src/qml/Qt6QmlFindQmlscInternal.cmake11
-rw-r--r--src/qml/Qt6QmlMacros.cmake4304
-rw-r--r--src/qml/Qt6QmlModuleDirMappingTemplate.qrc.in5
-rw-r--r--src/qml/Qt6QmlPluginTemplate.cpp.in22
-rw-r--r--src/qml/Qt6QmltcFileMappingTemplate.qrc.in5
-rw-r--r--src/qml/Qt6qmldirTemplate.cmake.in1
-rw-r--r--src/qml/animations/animations.pri18
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp120
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h62
-rw-r--r--src/qml/animations/qanimationgroupjob.cpp124
-rw-r--r--src/qml/animations/qanimationgroupjob_p.h64
-rw-r--r--src/qml/animations/qanimationjobutil_p.h56
-rw-r--r--src/qml/animations/qcontinuinganimationgroupjob.cpp62
-rw-r--r--src/qml/animations/qcontinuinganimationgroupjob_p.h42
-rw-r--r--src/qml/animations/qparallelanimationgroupjob.cpp68
-rw-r--r--src/qml/animations/qparallelanimationgroupjob_p.h42
-rw-r--r--src/qml/animations/qpauseanimationjob.cpp40
-rw-r--r--src/qml/animations/qpauseanimationjob_p.h42
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob.cpp121
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob_p.h48
-rw-r--r--src/qml/common/common.pri35
-rw-r--r--src/qml/common/qjsnumbercoercion.cpp62
-rw-r--r--src/qml/common/qjsnumbercoercion.h120
-rw-r--r--src/qml/common/qqmlapiversion_p.h56
-rw-r--r--src/qml/common/qqmljsdiagnosticmessage_p.h48
-rw-r--r--src/qml/common/qqmljsfixedpoolarray_p.h46
-rw-r--r--src/qml/common/qqmljsmemorypool_p.h66
-rw-r--r--src/qml/common/qqmljssourcelocation_p.h107
-rw-r--r--src/qml/common/qqmlsignalnames.cpp257
-rw-r--r--src/qml/common/qqmlsignalnames_p.h59
-rw-r--r--src/qml/common/qqmltranslation.cpp125
-rw-r--r--src/qml/common/qqmltranslation_p.h74
-rw-r--r--src/qml/common/qv4alloca_p.h46
-rw-r--r--src/qml/common/qv4calldata_p.h42
-rw-r--r--src/qml/common/qv4compileddata.cpp431
-rw-r--r--src/qml/common/qv4compileddata_p.h1104
-rw-r--r--src/qml/common/qv4staticvalue_p.h612
-rw-r--r--src/qml/common/qv4stringtoarrayindex_p.h46
-rw-r--r--src/qml/compat/removed_api.cpp42
-rw-r--r--src/qml/compiler/compiler.pri29
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp1188
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h479
-rw-r--r--src/qml/compiler/qv4bytecodegenerator.cpp92
-rw-r--r--src/qml/compiler/qv4bytecodegenerator_p.h81
-rw-r--r--src/qml/compiler/qv4bytecodehandler.cpp40
-rw-r--r--src/qml/compiler/qv4bytecodehandler_p.h47
-rw-r--r--src/qml/compiler/qv4codegen.cpp901
-rw-r--r--src/qml/compiler/qv4codegen_p.h188
-rw-r--r--src/qml/compiler/qv4compiler.cpp312
-rw-r--r--src/qml/compiler/qv4compiler_p.h61
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp86
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h96
-rw-r--r--src/qml/compiler/qv4compilercontrolflow_p.h51
-rw-r--r--src/qml/compiler/qv4compilerglobal_p.h40
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp164
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h66
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp292
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h85
-rw-r--r--src/qml/compiler/qv4util_p.h41
-rw-r--r--src/qml/configure.cmake195
-rw-r--r--src/qml/configure.json204
-rw-r--r--src/qml/debugger/debugger.pri28
-rw-r--r--src/qml/debugger/qqmlabstractprofileradapter.cpp40
-rw-r--r--src/qml/debugger/qqmlabstractprofileradapter_p.h50
-rw-r--r--src/qml/debugger/qqmlconfigurabledebugservice_p.h46
-rw-r--r--src/qml/debugger/qqmldebug.cpp74
-rw-r--r--src/qml/debugger/qqmldebug.h62
-rw-r--r--src/qml/debugger/qqmldebugconnector.cpp52
-rw-r--r--src/qml/debugger/qqmldebugconnector_p.h47
-rw-r--r--src/qml/debugger/qqmldebugpluginmanager_p.h51
-rw-r--r--src/qml/debugger/qqmldebugserver.cpp13
-rw-r--r--src/qml/debugger/qqmldebugserver_p.h43
-rw-r--r--src/qml/debugger/qqmldebugserverconnection.cpp16
-rw-r--r--src/qml/debugger/qqmldebugserverconnection_p.h46
-rw-r--r--src/qml/debugger/qqmldebugservice.cpp48
-rw-r--r--src/qml/debugger/qqmldebugservice_p.h48
-rw-r--r--src/qml/debugger/qqmldebugservicefactory.cpp13
-rw-r--r--src/qml/debugger/qqmldebugservicefactory_p.h43
-rw-r--r--src/qml/debugger/qqmldebugserviceinterfaces.cpp118
-rw-r--r--src/qml/debugger/qqmldebugserviceinterfaces_p.h130
-rw-r--r--src/qml/debugger/qqmldebugstatesdelegate_p.h41
-rw-r--r--src/qml/debugger/qqmldebugtranslationprotocol_p.h265
-rw-r--r--src/qml/debugger/qqmlprofiler.cpp40
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h59
-rw-r--r--src/qml/debugger/qqmlprofilerdefinitions_p.h58
-rw-r--r--src/qml/doc/images/cpp-qml-integration-flowchart.odgbin15028 -> 14138 bytes
-rw-r--r--src/qml/doc/images/cpp-qml-integration-flowchart.pngbin80498 -> 57846 bytes
-rw-r--r--src/qml/doc/images/cppintegration-ex.pngbin1777 -> 0 bytes
-rw-r--r--src/qml/doc/images/extending-qml-advanced-word-cloud.pngbin0 -> 73771 bytes
-rw-r--r--src/qml/doc/images/listmodel-nested.pngbin7493 -> 0 bytes
-rw-r--r--src/qml/doc/images/listmodel.pngbin3407 -> 0 bytes
-rw-r--r--src/qml/doc/images/objectmodel.pngbin347 -> 0 bytes
-rw-r--r--src/qml/doc/images/qmlsc-compilation-scheme.pngbin0 -> 43468 bytes
-rw-r--r--src/qml/doc/images/qmltc-compilation-scheme.pngbin0 -> 47278 bytes
-rw-r--r--src/qml/doc/images/statemachine-button-history.pngbin8074 -> 0 bytes
-rw-r--r--src/qml/doc/images/statemachine-button-nested.pngbin7051 -> 0 bytes
-rw-r--r--src/qml/doc/images/statemachine-button.pngbin4233 -> 0 bytes
-rw-r--r--src/qml/doc/images/statemachine-finished.pngbin5518 -> 0 bytes
-rw-r--r--src/qml/doc/images/statemachine-nonparallel.pngbin5350 -> 0 bytes
-rw-r--r--src/qml/doc/images/statemachine-parallel.pngbin8631 -> 0 bytes
-rw-r--r--src/qml/doc/qtqml.qdocconf41
-rw-r--r--src/qml/doc/snippets/cmake/qt_target_qml_sources/CMakeLists.txt46
-rw-r--r--src/qml/doc/snippets/cmake/qt_target_qml_sources/FunnySingleton.qml9
-rw-r--r--src/qml/doc/snippets/cmake/qt_target_qml_sources/TemplateFile.qml3
-rw-r--r--src/qml/doc/snippets/cmake/qt_target_qml_sources/doc/README.txt1
-rw-r--r--src/qml/doc/snippets/cmake/qt_target_qml_sources/nested/way/down/File.qml3
-rw-r--r--src/qml/doc/snippets/cmake/qt_target_qml_sources/some_old_thing.qml3
-rw-r--r--src/qml/doc/snippets/code/backend/backend.cpp71
-rw-r--r--src/qml/doc/snippets/code/backend/backend.h76
-rw-r--r--src/qml/doc/snippets/code/backend/main.cpp55
-rw-r--r--src/qml/doc/snippets/code/backend/main.qml57
-rw-r--r--src/qml/doc/snippets/code/doc_src_qtqml.cmake13
-rw-r--r--src/qml/doc/snippets/code/doc_src_qtqml.cpp53
-rw-r--r--src/qml/doc/snippets/code/doc_src_qtqml.pro3
-rw-r--r--src/qml/doc/snippets/code/src_network_access_qnetworkaccessmanager.cpp24
-rw-r--r--src/qml/doc/snippets/code/src_qml_qqmlengine.cpp51
-rw-r--r--src/qml/doc/snippets/code/src_qml_qqmllist.cpp47
-rw-r--r--src/qml/doc/snippets/code/src_qml_qqmlparserstatus.cpp19
-rw-r--r--src/qml/doc/snippets/code/src_script_qjsengine.cpp51
-rw-r--r--src/qml/doc/snippets/code/src_script_qjsvalue.cpp51
-rw-r--r--src/qml/doc/snippets/code/src_script_qjsvalueiterator.cpp51
-rw-r--r--src/qml/doc/snippets/qml/Button.qml53
-rw-r--r--src/qml/doc/snippets/qml/CMakeLists.txt15
-rw-r--r--src/qml/doc/snippets/qml/DynamicText.qml53
-rw-r--r--src/qml/doc/snippets/qml/MajorProject-CMakeLists.txt23
-rw-r--r--src/qml/doc/snippets/qml/SelfDestroyingRect.qml53
-rw-r--r--src/qml/doc/snippets/qml/Sprite.qml53
-rw-r--r--src/qml/doc/snippets/qml/XHRForm.qml83
-rw-r--r--src/qml/doc/snippets/qml/application.qml53
-rw-r--r--src/qml/doc/snippets/qml/comments.qml53
-rw-r--r--src/qml/doc/snippets/qml/component.qml53
-rw-r--r--src/qml/doc/snippets/qml/component/MyItem.qml53
-rw-r--r--src/qml/doc/snippets/qml/component/main.qml53
-rw-r--r--src/qml/doc/snippets/qml/createComponent-simple.qml53
-rw-r--r--src/qml/doc/snippets/qml/createComponent.qml53
-rw-r--r--src/qml/doc/snippets/qml/createQmlObject.qml68
-rw-r--r--src/qml/doc/snippets/qml/dynamicObjects-destroy.qml53
-rw-r--r--src/qml/doc/snippets/qml/events.qml59
-rw-r--r--src/qml/doc/snippets/qml/exposing-state/RequiredProperties.qml23
-rw-r--r--src/qml/doc/snippets/qml/exposing-state/createWithInitialProperties.cpp23
-rw-r--r--src/qml/doc/snippets/qml/exposing-state/singleton.h49
-rw-r--r--src/qml/doc/snippets/qml/exposing-state/useSingleton.qml9
-rw-r--r--src/qml/doc/snippets/qml/imports/chart.qml51
-rw-r--r--src/qml/doc/snippets/qml/imports/installed-module.qml53
-rw-r--r--src/qml/doc/snippets/qml/imports/merged-named-imports.qml55
-rw-r--r--src/qml/doc/snippets/qml/imports/named-imports.qml71
-rw-r--r--src/qml/doc/snippets/qml/imports/network-imports.qml51
-rw-r--r--src/qml/doc/snippets/qml/imports/qtquick-1.0.qml53
-rw-r--r--src/qml/doc/snippets/qml/imports/timeexample.qml51
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/connectjs.qml53
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/includejs/app.qml53
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/includejs/factorial.mjs51
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs56
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.cpp195
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.h56
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFive.qml57
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFour.js53
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFour.qml57
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleOne.qml57
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleThree.js53
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleThree.qml57
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleTwo.qml57
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/script.js51
-rw-r--r--src/qml/doc/snippets/qml/myProject-CMakeLists.txt13
-rw-r--r--src/qml/doc/snippets/qml/myimageprovider.txt15
-rw-r--r--src/qml/doc/snippets/qml/plugin.cpp.txt14
-rw-r--r--src/qml/doc/snippets/qml/properties.qml71
-rw-r--r--src/qml/doc/snippets/qml/qml-documents/A.qml14
-rw-r--r--src/qml/doc/snippets/qml/qml-documents/B.qml11
-rw-r--r--src/qml/doc/snippets/qml/qml-documents/Images.qml37
-rw-r--r--src/qml/doc/snippets/qml/qml-documents/LabeledImageBox.qml17
-rw-r--r--src/qml/doc/snippets/qml/qml-documents/inline-component.qml53
-rw-r--r--src/qml/doc/snippets/qml/qml-documents/inline-text-component.qml53
-rw-r--r--src/qml/doc/snippets/qml/qml-documents/non-trivial.qml53
-rw-r--r--src/qml/doc/snippets/qml/qml-documents/qmldocuments.qml53
-rw-r--r--src/qml/doc/snippets/qml/qsTr.qml53
-rw-r--r--src/qml/doc/snippets/qml/qsTrId.1.qml53
-rw-r--r--src/qml/doc/snippets/qml/qsTrId.qml53
-rw-r--r--src/qml/doc/snippets/qml/qsTranslate.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtBinding.1.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtBinding.2.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtBinding.3.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtBinding.4.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtLater.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtTrIdNoOp.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtTrNoOp.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtTranslateNoOp.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/context-advanced/MyItem.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/context-advanced/applicationdata.h51
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/context-advanced/connections.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/context-advanced/main.cpp51
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/context/MyItem.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/context/main.cpp51
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/functions-qml/MyItem.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/functions-qml/main.cpp51
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/loading/MyItem.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/loading/main.cpp51
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/properties-qml/MyItem.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/properties-qml/main.cpp51
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/resources/example.qdoc28
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/signals-qml/MyItem.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/signals-qml/main.cpp51
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/signals-qml/myclass.h51
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/variantlistmap/MyItem.qml53
-rw-r--r--src/qml/doc/snippets/qml/qtbinding/variantlistmap/main.cpp51
-rw-r--r--src/qml/doc/snippets/qml/qtobject.qml53
-rw-r--r--src/qml/doc/snippets/qml/reusablecomponents/Button.qml53
-rw-r--r--src/qml/doc/snippets/qml/reusablecomponents/application.qml53
-rw-r--r--src/qml/doc/snippets/qml/reusablecomponents/component.qml53
-rw-r--r--src/qml/doc/snippets/qml/reusablecomponents/focusbutton.qml53
-rw-r--r--src/qml/doc/snippets/qml/statemachine/Button.qml98
-rw-r--r--src/qml/doc/snippets/qml/statemachine/basicstate.qml65
-rw-r--r--src/qml/doc/snippets/qml/statemachine/finalstate.qml73
-rw-r--r--src/qml/doc/snippets/qml/statemachine/guardcondition.qml78
-rw-r--r--src/qml/doc/snippets/qml/statemachine/historystate.qml95
-rw-r--r--src/qml/doc/snippets/qml/statemachine/signaltransition.qml87
-rw-r--r--src/qml/doc/snippets/qml/statemachine/signaltransitionsignal.qml72
-rw-r--r--src/qml/doc/snippets/qml/statemachine/simplestatemachine.qml78
-rw-r--r--src/qml/doc/snippets/qml/statemachine/statemachine-button-history.qml159
-rw-r--r--src/qml/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml144
-rw-r--r--src/qml/doc/snippets/qml/statemachine/statemachine-button-nested.qml136
-rw-r--r--src/qml/doc/snippets/qml/statemachine/statemachine-button.qml110
-rw-r--r--src/qml/doc/snippets/qml/statemachine/timeouttransition.qml79
-rw-r--r--src/qml/doc/snippets/qml/workerscript/script.mjs4
-rw-r--r--src/qml/doc/snippets/qml/workerscript/workerscript.qml74
-rw-r--r--src/qml/doc/snippets/qml/xmlhttprequest.js25
-rw-r--r--src/qml/doc/snippets/qmllint/config.ini19
-rw-r--r--src/qml/doc/snippets/qmltc/CMakeLists.txt62
-rw-r--r--src/qml/doc/snippets/qmltc/MyButton.qml30
-rw-r--r--src/qml/doc/snippets/qmltc/MySlider.qml50
-rw-r--r--src/qml/doc/snippets/qmltc/colorpicker.cpp29
-rw-r--r--src/qml/doc/snippets/qmltc/colorpicker.h27
-rw-r--r--src/qml/doc/snippets/qmltc/myApp.qml73
-rw-r--r--src/qml/doc/snippets/qmltc/special/HelloWorld.qml19
-rw-r--r--src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp38
-rw-r--r--src/qml/doc/snippets/qmltc/tst_qmltc_examples.cpp179
-rw-r--r--src/qml/doc/snippets/qtjavascript/evaluation/main.cpp51
-rw-r--r--src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsascontainer.cpp24
-rw-r--r--src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsengine.cpp21
-rw-r--r--src/qml/doc/snippets/qtjavascript/integratingjswithcpp/qjsengine.cpp16
-rw-r--r--src/qml/doc/snippets/qtjavascript/registeringobjects/main.cpp51
-rw-r--r--src/qml/doc/snippets/qtjavascript/registeringvalues/main.cpp51
-rw-r--r--src/qml/doc/src/cmake/cmake-properties.qdoc208
-rw-r--r--src/qml/doc/src/cmake/cmake-variables.qdoc76
-rw-r--r--src/qml/doc/src/cmake/policy/qtp0001.qdoc39
-rw-r--r--src/qml/doc/src/cmake/policy/qtp0004.qdoc34
-rw-r--r--src/qml/doc/src/cmake/qt_add_qml_module.qdoc759
-rw-r--r--src/qml/doc/src/cmake/qt_add_qml_plugin.qdoc120
-rw-r--r--src/qml/doc/src/cmake/qt_deploy_qml_imports.qdoc116
-rw-r--r--src/qml/doc/src/cmake/qt_generate_deploy_qml_app_script.qdoc177
-rw-r--r--src/qml/doc/src/cmake/qt_generate_foreign_qml_types.qdoc77
-rw-r--r--src/qml/doc/src/cmake/qt_import_qml_plugins.qdoc55
-rw-r--r--src/qml/doc/src/cmake/qt_query_qml_module.qdoc213
-rw-r--r--src/qml/doc/src/cmake/qt_target_compile_qml_to_cpp.qdoc14
-rw-r--r--src/qml/doc/src/cmake/qt_target_qml_sources.qdoc206
-rw-r--r--src/qml/doc/src/cppclasses/topic.qdoc32
-rw-r--r--src/qml/doc/src/cppintegration/contextproperties.qdoc45
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc265
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc428
-rw-r--r--src/qml/doc/src/cppintegration/exposecppattributes.qdoc163
-rw-r--r--src/qml/doc/src/cppintegration/exposecppstate.qdoc66
-rw-r--r--src/qml/doc/src/cppintegration/extending-tutorial-advanced.qdoc380
-rw-r--r--src/qml/doc/src/cppintegration/extending-tutorial.qdoc225
-rw-r--r--src/qml/doc/src/cppintegration/integrating-with-js-values-from-cpp.qdoc162
-rw-r--r--src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc121
-rw-r--r--src/qml/doc/src/cppintegration/topic.qdoc111
-rw-r--r--src/qml/doc/src/examples.qdoc71
-rw-r--r--src/qml/doc/src/external-resources.qdoc96
-rw-r--r--src/qml/doc/src/includes/cmake-find-package-qml.qdocinc6
-rw-r--r--src/qml/doc/src/includes/cmake-qml-qt-finalize-target-warning.qdocinc9
-rw-r--r--src/qml/doc/src/includes/qqmlcomponent.qdoc51
-rw-r--r--src/qml/doc/src/includes/qualified-class-name.qdocinc7
-rw-r--r--src/qml/doc/src/javascript/date.qdoc132
-rw-r--r--src/qml/doc/src/javascript/dynamicobjectcreation.qdoc38
-rw-r--r--src/qml/doc/src/javascript/expressions.qdoc36
-rw-r--r--src/qml/doc/src/javascript/finetuning.qdoc67
-rw-r--r--src/qml/doc/src/javascript/functionlist.qdoc36
-rw-r--r--src/qml/doc/src/javascript/hostenvironment.qdoc74
-rw-r--r--src/qml/doc/src/javascript/imports.qdoc55
-rw-r--r--src/qml/doc/src/javascript/memory.qdoc211
-rw-r--r--src/qml/doc/src/javascript/number.qdoc53
-rw-r--r--src/qml/doc/src/javascript/qmlglobalobject.qdoc135
-rw-r--r--src/qml/doc/src/javascript/qtjavascript.qdoc28
-rw-r--r--src/qml/doc/src/javascript/resources.qdoc28
-rw-r--r--src/qml/doc/src/javascript/string.qdoc50
-rw-r--r--src/qml/doc/src/javascript/topic.qdoc55
-rw-r--r--src/qml/doc/src/javascript/xmlhttprequest.qdoc301
-rw-r--r--src/qml/doc/src/qmldiskcache.qdoc120
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc977
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc152
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc31
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/scope.qdoc29
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/structure.qdoc319
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/topic.qdoc34
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/cppplugins.qdoc33
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc48
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/legacymodules.qdoc28
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc650
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc120
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/topic.qdoc28
-rw-r--r--src/qml/doc/src/qmllanguageref/qmlreference.qdoc35
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/basics.qdoc37
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc52
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/imports.qdoc112
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc270
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc28
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/signals.qdoc204
-rw-r--r--src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc681
-rw-r--r--src/qml/doc/src/qmllanguageref/typesystem/namespaces.qdoc16
-rw-r--r--src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc33
-rw-r--r--src/qml/doc/src/qmllanguageref/typesystem/references.qdoc53
-rw-r--r--src/qml/doc/src/qmllanguageref/typesystem/sequencetypes.qdoc76
-rw-r--r--src/qml/doc/src/qmllanguageref/typesystem/topic.qdoc78
-rw-r--r--src/qml/doc/src/qmllanguageref/typesystem/valuetypes.qdoc606
-rw-r--r--src/qml/doc/src/qmllint/access-singleton-via-object.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/alias-cycle.qdoc60
-rw-r--r--src/qml/doc/src/qmllint/attached-property-reuse.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/compiler.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/deferred-property-id.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/deprecated.qdoc23
-rw-r--r--src/qml/doc/src/qmllint/duplicate-property-binding.qdoc122
-rw-r--r--src/qml/doc/src/qmllint/duplicated-name.qdoc70
-rw-r--r--src/qml/doc/src/qmllint/import.qdoc174
-rw-r--r--src/qml/doc/src/qmllint/incompatible-type.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/inheritance-cycle.qdoc46
-rw-r--r--src/qml/doc/src/qmllint/invalid-lint-directive.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/missing-enum-entry.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/missing-property.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/missing-type.qdoc240
-rw-r--r--src/qml/doc/src/qmllint/multiline-strings.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/non-list-property.qdoc85
-rw-r--r--src/qml/doc/src/qmllint/plugin.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/prefixed-import-type.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/qtqml-qmllint-warnings-and-errors.qdoc9
-rw-r--r--src/qml/doc/src/qmllint/read-only-property.qdoc38
-rw-r--r--src/qml/doc/src/qmllint/recursion-depth-errors.qdoc53
-rw-r--r--src/qml/doc/src/qmllint/required.qdoc65
-rw-r--r--src/qml/doc/src/qmllint/restricted-type.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/signal-handler-parameters.qdoc261
-rw-r--r--src/qml/doc/src/qmllint/syntax.duplicate-ids.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/syntax.id-quotation.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/syntax.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/top-level-component.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/uncreatable-type.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/unqualified.qdoc52
-rw-r--r--src/qml/doc/src/qmllint/unresolved-alias.qdoc50
-rw-r--r--src/qml/doc/src/qmllint/unresolved-type.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/unused-imports.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/use-proper-function.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/var-used-before-declaration.qdoc26
-rw-r--r--src/qml/doc/src/qmllint/with.qdoc50
-rw-r--r--src/qml/doc/src/qmlsa-plugin-system.md124
-rw-r--r--src/qml/doc/src/qmlsingletons.qdoc339
-rw-r--r--src/qml/doc/src/qmltypereference.qdoc136
-rw-r--r--src/qml/doc/src/qt6-changes.qdoc257
-rw-r--r--src/qml/doc/src/qtqml-cpp.qdoc43
-rw-r--r--src/qml/doc/src/qtqml-qtquick-compiler-tech.qdoc123
-rw-r--r--src/qml/doc/src/qtqml-tooling.qdoc48
-rw-r--r--src/qml/doc/src/qtqml-writing-a-module.qdoc461
-rw-r--r--src/qml/doc/src/qtqml.qdoc175
-rw-r--r--src/qml/doc/src/statemachine.qdoc328
-rw-r--r--src/qml/doc/src/tools/qtqml-tooling-qml.qdoc107
-rw-r--r--src/qml/doc/src/tools/qtqml-tooling-qmlformat.qdoc146
-rw-r--r--src/qml/doc/src/tools/qtqml-tooling-qmlimportscanner.qdoc15
-rw-r--r--src/qml/doc/src/tools/qtqml-tooling-qmllint.qdoc141
-rw-r--r--src/qml/doc/src/tools/qtqml-tooling-qmlls.qdoc168
-rw-r--r--src/qml/doc/src/tools/qtqml-tooling-qmlpreview.qdoc74
-rw-r--r--src/qml/doc/src/tools/qtqml-tooling-qmlprofiler.qdoc10
-rw-r--r--src/qml/doc/src/tools/qtqml-tooling-qmltyperegistrar.qdoc10
-rw-r--r--src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc92
-rw-r--r--src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-script-compiler.qdoc120
-rw-r--r--src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc283
-rw-r--r--src/qml/doc/src/tools/qtquickcompiler/qtqml-tool-qmlcachegen.qdoc13
-rw-r--r--src/qml/inlinecomponentutils_p.h161
-rw-r--r--src/qml/jit/jit.pri12
-rw-r--r--src/qml/jit/qv4assemblercommon.cpp78
-rw-r--r--src/qml/jit/qv4assemblercommon_p.h72
-rw-r--r--src/qml/jit/qv4baselineassembler.cpp117
-rw-r--r--src/qml/jit/qv4baselineassembler_p.h45
-rw-r--r--src/qml/jit/qv4baselinejit.cpp102
-rw-r--r--src/qml/jit/qv4baselinejit_p.h57
-rw-r--r--src/qml/jsapi/jsapi.pri12
-rw-r--r--src/qml/jsapi/qjsengine.cpp765
-rw-r--r--src/qml/jsapi/qjsengine.h346
-rw-r--r--src/qml/jsapi/qjsengine_p.h151
-rw-r--r--src/qml/jsapi/qjslist.cpp18
-rw-r--r--src/qml/jsapi/qjslist.h368
-rw-r--r--src/qml/jsapi/qjsmanagedvalue.cpp1145
-rw-r--r--src/qml/jsapi/qjsmanagedvalue.h130
-rw-r--r--src/qml/jsapi/qjsprimitivevalue.cpp340
-rw-r--r--src/qml/jsapi/qjsprimitivevalue.h966
-rw-r--r--src/qml/jsapi/qjsvalue.cpp786
-rw-r--r--src/qml/jsapi/qjsvalue.h84
-rw-r--r--src/qml/jsapi/qjsvalue_p.h425
-rw-r--r--src/qml/jsapi/qjsvalueiterator.cpp46
-rw-r--r--src/qml/jsapi/qjsvalueiterator.h40
-rw-r--r--src/qml/jsapi/qjsvalueiterator_p.h40
-rw-r--r--src/qml/jsruntime/jsruntime.pri174
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp66
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h45
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp125
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h115
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp157
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h112
-rw-r--r--src/qml/jsruntime/qv4arrayiterator.cpp49
-rw-r--r--src/qml/jsruntime/qv4arrayiterator_p.h45
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp202
-rw-r--r--src/qml/jsruntime/qv4arrayobject_p.h65
-rw-r--r--src/qml/jsruntime/qv4atomics.cpp50
-rw-r--r--src/qml/jsruntime/qv4atomics_p.h40
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp41
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h40
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper.cpp109
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper_p.h54
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper_unix.cpp63
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper_win.cpp75
-rw-r--r--src/qml/jsruntime/qv4context.cpp81
-rw-r--r--src/qml/jsruntime/qv4context_p.h50
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp93
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h42
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp380
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h221
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp17
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h46
-rw-r--r--src/qml/jsruntime/qv4domerrors.cpp (renamed from src/qml/qml/v8/qv4domerrors.cpp)40
-rw-r--r--src/qml/jsruntime/qv4domerrors_p.h57
-rw-r--r--src/qml/jsruntime/qv4engine.cpp1706
-rw-r--r--src/qml/jsruntime/qv4engine_p.h342
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h68
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp49
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h43
-rw-r--r--src/qml/jsruntime/qv4estable.cpp63
-rw-r--r--src/qml/jsruntime/qv4estable_p.h51
-rw-r--r--src/qml/jsruntime/qv4executableallocator.cpp58
-rw-r--r--src/qml/jsruntime/qv4executableallocator_p.h60
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp745
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit_p.h343
-rw-r--r--src/qml/jsruntime/qv4function.cpp221
-rw-r--r--src/qml/jsruntime/qv4function_p.h101
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp213
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h82
-rw-r--r--src/qml/jsruntime/qv4functiontable_noop.cpp40
-rw-r--r--src/qml/jsruntime/qv4functiontable_p.h42
-rw-r--r--src/qml/jsruntime/qv4functiontable_unix.cpp40
-rw-r--r--src/qml/jsruntime/qv4functiontable_win64.cpp46
-rw-r--r--src/qml/jsruntime/qv4generatorobject.cpp88
-rw-r--r--src/qml/jsruntime/qv4generatorobject_p.h48
-rw-r--r--src/qml/jsruntime/qv4global_p.h69
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp108
-rw-r--r--src/qml/jsruntime/qv4globalobject_p.h42
-rw-r--r--src/qml/jsruntime/qv4identifier.cpp207
-rw-r--r--src/qml/jsruntime/qv4identifier_p.h173
-rw-r--r--src/qml/jsruntime/qv4identifierhash.cpp190
-rw-r--r--src/qml/jsruntime/qv4identifierhash_p.h63
-rw-r--r--src/qml/jsruntime/qv4identifierhashdata_p.h86
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp90
-rw-r--r--src/qml/jsruntime/qv4identifiertable_p.h51
-rw-r--r--src/qml/jsruntime/qv4include.cpp124
-rw-r--r--src/qml/jsruntime/qv4include_p.h54
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp351
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h146
-rw-r--r--src/qml/jsruntime/qv4iterator.cpp40
-rw-r--r--src/qml/jsruntime/qv4iterator_p.h41
-rw-r--r--src/qml/jsruntime/qv4jscall.cpp46
-rw-r--r--src/qml/jsruntime/qv4jscall_p.h638
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp272
-rw-r--r--src/qml/jsruntime/qv4jsonobject_p.h49
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp306
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h196
-rw-r--r--src/qml/jsruntime/qv4managed.cpp54
-rw-r--r--src/qml/jsruntime/qv4managed_p.h59
-rw-r--r--src/qml/jsruntime/qv4mapiterator.cpp40
-rw-r--r--src/qml/jsruntime/qv4mapiterator_p.h42
-rw-r--r--src/qml/jsruntime/qv4mapobject.cpp46
-rw-r--r--src/qml/jsruntime/qv4mapobject_p.h42
-rw-r--r--src/qml/jsruntime/qv4math_p.h49
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp168
-rw-r--r--src/qml/jsruntime/qv4mathobject_p.h40
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp42
-rw-r--r--src/qml/jsruntime/qv4memberdata_p.h44
-rw-r--r--src/qml/jsruntime/qv4module.cpp76
-rw-r--r--src/qml/jsruntime/qv4module_p.h40
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp47
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h40
-rw-r--r--src/qml/jsruntime/qv4object.cpp231
-rw-r--r--src/qml/jsruntime/qv4object_p.h56
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp47
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h40
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp94
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h42
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp182
-rw-r--r--src/qml/jsruntime/qv4persistent_p.h82
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp51
-rw-r--r--src/qml/jsruntime/qv4profiling_p.h95
-rw-r--r--src/qml/jsruntime/qv4promiseobject.cpp136
-rw-r--r--src/qml/jsruntime/qv4promiseobject_p.h44
-rw-r--r--src/qml/jsruntime/qv4property_p.h42
-rw-r--r--src/qml/jsruntime/qv4propertykey.cpp55
-rw-r--r--src/qml/jsruntime/qv4propertykey_p.h138
-rw-r--r--src/qml/jsruntime/qv4proxy.cpp165
-rw-r--r--src/qml/jsruntime/qv4proxy_p.h40
-rw-r--r--src/qml/jsruntime/qv4qmetaobjectwrapper.cpp126
-rw-r--r--src/qml/jsruntime/qv4qmetaobjectwrapper_p.h66
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp535
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h75
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp2823
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h397
-rw-r--r--src/qml/jsruntime/qv4referenceobject.cpp10
-rw-r--r--src/qml/jsruntime/qv4referenceobject_p.h171
-rw-r--r--src/qml/jsruntime/qv4reflect.cpp57
-rw-r--r--src/qml/jsruntime/qv4reflect_p.h40
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp148
-rw-r--r--src/qml/jsruntime/qv4regexp_p.h46
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp202
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h86
-rw-r--r--src/qml/jsruntime/qv4resolvedtypereference.cpp98
-rw-r--r--src/qml/jsruntime/qv4resolvedtypereference_p.h113
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp502
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h43
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h248
-rw-r--r--src/qml/jsruntime/qv4runtimecodegen.cpp44
-rw-r--r--src/qml/jsruntime/qv4runtimecodegen_p.h44
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h61
-rw-r--r--src/qml/jsruntime/qv4script.cpp85
-rw-r--r--src/qml/jsruntime/qv4script_p.h48
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp1202
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h168
-rw-r--r--src/qml/jsruntime/qv4setiterator.cpp40
-rw-r--r--src/qml/jsruntime/qv4setiterator_p.h42
-rw-r--r--src/qml/jsruntime/qv4setobject.cpp49
-rw-r--r--src/qml/jsruntime/qv4setobject_p.h40
-rw-r--r--src/qml/jsruntime/qv4sparsearray.cpp46
-rw-r--r--src/qml/jsruntime/qv4sparsearray_p.h92
-rw-r--r--src/qml/jsruntime/qv4sqlerrors.cpp27
-rw-r--r--src/qml/jsruntime/qv4sqlerrors_p.h38
-rw-r--r--src/qml/jsruntime/qv4stackframe.cpp96
-rw-r--r--src/qml/jsruntime/qv4stackframe_p.h328
-rw-r--r--src/qml/jsruntime/qv4string.cpp120
-rw-r--r--src/qml/jsruntime/qv4string_p.h107
-rw-r--r--src/qml/jsruntime/qv4stringiterator.cpp44
-rw-r--r--src/qml/jsruntime/qv4stringiterator_p.h42
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp176
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h42
-rw-r--r--src/qml/jsruntime/qv4symbol.cpp49
-rw-r--r--src/qml/jsruntime/qv4symbol_p.h42
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp570
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h66
-rw-r--r--src/qml/jsruntime/qv4urlobject.cpp1539
-rw-r--r--src/qml/jsruntime/qv4urlobject_p.h293
-rw-r--r--src/qml/jsruntime/qv4value.cpp192
-rw-r--r--src/qml/jsruntime/qv4value_p.h139
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp80
-rw-r--r--src/qml/jsruntime/qv4variantobject_p.h44
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp243
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h46
-rw-r--r--src/qml/jsruntime/qv4vtable_p.h122
-rw-r--r--src/qml/memory/design.md125
-rw-r--r--src/qml/memory/memory.pri11
-rw-r--r--src/qml/memory/qv4heap_p.h73
-rw-r--r--src/qml/memory/qv4mm.cpp698
-rw-r--r--src/qml/memory/qv4mm_p.h264
-rw-r--r--src/qml/memory/qv4mmdefs_p.h113
-rw-r--r--src/qml/memory/qv4stacklimits.cpp382
-rw-r--r--src/qml/memory/qv4stacklimits_p.h74
-rw-r--r--src/qml/memory/qv4writebarrier.cpp36
-rw-r--r--src/qml/memory/qv4writebarrier_p.h182
-rw-r--r--src/qml/parser/parser.pri25
-rw-r--r--src/qml/parser/qqmljs.g966
-rw-r--r--src/qml/parser/qqmljsast.cpp419
-rw-r--r--src/qml/parser/qqmljsast_p.h907
-rw-r--r--src/qml/parser/qqmljsastfwd_p.h52
-rw-r--r--src/qml/parser/qqmljsastvisitor.cpp46
-rw-r--r--src/qml/parser/qqmljsastvisitor_p.h539
-rw-r--r--src/qml/parser/qqmljsengine_p.cpp158
-rw-r--r--src/qml/parser/qqmljsengine_p.h96
-rw-r--r--src/qml/parser/qqmljsglobal_p.h67
-rw-r--r--src/qml/parser/qqmljskeywords_p.h59
-rw-r--r--src/qml/parser/qqmljslexer.cpp1395
-rw-r--r--src/qml/parser/qqmljslexer_p.h234
-rw-r--r--src/qml/parser/qqmljssourcelocation_p.h87
-rw-r--r--src/qml/qml.pro70
-rw-r--r--src/qml/qml/ftw/ftw.pri26
-rw-r--r--src/qml/qml/ftw/qbipointer_p.h203
-rw-r--r--src/qml/qml/ftw/qbitfield_p.h167
-rw-r--r--src/qml/qml/ftw/qdoubleendedlist_p.h256
-rw-r--r--src/qml/qml/ftw/qfieldlist_p.h171
-rw-r--r--src/qml/qml/ftw/qfinitestack_p.h42
-rw-r--r--src/qml/qml/ftw/qflagpointer_p.h350
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp138
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h121
-rw-r--r--src/qml/qml/ftw/qintrusivelist.cpp40
-rw-r--r--src/qml/qml/ftw/qintrusivelist_p.h326
-rw-r--r--src/qml/qml/ftw/qlazilyallocated_p.h109
-rw-r--r--src/qml/qml/ftw/qlinkedstringhash_p.h42
-rw-r--r--src/qml/qml/ftw/qpodvector_p.h42
-rw-r--r--src/qml/qml/ftw/qprimefornumbits_p.h40
-rw-r--r--src/qml/qml/ftw/qqmlnullablevalue_p.h113
-rw-r--r--src/qml/qml/ftw/qqmlrefcount_p.h146
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp167
-rw-r--r--src/qml/qml/ftw/qqmlthread_p.h268
-rw-r--r--src/qml/qml/ftw/qrecursionwatcher_p.h42
-rw-r--r--src/qml/qml/ftw/qrecyclepool_p.h76
-rw-r--r--src/qml/qml/ftw/qstringhash_p.h140
-rw-r--r--src/qml/qml/qml.pri194
-rw-r--r--src/qml/qml/qqml.cpp2441
-rw-r--r--src/qml/qml/qqml.h792
-rw-r--r--src/qml/qml/qqmlabstractbinding.cpp174
-rw-r--r--src/qml/qml/qqmlabstractbinding_p.h120
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor.cpp40
-rw-r--r--src/qml/qml/qqmlabstracturlinterceptor.h43
-rw-r--r--src/qml/qml/qqmlanybinding_p.h473
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp276
-rw-r--r--src/qml/qml/qqmlapplicationengine.h49
-rw-r--r--src/qml/qml/qqmlapplicationengine_p.h53
-rw-r--r--src/qml/qml/qqmlbinding.cpp709
-rw-r--r--src/qml/qml/qqmlbinding_p.h129
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp241
-rw-r--r--src/qml/qml/qqmlboundsignal_p.h89
-rw-r--r--src/qml/qml/qqmlboundsignalexpressionpointer_p.h81
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions.cpp (renamed from src/qml/qml/v8/qqmlbuiltinfunctions.cpp)1875
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions_p.h265
-rw-r--r--src/qml/qml/qqmlcleanup.cpp116
-rw-r--r--src/qml/qml/qqmlcleanup_p.h84
-rw-r--r--src/qml/qml/qqmlcomponent.cpp897
-rw-r--r--src/qml/qml/qqmlcomponent.h68
-rw-r--r--src/qml/qml/qqmlcomponent_p.h283
-rw-r--r--src/qml/qml/qqmlcomponentandaliasresolver_p.h480
-rw-r--r--src/qml/qml/qqmlcomponentattached_p.h81
-rw-r--r--src/qml/qml/qqmlcontext.cpp835
-rw-r--r--src/qml/qml/qqmlcontext.h55
-rw-r--r--src/qml/qml/qqmlcontext_p.h382
-rw-r--r--src/qml/qml/qqmlcontextdata.cpp346
-rw-r--r--src/qml/qml/qqmlcontextdata_p.h468
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp153
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h58
-rw-r--r--src/qml/qml/qqmldata_p.h258
-rw-r--r--src/qml/qml/qqmldatablob.cpp128
-rw-r--r--src/qml/qml/qqmldatablob_p.h64
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp97
-rw-r--r--src/qml/qml/qqmldelayedcallqueue_p.h45
-rw-r--r--src/qml/qml/qqmldirdata.cpp70
-rw-r--r--src/qml/qml/qqmldirdata_p.h72
-rw-r--r--src/qml/qml/qqmlengine.cpp1803
-rw-r--r--src/qml/qml/qqmlengine.h100
-rw-r--r--src/qml/qml/qqmlengine_p.h417
-rw-r--r--src/qml/qml/qqmlenumdata_p.h40
-rw-r--r--src/qml/qml/qqmlenumvalue_p.h41
-rw-r--r--src/qml/qml/qqmlerror.cpp78
-rw-r--r--src/qml/qml/qqmlerror.h53
-rw-r--r--src/qml/qml/qqmlexpression.cpp97
-rw-r--r--src/qml/qml/qqmlexpression.h43
-rw-r--r--src/qml/qml/qqmlexpression_p.h46
-rw-r--r--src/qml/qml/qqmlextensioninterface.cpp17
-rw-r--r--src/qml/qml/qqmlextensioninterface.h46
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp115
-rw-r--r--src/qml/qml/qqmlextensionplugin.h53
-rw-r--r--src/qml/qml/qqmlextensionplugin_p.h42
-rw-r--r--src/qml/qml/qqmlfile.cpp420
-rw-r--r--src/qml/qml/qqmlfile.h46
-rw-r--r--src/qml/qml/qqmlfileselector.cpp115
-rw-r--r--src/qml/qml/qqmlfileselector.h48
-rw-r--r--src/qml/qml/qqmlfileselector_p.h46
-rw-r--r--src/qml/qml/qqmlfinalizer.cpp59
-rw-r--r--src/qml/qml/qqmlfinalizer_p.h34
-rw-r--r--src/qml/qml/qqmlglobal.cpp923
-rw-r--r--src/qml/qml/qqmlglobal_p.h180
-rw-r--r--src/qml/qml/qqmlguard_p.h162
-rw-r--r--src/qml/qml/qqmlguardedcontextdata_p.h95
-rw-r--r--src/qml/qml/qqmlimport.cpp1964
-rw-r--r--src/qml/qml/qqmlimport_p.h405
-rw-r--r--src/qml/qml/qqmlincubator.cpp225
-rw-r--r--src/qml/qml/qqmlincubator.h44
-rw-r--r--src/qml/qml/qqmlincubator_p.h72
-rw-r--r--src/qml/qml/qqmlinfo.cpp133
-rw-r--r--src/qml/qml/qqmlinfo.h86
-rw-r--r--src/qml/qml/qqmlirloader.cpp149
-rw-r--r--src/qml/qml/qqmlirloader_p.h42
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp381
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h127
-rw-r--r--src/qml/qml/qqmllist.cpp350
-rw-r--r--src/qml/qml/qqmllist.h228
-rw-r--r--src/qml/qml/qqmllist_p.h230
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp741
-rw-r--r--src/qml/qml/qqmllistwrapper_p.h89
-rw-r--r--src/qml/qml/qqmllocale.cpp640
-rw-r--r--src/qml/qml/qqmllocale_p.h287
-rw-r--r--src/qml/qml/qqmlloggingcategory.cpp91
-rw-r--r--src/qml/qml/qqmlloggingcategory_p.h49
-rw-r--r--src/qml/qml/qqmlmetamoduleregistration.cpp26
-rw-r--r--src/qml/qml/qqmlmetaobject.cpp298
-rw-r--r--src/qml/qml/qqmlmetaobject_p.h217
-rw-r--r--src/qml/qml/qqmlmetatype.cpp1674
-rw-r--r--src/qml/qml/qqmlmetatype_p.h352
-rw-r--r--src/qml/qml/qqmlmetatypedata.cpp219
-rw-r--r--src/qml/qml/qqmlmetatypedata_p.h127
-rw-r--r--src/qml/qml/qqmlmoduleregistration.cpp68
-rw-r--r--src/qml/qml/qqmlmoduleregistration.h52
-rw-r--r--src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp55
-rw-r--r--src/qml/qml/qqmlnetworkaccessmanagerfactory.h40
-rw-r--r--src/qml/qml/qqmlnotifier.cpp52
-rw-r--r--src/qml/qml/qqmlnotifier_p.h57
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp1286
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h240
-rw-r--r--src/qml/qml/qqmlobjectorgadget.cpp45
-rw-r--r--src/qml/qml/qqmlobjectorgadget_p.h56
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp234
-rw-r--r--src/qml/qml/qqmlopenmetaobject_p.h65
-rw-r--r--src/qml/qml/qqmlparserstatus.cpp54
-rw-r--r--src/qml/qml/qqmlparserstatus.h40
-rw-r--r--src/qml/qml/qqmlplatform.cpp44
-rw-r--r--src/qml/qml/qqmlplatform_p.h46
-rw-r--r--src/qml/qml/qqmlpluginimporter.cpp612
-rw-r--r--src/qml/qml/qqmlpluginimporter_p.h81
-rw-r--r--src/qml/qml/qqmlprivate.h889
-rw-r--r--src/qml/qml/qqmlproperty.cpp1149
-rw-r--r--src/qml/qml/qqmlproperty.h63
-rw-r--r--src/qml/qml/qqmlproperty_p.h119
-rw-r--r--src/qml/qml/qqmlpropertybinding.cpp383
-rw-r--r--src/qml/qml/qqmlpropertybinding_p.h421
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp872
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h394
-rw-r--r--src/qml/qml/qqmlpropertycachecreator.cpp163
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h961
-rw-r--r--src/qml/qml/qqmlpropertycachemethodarguments_p.h52
-rw-r--r--src/qml/qml/qqmlpropertycachevector_p.h159
-rw-r--r--src/qml/qml/qqmlpropertydata_p.h416
-rw-r--r--src/qml/qml/qqmlpropertyindex_p.h40
-rw-r--r--src/qml/qml/qqmlpropertyresolver.cpp56
-rw-r--r--src/qml/qml/qqmlpropertyresolver_p.h50
-rw-r--r--src/qml/qml/qqmlpropertytopropertybinding.cpp128
-rw-r--r--src/qml/qml/qqmlpropertytopropertybinding_p.h64
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp509
-rw-r--r--src/qml/qml/qqmlpropertyvalidator_p.h72
-rw-r--r--src/qml/qml/qqmlpropertyvalueinterceptor.cpp57
-rw-r--r--src/qml/qml/qqmlpropertyvalueinterceptor_p.h44
-rw-r--r--src/qml/qml/qqmlpropertyvaluesource.cpp42
-rw-r--r--src/qml/qml/qqmlpropertyvaluesource.h40
-rw-r--r--src/qml/qml/qqmlproxymetaobject.cpp179
-rw-r--r--src/qml/qml/qqmlproxymetaobject_p.h72
-rw-r--r--src/qml/qml/qqmlregistration.h15
-rw-r--r--src/qml/qml/qqmlscriptblob.cpp146
-rw-r--r--src/qml/qml/qqmlscriptblob_p.h46
-rw-r--r--src/qml/qml/qqmlscriptdata.cpp136
-rw-r--r--src/qml/qml/qqmlscriptdata_p.h72
-rw-r--r--src/qml/qml/qqmlscriptstring.cpp64
-rw-r--r--src/qml/qml/qqmlscriptstring.h43
-rw-r--r--src/qml/qml/qqmlscriptstring_p.h41
-rw-r--r--src/qml/qml/qqmlsourcecoordinate_p.h42
-rw-r--r--src/qml/qml/qqmlstaticmetaobject.cpp51
-rw-r--r--src/qml/qml/qqmlstaticmetaobject_p.h68
-rw-r--r--src/qml/qml/qqmlstringconverters.cpp231
-rw-r--r--src/qml/qml/qqmlstringconverters_p.h132
-rw-r--r--src/qml/qml/qqmltype.cpp743
-rw-r--r--src/qml/qml/qqmltype_p.h126
-rw-r--r--src/qml/qml/qqmltype_p_p.h287
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp1005
-rw-r--r--src/qml/qml/qqmltypecompiler_p.h174
-rw-r--r--src/qml/qml/qqmltypedata.cpp722
-rw-r--r--src/qml/qml/qqmltypedata_p.h93
-rw-r--r--src/qml/qml/qqmltypeloader.cpp774
-rw-r--r--src/qml/qml/qqmltypeloader_p.h146
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp42
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h43
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent.cpp98
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent_p.h69
-rw-r--r--src/qml/qml/qqmltypeloaderthread.cpp104
-rw-r--r--src/qml/qml/qqmltypeloaderthread_p.h79
-rw-r--r--src/qml/qml/qqmltypemodule.cpp155
-rw-r--r--src/qml/qml/qqmltypemodule_p.h128
-rw-r--r--src/qml/qml/qqmltypemodule_p_p.h89
-rw-r--r--src/qml/qml/qqmltypemoduleversion.cpp72
-rw-r--r--src/qml/qml/qqmltypemoduleversion_p.h61
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp167
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h184
-rw-r--r--src/qml/qml/qqmltypenotavailable.cpp53
-rw-r--r--src/qml/qml/qqmltypenotavailable_p.h72
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp383
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h51
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp326
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h314
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding.cpp45
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding_p.h42
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp828
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h158
-rw-r--r--src/qml/qml/qqmlvme.cpp69
-rw-r--r--src/qml/qml/qqmlvme_p.h116
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp1034
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h205
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp321
-rw-r--r--src/qml/qml/qqmlxmlhttprequest_p.h42
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h200
-rw-r--r--src/qml/qml/v8/qv4domerrors_p.h93
-rw-r--r--src/qml/qml/v8/qv4sqlerrors.cpp63
-rw-r--r--src/qml/qml/v8/qv4sqlerrors_p.h74
-rw-r--r--src/qml/qml/v8/v8.pri9
-rw-r--r--src/qml/qml_compile_hash_p.h.in15
-rw-r--r--src/qml/qmldirparser/qmldirparser.pri8
-rw-r--r--src/qml/qmldirparser/qqmldirparser.cpp465
-rw-r--r--src/qml/qmldirparser/qqmldirparser_p.h139
-rw-r--r--src/qml/qmldirparser/qqmlimportresolver.cpp86
-rw-r--r--src/qml/qmldirparser/qqmlimportresolver_p.h31
-rw-r--r--src/qml/qmltc/qqmltcobjectcreationhelper.cpp63
-rw-r--r--src/qml/qmltc/qqmltcobjectcreationhelper_p.h125
-rw-r--r--src/qml/qmltc/supportlibrary/qqmlcppbinding.cpp163
-rw-r--r--src/qml/qmltc/supportlibrary/qqmlcppbinding_p.h64
-rw-r--r--src/qml/qmltc/supportlibrary/qqmlcpponassignment.cpp20
-rw-r--r--src/qml/qmltc/supportlibrary/qqmlcpponassignment_p.h46
-rw-r--r--src/qml/qmltc/supportlibrary/qqmlcpptypehelpers_p.h28
-rw-r--r--src/qml/qqmlbuiltins_p.h407
-rw-r--r--src/qml/qt_cmdline.cmake2
-rw-r--r--src/qml/qtqml.tracepoints14
-rw-r--r--src/qml/qtqmlcompilerglobal.h48
-rw-r--r--src/qml/qtqmlcompilerglobal_p.h42
-rw-r--r--src/qml/qtqmlglobal.h70
-rw-r--r--src/qml/qtqmlglobal_p.h54
-rw-r--r--src/qml/types/qqmlbind.cpp903
-rw-r--r--src/qml/types/qqmlbind_p.h60
-rw-r--r--src/qml/types/qqmlconnections.cpp300
-rw-r--r--src/qml/types/qqmlconnections_p.h59
-rw-r--r--src/qml/types/qqmlmodelindexvaluetype.cpp68
-rw-r--r--src/qml/types/qqmlmodelindexvaluetype_p.h164
-rw-r--r--src/qml/types/qqmltimer.cpp42
-rw-r--r--src/qml/types/qqmltimer_p.h46
-rw-r--r--src/qml/types/types.pri22
-rw-r--r--src/qml/util/qqmlpropertymap.cpp103
-rw-r--r--src/qml/util/qqmlpropertymap.h44
-rw-r--r--src/qml/util/util.pri5
833 files changed, 79142 insertions, 54522 deletions
diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt
new file mode 100644
index 0000000000..cbcdc2f8f9
--- /dev/null
+++ b/src/qml/CMakeLists.txt
@@ -0,0 +1,884 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+include(Qt6QmlBuildInternals.cmake)
+
+#####################################################################
+## Qml Module:
+#####################################################################
+
+# Need to evaluate Qml features early. We can't wait until
+# qt_internal_add_qml_module() is executed because we need feature evaluation
+# to determine some of the arguments to that command.
+qt_feature_evaluate_features("${CMAKE_CURRENT_SOURCE_DIR}/configure.cmake")
+
+set(module_dynamic_qml_imports
+ QtQml.Models/auto
+)
+
+if (QT_FEATURE_qml_worker_script)
+ list(APPEND module_dynamic_qml_imports
+ QtQml.WorkerScript/auto
+ )
+endif()
+
+set(extra_cmake_files)
+set(extra_cmake_includes)
+if(ANDROID)
+ list(APPEND extra_cmake_files
+ "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}AndroidQmlMacros.cmake")
+ list(APPEND extra_cmake_includes
+ "${INSTALL_CMAKE_NAMESPACE}AndroidQmlMacros.cmake")
+endif()
+
+set_source_files_properties(
+ qml/qqmlcomponent.h qml/qqmlcomponent.cpp qml/qqmlcomponent_p.h
+ qml/qqmlcomponentattached_p.h
+ qml/qqmlscriptstring.h qml/qqmlscriptstring_p.h qml/qqmlscriptstring.cpp
+ PROPERTIES
+ SKIP_AUTOMOC TRUE
+)
+
+set(extra_manual_moc_deps "")
+if(QT_FEATURE_qml_network)
+ list(APPEND extra_manual_moc_deps Qt6::Network)
+endif()
+# We want QQmlComponent, QQmlComponentAttached, and QQmlScriptString to be available as metatypes in
+# the builtins, but without depending on QtQml and without duplicating the metaobjects.
+qt_manual_moc(extra_builtins_moc_files
+ OUTPUT_MOC_JSON_FILES extra_builtins_json_list
+ qml/qqmlcomponent.h
+ qml/qqmlcomponentattached_p.h
+ qml/qqmlscriptstring.h
+ TARGETS Qt6::Qml Qt6::Core ${extra_manual_moc_deps}
+)
+
+# The moc files are included directly by qqmlcomponent.cpp and qqmlscriptstring.cpp
+set_source_files_properties(${extra_builtins_moc_files} PROPERTIES HEADER_FILE_ONLY ON)
+
+qt_internal_add_module(QmlBuiltins
+ STATIC
+ NO_GENERATE_METATYPES # we do that manually below
+ SOURCES
+ qqmlbuiltins_p.h
+)
+
+add_custom_target(ExtraBuiltinsJson DEPENDS ${extra_builtins_json_list})
+add_custom_target(ExtraBuiltinsMocs DEPENDS ${extra_builtins_moc_files})
+
+target_link_libraries(QmlBuiltins PRIVATE Qt::Core Qt::QmlIntegration)
+
+# We generally need to copy the files into the build directory,
+# so that they are located together with the QML modules
+qt_path_join(qml_build_dir "${QT_BUILD_DIR}" "${INSTALL_QMLDIR}")
+
+# Simulate conditions that qt6_add_qml_module() would normally set up for us
+set_target_properties(QmlBuiltins PROPERTIES
+ QT_QML_MODULE_VERSION 1.0
+ QT_QML_MODULE_URI QML
+ QT_QML_MODULE_TYPEINFO builtins.qmltypes
+ QT_QML_MODULE_OUTPUT_DIRECTORY ${qml_build_dir}
+)
+
+qt_internal_add_qml_module(Qml
+ URI "QtQml.Base"
+ VERSION "${PROJECT_VERSION}"
+ DESIGNER_SUPPORTED
+ __QT_INTERNAL_SYSTEM_MODULE
+ PLUGIN_TARGET qmlplugin
+ CLASS_NAME QtQmlPlugin
+ PLUGIN_TYPES qmltooling
+ IMPORTS
+ QML/1.0
+ SOURCES
+ ../3rdparty/masm/assembler/ARM64Assembler.h
+ ../3rdparty/masm/assembler/ARMv7Assembler.cpp ../3rdparty/masm/assembler/ARMv7Assembler.h
+ ../3rdparty/masm/assembler/AbstractMacroAssembler.h
+ ../3rdparty/masm/assembler/AssemblerBuffer.h
+ ../3rdparty/masm/assembler/AssemblerBufferWithConstantPool.h
+ ../3rdparty/masm/assembler/CodeLocation.h
+ ../3rdparty/masm/assembler/LinkBuffer.cpp ../3rdparty/masm/assembler/LinkBuffer.h
+ ../3rdparty/masm/assembler/MIPSAssembler.h
+ ../3rdparty/masm/assembler/MacroAssembler.h
+ ../3rdparty/masm/assembler/MacroAssemblerARM64.h
+ ../3rdparty/masm/assembler/MacroAssemblerARMv7.h
+ ../3rdparty/masm/assembler/MacroAssemblerCodeRef.h
+ ../3rdparty/masm/assembler/MacroAssemblerMIPS.h
+ ../3rdparty/masm/assembler/MacroAssemblerX86.h
+ ../3rdparty/masm/assembler/MacroAssemblerX86Common.h
+ ../3rdparty/masm/assembler/MacroAssemblerX86_64.h
+ ../3rdparty/masm/assembler/X86Assembler.h
+ ../3rdparty/masm/assembler/ARMv7Assembler.cpp
+ ../3rdparty/masm/disassembler/ARM64/A64DOpcode.cpp ../3rdparty/masm/disassembler/ARM64/A64DOpcode.h
+ ../3rdparty/masm/disassembler/ARM64Disassembler.cpp
+ ../3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp ../3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
+ ../3rdparty/masm/disassembler/ARMv7Disassembler.cpp
+ ../3rdparty/masm/disassembler/Disassembler.cpp
+ ../3rdparty/masm/disassembler/Mips32Disassembler.cpp
+ ../3rdparty/masm/disassembler/UDis86Disassembler.cpp
+ ../3rdparty/masm/disassembler/mips32/Mips32Opcode.cpp ../3rdparty/masm/disassembler/mips32/Mips32Opcode.h
+ ../3rdparty/masm/stubs/Options.cpp
+ ../3rdparty/masm/stubs/WTFStubs.cpp ../3rdparty/masm/stubs/WTFStubs.h
+ ../3rdparty/masm/stubs/wtf/FastAllocBase.h
+ ../3rdparty/masm/stubs/wtf/FastMalloc.h
+ ../3rdparty/masm/stubs/wtf/Noncopyable.h
+ ../3rdparty/masm/stubs/wtf/OwnPtr.h
+ ../3rdparty/masm/stubs/wtf/PassOwnPtr.h
+ ../3rdparty/masm/stubs/wtf/PassRefPtr.h
+ ../3rdparty/masm/stubs/wtf/RefCounted.h
+ ../3rdparty/masm/stubs/wtf/RefPtr.h
+ ../3rdparty/masm/stubs/wtf/TypeTraits.h
+ ../3rdparty/masm/stubs/wtf/UnusedParam.h
+ ../3rdparty/masm/stubs/wtf/Vector.h
+ ../3rdparty/masm/stubs/yarr/YarrUnicodeProperties.cpp
+ ../3rdparty/masm/wtf/ASCIICType.h
+ ../3rdparty/masm/wtf/Assertions.h
+ ../3rdparty/masm/wtf/Atomics.h
+ ../3rdparty/masm/wtf/BumpPointerAllocator.h
+ ../3rdparty/masm/wtf/CheckedArithmetic.h
+ ../3rdparty/masm/wtf/Compiler.h
+ ../3rdparty/masm/wtf/CryptographicallyRandomNumber.h
+ ../3rdparty/masm/wtf/DataLog.h
+ ../3rdparty/masm/wtf/DynamicAnnotations.h
+ ../3rdparty/masm/wtf/EnumClass.h
+ ../3rdparty/masm/wtf/FeatureDefines.h
+ ../3rdparty/masm/wtf/FilePrintStream.cpp ../3rdparty/masm/wtf/FilePrintStream.h
+ ../3rdparty/masm/wtf/Locker.h
+ ../3rdparty/masm/wtf/MathExtras.h
+ ../3rdparty/masm/wtf/NotFound.h
+ ../3rdparty/masm/wtf/NullPtr.h
+ ../3rdparty/masm/wtf/OSAllocator.h
+ ../3rdparty/masm/wtf/PageAllocation.h
+ ../3rdparty/masm/wtf/PageAllocationAligned.cpp ../3rdparty/masm/wtf/PageAllocationAligned.h
+ ../3rdparty/masm/wtf/PageBlock.cpp ../3rdparty/masm/wtf/PageBlock.h
+ ../3rdparty/masm/wtf/PageReservation.h
+ ../3rdparty/masm/wtf/Platform.h
+ ../3rdparty/masm/wtf/PossiblyNull.h
+ ../3rdparty/masm/wtf/PrintStream.cpp ../3rdparty/masm/wtf/PrintStream.h
+ ../3rdparty/masm/wtf/RawPointer.h
+ ../3rdparty/masm/wtf/SegmentedVector.h
+ ../3rdparty/masm/wtf/StdLibExtras.h
+ ../3rdparty/masm/wtf/VMTags.h
+ ../3rdparty/masm/yarr/Yarr.h
+ ../3rdparty/masm/yarr/YarrCanonicalizeUCS2.cpp ../3rdparty/masm/yarr/YarrCanonicalizeUCS2.h
+ ../3rdparty/masm/yarr/YarrCanonicalizeUnicode.cpp
+ ../3rdparty/masm/yarr/YarrInterpreter.cpp ../3rdparty/masm/yarr/YarrInterpreter.h
+ ../3rdparty/masm/yarr/YarrJIT.cpp ../3rdparty/masm/yarr/YarrJIT.h
+ ../3rdparty/masm/yarr/YarrParser.h
+ ../3rdparty/masm/yarr/YarrPattern.cpp ../3rdparty/masm/yarr/YarrPattern.h
+ ../3rdparty/masm/yarr/YarrSyntaxChecker.cpp ../3rdparty/masm/yarr/YarrSyntaxChecker.h
+ ../3rdparty/masm/yarr/YarrUnicodeProperties.h
+ common/qjsnumbercoercion.cpp common/qjsnumbercoercion.h
+ common/qqmljsdiagnosticmessage_p.h
+ common/qqmljsfixedpoolarray_p.h
+ common/qqmljsmemorypool_p.h
+ common/qqmljssourcelocation_p.h
+ common/qv4alloca_p.h
+ common/qv4calldata_p.h
+ common/qv4compileddata.cpp common/qv4compileddata_p.h
+ common/qv4staticvalue_p.h
+ common/qv4stringtoarrayindex_p.h
+ common/qqmltranslation.cpp common/qqmltranslation_p.h
+ common/qqmlsignalnames_p.h common/qqmlsignalnames.cpp
+ compat/removed_api.cpp
+ compiler/qqmlirbuilder.cpp compiler/qqmlirbuilder_p.h
+ compiler/qv4bytecodegenerator.cpp compiler/qv4bytecodegenerator_p.h
+ compiler/qv4bytecodehandler.cpp compiler/qv4bytecodehandler_p.h
+ compiler/qv4codegen.cpp compiler/qv4codegen_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/qv4util_p.h
+ debugger/qqmldebug.h
+ debugger/qqmldebugconnector_p.h
+ debugger/qqmldebugserviceinterfaces_p.h
+ debugger/qqmldebugstatesdelegate_p.h
+ debugger/qqmlprofiler_p.h
+ inlinecomponentutils_p.h
+ jsapi/qjsengine.cpp jsapi/qjsengine.h jsapi/qjsengine_p.h
+ jsapi/qjslist.cpp jsapi/qjslist.h
+ jsapi/qjsmanagedvalue.cpp jsapi/qjsmanagedvalue.h
+ jsapi/qjsprimitivevalue.cpp jsapi/qjsprimitivevalue.h
+ jsapi/qjsvalue.cpp jsapi/qjsvalue.h jsapi/qjsvalue_p.h
+ jsapi/qjsvalueiterator.cpp jsapi/qjsvalueiterator.h jsapi/qjsvalueiterator_p.h
+ jsruntime/qv4argumentsobject.cpp jsruntime/qv4argumentsobject_p.h
+ jsruntime/qv4arraybuffer.cpp jsruntime/qv4arraybuffer_p.h
+ jsruntime/qv4arraydata.cpp jsruntime/qv4arraydata_p.h
+ jsruntime/qv4arrayiterator.cpp jsruntime/qv4arrayiterator_p.h
+ jsruntime/qv4arrayobject.cpp jsruntime/qv4arrayobject_p.h
+ jsruntime/qv4atomics.cpp jsruntime/qv4atomics_p.h
+ jsruntime/qv4booleanobject.cpp jsruntime/qv4booleanobject_p.h
+ jsruntime/qv4compilationunitmapper.cpp jsruntime/qv4compilationunitmapper_p.h
+ jsruntime/qv4context.cpp jsruntime/qv4context_p.h
+ jsruntime/qv4dataview.cpp jsruntime/qv4dataview_p.h
+ jsruntime/qv4dateobject.cpp jsruntime/qv4dateobject_p.h
+ jsruntime/qv4debugging.cpp jsruntime/qv4debugging_p.h
+ jsruntime/qv4domerrors.cpp jsruntime/qv4domerrors_p.h
+ jsruntime/qv4engine.cpp jsruntime/qv4engine_p.h
+ jsruntime/qv4enginebase_p.h
+ jsruntime/qv4errorobject.cpp jsruntime/qv4errorobject_p.h
+ jsruntime/qv4estable.cpp jsruntime/qv4estable_p.h
+ jsruntime/qv4executableallocator.cpp jsruntime/qv4executableallocator_p.h
+ jsruntime/qv4executablecompilationunit.cpp jsruntime/qv4executablecompilationunit_p.h
+ jsruntime/qv4function.cpp jsruntime/qv4function_p.h
+ jsruntime/qv4functionobject.cpp jsruntime/qv4functionobject_p.h
+ jsruntime/qv4functiontable_p.h
+ jsruntime/qv4generatorobject.cpp jsruntime/qv4generatorobject_p.h
+ jsruntime/qv4global_p.h
+ jsruntime/qv4globalobject.cpp jsruntime/qv4globalobject_p.h
+ jsruntime/qv4identifierhash.cpp jsruntime/qv4identifierhash_p.h
+ jsruntime/qv4identifierhashdata_p.h
+ jsruntime/qv4identifiertable.cpp jsruntime/qv4identifiertable_p.h
+ jsruntime/qv4include.cpp jsruntime/qv4include_p.h
+ jsruntime/qv4internalclass.cpp jsruntime/qv4internalclass_p.h
+ jsruntime/qv4iterator.cpp jsruntime/qv4iterator_p.h
+ jsruntime/qv4jscall_p.h jsruntime/qv4jscall.cpp
+ jsruntime/qv4jsonobject.cpp jsruntime/qv4jsonobject_p.h
+ jsruntime/qv4lookup.cpp jsruntime/qv4lookup_p.h
+ jsruntime/qv4managed.cpp jsruntime/qv4managed_p.h
+ jsruntime/qv4mapiterator.cpp jsruntime/qv4mapiterator_p.h
+ jsruntime/qv4mapobject.cpp jsruntime/qv4mapobject_p.h
+ jsruntime/qv4math_p.h
+ jsruntime/qv4mathobject.cpp jsruntime/qv4mathobject_p.h
+ jsruntime/qv4memberdata.cpp jsruntime/qv4memberdata_p.h
+ jsruntime/qv4module.cpp jsruntime/qv4module_p.h
+ jsruntime/qv4numberobject.cpp jsruntime/qv4numberobject_p.h
+ jsruntime/qv4object.cpp jsruntime/qv4object_p.h
+ jsruntime/qv4objectiterator.cpp jsruntime/qv4objectiterator_p.h
+ jsruntime/qv4objectproto.cpp jsruntime/qv4objectproto_p.h
+ jsruntime/qv4persistent.cpp jsruntime/qv4persistent_p.h
+ jsruntime/qv4profiling_p.h
+ jsruntime/qv4promiseobject.cpp jsruntime/qv4promiseobject_p.h
+ jsruntime/qv4property_p.h
+ jsruntime/qv4propertykey.cpp jsruntime/qv4propertykey_p.h
+ jsruntime/qv4proxy.cpp jsruntime/qv4proxy_p.h
+ jsruntime/qv4qmetaobjectwrapper.cpp jsruntime/qv4qmetaobjectwrapper_p.h
+ jsruntime/qv4qmlcontext.cpp jsruntime/qv4qmlcontext_p.h
+ jsruntime/qv4qobjectwrapper.cpp jsruntime/qv4qobjectwrapper_p.h
+ jsruntime/qv4reflect.cpp jsruntime/qv4reflect_p.h
+ jsruntime/qv4regexp.cpp jsruntime/qv4regexp_p.h
+ jsruntime/qv4regexpobject.cpp jsruntime/qv4regexpobject_p.h
+ jsruntime/qv4resolvedtypereference.cpp jsruntime/qv4resolvedtypereference_p.h
+ jsruntime/qv4runtime.cpp jsruntime/qv4runtime_p.h
+ jsruntime/qv4runtimeapi_p.h
+ jsruntime/qv4runtimecodegen.cpp jsruntime/qv4runtimecodegen_p.h
+ jsruntime/qv4scopedvalue_p.h
+ jsruntime/qv4script.cpp jsruntime/qv4script_p.h
+ jsruntime/qv4setiterator.cpp jsruntime/qv4setiterator_p.h
+ jsruntime/qv4setobject.cpp jsruntime/qv4setobject_p.h
+ jsruntime/qv4sparsearray.cpp jsruntime/qv4sparsearray_p.h
+ jsruntime/qv4sqlerrors.cpp jsruntime/qv4sqlerrors_p.h
+ jsruntime/qv4stackframe.cpp jsruntime/qv4stackframe_p.h
+ jsruntime/qv4string.cpp jsruntime/qv4string_p.h
+ jsruntime/qv4stringiterator.cpp jsruntime/qv4stringiterator_p.h
+ jsruntime/qv4stringobject.cpp jsruntime/qv4stringobject_p.h
+ jsruntime/qv4symbol.cpp jsruntime/qv4symbol_p.h
+ jsruntime/qv4typedarray.cpp jsruntime/qv4typedarray_p.h
+ jsruntime/qv4urlobject.cpp jsruntime/qv4urlobject_p.h
+ jsruntime/qv4value.cpp jsruntime/qv4value_p.h
+ jsruntime/qv4variantobject.cpp jsruntime/qv4variantobject_p.h
+ jsruntime/qv4vme_moth.cpp jsruntime/qv4vme_moth_p.h
+ jsruntime/qv4sequenceobject.cpp jsruntime/qv4sequenceobject_p.h
+ jsruntime/qv4vtable_p.h
+ jsruntime/qv4referenceobject.cpp jsruntime/qv4referenceobject_p.h
+ memory/qv4heap_p.h
+ memory/qv4mm.cpp memory/qv4mm_p.h
+ memory/qv4mmdefs_p.h
+ memory/qv4stacklimits.cpp memory/qv4stacklimits_p.h
+ memory/qv4writebarrier_p.h memory/qv4writebarrier.cpp
+ parser/qqmljsast.cpp parser/qqmljsast_p.h
+ parser/qqmljsastfwd_p.h
+ parser/qqmljsastvisitor.cpp parser/qqmljsastvisitor_p.h
+ parser/qqmljsengine_p.h
+ parser/qqmljsglobal_p.h
+ parser/qqmljskeywords_p.h
+ parser/qqmljslexer.cpp parser/qqmljslexer_p.h
+ qml/ftw/qdoubleendedlist_p.h
+ qml/ftw/qfieldlist_p.h
+ qml/ftw/qfinitestack_p.h
+ qml/ftw/qbipointer_p.h
+ qml/ftw/qhashedstring.cpp qml/ftw/qhashedstring_p.h
+ qml/ftw/qintrusivelist.cpp qml/ftw/qintrusivelist_p.h
+ qml/ftw/qlazilyallocated_p.h
+ qml/ftw/qlinkedstringhash_p.h
+ qml/ftw/qpodvector_p.h
+ qml/ftw/qprimefornumbits_p.h
+ qml/ftw/qqmlnullablevalue_p.h
+ qml/ftw/qqmlrefcount_p.h
+ qml/ftw/qqmlthread.cpp qml/ftw/qqmlthread_p.h
+ qml/ftw/qrecursionwatcher_p.h
+ qml/ftw/qrecyclepool_p.h
+ qml/ftw/qstringhash_p.h
+ qml/qqmlregistration.h
+ qml/qqml.cpp qml/qqml.h
+ qml/qqmlabstractbinding.cpp qml/qqmlabstractbinding_p.h
+ qml/qqmlabstracturlinterceptor.cpp qml/qqmlabstracturlinterceptor.h
+ qml/qqmlapplicationengine.cpp qml/qqmlapplicationengine.h qml/qqmlapplicationengine_p.h
+ qml/qqmlbinding.cpp qml/qqmlbinding_p.h
+ qml/qqmlboundsignal.cpp qml/qqmlboundsignal_p.h
+ qml/qqmlbuiltinfunctions.cpp qml/qqmlbuiltinfunctions_p.h
+ qml/qqmlcomponent.cpp qml/qqmlcomponent.h qml/qqmlcomponent_p.h
+ qml/qqmlcomponentandaliasresolver_p.h
+ qml/qqmlcomponentattached_p.h
+ qml/qqmlcontext.cpp qml/qqmlcontext.h qml/qqmlcontext_p.h
+ qml/qqmlcontextdata.cpp qml/qqmlcontextdata_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.h
+ qml/qqmlexpression.cpp qml/qqmlexpression.h qml/qqmlexpression_p.h
+ qml/qqmlextensioninterface.cpp qml/qqmlextensioninterface.h
+ qml/qqmlextensionplugin.cpp qml/qqmlextensionplugin.h qml/qqmlextensionplugin_p.h
+ qml/qqmlfile.cpp qml/qqmlfile.h
+ qml/qqmlfileselector.cpp qml/qqmlfileselector.h qml/qqmlfileselector_p.h
+ qml/qqmlglobal.cpp qml/qqmlglobal_p.h
+ qml/qqmlguard_p.h
+ qml/qqmlguardedcontextdata_p.h
+ qml/qqmlimport.cpp qml/qqmlimport_p.h
+ qml/qqmlincubator.cpp qml/qqmlincubator.h qml/qqmlincubator_p.h
+ qml/qqmlinfo.cpp qml/qqmlinfo.h
+ qml/qqmlirloader.cpp qml/qqmlirloader_p.h
+ qml/qqmljavascriptexpression.cpp qml/qqmljavascriptexpression_p.h
+ qml/qqmllist.cpp qml/qqmllist.h qml/qqmllist_p.h
+ qml/qqmllistwrapper.cpp qml/qqmllistwrapper_p.h
+ qml/qqmlloggingcategory.cpp qml/qqmlloggingcategory_p.h
+ qml/qqmlmetamoduleregistration.cpp
+ qml/qqmlmetaobject.cpp qml/qqmlmetaobject_p.h
+ qml/qqmlmetatype.cpp qml/qqmlmetatype_p.h
+ qml/qqmlmetatypedata.cpp qml/qqmlmetatypedata_p.h
+ qml/qqmlmoduleregistration.cpp qml/qqmlmoduleregistration.h
+ qml/qqmlnetworkaccessmanagerfactory.cpp qml/qqmlnetworkaccessmanagerfactory.h
+ qml/qqmlnotifier.cpp qml/qqmlnotifier_p.h
+ qml/qqmlobjectcreator.cpp qml/qqmlobjectcreator_p.h
+ qml/qqmlobjectorgadget.cpp qml/qqmlobjectorgadget_p.h
+ qml/qqmlopenmetaobject.cpp qml/qqmlopenmetaobject_p.h
+ qml/qqmlparserstatus.cpp qml/qqmlparserstatus.h
+ qml/qqmlplatform.cpp qml/qqmlplatform_p.h
+ qml/qqmlpluginimporter.cpp qml/qqmlpluginimporter_p.h
+ qml/qqmlprivate.h
+ qml/qqmlproperty.cpp qml/qqmlproperty.h qml/qqmlproperty_p.h
+ qml/qqmlpropertybinding.cpp qml/qqmlpropertybinding_p.h
+ qml/qqmlanybinding_p.h
+ qml/qqmlpropertycache.cpp qml/qqmlpropertycache_p.h
+ qml/qqmlpropertycachecreator.cpp qml/qqmlpropertycachecreator_p.h
+ qml/qqmlpropertycachemethodarguments_p.h
+ qml/qqmlpropertycachevector_p.h
+ qml/qqmlpropertydata_p.h
+ qml/qqmlpropertyindex_p.h
+ qml/qqmlpropertyresolver.cpp qml/qqmlpropertyresolver_p.h
+ qml/qqmlpropertytopropertybinding.cpp qml/qqmlpropertytopropertybinding_p.h
+ qml/qqmlpropertyvalidator.cpp qml/qqmlpropertyvalidator_p.h
+ qml/qqmlpropertyvalueinterceptor.cpp qml/qqmlpropertyvalueinterceptor_p.h
+ qml/qqmlfinalizer.cpp qml/qqmlfinalizer_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/qqmlstringconverters.cpp qml/qqmlstringconverters_p.h
+ 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/qqmltypemoduleversion.cpp qml/qqmltypemoduleversion_p.h
+ qml/qqmltypenamecache.cpp qml/qqmltypenamecache_p.h
+ qml/qqmltypewrapper.cpp qml/qqmltypewrapper_p.h
+ qml/qqmlvaluetype.cpp qml/qqmlvaluetype_p.h
+ qml/qqmlvaluetypeproxybinding.cpp qml/qqmlvaluetypeproxybinding_p.h
+ qml/qqmlvaluetypewrapper.cpp qml/qqmlvaluetypewrapper_p.h
+ qml/qqmlvme.cpp qml/qqmlvme_p.h
+ qml/qqmlvmemetaobject.cpp qml/qqmlvmemetaobject_p.h
+ qmldirparser/qqmldirparser.cpp qmldirparser/qqmldirparser_p.h
+ qmldirparser/qqmlimportresolver.cpp qmldirparser/qqmlimportresolver_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
+ util/qqmlpropertymap.cpp util/qqmlpropertymap.h
+
+ qmltc/qqmltcobjectcreationhelper_p.h
+ qmltc/qqmltcobjectcreationhelper.cpp
+ qmltc/supportlibrary/qqmlcppbinding_p.h
+ qmltc/supportlibrary/qqmlcppbinding.cpp
+ qmltc/supportlibrary/qqmlcpponassignment_p.h
+ qmltc/supportlibrary/qqmlcpponassignment.cpp
+ qmltc/supportlibrary/qqmlcpptypehelpers_p.h
+ NO_UNITY_BUILD_SOURCES
+ jsapi/qjsvalue.cpp # \.
+ jsruntime/qv4engine.cpp # > WTF::String vs. QV4::String, dto. Object
+ jsruntime/qv4jsonobject.cpp # |
+ jsruntime/qv4object.cpp # |
+ jsruntime/qv4proxy.cpp # |
+ jsruntime/qv4qmlcontext.cpp # |
+ jsruntime/qv4reflect.cpp # |
+ jsruntime/qv4regexpobject.cpp # |
+ jsruntime/qv4script.cpp # | ((also?) Function)
+ jsruntime/qv4string.cpp # |
+ jsruntime/qv4stringobject.cpp # | ((also?) Property)
+ jsruntime/qv4typedarray.cpp # |
+ jsruntime/qv4urlobject.cpp # | ((also?) Property)
+ qml/qqmlbuiltinfunctions.cpp # |
+ qml/qqmllistwrapper.cpp # |
+ qml/qqmllocale.cpp # |
+ qml/qqmltypecompiler.cpp # | (also Binding)
+ qml/qqmltypewrapper.cpp # |
+ qml/qqmlxmlhttprequest.cpp # / (also Document)
+ jsruntime/qv4managed.cpp # QQmlJS::Managed vs. QV4::Managed
+ jsruntime/qv4module.cpp # QV4::Compiler::Module vs. QV4::Module
+ jsruntime/qv4vme_moth.cpp # 'MOTH_BEGIN_INSTR' macro redefined (from qv4instr_moth.cpp)
+ qml/qqmltypecompiler.cpp # 'COMPILE_EXCEPTION' macro redefined (from qqmlirbuilder.cpp)
+ qml/qqmlmetamoduleregistration.cpp # declares 'registration' clashing with qml_* files
+ DEFINES
+ BUILDING_QT__
+ ENABLE_ASSEMBLER_WX_EXCLUSIVE=1
+ ENABLE_DFG_JIT=0
+ ENABLE_DFG_JIT_UTILITY_METHODS=1
+ ENABLE_JIT_CONSTANT_BLINDING=0
+ ENABLE_LLINT=0
+ JS_EXPORT_PRIVATE= # special case
+ QT_NO_FOREACH
+ QT_NO_INTEGER_EVENT_COORDINATES
+ QT_NO_URL_CAST_FROM_STRING
+ WTFInvokeCrashHook=qmlWTFInvokeCrashHook
+ WTFReportAssertionFailure=qmlWTFReportAssertionFailure
+ WTFReportAssertionFailureWithMessage=qmlWTFReportAssertionFailureWithMessage
+ WTFReportBacktrace=qmlWTFReportBacktrace
+ WTF_EXPORT_PRIVATE= # special case
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_BINARY_DIR}/.generated
+ ${CMAKE_CURRENT_BINARY_DIR}/compiler
+ ${CMAKE_CURRENT_BINARY_DIR}/jsruntime
+ ${CMAKE_CURRENT_BINARY_DIR}/memory
+ ${CMAKE_CURRENT_BINARY_DIR}/qml
+ ${CMAKE_CURRENT_BINARY_DIR}/qmldirparser
+ ../3rdparty/masm
+ ../3rdparty/masm/assembler
+ ../3rdparty/masm/disassembler
+ ../3rdparty/masm/disassembler/udis86
+ ../3rdparty/masm/jit
+ ../3rdparty/masm/runtime
+ ../3rdparty/masm/stubs
+ ../3rdparty/masm/stubs/runtime
+ ../3rdparty/masm/stubs/wtf
+ ../3rdparty/masm/wtf
+ compiler
+ debugger
+ jsruntime
+ memory
+ qml
+ qmldirparser
+ LIBRARIES
+ Qt::CorePrivate
+ ${FWCoreFoundation}
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::QmlIntegration
+ Qt::QmlBuiltins
+ PRIVATE_MODULE_INTERFACE
+ Qt::CorePrivate
+ Qt::QmlBuiltinsPrivate
+ EXTRA_CMAKE_FILES
+ "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}qmldirTemplate.cmake.in"
+ "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlPluginTemplate.cpp.in"
+ "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlFindQmlscInternal.cmake"
+ "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlDeploySupport.cmake"
+ "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlModuleDirMappingTemplate.qrc.in"
+ "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmltcFileMappingTemplate.qrc.in"
+ ${extra_cmake_files}
+ EXTRA_CMAKE_INCLUDES
+ "${INSTALL_CMAKE_NAMESPACE}QmlFindQmlscInternal.cmake"
+ ${extra_cmake_includes}
+ GENERATE_CPP_EXPORTS
+ POLICIES
+ QTP0001
+ QTP0004
+)
+
+_qt_internal_add_qml_deploy_info_finalizer(Qml)
+
+target_include_directories(QmlBuiltins PRIVATE
+ $<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::QmlPrivate,INTERFACE_INCLUDE_DIRECTORIES>
+)
+
+set(builtins_typeregistration_args
+ MANUAL_MOC_JSON_FILES ${extra_builtins_json_list}
+ REGISTRATIONS_TARGET Qml
+)
+
+get_target_property(qt_namespace ${QT_CMAKE_EXPORT_NAMESPACE}::Core _qt_namespace)
+if(qt_namespace)
+ list(APPEND builtins_typeregistration_args NAMESPACE ${qt_namespace})
+endif()
+
+_qt_internal_qml_type_registration(QmlBuiltins ${builtins_typeregistration_args})
+add_dependencies(QmlBuiltins ExtraBuiltinsJson)
+
+_qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+add_custom_command(
+ OUTPUT
+ "${qml_build_dir}/jsroot.qmltypes"
+ DEPENDS
+ ${QT_CMAKE_EXPORT_NAMESPACE}::qmltyperegistrar
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qmltyperegistrar>
+ --jsroot --generate-qmltypes "${qml_build_dir}/jsroot.qmltypes"
+ COMMENT "Generating jsroot.qmltypes"
+ VERBATIM
+)
+
+get_target_property(builtins_metatypes_file "QmlBuiltins" INTERFACE_QT_META_TYPES_BUILD_FILE)
+
+_qt_internal_get_metatypes_install_dir(
+ ""
+ "${INSTALL_ARCHDATADIR}"
+ metatypes_install_dir
+)
+
+_qt_internal_assign_install_metatypes_files_and_properties(
+ QmlBuiltins
+ INSTALL_DIR "${metatypes_install_dir}"
+)
+
+qt_install(
+ FILES "${builtins_metatypes_file}"
+ DESTINATION "${metatypes_install_dir}"
+)
+
+set(builtins_output_files "")
+list(APPEND builtins_output_files "${qml_build_dir}/builtins.qmltypes")
+list(APPEND builtins_output_files "${qml_build_dir}/jsroot.qmltypes")
+
+add_custom_target(BuiltinsOutput DEPENDS ${builtins_output_files})
+
+qt_install(
+ FILES ${builtins_output_files}
+ DESTINATION "${INSTALL_QMLDIR}"
+)
+
+add_dependencies(Qml ExtraBuiltinsMocs)
+add_dependencies(Qml BuiltinsOutput)
+
+qt_update_ignore_pch_source(Qml "compat/removed_api.cpp")
+
+set_source_files_properties(compat/removed_api.cpp
+ jsruntime/qv4mathobject.cpp # math.h issues on Windows
+ PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
+
+
+qt_internal_add_qml_module(QmlMeta
+ URI "QtQml"
+ VERSION "${PROJECT_VERSION}"
+ DESIGNER_SUPPORTED
+ CLASS_NAME QtQmlMetaPlugin
+ PLUGIN_TARGET QmlMeta
+
+ # Prevent type registration
+ NO_GENERATE_QMLTYPES
+
+ PAST_MAJOR_VERSIONS 2
+ IMPORTS
+ QtQml.Base/auto
+ ${module_dynamic_qml_imports}
+)
+
+# Add the QtQml qmldir to libQtQml, too.
+# Since we also provide the (bare bones) type registration in libQtQml,
+# this makes the complete module reside in libQtQml. There is no need to
+# load the QmlMeta plugin, then.
+# Se still provide the plugin so that static linking works.
+get_target_property(qtqml_out_dir QmlMeta QT_QML_MODULE_OUTPUT_DIRECTORY)
+qt_internal_add_resource(Qml "qmlMetaQmldir"
+ PREFIX
+ "/qt-project.org/imports/QtQml"
+ FILES
+ ${qtqml_out_dir}/qmldir
+)
+
+# Linking to the static qml plugin should also automatically link to the worker script
+# static plugin otherwise you get errors like
+# module "QtQml.WorkerScript" plugin "workerscriptplugin" not found
+# import QtQuick 2.0
+# ^
+if(QT_FEATURE_qml_worker_script)
+ _qt_internal_add_qml_static_plugin_dependency(qmlplugin workerscriptplugin)
+endif()
+# Same for the QmlMeta qml plugin, otherwise you get
+# module "QtQuick" version 6.6 cannot be imported because:
+# module "QtQml" plugin "qmlmetaplugin" not found
+# import QtQuick
+# ^
+_qt_internal_add_qml_static_plugin_dependency(qmlplugin QmlMeta)
+
+# special case begin remove the block, handled manually
+# QLALR Grammars:
+#qt_process_qlalr(
+# Qml
+# parser/qqmljs.g
+# ""
+#)
+
+qt_declarative_write_tag_header(Qml)
+set(_qt_qlalr_flags "--no-debug" "--qt")
+qt_process_qlalr(Qml "${CMAKE_CURRENT_SOURCE_DIR}/parser/qqmljs.g" "${_qt_qlalr_flags}")
+qt_declarative_generate_reg_exp_jit_tables(Qml)
+# special case end
+
+qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_network
+ SOURCES
+ qml/qqmltypeloadernetworkreplyproxy.cpp qml/qqmltypeloadernetworkreplyproxy_p.h
+ PUBLIC_LIBRARIES
+ Qt::Network
+)
+
+qt_internal_extend_target(Qml CONDITION MSVC AND (TEST_architecture_arch STREQUAL "i386")
+ LINK_OPTIONS
+ "/BASE:0x66000000"
+)
+
+qt_internal_extend_target(Qml CONDITION MSVC
+ DEFINES
+ _CRT_SECURE_NO_WARNINGS
+)
+
+qt_internal_extend_target(Qml CONDITION WIN32
+ SOURCES
+ ../3rdparty/masm/wtf/OSAllocatorWin.cpp
+ jsruntime/qv4compilationunitmapper_win.cpp
+ PUBLIC_LIBRARIES
+ shell32
+)
+
+qt_internal_extend_target(Qml CONDITION LINUX AND QT_FEATURE_dlopen
+ LIBRARIES
+ dl
+)
+
+#### Keys ignored in scope 7:.:.:qml.pro:solaris-cc_x_:
+# QMAKE_CXXFLAGS_RELEASE = "--O2"
+
+qt_internal_extend_target(Qml CONDITION GCC AND (TEST_architecture_arch STREQUAL "mips")
+ COMPILE_OPTIONS
+ -fno-reorder-blocks
+)
+
+qt_internal_extend_target(Qml CONDITION EXISTS "qqml_enable_gcov"
+ LIBRARIES
+ gcov
+ COMPILE_OPTIONS
+ -fno-elide-constructors
+ -fprofile-arcs
+ -ftest-coverage
+)
+
+qt_internal_extend_target(Qml CONDITION release AND MSVC AND (QT_CL_MAJOR_VERSION EQUAL 19) AND (QT_CL_MINOR_VERSION EQUAL 00) AND (QT_CL_PATCH_VERSION GREATER 24212)
+ COMPILE_OPTIONS
+ -d2SSAOptimizer-
+)
+
+#### Keys ignored in scope 11:.:.:qml.pro:ICC:
+# WERROR = "-ww2415"
+
+#### Keys ignored in scope 12:.:.:qml.pro:(QT_CLANG_MAJOR_VERSION GREATER 3) OR (QT_CLANG_MINOR_VERSION GREATER 3) OR (QT_APPLE_CLANG_MAJOR_VERSION GREATER 5) OR ( (QT_APPLE_CLANG_MAJOR_VERSION EQUAL 5) AND (QT_APPLE_CLANG_MINOR_VERSION GREATER 0) ):
+# WERROR = "-Wno-error=unused-const-variable"
+
+qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_jit
+ SOURCES
+ jit/qv4assemblercommon.cpp jit/qv4assemblercommon_p.h
+ jit/qv4baselineassembler.cpp jit/qv4baselineassembler_p.h
+ jit/qv4baselinejit.cpp jit/qv4baselinejit_p.h
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_BINARY_DIR}/jit
+ jit
+)
+
+qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_animation
+ SOURCES
+ animations/qabstractanimationjob.cpp animations/qabstractanimationjob_p.h
+ animations/qanimationgroupjob.cpp animations/qanimationgroupjob_p.h
+ animations/qanimationjobutil_p.h
+ animations/qcontinuinganimationgroupjob.cpp animations/qcontinuinganimationgroupjob_p.h
+ animations/qparallelanimationgroupjob.cpp animations/qparallelanimationgroupjob_p.h
+ animations/qpauseanimationjob.cpp animations/qpauseanimationjob_p.h
+ animations/qsequentialanimationgroupjob.cpp animations/qsequentialanimationgroupjob_p.h
+ types/qqmltimer.cpp types/qqmltimer_p.h
+ INCLUDE_DIRECTORIES
+ animations
+)
+
+qt_internal_extend_target(Qml CONDITION GCC AND QT_COMPILER_VERSION_MAJOR STREQUAL 5
+ COMPILE_OPTIONS
+ -fno-strict-aliasing
+)
+
+qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_debug
+ SOURCES
+ debugger/qqmlabstractprofileradapter.cpp debugger/qqmlabstractprofileradapter_p.h
+ debugger/qqmlconfigurabledebugservice_p.h
+ debugger/qqmldebug.cpp
+ debugger/qqmldebugconnector.cpp
+ debugger/qqmldebugpluginmanager_p.h
+ debugger/qqmldebugserver.cpp debugger/qqmldebugserver_p.h
+ debugger/qqmldebugserverconnection.cpp debugger/qqmldebugserverconnection_p.h
+ debugger/qqmldebugservice.cpp debugger/qqmldebugservice_p.h
+ debugger/qqmldebugservicefactory.cpp debugger/qqmldebugservicefactory_p.h
+ debugger/qqmldebugserviceinterfaces.cpp
+ debugger/qqmldebugtranslationprotocol_p.h
+ debugger/qqmlprofiler.cpp
+ debugger/qqmlprofilerdefinitions_p.h
+ jsruntime/qv4profiling.cpp
+)
+
+qt_internal_extend_target(Qml CONDITION UNIX
+ SOURCES
+ jsruntime/qv4compilationunitmapper_unix.cpp
+ jsruntime/qv4functiontable_unix.cpp
+)
+
+qt_internal_extend_target(Qml CONDITION (TEST_architecture_arch STREQUAL "x86_64") AND WIN32
+ SOURCES
+ jsruntime/qv4functiontable_win64.cpp
+)
+
+qt_internal_extend_target(Qml CONDITION WIN32 AND NOT (TEST_architecture_arch STREQUAL "x86_64")
+ SOURCES
+ jsruntime/qv4functiontable_noop.cpp
+)
+
+qt_internal_extend_target(Qml CONDITION valgrind
+ DEFINES
+ V4_USE_VALGRIND
+)
+
+qt_internal_extend_target(Qml CONDITION heaptrack
+ DEFINES
+ V4_USE_HEAPTRACK
+)
+
+qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_xml_http_request
+ SOURCES
+ qml/qqmlxmlhttprequest.cpp qml/qqmlxmlhttprequest_p.h
+)
+
+qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_locale
+ SOURCES
+ qml/qqmllocale.cpp qml/qqmllocale_p.h
+)
+
+qt_internal_extend_target(Qml CONDITION ANDROID
+ DEFINES
+ LIBS_SUFFIX="_${ANDROID_ABI}.so" # special case
+)
+
+qt_internal_extend_target(Qml CONDITION hpux-_x_ OR solaris-_x_ OR (QT_FEATURE_clock_gettime AND linux-_x_)
+ LIBRARIES
+ rt
+)
+
+qt_internal_extend_target(Qml CONDITION disassembler AND ((TEST_architecture_arch STREQUAL "i386") OR (TEST_architecture_arch STREQUAL "x86_64"))
+ DEFINES
+ WTF_USE_UDIS86=1
+)
+
+qt_internal_extend_target(Qml CONDITION (TEST_architecture_arch STREQUAL "arm") AND disassembler
+ DEFINES
+ WTF_USE_ARMV7_DISASSEMBLER=1
+)
+
+qt_internal_extend_target(Qml CONDITION (TEST_architecture_arch STREQUAL "arm64") AND disassembler
+ DEFINES
+ WTF_USE_ARM64_DISASSEMBLER=1
+)
+
+qt_internal_extend_target(Qml CONDITION (TEST_architecture_arch STREQUAL "mips") AND disassembler
+ DEFINES
+ WTF_USE_MIPS32_DISASSEMBLER=1
+)
+
+qt_internal_extend_target(Qml CONDITION NOT disassembler
+ DEFINES
+ WTF_USE_UDIS86=0
+)
+
+qt_internal_extend_target(Qml CONDITION CMAKE_BUILD_TYPE STREQUAL Release
+ DEFINES
+ NDEBUG
+)
+
+qt_internal_extend_target(Qml CONDITION GCC AND QT_COMPILER_VERSION_MAJOR STRGREATER 6 AND NOT CLANG AND NOT ICC
+ COMPILE_OPTIONS
+ -Wno-expansion-to-defined
+)
+
+#### Keys ignored in scope 66:.:../3rdparty/masm:../3rdparty/masm/masm-defs.pri:(QT_COMPILER_VERSION_MAJOR STRGREATER 6):
+# QMAKE_CXXFLAGS_WARN_ON = "-Wno-expansion-to-defined"
+
+qt_internal_extend_target(Qml CONDITION INTEGRITY
+ SOURCES
+ ../3rdparty/masm/wtf/OSAllocatorIntegrity.cpp
+)
+
+qt_internal_extend_target(Qml CONDITION UNIX AND NOT INTEGRITY
+ SOURCES
+ ../3rdparty/masm/wtf/OSAllocatorPosix.cpp
+)
+
+qt_internal_extend_target(Qml CONDITION DEFINES___contains___WTF_USE_UDIS86=1
+ SOURCES
+ ../3rdparty/masm/disassembler/udis86/udis86.c
+ ../3rdparty/masm/disassembler/udis86/udis86_decode.c
+ ../3rdparty/masm/disassembler/udis86/udis86_input.c
+ ../3rdparty/masm/disassembler/udis86/udis86_itab_holder.c
+ ../3rdparty/masm/disassembler/udis86/udis86_syn.c
+ ../3rdparty/masm/disassembler/udis86/udis86_syn-att.c
+ ../3rdparty/masm/disassembler/udis86/udis86_syn-intel.c
+)
+
+qt_internal_generate_tracepoints(Qml qml
+ SOURCES
+ qml/qqmlobjectcreator.cpp
+ qml/qqmlboundsignal.cpp
+ qml/qqmlbinding.cpp
+ qml/qqmltypeloader.cpp
+ jsruntime/qv4vme_moth.cpp
+)
+
+qt_internal_add_docs(Qml
+ doc/qtqml.qdocconf
+)
+
+# include snippet projects for developer shared builds
+# static builds fail with
+# CMake Error: AUTOMOC for target qt_target_qml_sources_example_resources_3:
+# The "moc" executable does not exist
+if(QT_FEATURE_private_tests AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.19" AND QT_BUILD_SHARED_LIBS)
+ add_subdirectory(doc/snippets/cmake/qt_target_qml_sources)
+ qt_autogen_tools(qt_target_qml_sources_example ENABLE_AUTOGEN_TOOLS moc)
+ qt_autogen_tools(qt_target_qml_sources_exampleplugin ENABLE_AUTOGEN_TOOLS moc)
+endif()
+
+# The Qml_sync_headers target doesn't exist when this CMakeLists is executed. So the qmlplugin
+# plugin target misses the dependency on Qml_sync_headers target. This leads to the
+# "unknown IID" issue when moc processes plugin sources, because of missing header aliases.
+# Qml_sync_headers target is created later by the finalizer in the directory scope so we add this
+# dependency manually instead of relying on qt_internal_add_qml_module logic. Same is applicable
+# for the QmlMeta and the QmlBuiltins target.
+set_property(TARGET qmlplugin APPEND PROPERTY AUTOGEN_TARGET_DEPENDS
+ Qml_sync_headers)
+set_property(TARGET QmlMeta APPEND PROPERTY AUTOGEN_TARGET_DEPENDS
+ Qml_sync_headers)
+set_property(TARGET QmlBuiltins APPEND PROPERTY AUTOGEN_TARGET_DEPENDS
+ Qml_sync_headers)
diff --git a/src/qml/Qt5QmlConfigExtras.cmake.in b/src/qml/Qt5QmlConfigExtras.cmake.in
deleted file mode 100644
index 9ddb9885cd..0000000000
--- a/src/qml/Qt5QmlConfigExtras.cmake.in
+++ /dev/null
@@ -1,5 +0,0 @@
-file(GLOB _qt5qml_other_plugins "${CMAKE_CURRENT_LIST_DIR}/Qt5Qml_*Factory.cmake")
-
-foreach(_other_plugin ${_qt5qml_other_plugins})
- include(${_other_plugin} OPTIONAL)
-endforeach()
diff --git a/src/qml/Qt6AndroidQmlMacros.cmake b/src/qml/Qt6AndroidQmlMacros.cmake
new file mode 100644
index 0000000000..5f6f01fd76
--- /dev/null
+++ b/src/qml/Qt6AndroidQmlMacros.cmake
@@ -0,0 +1,139 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Recursively scans the potential_qml_modules given as list of targets by LINK_LIBRARIES. Examines
+# .qml files given as part of the QT_QML_MODULE_QML_FILES target property, and collects their
+# directories in out_var. These directories can be used as "root path" for qmlimportscanner.
+function(_qt_internal_find_qml_root_paths potential_qml_modules out_var)
+ set(qml_root_paths "")
+ set(processed "")
+
+ set(potential_qml_modules_queue ${potential_qml_modules})
+ while(TRUE)
+ list(LENGTH potential_qml_modules_queue length)
+ if(${length} STREQUAL "0")
+ break()
+ endif()
+
+ list(POP_FRONT potential_qml_modules_queue lib)
+
+ if(NOT TARGET ${lib})
+ continue()
+ endif()
+
+ list(FIND processed ${lib} found)
+ if(${found} GREATER_EQUAL "0")
+ continue()
+ endif()
+
+ get_target_property(root_paths ${lib} _qt_internal_qml_root_path)
+ if(root_paths)
+ foreach(root_path IN LISTS root_paths)
+ list(APPEND qml_root_paths "${root_path}")
+ endforeach()
+ endif()
+
+ get_target_property(qml_files ${lib} QT_QML_MODULE_QML_FILES)
+
+ foreach(qml_file IN LISTS qml_files)
+ get_filename_component(extension "${qml_file}" LAST_EXT)
+ if(NOT extension STREQUAL ".qml")
+ continue()
+ endif()
+
+ get_filename_component(dir "${qml_file}" DIRECTORY)
+ get_filename_component(absolute_dir "${dir}" ABSOLUTE)
+ list(APPEND qml_root_paths "${absolute_dir}")
+ endforeach()
+
+ # We have to consider all dependencies here, not only QML modules.
+ # Further QML modules may be indirectly linked via an intermediate library that is not
+ # a QML module.
+ get_target_property(dependencies ${lib} LINK_LIBRARIES)
+ foreach(dependency IN LISTS dependencies)
+ list(APPEND potential_qml_modules_queue ${dependency})
+ endforeach()
+
+ list(APPEND processed ${lib})
+ endwhile()
+
+ list(REMOVE_DUPLICATES qml_root_paths)
+ set(${out_var} "${qml_root_paths}" PARENT_SCOPE)
+endfunction()
+
+# The function collects qml root paths and sets the _qt_internal_qml_root_path property to the
+# ${target} based on the provided qml source files. _qt_internal_qml_root_path is used on purpose
+# to not trigger the the QTP0002 warning without user intention.
+function(_qt_internal_collect_qml_root_paths target)
+ get_target_property(qml_root_paths ${target} _qt_internal_qml_root_path)
+ if(NOT qml_root_paths)
+ set(qml_root_paths "")
+ endif()
+ foreach(file IN LISTS ARGN)
+ get_filename_component(extension "${file}" LAST_EXT)
+ if(NOT extension STREQUAL ".qml")
+ continue()
+ endif()
+
+ get_filename_component(dir "${file}" DIRECTORY)
+ get_filename_component(absolute_dir "${dir}" ABSOLUTE)
+ list(APPEND qml_root_paths "${absolute_dir}")
+ endforeach()
+
+ get_target_property(potential_qml_modules ${target} LINK_LIBRARIES)
+
+ _qt_internal_find_qml_root_paths(${potential_qml_modules} more_paths)
+ if(more_paths)
+ foreach(path IN LISTS more_paths)
+ list(APPEND qml_root_paths ${path})
+ endforeach()
+ endif()
+
+ list(REMOVE_DUPLICATES qml_root_paths)
+ set_target_properties(${target} PROPERTIES _qt_internal_qml_root_path "${qml_root_paths}")
+endfunction()
+
+# The function extracts the required QML properties from the 'target' and
+# appends them to the 'out_var' using the corresponding JSON keys.
+function(_qt_internal_generate_android_qml_deployment_settings out_var target)
+ get_target_property(target_source_dir ${target} SOURCE_DIR)
+
+ # QML import paths
+ _qt_internal_collect_target_qml_import_paths(qml_import_paths ${target})
+ get_target_property(native_qml_import_paths "${target}" _qt_native_qml_import_paths)
+ if(native_qml_import_paths)
+ list(PREPEND native_qml_import_paths "${qml_import_paths}")
+ else()
+ set(native_qml_import_paths "${qml_import_paths}")
+ endif()
+ list(REMOVE_DUPLICATES native_qml_import_paths)
+ set_property(TARGET "${target}" PROPERTY
+ _qt_native_qml_import_paths "${native_qml_import_paths}")
+ _qt_internal_add_android_deployment_multi_value_property(${out_var} "qml-import-paths"
+ ${target} "_qt_native_qml_import_paths")
+
+ # Primitive QML root path: The target's source directory.
+ # We need this for backwards compatibility because people might not declare a proper QML module
+ # and instead add the .qml files as resources. In that case we won't see them below.
+ file(TO_CMAKE_PATH "${target_source_dir}" native_target_source_dir)
+ set_property(TARGET ${target} APPEND PROPERTY
+ _qt_android_native_qml_root_paths "${native_target_source_dir}")
+
+ # QML root paths, recursively across all linked libraries
+ set(root_paths ${target_source_dir})
+ _qt_internal_find_qml_root_paths(${target} root_paths)
+ foreach(root_path IN LISTS root_paths)
+ file(TO_CMAKE_PATH "${root_path}" native_root_path)
+ set_property(TARGET ${target} APPEND PROPERTY
+ _qt_android_native_qml_root_paths "${native_root_path}")
+ endforeach()
+
+ _qt_internal_add_android_deployment_list_property(${out_var} "qml-root-path"
+ ${target} "_qt_android_native_qml_root_paths")
+
+ # Override qmlimportscanner binary path
+ _qt_internal_add_tool_to_android_deployment_settings(${out_var} qmlimportscanner
+ "qml-importscanner-binary" ${target})
+
+ set(${out_var} "${${out_var}}" PARENT_SCOPE)
+endfunction()
diff --git a/src/qml/Qt6QmlBuildInternals.cmake b/src/qml/Qt6QmlBuildInternals.cmake
new file mode 100644
index 0000000000..7b181fabde
--- /dev/null
+++ b/src/qml/Qt6QmlBuildInternals.cmake
@@ -0,0 +1,470 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#
+# QtDeclarative Specific extensions
+#
+
+include_guard(GLOBAL)
+
+macro(qt_internal_get_internal_add_qml_module_keywords
+ option_args single_args multi_args
+ internal_option_args internal_single_args internal_multi_args)
+ set(${option_args}
+ DESIGNER_SUPPORTED
+ FOLLOW_FOREIGN_VERSIONING
+ NO_PLUGIN
+ NO_PLUGIN_OPTIONAL
+ NO_CREATE_PLUGIN_TARGET
+ NO_GENERATE_PLUGIN_SOURCE
+ NO_GENERATE_QMLTYPES
+ NO_GENERATE_QMLDIR
+ NO_LINT
+ NO_CACHEGEN
+ ENABLE_TYPE_COMPILER
+ __QT_INTERNAL_STATIC_MODULE
+ __QT_INTERNAL_SYSTEM_MODULE
+ )
+ set(${single_args}
+ URI
+ VERSION
+ PLUGIN_TARGET
+ TYPEINFO
+ CLASS_NAME
+ TYPE_COMPILER_NAMESPACE
+ )
+ set(${multi_args}
+ QML_FILES
+ RESOURCES
+ IMPORTS
+ IMPORT_PATH
+ OPTIONAL_IMPORTS
+ DEFAULT_IMPORTS
+ DEPENDENCIES
+ PAST_MAJOR_VERSIONS
+ )
+ # Args used by qt_internal_add_qml_module directly, which should not be passed to any other
+ # functions.
+ #
+ # INSTALL_SOURCE_QMLTYPES takes a path to an existing plugins.qmltypes file that should be
+ # installed.
+ #
+ # INSTALL_SOURCE_QMLDIR takes a path to an existing qmldir file that should be installed.
+ set(${internal_option_args}
+ )
+ set(${internal_single_args}
+ INSTALL_SOURCE_QMLTYPES
+ INSTALL_SOURCE_QMLDIR
+ )
+ set(${internal_multi_args}
+ )
+
+endmacro()
+
+# This function is essentially a wrapper around qt6_add_qml_module().
+# It creates the targets explicitly and sets up internal properties before
+# passing those targets to qt6_add_qml_module() for further updates.
+# All keywords supported by qt_internal_add_module() can be used, as can most
+# keywords for qt6_add_qml_module() except RESOURCE_PREFIX and
+# OUTPUT_TARGETS.
+#
+# OUTPUT_DIRECTORY and INSTALL_DIRECTORY will be given more appropriate defaults
+# if not provided by the caller. The defaults are usually what you want to use.
+#
+# - SOURCES is only passed through to qt_internal_add_plugin() or
+# qt_internal_add_module() but not to qt6_add_qml_module().
+#
+# See qt_internal_add_plugin() and qt6_add_qml_module() for the full set of
+# supported keywords.
+function(qt_internal_add_qml_module target)
+
+ qt_internal_get_internal_add_module_keywords(
+ module_option_args
+ module_single_args
+ module_multi_args
+ )
+
+ qt_internal_get_internal_add_qml_module_keywords(
+ qml_module_option_args
+ qml_module_single_args
+ qml_module_multi_args
+ qml_module_internal_option_args
+ qml_module_internal_single_args
+ qml_module_internal_multi_args
+ )
+ # TODO: Remove these once all repos have been updated to not use them
+ set(ignore_option_args
+ PLUGIN_OPTIONAL # Now the default
+ GENERATE_QMLTYPES # Now the default
+ INSTALL_QMLTYPES # Now the default
+ )
+
+ set(option_args
+ ${module_option_args}
+ ${qml_module_option_args}
+ ${ignore_option_args}
+ ${qml_module_internal_option_args}
+ )
+ set(single_args
+ ${module_single_args}
+ ${qml_module_single_args}
+ ${qml_module_internal_single_args}
+ )
+ set(multi_args
+ ${module_multi_args}
+ ${qml_module_multi_args}
+ ${qml_module_internal_multi_args}
+ )
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${option_args}"
+ "${single_args}"
+ "${multi_args}"
+ )
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ set(QT_QML_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_QMLDIR}")
+ string(REPLACE "." "/" target_path ${arg_URI})
+ if(NOT arg_OUTPUT_DIRECTORY)
+ set(arg_OUTPUT_DIRECTORY "${QT_QML_OUTPUT_DIRECTORY}/${target_path}")
+ endif()
+ if(NOT arg_INSTALL_DIRECTORY)
+ set(arg_INSTALL_DIRECTORY "${INSTALL_QMLDIR}/${target_path}")
+ endif()
+ if(arg_NO_PLUGIN)
+ unset(arg_PLUGIN_TARGET)
+ elseif(NOT arg_PLUGIN_TARGET)
+ set(arg_PLUGIN_TARGET ${target}plugin)
+ endif()
+
+ set(plugin_args "")
+ if(arg_NO_PLUGIN OR NOT arg_PLUGIN_TARGET STREQUAL target)
+ # Allow using an existing backing target.
+ if(NOT TARGET ${target})
+ # Create the backing target now to handle module-related things
+ qt_remove_args(module_args
+ ARGS_TO_REMOVE
+ ${ignore_option_args}
+ ${qml_module_option_args}
+ ${qml_module_single_args}
+ ${qml_module_multi_args}
+ ${qml_module_internal_option_args}
+ ${qml_module_internal_single_args}
+ ${qml_module_internal_multi_args}
+ OUTPUT_DIRECTORY
+ INSTALL_DIRECTORY
+ ALL_ARGS
+ ${option_args}
+ ${single_args}
+ ${multi_args}
+ ARGS
+ ${ARGN}
+ )
+ qt_internal_add_module(${target} ${module_args})
+ elseif(arg_SOURCES)
+ # If a module target was pre-created, we still need to pass the additional sources.
+ target_sources(${target} PRIVATE ${arg_SOURCES})
+ endif()
+ else()
+ # Since we are not creating a separate backing target, we have to pass
+ # through the default args to the plugin target creation instead
+ qt_internal_get_internal_add_plugin_keywords(
+ plugin_option_args plugin_single_args plugin_multi_args
+ )
+ set(args_to_remove ${option_args} ${single_args} ${multi_args})
+ list(REMOVE_ITEM args_to_remove
+ ${plugin_option_args}
+ ${plugin_single_args}
+ ${plugin_multi_args}
+ )
+ qt_remove_args(plugin_args
+ ARGS_TO_REMOVE
+ ${args_to_remove}
+ DEFAULT_IF
+ OUTPUT_DIRECTORY
+ INSTALL_DIRECTORY
+ CLASS_NAME
+ ALL_ARGS
+ ${option_args}
+ ${single_args}
+ ${multi_args}
+ ARGS
+ ${ARGN}
+ )
+ endif()
+
+ set(add_qml_module_args "")
+
+ if(NOT arg_NO_PLUGIN AND NOT arg_NO_CREATE_PLUGIN_TARGET)
+ # If the qt_internal_add_qml_module call didn't specify a CLASS_NAME, we need to pre-compute
+ # it here and pass it along to qt_internal_add_plugin -> qt_add_plugin so that
+ # qt_add_qml_plugin does not complain about differing class names (the default pre-computed
+ # class name of a regular plugin and qml plugin are different).
+ if(NOT arg_CLASS_NAME)
+ _qt_internal_compute_qml_plugin_class_name_from_uri("${arg_URI}" arg_CLASS_NAME)
+ endif()
+
+ # Create plugin target now so we can set internal things
+ list(APPEND plugin_args
+ PLUGIN_TYPE qml_plugin
+ DEFAULT_IF FALSE
+ OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
+ INSTALL_DIRECTORY ${arg_INSTALL_DIRECTORY}
+ CLASS_NAME ${arg_CLASS_NAME}
+ )
+
+ qt_internal_add_plugin(${arg_PLUGIN_TARGET} ${plugin_args})
+
+ # Use the plugin target name as the main part of the plugin basename.
+ set(plugin_basename "${arg_PLUGIN_TARGET}")
+
+ # If the target name already ends with a "plugin" suffix, remove it and re-add it to the end
+ # of the base name after the infix.
+ if(plugin_basename MATCHES "(.+)plugin$")
+ set(plugin_basename "${CMAKE_MATCH_1}")
+ endif()
+
+ # Add a the infix if Qt was configured with one.
+ if(QT_LIBINFIX)
+ string(APPEND plugin_basename "${QT_LIBINFIX}")
+ endif()
+
+ # Add the "plugin" suffix after the infix.
+ string(APPEND plugin_basename "plugin")
+
+ # Lowercase the whole thing and use it as the basename of the plugin library.
+ string(TOLOWER "${plugin_basename}" plugin_basename)
+ set_target_properties(${arg_PLUGIN_TARGET} PROPERTIES
+ OUTPUT_NAME "${plugin_basename}"
+ )
+
+ get_target_property(export_name ${arg_PLUGIN_TARGET} EXPORT_NAME)
+ if(export_name)
+ list(APPEND add_qml_module_args
+ INSTALLED_PLUGIN_TARGET "${QT_CMAKE_EXPORT_NAMESPACE}::${export_name}"
+ )
+ else()
+ list(APPEND add_qml_module_args
+ INSTALLED_PLUGIN_TARGET "${QT_CMAKE_EXPORT_NAMESPACE}::${arg_PLUGIN_TARGET}"
+ )
+ endif()
+
+ if(NOT arg_PLUGIN_TARGET STREQUAL target)
+ get_target_property(lib_type ${arg_PLUGIN_TARGET} TYPE)
+ if(lib_type STREQUAL "STATIC_LIBRARY")
+ # This is needed so that the dependency on the backing target
+ # is included in the plugin's find_package() support.
+ # The naming of backing targets and plugins don't typically
+ # follow the pattern of other plugins with regard to Private
+ # suffixes, so the dependency logic in qt_internal_add_plugin()
+ # doesn't find these. For non-static builds, the private
+ # dependency doesn't get exposed to find_package(), so we don't
+ # have to make the dependency known for that case.
+ set_property(TARGET ${arg_PLUGIN_TARGET} APPEND PROPERTY
+ _qt_target_deps "${INSTALL_CMAKE_NAMESPACE}${target}\;${PROJECT_VERSION}"
+ )
+ endif()
+ endif()
+ endif()
+
+ # TODO: Check if we need arg_SOURCES in this condition
+ if (arg_SOURCES AND NOT arg_TYPEINFO)
+ set(arg_TYPEINFO "plugins.qmltypes")
+ endif()
+
+ # Pass through options if given (these are present/absent, not true/false)
+ foreach(opt IN LISTS qml_module_option_args)
+ if(arg_${opt})
+ list(APPEND add_qml_module_args ${opt})
+ endif()
+ endforeach()
+
+ # Pass through single and multi-value args as provided.
+ foreach(arg IN LISTS qml_module_single_args qml_module_multi_args)
+ if(DEFINED arg_${arg})
+ list(APPEND add_qml_module_args ${arg} ${arg_${arg}})
+ endif()
+ endforeach()
+
+ if (arg_FOLLOW_FOREIGN_VERSIONING)
+ message(FATAL_ERROR "Do not set FOLLOW_FOREIGN_VERSIONING for module ${target}. It is already set by default for internal modules.")
+ endif()
+
+ get_target_property(qt_namespace ${QT_CMAKE_EXPORT_NAMESPACE}::Core _qt_namespace)
+ if(qt_namespace)
+ list(APPEND add_qml_module_args NAMESPACE ${qt_namespace})
+ endif()
+
+ if (arg_ENABLE_TYPE_COMPILER AND NOT arg_TYPE_COMPILER_NAMESPACE)
+ # if qmltc namespace is not specified explicitly, use Qt's namespace
+ list(APPEND add_qml_module_args TYPE_COMPILER_NAMESPACE ${qt_namespace})
+ endif()
+
+ # Update the backing and plugin targets with qml-specific things.
+ qt6_add_qml_module(${target}
+ ${add_qml_module_args}
+ OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
+ RESOURCE_PREFIX "/qt-project.org/imports"
+ OUTPUT_TARGETS output_targets
+ FOLLOW_FOREIGN_VERSIONING
+ )
+
+ if(TARGET "${target}" AND NOT target STREQUAL "Qml")
+ qt_internal_add_autogen_sync_header_dependencies(${target} Qml)
+ endif()
+ if(TARGET "${arg_PLUGIN_TARGET}" AND NOT target STREQUAL arg_PLUGIN_TARGET)
+ qt_internal_add_autogen_sync_header_dependencies(${arg_PLUGIN_TARGET} Qml)
+ endif()
+
+ if(output_targets)
+ set(plugin_export_targets)
+ set(backing_lib_export_targets)
+
+ # Separate which output target should go to which export set.
+ # The plugin initializer library should go to the plugin export set, the rest should go to
+ # the backing lib export set.
+ # In the case when the plugin target is the same as the backing lib target, all of the
+ # output targets will go to the plugin export set.
+
+ foreach(output_target IN LISTS output_targets)
+ get_target_property(is_plugin_init ${output_target} _is_qt_plugin_init_target)
+ if(is_plugin_init)
+ list(APPEND plugin_export_targets ${output_target})
+
+ # Plugin initializers associated with an internal module need the internal
+ # platform flags.
+ qt_internal_link_internal_platform_for_object_library("${output_target}")
+ else()
+ list(APPEND backing_lib_export_targets ${output_target})
+ endif()
+ endforeach()
+
+ if(backing_lib_export_targets)
+ qt_install(TARGETS ${backing_lib_export_targets}
+ EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets"
+ DESTINATION "${arg_INSTALL_DIRECTORY}"
+ )
+ qt_internal_record_rcc_object_files(${target} "${backing_lib_export_targets}"
+ INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}"
+ )
+
+ qt_internal_add_targets_to_additional_targets_export_file(
+ TARGETS ${backing_lib_export_targets}
+ EXPORT_NAME_PREFIX "${INSTALL_CMAKE_NAMESPACE}${target}"
+ )
+ endif()
+
+ if(arg_PLUGIN_TARGET AND plugin_export_targets)
+ qt_install(TARGETS ${plugin_export_targets}
+ EXPORT "${INSTALL_CMAKE_NAMESPACE}${arg_PLUGIN_TARGET}Targets"
+ DESTINATION "${arg_INSTALL_DIRECTORY}"
+ )
+
+ qt_internal_add_targets_to_additional_targets_export_file(
+ TARGETS ${plugin_export_targets}
+ EXPORT_NAME_PREFIX "${INSTALL_CMAKE_NAMESPACE}${arg_PLUGIN_TARGET}"
+ )
+ endif()
+ endif()
+
+ if(DEFINED arg_QML_FILES OR DEFINED arg_RESOURCES)
+ foreach(resource_file IN LISTS arg_QML_FILES arg_RESOURCES)
+ __qt_get_relative_resource_path_for_file(file_resource_path ${resource_file})
+ get_filename_component(resource_dir ${file_resource_path} DIRECTORY)
+ get_filename_component(resource_name ${file_resource_path} NAME)
+ if(resource_dir)
+ set(dest "${arg_INSTALL_DIRECTORY}/${resource_dir}")
+ else()
+ set(dest "${arg_INSTALL_DIRECTORY}")
+ endif()
+ qt_install(
+ FILES ${resource_file}
+ DESTINATION ${dest}
+ RENAME ${resource_name}
+ )
+ endforeach()
+ endif()
+
+ if(NOT arg_NO_GENERATE_QMLTYPES)
+ qt_install(
+ FILES ${arg_OUTPUT_DIRECTORY}/$<TARGET_PROPERTY:${target},QT_QML_MODULE_TYPEINFO>
+ DESTINATION "${arg_INSTALL_DIRECTORY}"
+ )
+
+ # Assign the install time metatypes file of the backing library to the plugin.
+ # Only do it if the backing library is different from the plugin and we do generate
+ # qml types.
+ # The install time metatypes only apply to Qt's own qml plugins, not to user project
+ # qml plugins.
+ if(arg_PLUGIN_TARGET AND
+ TARGET "${arg_PLUGIN_TARGET}" AND NOT target STREQUAL arg_PLUGIN_TARGET)
+ _qt_internal_get_metatypes_install_dir(
+ ""
+ "${INSTALL_ARCHDATADIR}"
+ install_dir
+ )
+
+ _qt_internal_assign_install_metatypes_files_and_properties(
+ "${arg_PLUGIN_TARGET}"
+ INSTALL_DIR "${install_dir}"
+ )
+ endif()
+ endif()
+
+ if(NOT arg_NO_GENERATE_QMLDIR)
+ qt_install(
+ FILES ${arg_OUTPUT_DIRECTORY}/qmldir
+ DESTINATION "${arg_INSTALL_DIRECTORY}"
+ )
+
+ get_target_property(extra_qmldirs ${target} _qt_internal_extra_qmldirs)
+ if(extra_qmldirs)
+ foreach(extra_qmldir IN LISTS extra_qmldirs)
+ __qt_get_relative_resource_path_for_file(qmldir_resource_path ${extra_qmldir})
+ get_filename_component(qmldir_dir ${qmldir_resource_path} DIRECTORY)
+ qt_install(
+ FILES ${extra_qmldir}
+ DESTINATION "${arg_INSTALL_DIRECTORY}/${qmldir_dir}"
+ )
+ endforeach()
+ endif()
+ endif()
+
+ if(arg_INSTALL_SOURCE_QMLTYPES)
+ message(AUTHOR_WARNING
+ "INSTALL_SOURCE_QMLTYPES option is deprecated and should not be used. "
+ "Please port your module to use declarative type registration.")
+
+ set(files ${arg_INSTALL_SOURCE_QMLTYPES})
+ if(QT_WILL_INSTALL)
+ install(
+ FILES ${files}
+ DESTINATION "${arg_INSTALL_DIRECTORY}"
+ )
+ else()
+ file(
+ COPY ${files}
+ DESTINATION "${arg_OUTPUT_DIRECTORY}"
+ )
+ endif()
+ endif()
+
+ if(arg_INSTALL_SOURCE_QMLDIR)
+ message(AUTHOR_WARNING
+ "INSTALL_SOURCE_QMLDIR option is deprecated and should not be used. "
+ "Please port your module to use declarative type registration.")
+
+ set(files ${arg_INSTALL_SOURCE_QMLDIR})
+ if(QT_WILL_INSTALL)
+ install(
+ FILES ${files}
+ DESTINATION "${arg_INSTALL_DIRECTORY}"
+ )
+ else()
+ file(
+ COPY ${files}
+ DESTINATION "${arg_OUTPUT_DIRECTORY}"
+ )
+ endif()
+ endif()
+endfunction()
diff --git a/src/qml/Qt6QmlConfigExtras.cmake.in b/src/qml/Qt6QmlConfigExtras.cmake.in
new file mode 100644
index 0000000000..64228fddc3
--- /dev/null
+++ b/src/qml/Qt6QmlConfigExtras.cmake.in
@@ -0,0 +1,16 @@
+if(NOT QT_NO_CREATE_TARGETS)
+ set(__qt_qml_target @QT_CMAKE_EXPORT_NAMESPACE@::Qml)
+ get_property(__qt_qml_aliased_target TARGET ${__qt_qml_target} PROPERTY ALIASED_TARGET)
+ if(__qt_qml_aliased_target)
+ set(__qt_qml_target "${__qt_qml_aliased_target}")
+ endif()
+ if("@BUILD_SHARED_LIBS@")
+ _qt_internal_add_qml_deploy_info_finalizer("${__qt_qml_target}")
+ endif()
+ set_property(TARGET ${__qt_qml_target} APPEND PROPERTY
+ INTERFACE_QT_EXECUTABLE_FINALIZERS
+ qt@PROJECT_VERSION_MAJOR@_import_qml_plugins
+ )
+ unset(__qt_qml_target)
+ unset(__qt_qml_aliased_target)
+endif()
diff --git a/src/qml/Qt6QmlDeploySupport.cmake b/src/qml/Qt6QmlDeploySupport.cmake
new file mode 100644
index 0000000000..a230e71409
--- /dev/null
+++ b/src/qml/Qt6QmlDeploySupport.cmake
@@ -0,0 +1,331 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# NOTE: This code should only ever be executed in script mode. It expects to be
+# used either as part of an install(CODE) call or called by a script
+# invoked via cmake -P as a POST_BUILD step. It would not normally be
+# included directly, it should be pulled in automatically by the deploy
+# support set up by qtbase.
+
+cmake_minimum_required(VERSION 3.16...3.21)
+
+function(qt6_deploy_qml_imports)
+ set(no_value_options
+ NO_QT_IMPORTS
+ )
+ set(single_value_options
+ TARGET
+ PLUGINS_DIR # Internal option, only used for macOS app bundle targets
+ QML_DIR
+ PLUGINS_FOUND # Name of an output variable
+ )
+ set(multi_value_options "")
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unparsed arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+
+ if(NOT arg_TARGET)
+ message(FATAL_ERROR "TARGET must be specified")
+ endif()
+
+ if(NOT arg_QML_DIR)
+ set(arg_QML_DIR "${QT_DEPLOY_QML_DIR}")
+ endif()
+
+ if(NOT arg_PLUGINS_DIR)
+ set(arg_PLUGINS_DIR "${QT_DEPLOY_PLUGINS_DIR}")
+ endif()
+
+ # The target's finalizer should have written out this file
+ string(MAKE_C_IDENTIFIER "${arg_TARGET}" target_id)
+ set(filename "${__QT_DEPLOY_IMPL_DIR}/deploy_qml_imports/${target_id}")
+ if(__QT_DEPLOY_GENERATOR_IS_MULTI_CONFIG)
+ string(APPEND filename "-${__QT_DEPLOY_ACTIVE_CONFIG}")
+ endif()
+ string(APPEND filename ".cmake")
+ if(NOT EXISTS "${filename}")
+ message(FATAL_ERROR
+ "No QML imports information recorded for target ${arg_TARGET}. "
+ "The target must be an executable and qt_add_qml_module() must "
+ "have been called with it. If using a CMake version lower than 3.19, ensure "
+ "that the executable is manually finalized with qt_finalize_target(). "
+ "Missing file:\n ${filename}"
+ )
+ endif()
+ include(${filename})
+
+endfunction()
+
+if(NOT __QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_deploy_qml_imports)
+ if(__QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ qt6_deploy_qml_imports(${ARGV})
+
+ cmake_parse_arguments(PARSE_ARGV 0 arg "" "PLUGINS_FOUND" "")
+ if(arg_PLUGINS_FOUND)
+ set(${arg_PLUGINS_FOUND} ${${arg_PLUGINS_FOUND}} PARENT_SCOPE)
+ endif()
+ else()
+ message(FATAL_ERROR "qt_deploy_qml_imports() is only available in Qt 6.")
+ endif()
+ endfunction()
+endif()
+
+function(_qt_internal_deploy_qml_imports_for_target)
+ set(no_value_options
+ BUNDLE
+ NO_QT_IMPORTS
+ )
+ set(single_value_options
+ IMPORTS_FILE
+ PLUGINS_FOUND
+ QML_DIR
+ PLUGINS_DIR
+ )
+ set(multi_value_options "")
+
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+ foreach(opt IN LISTS single_value_options)
+ if(NOT arg_${opt})
+ message(FATAL_ERROR "Required argument not provided: ${opt}")
+ endif()
+ endforeach()
+
+ include("${arg_IMPORTS_FILE}")
+
+ macro(_qt_internal_parse_qml_imports_entry prefix index)
+ cmake_parse_arguments("${prefix}"
+ ""
+ "CLASSNAME;NAME;PATH;PLUGIN;RELATIVEPATH;TYPE;VERSION;LINKTARGET"
+ ""
+ ${qml_import_scanner_import_${index}}
+ )
+ endmacro()
+
+ get_filename_component(install_prefix_abs "${QT_DEPLOY_PREFIX}" ABSOLUTE)
+ set(plugins_found "")
+
+ if(__QT_DEPLOY_POST_BUILD)
+ message(STATUS "Running macOS bundle QML support POST_BUILD routine.")
+ endif()
+
+ # Parse the generated cmake file. It is possible for the scanner to find no
+ # usage of QML, in which case the import count is 0.
+ if(qml_import_scanner_imports_count GREATER 0)
+ set(processed_names "")
+ math(EXPR last_index "${qml_import_scanner_imports_count} - 1")
+ foreach(index RANGE 0 ${last_index})
+ _qt_internal_parse_qml_imports_entry(entry ${index})
+
+ if("${entry_NAME}" STREQUAL "")
+ message(WARNING "No NAME at scan index ${index}: ${imports_file}")
+ continue()
+ endif()
+
+ # A plugin might have multiple entries (e.g. for different versions).
+ # Only copy it once.
+ if("${entry_NAME}" IN_LIST processed_names)
+ continue()
+ endif()
+ # Even if we skip this one, we don't need to process it again
+ list(APPEND processed_names ${entry_NAME})
+
+ if("${entry_PATH}" STREQUAL "" OR
+ "${entry_PLUGIN}" STREQUAL "" OR
+ "${entry_RELATIVEPATH}" STREQUAL "")
+ # These might be a valid QML module, but not have a plugin library.
+ # We only care about modules that have a plugin we need to copy.
+ continue()
+ endif()
+
+ if(arg_NO_QT_IMPORTS AND
+ "${entry_LINKTARGET}" MATCHES "${__QT_CMAKE_EXPORT_NAMESPACE}::")
+ continue()
+ endif()
+
+ # For installation, we want the qmldir file and its plugin. If the
+ # CMake project generating the plugin sets version details on its
+ # CMake target, we might have symlinks and version numbers in the
+ # file names, so account for those. There should never be plugin
+ # libraries for more than one QML module in the directory, so we
+ # shouldn't need to worry about matching plugins we don't want.
+ set(relative_qmldir "${arg_QML_DIR}/${entry_RELATIVEPATH}")
+ if("${CMAKE_INSTALL_PREFIX}" STREQUAL "")
+ set(install_qmldir "./${relative_qmldir}")
+ else()
+ set(install_qmldir "${CMAKE_INSTALL_PREFIX}/${relative_qmldir}")
+ endif()
+ set(dest_qmldir "${QT_DEPLOY_PREFIX}/${relative_qmldir}")
+ if(arg_BUNDLE)
+ if("${CMAKE_INSTALL_PREFIX}" STREQUAL "")
+ set(install_plugin "./${arg_PLUGINS_DIR}")
+ else()
+ set(install_plugin "${CMAKE_INSTALL_PREFIX}/${arg_PLUGINS_DIR}")
+ endif()
+ set(dest_plugin "${QT_DEPLOY_PREFIX}/${arg_PLUGINS_DIR}")
+ else()
+ set(install_plugin "${install_qmldir}")
+ set(dest_plugin "${dest_qmldir}")
+ endif()
+
+ file(INSTALL "${entry_PATH}/qmldir" DESTINATION "${install_qmldir}")
+
+ if(__QT_DEPLOY_POST_BUILD)
+ # We are being invoked as a post-build step. The plugin might
+ # not exist yet, so we can't even glob for it, let alone copy
+ # it. We know what its name should be though, so we can create
+ # a symlink to where it will eventually be, which will be enough
+ # to allow it to run from the build tree. It won't matter if
+ # the plugin gets updated later in the build, the symlink will
+ # still be pointing at the right location.
+ # In theory, this could be possible for any platform that
+ # supports symlinks (which all do in some form now, even
+ # Windows if the right permissions are set), but we only really
+ # expect to need this for macOS app bundles.
+ if(DEFINED __QT_DEPLOY_TARGET_${entry_LINKTARGET}_FILE)
+ set(source_file "${__QT_DEPLOY_TARGET_${entry_LINKTARGET}_FILE}")
+ get_filename_component(source_file_name "${source_file}" NAME)
+ set(final_destination "${dest_qmldir}/${source_file_name}")
+ else()
+ # TODO: This is inconsistent with what we do further down below for the
+ # installation case. There we file(GLOB) any files we find, whereas here we
+ # build the path manually, because the file might not exist yet.
+ # Ideally both cases should use neither file(GLOB) nor manual path building,
+ # and instead rely on available target information or qmldir information.
+ # Currently that is not possible because we don't have all targets exposed
+ # via the __QT_DEPLOY_TARGET_{target} mechanism, only those that are built as
+ # part of the current project, and the qmldir -> qmlimportscanner does print
+ # the full file path, because there is one qmldir, but possibly 2+ plugins
+ # (debug and release).
+ set(plugin_suffix "")
+ if(__QT_DEPLOY_ACTIVE_CONFIG STREQUAL "Debug")
+ string(APPEND plugin_suffix "${__QT_DEPLOY_QT_DEBUG_POSTFIX}")
+ endif()
+
+ set(source_file "${entry_PATH}/lib${entry_PLUGIN}${plugin_suffix}.dylib")
+ set(final_destination "${dest_qmldir}/lib${entry_PLUGIN}${plugin_suffix}.dylib")
+ endif()
+
+ message(STATUS "Symlinking: ${final_destination}")
+ file(CREATE_LINK
+ "${source_file}"
+ "${final_destination}"
+ SYMBOLIC
+ )
+
+ # We don't add this plugin to plugins_found because we don't
+ # actually make a copy of the plugin. We don't want the caller
+ # thinking they should further process what would still be the
+ # original plugin in the build tree.
+ continue()
+ endif()
+
+ # Deploy the plugin.
+ if(DEFINED __QT_DEPLOY_TARGET_${entry_LINKTARGET}_FILE)
+ set(files "${__QT_DEPLOY_TARGET_${entry_LINKTARGET}_FILE}")
+ else()
+ # We don't know the exact target file name. Fall back to file name heuristics.
+
+ # Construct a regular expression that matches the plugin's file name.
+ set(plugin_regex "^(.*/)?(lib)?${entry_PLUGIN}")
+ if(__QT_DEPLOY_QT_IS_MULTI_CONFIG_BUILD_WITH_DEBUG)
+ # If our application is a release build, do not match any debug suffix.
+ # If our application is a debug build, match exactly a debug suffix.
+ if(__QT_DEPLOY_ACTIVE_CONFIG STREQUAL "Debug")
+ string(APPEND plugin_regex "${__QT_DEPLOY_QT_DEBUG_POSTFIX}")
+ endif()
+ else()
+ # The Qt installation does only contain one build of the plugin. We match any
+ # possible debug suffix, or none.
+ string(APPEND plugin_regex ".*")
+ endif()
+ string(APPEND plugin_regex "\\.(so|dylib|dll)(\\.[0-9]+)*$")
+
+ file(GLOB files LIST_DIRECTORIES false "${entry_PATH}/*${entry_PLUGIN}*")
+ list(FILTER files INCLUDE REGEX "${plugin_regex}")
+ endif()
+ file(INSTALL ${files} DESTINATION "${install_plugin}" USE_SOURCE_PERMISSIONS)
+
+ get_filename_component(dest_plugin_abs "${dest_plugin}" ABSOLUTE)
+ if(__QT_DEPLOY_TOOL STREQUAL "GRD")
+ # Use the full plugin path for deployment. This is necessary for file(GRD) to
+ # resolve the dependencies of the plugins.
+ list(APPEND plugins_found ${files})
+ else()
+ # Use relative paths for the plugins. If we used full paths here, macdeployqt would
+ # modify the RPATHS of plugins in the Qt installation.
+ file(RELATIVE_PATH rel_path "${install_prefix_abs}" "${dest_plugin_abs}")
+ foreach(file IN LISTS files)
+ get_filename_component(filename "${file}" NAME)
+ list(APPEND plugins_found "${rel_path}/${filename}")
+ endforeach()
+ endif()
+
+ # Install runtime dependencies on Windows.
+ if(__QT_DEPLOY_SYSTEM_NAME STREQUAL "Windows")
+ foreach(file IN LISTS __QT_DEPLOY_TARGET_${entry_LINKTARGET}_RUNTIME_DLLS)
+ if(__QT_DEPLOY_VERBOSE)
+ message(STATUS "runtime dependency for QML plugin '${entry_PLUGIN}':")
+ endif()
+ file(INSTALL ${file} DESTINATION "${QT_DEPLOY_PREFIX}/${QT_DEPLOY_BIN_DIR}")
+ endforeach()
+ endif()
+
+ if(__QT_DEPLOY_TOOL STREQUAL "GRD" AND __QT_DEPLOY_MUST_ADJUST_PLUGINS_RPATH)
+ # The RPATHs of the installed plugins do not match Qt's original lib directory.
+ # We must set the RPATH to point to QT_DEPLOY_LIBDIR.
+ _qt_internal_get_rpath_origin(rpath_origin)
+ foreach(file_path IN LISTS files)
+ get_filename_component(file_name ${file_path} NAME)
+ file(RELATIVE_PATH rel_lib_dir "${dest_plugin}"
+ "${QT_DEPLOY_PREFIX}/${QT_DEPLOY_LIB_DIR}"
+ )
+ _qt_internal_set_rpath(
+ FILE "${dest_plugin}/${file_name}"
+ NEW_RPATH "${rpath_origin}/${rel_lib_dir}"
+ )
+ endforeach()
+ endif()
+
+ if(arg_BUNDLE)
+ # Actual plugin binaries will be in PlugIns, but qmldir files
+ # expect them to be in the same directory as themselves
+ # (i.e. under Resources/qml/...). Add a symlink at the place
+ # the qmldir expects the binary to be. This arrangement keeps
+ # binaries under PlugIns and non-binaries under Resources,
+ # which is required for code signing to work properly.
+ get_filename_component(dest_qmldir_abs "${dest_qmldir}" ABSOLUTE)
+ file(RELATIVE_PATH rel_path "${dest_qmldir_abs}" "${dest_plugin_abs}")
+ foreach(plugin_file IN LISTS files)
+ get_filename_component(filename "${plugin_file}" NAME)
+
+ set(final_destination "${dest_qmldir}/${filename}")
+ message(STATUS "Symlinking: ${final_destination}")
+ file(CREATE_LINK "${rel_path}/${filename}" "${final_destination}" SYMBOLIC)
+ endforeach()
+ endif()
+ endforeach()
+ endif()
+
+ set(${arg_PLUGINS_FOUND} ${plugins_found} PARENT_SCOPE)
+
+endfunction()
+
+function(_qt_internal_show_skip_qml_runtime_deploy_message)
+ # Don't show the message in static Qt builds, it can be misleading, because we still
+ # run qmlimportscanner / link the static qml plguins into the binary despite not having
+ # a qml deployment step.
+ if(__QT_DEPLOY_IS_SHARED_LIBS_BUILD)
+ message(STATUS "Skipping QML module deployment steps.")
+ endif()
+endfunction()
diff --git a/src/qml/Qt6QmlFindQmlscInternal.cmake b/src/qml/Qt6QmlFindQmlscInternal.cmake
new file mode 100644
index 0000000000..fc5bff1e2c
--- /dev/null
+++ b/src/qml/Qt6QmlFindQmlscInternal.cmake
@@ -0,0 +1,11 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if (QT_NO_FIND_QMLSC)
+ return()
+endif()
+
+set(QT_NO_FIND_QMLSC TRUE)
+
+# FIXME: Make this work with cross-builds
+find_package(Qt6QmlCompilerPlusPrivate QUIET)
diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake
new file mode 100644
index 0000000000..a64e2eea6b
--- /dev/null
+++ b/src/qml/Qt6QmlMacros.cmake
@@ -0,0 +1,4304 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#
+# Q6QmlMacros
+#
+
+set(__qt_qml_macros_module_base_dir "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "")
+
+# Install support uses the CMAKE_INSTALL_xxxDIR variables. Include this here
+# so that it is more likely to get pulled in earlier at a higher level, and also
+# to avoid re-including it many times later
+include(GNUInstallDirs)
+_qt_internal_add_deploy_support("${CMAKE_CURRENT_LIST_DIR}/Qt6QmlDeploySupport.cmake")
+
+function(qt6_add_qml_module target)
+ set(args_option
+ STATIC
+ SHARED
+ DESIGNER_SUPPORTED
+ FOLLOW_FOREIGN_VERSIONING
+ AUTO_RESOURCE_PREFIX
+ NO_PLUGIN
+ NO_PLUGIN_OPTIONAL
+ NO_CREATE_PLUGIN_TARGET
+ NO_GENERATE_PLUGIN_SOURCE
+ NO_GENERATE_QMLTYPES
+ NO_GENERATE_QMLDIR
+ NO_LINT
+ NO_CACHEGEN
+ NO_RESOURCE_TARGET_PATH
+ NO_IMPORT_SCAN
+ ENABLE_TYPE_COMPILER
+
+ # Used to mark modules as having static side effects (i.e. if they install an image provider)
+ __QT_INTERNAL_STATIC_MODULE
+ # Used to mark modules as being a system module that provides all builtins
+ __QT_INTERNAL_SYSTEM_MODULE
+ # Give the resource for the qmldir a unique name; TODO: Remove once we can
+ __QT_INTERNAL_DISAMBIGUATE_QMLDIR_RESOURCE
+ )
+
+ set(args_single
+ PLUGIN_TARGET
+ INSTALLED_PLUGIN_TARGET # Internal option only, it may be removed
+ OUTPUT_TARGETS
+ RESOURCE_PREFIX
+ URI
+ TARGET_PATH # Internal option only, it may be removed
+ VERSION
+ OUTPUT_DIRECTORY
+ CLASS_NAME
+ TYPEINFO
+ NAMESPACE
+ # TODO: We don't handle installation, warn if callers used these with the old
+ # API and eventually remove them once we have updated all other repos
+ RESOURCE_EXPORT
+ INSTALL_DIRECTORY
+ INSTALL_LOCATION
+ TYPE_COMPILER_NAMESPACE
+ QMLTC_EXPORT_DIRECTIVE
+ QMLTC_EXPORT_FILE_NAME
+ )
+
+ set(args_multi
+ SOURCES
+ QML_FILES
+ RESOURCES
+ IMPORTS
+ IMPORT_PATH
+ OPTIONAL_IMPORTS
+ DEFAULT_IMPORTS
+ DEPENDENCIES
+ PAST_MAJOR_VERSIONS
+ )
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${args_option}"
+ "${args_single}"
+ "${args_multi}"
+ )
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown/unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+
+ # Warn about options we no longer need/use (these were used by the internal
+ # targets and examples, but the logic has been shifted to
+ # qt_internal_add_qml_module() or left as a responsibility of the caller).
+ if(DEFINED arg_RESOURCE_EXPORT)
+ message(AUTHOR_WARNING
+ "RESOURCE_EXPORT will be ignored. This function does not handle "
+ "installation, which is what RESOURCE_EXPORT was previously used "
+ "for. Please update your project to install the target directly."
+ )
+ endif()
+
+ if(DEFINED arg_INSTALL_DIRECTORY)
+ message(AUTHOR_WARNING
+ "INSTALL_DIRECTORY will be ignored. This function does not handle "
+ "installation, please update your project to install the target "
+ "directly."
+ )
+ endif()
+
+ if(DEFINED arg_INSTALL_LOCATION)
+ message(AUTHOR_WARNING
+ "INSTALL_LOCATION will be ignored. This function does not handle "
+ "installation, please update your project to install the target "
+ "directly."
+ )
+ endif()
+
+ # Mandatory arguments
+ if (NOT arg_URI)
+ message(FATAL_ERROR
+ "Called without a module URI. Please specify one using the URI argument."
+ )
+ endif()
+
+ if (NOT arg_VERSION)
+ set(arg_VERSION "254.254")
+ elseif ("${arg_VERSION}" MATCHES "^([0-9]+\\.[0-9]+)\\.[0-9]+$")
+ set(arg_VERSION "${CMAKE_MATCH_1}")
+ elseif (NOT "${arg_VERSION}" MATCHES "^[0-9]+\\.[0-9]+$")
+ message(FATAL_ERROR
+ "Called with an invalid version argument: '${arg_VERSION}'. "
+ "Expected version in the form: VersionMajor.VersionMinor."
+ )
+ endif()
+
+ # Other arguments and checking for invalid combinations
+ if (NOT arg_TARGET_PATH)
+ # NOTE: This will always be used for copying things to the build
+ # directory, but it will not be used for resource paths if
+ # NO_RESOURCE_TARGET_PATH was given.
+ string(REPLACE "." "/" arg_TARGET_PATH ${arg_URI})
+ endif()
+
+ if(arg_NO_PLUGIN AND DEFINED arg_PLUGIN_TARGET)
+ message(FATAL_ERROR
+ "NO_PLUGIN was specified, but PLUGIN_TARGET was also given. "
+ "At most one of these can be present."
+ )
+ endif()
+
+ if (NOT arg_ENABLE_TYPE_COMPILER)
+ if (DEFINED arg_TYPE_COMPILER_NAMESPACE)
+ message(WARNING
+ "TYPE_COMPILER_NAMESPACE is set, but ENABLE_TYPE_COMPILER is not specified. "
+ "The TYPE_COMPILER_NAMESPACE value will be ignored."
+ )
+ endif()
+
+ if (DEFINED arg_QMLTC_EXPORT_DIRECTIVE)
+ message(WARNING
+ "QMLTC_EXPORT_DIRECTIVE is set, but ENABLE_TYPE_COMPILER is not specified. "
+ "The QMLTC_EXPORT_DIRECTIVE value will be ignored."
+ )
+ endif()
+ if (DEFINED arg_QMLTC_EXPORT_FILE_NAME)
+ message(WARNING
+ "QMLTC_EXPORT_FILE_NAME is set, but ENABLE_TYPE_COMPILER is not specified. "
+ "The QMLTC_EXPORT_FILE_NAME will be ignored."
+ )
+ endif()
+ else()
+ if ((DEFINED arg_QMLTC_EXPORT_FILE_NAME) AND (NOT (DEFINED arg_QMLTC_EXPORT_DIRECTIVE)))
+ message(FATAL_ERROR
+ "Specifying a value for QMLTC_EXPORT_FILE_NAME also requires one for QMLTC_EXPORT_DIRECTIVE."
+ )
+ endif()
+ endif()
+
+ set(is_executable FALSE)
+ if(TARGET ${target})
+ if(arg_STATIC OR arg_SHARED)
+ message(FATAL_ERROR
+ "Cannot use STATIC or SHARED keyword when passed an existing target (${target})"
+ )
+ endif()
+
+ # With CMake 3.17 and earlier, a source file's generated property isn't
+ # visible outside of the directory scope in which it is set. That can
+ # lead to build errors for things like type registration due to CMake
+ # thinking nothing will create a missing file on the first run. With
+ # CMake 3.18 or later, we can force that visibility. Policy CMP0118
+ # added in CMake 3.20 should have made this unnecessary, but we can't
+ # rely on that because the user project controls what it is set to at
+ # the point where it matters, which is the end of the target's
+ # directory scope (hence we can't even test for it here).
+ get_target_property(source_dir ${target} SOURCE_DIR)
+ if(NOT source_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR AND
+ CMAKE_VERSION VERSION_LESS "3.18")
+ message(WARNING
+ "qt6_add_qml_module() is being called in a different "
+ "directory scope to the one in which the target \"${target}\" "
+ "was created. CMake 3.18 or later is required to generate a "
+ "project robustly for this scenario, but you are using "
+ "CMake ${CMAKE_VERSION}. Ideally, qt6_add_qml_module() should "
+ "only be called from the same scope as the one the target was "
+ "created in to avoid dependency and visibility problems."
+ )
+ endif()
+
+ get_target_property(backing_target_type ${target} TYPE)
+ get_target_property(is_android_executable "${target}" _qt_is_android_executable)
+ if (backing_target_type STREQUAL "EXECUTABLE" OR is_android_executable)
+ if(DEFINED arg_PLUGIN_TARGET)
+ message(FATAL_ERROR
+ "A QML module with an executable as its backing target "
+ "cannot have a plugin."
+ )
+ endif()
+ if(arg_NO_CREATE_PLUGIN_TARGET)
+ message(WARNING
+ "A QML module with an executable as its backing target "
+ "cannot have a plugin. The NO_CREATE_PLUGIN_TARGET option "
+ "has no effect and should be removed."
+ )
+ endif()
+ set(arg_NO_PLUGIN TRUE)
+ set(lib_type "")
+ set(is_executable TRUE)
+ elseif(arg_NO_RESOURCE_TARGET_PATH)
+ message(FATAL_ERROR
+ "NO_RESOURCE_TARGET_PATH cannot be used for a backing target "
+ "that is not an executable"
+ )
+ elseif(backing_target_type STREQUAL "STATIC_LIBRARY")
+ set(lib_type STATIC)
+ elseif(backing_target_type MATCHES "(SHARED|MODULE)_LIBRARY")
+ set(lib_type SHARED)
+ else()
+ message(FATAL_ERROR "Unsupported backing target type: ${backing_target_type}")
+ endif()
+ else()
+ if(arg_STATIC AND arg_SHARED)
+ message(FATAL_ERROR
+ "Both STATIC and SHARED specified, at most one can be given"
+ )
+ endif()
+
+ if(arg_NO_RESOURCE_TARGET_PATH)
+ message(FATAL_ERROR
+ "NO_RESOURCE_TARGET_PATH can only be provided when an existing "
+ "executable target is passed in as the backing target"
+ )
+ endif()
+
+ # Explicit arguments take precedence, otherwise default to using the same
+ # staticality as what Qt was built with. This follows the already
+ # established default behavior for building ordinary Qt plugins.
+ # We don't allow the standard CMake BUILD_SHARED_LIBS variable to control
+ # the default because that can lead to different defaults depending on
+ # whether you build with a separate backing target or not.
+ if(arg_STATIC)
+ set(lib_type STATIC)
+ elseif(arg_SHARED)
+ set(lib_type SHARED)
+ elseif(QT6_IS_SHARED_LIBS_BUILD)
+ set(lib_type SHARED)
+ else()
+ set(lib_type STATIC)
+ endif()
+ endif()
+
+ if(arg_NO_PLUGIN)
+ # Simplifies things a bit further below
+ set(arg_PLUGIN_TARGET "")
+ elseif(NOT DEFINED arg_PLUGIN_TARGET)
+ if(arg_NO_CREATE_PLUGIN_TARGET)
+ # We technically could allow this and rely on the project using the
+ # default plugin target name, but not doing so gives us the
+ # flexibility to potentially change that default later if needed.
+ message(FATAL_ERROR
+ "PLUGIN_TARGET must also be provided when NO_CREATE_PLUGIN_TARGET "
+ "is used. If you want to disable creating a plugin altogether, "
+ "use the NO_PLUGIN option instead."
+ )
+ endif()
+ set(arg_PLUGIN_TARGET ${target}plugin)
+ endif()
+ if(arg_NO_CREATE_PLUGIN_TARGET AND arg_PLUGIN_TARGET STREQUAL target AND NOT TARGET ${target})
+ message(FATAL_ERROR
+ "PLUGIN_TARGET is the same as the backing target, which is allowed, "
+ "but NO_CREATE_PLUGIN_TARGET was also given and the target does not "
+ "exist. Either ensure the target is already created or do not "
+ "specify NO_CREATE_PLUGIN_TARGET."
+ )
+ endif()
+ if(NOT arg_INSTALLED_PLUGIN_TARGET)
+ set(arg_INSTALLED_PLUGIN_TARGET ${arg_PLUGIN_TARGET})
+ endif()
+
+ set(no_gen_source)
+ if(arg_NO_GENERATE_PLUGIN_SOURCE)
+ set(no_gen_source NO_GENERATE_PLUGIN_SOURCE)
+ endif()
+
+ if(arg_OUTPUT_DIRECTORY)
+ get_filename_component(arg_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
+ ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}"
+ )
+ else()
+ if("${QT_QML_OUTPUT_DIRECTORY}" STREQUAL "")
+ set(arg_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ # For libraries, we assume/require that the source directory
+ # structure is consistent with the target path. For executables,
+ # the source directory will usually not reflect the target path
+ # and the project will often expect to be able to use resource
+ # paths that don't include the target path (they need the
+ # NO_RESOURCE_TARGET_PATH option if they do that). Tooling always
+ # needs the target path in the file system though, so the output
+ # directory should always have it. Handle the special case for
+ # executables to ensure this is what we get.
+ if(is_executable)
+ string(APPEND arg_OUTPUT_DIRECTORY "/${arg_TARGET_PATH}")
+ endif()
+ else()
+ if(NOT IS_ABSOLUTE "${QT_QML_OUTPUT_DIRECTORY}")
+ message(FATAL_ERROR
+ "QT_QML_OUTPUT_DIRECTORY must be an absolute path, but given: "
+ "${QT_QML_OUTPUT_DIRECTORY}"
+ )
+ endif()
+ # This inherently does what we want for libraries and executables
+ set(arg_OUTPUT_DIRECTORY ${QT_QML_OUTPUT_DIRECTORY}/${arg_TARGET_PATH})
+ endif()
+ endif()
+
+ # Sanity check that we are not trying to have two different QML modules use
+ # the same output directory.
+ get_property(dirs GLOBAL PROPERTY _qt_all_qml_output_dirs)
+ if(dirs)
+ list(FIND dirs "${arg_OUTPUT_DIRECTORY}" index)
+ if(NOT index EQUAL -1)
+ get_property(qml_targets GLOBAL PROPERTY _qt_all_qml_targets)
+ list(GET qml_targets ${index} other_target)
+ message(FATAL_ERROR
+ "Output directory for target \"${target}\" is already used by "
+ "another QML module (target \"${other_target}\"). "
+ "Output directory is:\n ${arg_OUTPUT_DIRECTORY}\n"
+ )
+ endif()
+ endif()
+ set_property(GLOBAL APPEND PROPERTY _qt_all_qml_uris ${arg_URI})
+ set_property(GLOBAL APPEND PROPERTY _qt_all_qml_output_dirs ${arg_OUTPUT_DIRECTORY})
+ set_property(GLOBAL APPEND PROPERTY _qt_all_qml_targets ${target})
+
+ if(NOT arg_CLASS_NAME AND TARGET "${arg_PLUGIN_TARGET}")
+ get_target_property(class_name ${arg_PLUGIN_TARGET} QT_PLUGIN_CLASS_NAME)
+ if(class_name)
+ set(arg_CLASS_NAME)
+ endif()
+ endif()
+ if(NOT arg_CLASS_NAME)
+ _qt_internal_compute_qml_plugin_class_name_from_uri("${arg_URI}" arg_CLASS_NAME)
+ endif()
+
+ if(TARGET ${target})
+ if(arg_PLUGIN_TARGET STREQUAL target)
+ # Insert the plugin's URI into its meta data to enable usage
+ # of static plugins in QtDeclarative (like in mkspecs/features/qml_plugin.prf).
+ set_property(TARGET ${target} APPEND PROPERTY
+ AUTOMOC_MOC_OPTIONS "-Muri=${arg_URI}"
+ )
+ endif()
+ else()
+ if(arg_PLUGIN_TARGET STREQUAL target)
+ set(conditional_args ${no_gen_source})
+ if(arg_NAMESPACE)
+ list(APPEND conditional_args NAMESPACE ${arg_NAMESPACE})
+ endif()
+ qt6_add_qml_plugin(${target}
+ ${lib_type}
+ OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
+ URI ${arg_URI}
+ CLASS_NAME ${arg_CLASS_NAME}
+ ${conditional_args}
+ )
+ else()
+ qt6_add_library(${target} ${lib_type})
+ endif()
+ endif()
+
+ if(NOT target STREQUAL Qml)
+ target_link_libraries(${target} PRIVATE ${QT_CMAKE_EXPORT_NAMESPACE}::Qml)
+ endif()
+
+ if(NOT arg_TYPEINFO AND NOT arg_NO_GENERATE_QMLTYPES)
+ set(arg_TYPEINFO ${target}.qmltypes)
+ endif()
+
+ foreach(import_set IN ITEMS IMPORTS OPTIONAL_IMPORTS DEFAULT_IMPORTS)
+ foreach(import IN LISTS arg_${import_set})
+ string(FIND ${import} "/" slash_position REVERSE)
+ if (slash_position EQUAL -1)
+ set_property(TARGET ${target} APPEND PROPERTY
+ QT_QML_MODULE_${import_set} "${import}"
+ )
+ else()
+ string(SUBSTRING ${import} 0 ${slash_position} import_module)
+ math(EXPR slash_position "${slash_position} + 1")
+ string(SUBSTRING ${import} ${slash_position} -1 import_version)
+ if (import_version MATCHES "^([0-9]+(\\.[0-9]+)?|auto)$")
+ set_property(TARGET ${target} APPEND PROPERTY
+ QT_QML_MODULE_${import_set} "${import_module} ${import_version}"
+ )
+ else()
+ message(FATAL_ERROR
+ "Invalid module ${import} version number. "
+ "Expected 'VersionMajor', 'VersionMajor.VersionMinor' or 'auto'."
+ )
+ endif()
+ endif()
+ endforeach()
+ endforeach()
+
+ foreach(dependency IN LISTS arg_DEPENDENCIES)
+ string(FIND ${dependency} "/" slash_position REVERSE)
+ if (slash_position EQUAL -1)
+ set_property(TARGET ${target} APPEND PROPERTY
+ QT_QML_MODULE_DEPENDENCIES "${dependency}"
+ )
+ else()
+ string(SUBSTRING ${dependency} 0 ${slash_position} dep_module_uri)
+ math(EXPR slash_position "${slash_position} + 1")
+ string(SUBSTRING ${dependency} ${slash_position} -1 dep_version)
+ if (dep_version MATCHES "^([0-9]+(\\.[0-9]+)?|auto)$")
+ set_property(TARGET ${target} APPEND PROPERTY
+ QT_QML_MODULE_DEPENDENCIES "${dep_module_uri} ${dep_version}"
+ )
+ else()
+ message(FATAL_ERROR
+ "Invalid module dependency version number. "
+ "Expected 'VersionMajor', 'VersionMajor.VersionMinor' or 'auto'."
+ )
+ endif()
+ endif()
+ endforeach()
+ _qt_internal_collect_qml_module_dependencies(${target})
+
+ if(arg_AUTO_RESOURCE_PREFIX)
+ if(arg_RESOURCE_PREFIX)
+ message(FATAL_ERROR
+ "Both RESOURCE_PREFIX and AUTO_RESOURCE_PREFIX are specified for ${target}. "
+ "You can only have one."
+ )
+ else()
+ set(arg_RESOURCE_PREFIX "/qt/qml")
+ message(DEPRECATION "AUTO_RESOURCE_PREFIX is deprecated. "
+ "Please use the qt_policy(SET) command to set the QTP0001 policy, "
+ "or use the qt_standard_project_setup() command to set your preferred "
+ "REQUIRES to get the preferred behavior. "
+ "Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details.")
+ endif()
+ elseif(arg_RESOURCE_PREFIX)
+ _qt_internal_canonicalize_resource_path("${arg_RESOURCE_PREFIX}" arg_RESOURCE_PREFIX)
+ elseif(arg_NO_RESOURCE_TARGET_PATH)
+ # Suppress the warning if NO_RESOURCE_TARGET_PATH is given.
+ # In that case, we assume the user knows what they want.
+ set(arg_RESOURCE_PREFIX "/")
+ else()
+ __qt_internal_setup_policy(QTP0001 "6.5.0"
+"':/qt/qml/' is the default resource prefix for QML modules. \
+Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details."
+ )
+ qt6_policy(GET QTP0001 use_auto_prefix_policy)
+ if ("${use_auto_prefix_policy}" STREQUAL "NEW")
+ set(arg_RESOURCE_PREFIX "/qt/qml")
+ else()
+ set(arg_RESOURCE_PREFIX "/")
+ endif()
+ endif()
+
+ if(arg_NO_RESOURCE_TARGET_PATH)
+ set(qt_qml_module_resource_prefix "${arg_RESOURCE_PREFIX}")
+ else()
+ if(arg_RESOURCE_PREFIX STREQUAL "/") # Checked so we prevent double-slash
+ set(qt_qml_module_resource_prefix "/${arg_TARGET_PATH}")
+ else()
+ set(qt_qml_module_resource_prefix "${arg_RESOURCE_PREFIX}/${arg_TARGET_PATH}")
+ endif()
+ endif()
+
+ set_target_properties(${target} PROPERTIES
+ QT_QML_MODULE_NO_LINT "${arg_NO_LINT}"
+ QT_QML_MODULE_NO_CACHEGEN "${arg_NO_CACHEGEN}"
+ QT_QML_MODULE_NO_GENERATE_QMLDIR "${arg_NO_GENERATE_QMLDIR}"
+ QT_QML_MODULE_NO_PLUGIN "${arg_NO_PLUGIN}"
+ QT_QML_MODULE_NO_PLUGIN_OPTIONAL "${arg_NO_PLUGIN_OPTIONAL}"
+ QT_QML_MODULE_NO_IMPORT_SCAN "${arg_NO_IMPORT_SCAN}"
+ _qt_qml_module_follow_foreign_versioning "${arg_FOLLOW_FOREIGN_VERSIONING}"
+ QT_QML_MODULE_URI "${arg_URI}"
+ QT_QML_MODULE_TARGET_PATH "${arg_TARGET_PATH}"
+ QT_QML_MODULE_VERSION "${arg_VERSION}"
+ QT_QML_MODULE_CLASS_NAME "${arg_CLASS_NAME}"
+
+ QT_QML_MODULE_PLUGIN_TARGET "${arg_PLUGIN_TARGET}"
+ QT_QML_MODULE_INSTALLED_PLUGIN_TARGET "${arg_INSTALLED_PLUGIN_TARGET}"
+
+ # Also Save the PLUGIN_TARGET values in a separate property to circumvent
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/21484 when exporting the properties
+ _qt_qml_module_plugin_target "${arg_PLUGIN_TARGET}"
+ _qt_qml_module_installed_plugin_target "${arg_INSTALLED_PLUGIN_TARGET}"
+
+ QT_QML_MODULE_DESIGNER_SUPPORTED "${arg_DESIGNER_SUPPORTED}"
+ QT_QML_MODULE_IS_STATIC "${arg___QT_INTERNAL_STATIC_MODULE}"
+ QT_QML_MODULE_IS_SYSTEM "${arg___QT_INTERNAL_SYSTEM_MODULE}"
+ QT_QML_MODULE_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
+ QT_QML_MODULE_RESOURCE_PREFIX "${qt_qml_module_resource_prefix}"
+ QT_QML_MODULE_PAST_MAJOR_VERSIONS "${arg_PAST_MAJOR_VERSIONS}"
+
+ # TODO: Check how this is used by qt6_android_generate_deployment_settings()
+ QT_QML_IMPORT_PATH "${arg_IMPORT_PATH}"
+ )
+
+ if(arg_TYPEINFO)
+ set_target_properties(${target} PROPERTIES
+ QT_QML_MODULE_TYPEINFO "${arg_TYPEINFO}"
+ )
+ endif()
+
+ # Executables don't have a plugin target, so no need to export the properties.
+ if(NOT backing_target_type STREQUAL "EXECUTABLE" AND NOT is_android_executable)
+ set_property(TARGET ${target} APPEND PROPERTY
+ EXPORT_PROPERTIES _qt_qml_module_plugin_target _qt_qml_module_installed_plugin_target
+ )
+ endif()
+
+ if(NOT arg_NO_GENERATE_QMLTYPES)
+ set(type_registration_extra_args "")
+ if(arg_NAMESPACE)
+ list(APPEND type_registration_extra_args NAMESPACE ${arg_NAMESPACE})
+ endif()
+ set_target_properties(${target} PROPERTIES _qt_internal_has_qmltypes TRUE)
+ _qt_internal_qml_type_registration(${target} ${type_registration_extra_args})
+ else()
+ set_target_properties(${target} PROPERTIES _qt_internal_has_qmltypes FALSE)
+ endif()
+
+ set(output_targets)
+
+ if(NOT arg_NO_GENERATE_QMLDIR)
+ _qt_internal_target_generate_qmldir(${target})
+ set_source_files_properties(${arg_OUTPUT_DIRECTORY}/qmldir
+ PROPERTIES GENERATED TRUE
+ )
+
+ if(${arg___QT_INTERNAL_DISAMBIGUATE_QMLDIR_RESOURCE})
+ # TODO: Make this the default and remove the option
+ string(REPLACE "/" "_" qmldir_resource_name "${target}_qmldir_${arg_TARGET_PATH}")
+ else()
+ # Embed qmldir in qrc. The following comments relate mostly to Qt5->6 transition.
+ # The requirement to keep the same resource name might no longer apply, but it doesn't
+ # currently appear to cause any hinderance to keep it.
+ # The qmldir resource name needs to match the one generated by qmake's qml_module.prf,
+ # to ensure that all Q_INIT_RESOURCE(resource_name) calls in Qt code don't lead to
+ # undefined symbol errors when linking an application project.
+ # The Q_INIT_RESOURCE() calls are not strictly necessary anymore because the CMake Qt
+ # build passes around the compiled resources as object files.
+ # These object files have global initiliazers that don't get discared when linked into
+ # an application (as opposed to when the resource libraries were embedded into the
+ # static libraries when Qt was built with qmake).
+ # The reason to match the naming is to ensure that applications link successfully
+ # regardless if Qt was built with CMake or qmake, while the build system transition
+ # phase is still happening.
+ string(REPLACE "/" "_" qmldir_resource_name "qmake_${arg_TARGET_PATH}")
+ endif()
+
+ # The qmldir file ALWAYS has to be under the target path, even in the
+ # resources. If it isn't, an explicit import can't find it. We need a
+ # second copy NOT under the target path if NO_RESOURCE_TARGET_PATH is
+ # given so that the implicit import will work.
+ set(prefixes "${qt_qml_module_resource_prefix}")
+ if(arg_NO_RESOURCE_TARGET_PATH)
+ # The above prefixes item won't include the target path, so add a
+ # second one that does.
+ if(qt_qml_module_resource_prefix STREQUAL "/")
+ list(APPEND prefixes "/${arg_TARGET_PATH}")
+ else()
+ list(APPEND prefixes "${qt_qml_module_resource_prefix}/${arg_TARGET_PATH}")
+ endif()
+ endif()
+ set_source_files_properties(${arg_OUTPUT_DIRECTORY}/qmldir
+ PROPERTIES QT_RESOURCE_ALIAS "qmldir"
+ )
+
+ foreach(prefix IN LISTS prefixes)
+ set(resource_targets)
+ qt6_add_resources(${target} ${qmldir_resource_name}
+ FILES ${arg_OUTPUT_DIRECTORY}/qmldir
+ PREFIX "${prefix}"
+ OUTPUT_TARGETS resource_targets
+ )
+
+ # Save the resource name in a property so we can reference it later in a qml plugin
+ # constructor, to avoid discarding the resource if it's in a static library.
+ __qt_internal_sanitize_resource_name(
+ sanitized_qmldir_resource_name "${qmldir_resource_name}")
+ set_property(TARGET ${target} APPEND PROPERTY
+ _qt_qml_module_sanitized_resource_names "${sanitized_qmldir_resource_name}")
+
+ list(APPEND output_targets ${resource_targets})
+ # If we are adding the same file twice, we need a different resource
+ # name for the second one. It has the same QT_RESOURCE_ALIAS but a
+ # different prefix, so we can't put it in the same resource.
+ string(APPEND qmldir_resource_name "_copy")
+ endforeach()
+ endif()
+
+ if(NOT arg_NO_PLUGIN AND NOT arg_NO_CREATE_PLUGIN_TARGET)
+ # This also handles the case where ${arg_PLUGIN_TARGET} already exists,
+ # including where it is the same as ${target}. If ${arg_PLUGIN_TARGET}
+ # already exists, it will update the necessary things that are specific
+ # to qml plugins.
+ if(TARGET ${arg_PLUGIN_TARGET})
+ set(plugin_args "")
+ else()
+ set(plugin_args ${lib_type})
+ endif()
+ list(APPEND plugin_args ${no_gen_source})
+ if(arg_NAMESPACE)
+ list(APPEND plugin_args NAMESPACE ${arg_NAMESPACE})
+ endif()
+ qt6_add_qml_plugin(${arg_PLUGIN_TARGET}
+ ${plugin_args}
+ OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
+ BACKING_TARGET ${target}
+ CLASS_NAME ${arg_CLASS_NAME}
+ )
+ endif()
+
+ if(TARGET "${arg_PLUGIN_TARGET}" AND NOT arg_PLUGIN_TARGET STREQUAL target)
+ target_link_libraries(${arg_PLUGIN_TARGET} PRIVATE ${target})
+ endif()
+
+ target_sources(${target} PRIVATE ${arg_SOURCES})
+
+ # QML tooling might need to map build dir paths to source dir paths. Create
+ # a mapping file before qt6_target_qml_sources() to be able to use it
+ _qt_internal_qml_map_build_files(${target} ${qt_qml_module_resource_prefix} dir_map_qrc)
+ # use different property from _qt_generated_qrc_files since this qrc is
+ # special (and is not a real resource file)
+ set_property(TARGET ${target} APPEND PROPERTY _qt_qml_meta_qrc_files "${dir_map_qrc}")
+
+ set(cache_target)
+ qt6_target_qml_sources(${target}
+ __QT_INTERNAL_FORCE_DEFER_QMLDIR
+ QML_FILES ${arg_QML_FILES}
+ RESOURCES ${arg_RESOURCES}
+ OUTPUT_TARGETS cache_target
+ PREFIX "${qt_qml_module_resource_prefix}"
+ )
+ list(APPEND output_targets ${cache_target})
+
+ # Build an init object library for static plugins and propagate it along with the plugin
+ # target.
+ # TODO: Figure out if we can move this code block into qt_add_qml_plugin. Need to consider
+ # various corner cases.
+ # QTBUG-96937
+ if(TARGET "${arg_PLUGIN_TARGET}")
+ get_target_property(plugin_lib_type ${arg_PLUGIN_TARGET} TYPE)
+ if(plugin_lib_type STREQUAL "STATIC_LIBRARY")
+ __qt_internal_add_static_plugin_init_object_library(
+ "${arg_PLUGIN_TARGET}" plugin_init_target)
+ list(APPEND output_targets ${plugin_init_target})
+
+ __qt_internal_propagate_object_library("${arg_PLUGIN_TARGET}" "${plugin_init_target}")
+ endif()
+ endif()
+
+ if(NOT arg_NO_GENERATE_QMLDIR)
+ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.19.0")
+ # Defer the write to allow more qml files to be added later by calls to
+ # qt6_target_qml_sources(). We wrap the deferred call with EVAL CODE
+ # so that ${target} is evaluated now rather than the end of the scope.
+ # We also delay target finalization until after our deferred write
+ # because the qmldir file must be written before any finalizer
+ # might call qt_import_qml_plugins().
+ cmake_language(EVAL CODE
+ "cmake_language(DEFER ID_VAR write_id CALL _qt_internal_write_deferred_qmldir_file ${target})"
+ )
+ _qt_internal_delay_finalization_until_after(${write_id})
+ else()
+ # Can't defer the write, have to do it now
+ _qt_internal_write_deferred_qmldir_file(${target})
+ endif()
+ endif()
+
+ if (arg_ENABLE_TYPE_COMPILER)
+ if (DEFINED arg_TYPE_COMPILER_NAMESPACE AND NOT $<STREQUAL:"${arg_TYPE_COMPILER_NAMESPACE}","">)
+ set(qmltc_namespace ${arg_TYPE_COMPILER_NAMESPACE})
+ else()
+ string(REPLACE "." "::" qmltc_namespace "${arg_URI}")
+ endif()
+ _qt_internal_target_enable_qmltc(${target}
+ QML_FILES ${arg_QML_FILES}
+ IMPORT_PATHS ${arg_IMPORT_PATH}
+ NAMESPACE ${qmltc_namespace}
+ EXPORT_MACRO_NAME ${arg_QMLTC_EXPORT_DIRECTIVE}
+ EXPORT_FILE_NAME ${arg_QMLTC_EXPORT_FILE_NAME}
+ MODULE ${arg_URI}
+ )
+ endif()
+
+ if(arg_OUTPUT_TARGETS)
+ set(${arg_OUTPUT_TARGETS} ${output_targets} PARENT_SCOPE)
+ endif()
+
+
+ set(ensure_set_properties
+ QT_QML_MODULE_PLUGIN_TYPES_FILE
+ QT_QML_MODULE_QML_FILES
+ QT_QML_MODULE_RESOURCES # Original files as provided by the project (absolute)
+ QT_QML_MODULE_RESOURCE_PATHS # By qmlcachegen (resource paths)
+ QT_QMLCACHEGEN_DIRECT_CALLS
+ QT_QMLCACHEGEN_EXECUTABLE
+ QT_QMLCACHEGEN_ARGUMENTS
+ )
+ foreach(prop IN LISTS ensure_set_properties)
+ get_target_property(val ${target} ${prop})
+ if("${val}" MATCHES "-NOTFOUND$")
+ set_target_properties(${target} PROPERTIES ${prop} "")
+ endif()
+ endforeach()
+
+ if(${QT_QML_GENERATE_QMLLS_INI})
+ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.19.0")
+ # collect all build dirs obtained from all the qt_add_qml_module calls and
+ # write the .qmlls.ini file in a deferred call
+
+ if(NOT "${arg_OUTPUT_DIRECTORY}" STREQUAL "")
+ set(output_folder "${arg_OUTPUT_DIRECTORY}")
+ else()
+ set(output_folder "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ string(REPLACE "." ";" uri_bits "${arg_URI}")
+ set(build_folder "${output_folder}")
+ foreach(bit IN LISTS uri_bits)
+ get_filename_component(build_folder "${build_folder}" DIRECTORY)
+ endforeach()
+ get_directory_property(_qmlls_ini_build_folders _qmlls_ini_build_folders)
+ list(APPEND _qmlls_ini_build_folders "${build_folder}")
+ set_directory_properties(PROPERTIES _qmlls_ini_build_folders "${_qmlls_ini_build_folders}")
+
+ # if no call with id 'qmlls_ini_generation_id' was deferred for this directory, do it now
+ cmake_language(DEFER GET_CALL qmlls_ini_generation_id call)
+ if("${call}" STREQUAL "")
+ cmake_language(EVAL CODE
+ "cmake_language(DEFER ID qmlls_ini_generation_id CALL _qt_internal_write_deferred_qmlls_ini_file)"
+ )
+ endif()
+ else()
+ get_property(__qt_internal_generate_qmlls_ini_warning GLOBAL PROPERTY __qt_internal_generate_qmlls_ini_warning)
+ if (NOT "${__qt_internal_generate_qmlls_ini_warning}")
+ message(WARNING "QT_QML_GENERATE_QMLLS_INI is not supported on CMake versions < 3.19, disabling...")
+ set_property(GLOBAL PROPERTY __qt_internal_generate_qmlls_ini_warning ON)
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function(_qt_internal_write_deferred_qmlls_ini_file)
+ set(qmlls_ini_file "${CMAKE_CURRENT_SOURCE_DIR}/.qmlls.ini")
+ get_directory_property(_qmlls_ini_build_folders _qmlls_ini_build_folders)
+ list(REMOVE_DUPLICATES _qmlls_ini_build_folders)
+ if(NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+ # replace cmake list separator ';' with unix path separator ':'
+ string(REPLACE ";" ":" concatenated_build_dirs "${_qmlls_ini_build_folders}")
+ else()
+ # cmake list separator and windows path separator are both ';', so no replacement needed
+ set(concatenated_build_dirs "${_qmlls_ini_build_folders}")
+ endif()
+ set(file_content "[General]\nbuildDir=${concatenated_build_dirs}\nno-cmake-calls=false\n")
+ file(CONFIGURE OUTPUT "${qmlls_ini_file}" CONTENT "${file_content}")
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_add_qml_module)
+ qt6_add_qml_module(${ARGV})
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "OUTPUT_TARGETS" "")
+ if(arg_OUTPUT_TARGETS)
+ set(${arg_OUTPUT_TARGETS} ${${arg_OUTPUT_TARGETS}} PARENT_SCOPE)
+ endif()
+ endfunction()
+endif()
+
+# Make the prefix conform to the following:
+# - Starts with a "/"
+# - Does not end with a "/" unless the prefix is exactly "/"
+function(_qt_internal_canonicalize_resource_path path out_var)
+ if(NOT path)
+ set(path "/")
+ endif()
+ if(NOT path MATCHES "^/")
+ string(PREPEND path "/")
+ endif()
+ if(path MATCHES [[(.+)/$]])
+ set(path "${CMAKE_MATCH_1}")
+ endif()
+ set(${out_var} "${path}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_get_escaped_uri uri out_var)
+ string(REGEX REPLACE "[^A-Za-z0-9]" "_" escaped_uri "${uri}")
+ set(${out_var} "${escaped_uri}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_compute_qml_plugin_class_name_from_uri uri out_var)
+ _qt_internal_get_escaped_uri("${uri}" escaped_uri)
+ set(${out_var} "${escaped_uri}Plugin" PARENT_SCOPE)
+endfunction()
+
+macro(_qt_internal_genex_getproperty var target property)
+ set(${var} "$<TARGET_PROPERTY:${target},${property}>")
+ set(have_${var} "$<BOOL:${${var}}>")
+endmacro()
+
+macro(_qt_internal_genex_getjoinedproperty var target property item_prefix glue)
+ _qt_internal_genex_getproperty(${var} ${target} ${property})
+ set(${var} "$<${have_${var}}:${item_prefix}$<JOIN:${${var}},${glue}${item_prefix}>>")
+endmacro()
+
+
+# Creates a genex that will call a c++ macro on each of the list values.
+# Handles empty lists.
+macro(_qt_internal_genex_get_list_joined_with_macro var input_list macro_name with_ending_semicolon)
+ set(${var} "${input_list}")
+ set(have_${var} "$<BOOL:${${var}}>")
+
+ set(_macro_begin "${macro_name}(")
+ set(_macro_end ")")
+ if(with_ending_semicolon)
+ string(APPEND _macro_end ";")
+ endif()
+ set(_macro_glue "${_macro_end}\n${_macro_begin}")
+
+ string(JOIN "" ${var}
+ "${_macro_begin}"
+ "$<JOIN:${${var}},${_macro_glue}>"
+ "${_macro_end}")
+
+ set(${var} "$<${have_${var}}:${${var}}>")
+
+ unset(_macro_begin)
+ unset(_macro_end)
+ unset(_macro_glue)
+endmacro()
+
+# Reads a target property that contains a list of values and creates a genex that will
+# call a c++ macro on each of the values.
+# Handles empty properties.
+macro(_qt_internal_genex_get_property_joined_with_macro var target property macro_name
+ with_ending_semicolon)
+ _qt_internal_genex_getproperty(${var} ${target} ${property})
+ _qt_internal_genex_get_list_joined_with_macro("${var}" "${${var}}" "${macro_name}"
+ "${with_ending_semicolon}")
+endmacro()
+
+macro(_qt_internal_genex_getoption var target property)
+ set(${var} "$<BOOL:$<TARGET_PROPERTY:${target},${property}>>")
+endmacro()
+
+# Gets the Qt import paths, prepends -I, appends the values to the given import_paths_var output
+# variable.
+function(_qt_internal_extend_qml_import_paths import_paths_var)
+ set(local_var ${${import_paths_var}})
+
+ _qt_internal_get_main_qt_qml_import_paths(qt_import_paths)
+
+ # Append the paths instead of prepending them, to ensure Qt import paths are searched after
+ # any target or build dir specific import paths.
+ foreach(import_path IN LISTS qt_import_paths)
+ list(APPEND local_var -I "${import_path}")
+ endforeach()
+
+ set(${import_paths_var} ${local_var} PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_assign_to_qmllint_targets_folder target)
+ get_property(folder_name GLOBAL PROPERTY QT_QMLLINTER_TARGETS_FOLDER)
+ if("${folder_name}" STREQUAL "")
+ get_property(__qt_qt_targets_folder GLOBAL PROPERTY QT_TARGETS_FOLDER)
+ set(folder_name "${__qt_qt_targets_folder}/QmlLinter")
+ set_property(GLOBAL PROPERTY QT_QMLLINTER_TARGETS_FOLDER ${folder_name})
+ endif()
+ set_property(TARGET ${target} PROPERTY FOLDER "${folder_name}")
+endfunction()
+
+function(_qt_internal_target_enable_qmllint target)
+ set(lint_target ${target}_qmllint)
+ set(lint_target_json ${target}_qmllint_json)
+ set(lint_target_module ${target}_qmllint_module)
+ if(TARGET ${lint_target} OR TARGET ${target}_qmllint_json OR TARGET ${target}_qmllint_module)
+ return()
+ endif()
+
+ _qt_internal_genex_getproperty(qmllint_files ${target} QT_QML_LINT_FILES)
+ _qt_internal_genex_getjoinedproperty(import_args ${target}
+ QT_QML_IMPORT_PATH "-I$<SEMICOLON>" "$<SEMICOLON>"
+ )
+ _qt_internal_genex_getjoinedproperty(qrc_args ${target}
+ _qt_generated_qrc_files "--resource$<SEMICOLON>" "$<SEMICOLON>"
+ )
+
+ # Facilitate self-import so it can find the qmldir file. We also try to walk
+ # back up the directory structure to find a base path under which this QML
+ # module is located. Such a base path is likely to be used for other QML
+ # modules that we might need to find, so add it to the import path if we
+ # find a compatible directory structure. It doesn't make sense to do this
+ # for an executable though, since it can never be found as a QML module for
+ # a different QML module/target.
+ get_target_property(target_type ${target} TYPE)
+ get_target_property(is_android_executable ${target} _qt_is_android_executable)
+ if(target_type STREQUAL "EXECUTABLE" OR is_android_executable)
+ # The executable's own QML module's qmldir file will usually be under a
+ # subdirectory (matching the module's target path) below the target's
+ # build directory.
+ list(APPEND import_args -I "$<TARGET_PROPERTY:${target},BINARY_DIR>")
+ elseif(target_type MATCHES "LIBRARY")
+ get_target_property(output_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
+ get_target_property(target_path ${target} QT_QML_MODULE_TARGET_PATH)
+ if(output_dir MATCHES "${target_path}$")
+ string(REGEX REPLACE "(.*)/${target_path}" "\\1" base_dir "${output_dir}")
+ list(APPEND import_args -I "${base_dir}")
+ else()
+ message(WARNING
+ "The ${target} target is a QML module with target path ${target_path}. "
+ "It uses an OUTPUT_DIRECTORY of ${output_dir}, which should end in the "
+ "same target path, but doesn't. Tooling such as qmllint may not work "
+ "correctly."
+ )
+ endif()
+ endif()
+
+ if(NOT "${QT_QML_OUTPUT_DIRECTORY}" STREQUAL "")
+ list(APPEND import_args -I "${QT_QML_OUTPUT_DIRECTORY}")
+ endif()
+
+ _qt_internal_extend_qml_import_paths(import_args)
+
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+
+ set(qmllint_args
+ --bare
+ ${import_args}
+ ${qrc_args}
+ ${qmllint_files}
+ )
+
+ get_target_property(target_binary_dir ${target} BINARY_DIR)
+ set(qmllint_dir ${target_binary_dir}/.rcc/qmllint)
+ set(qmllint_rsp_path ${qmllint_dir}/${target}.rsp)
+
+ file(GENERATE
+ OUTPUT "${qmllint_rsp_path}"
+ CONTENT "$<JOIN:${qmllint_args},\n>\n"
+ )
+
+ set(cmd
+ ${tool_wrapper}
+ $<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qmllint>
+ @${qmllint_rsp_path}
+ )
+
+ set(cmd_dummy ${CMAKE_COMMAND} -E echo "Nothing to do for target ${lint_target}.")
+
+ # We need this target to depend on all qml type registrations. This is the
+ # only way we can be sure that all *.qmltypes files for any QML modules we
+ # depend on will have been generated.
+ add_custom_target(${lint_target}
+ COMMAND "$<IF:${have_qmllint_files},${cmd},${cmd_dummy}>"
+ COMMAND_EXPAND_LISTS
+ DEPENDS
+ ${QT_CMAKE_EXPORT_NAMESPACE}::qmllint
+ ${qmllint_files}
+ ${qmllint_rsp_path}
+ $<TARGET_NAME_IF_EXISTS:all_qmltyperegistrations>
+ WORKING_DIRECTORY "$<TARGET_PROPERTY:${target},SOURCE_DIR>"
+ )
+ _qt_internal_assign_to_qmllint_targets_folder(${lint_target})
+
+ list(APPEND qmllint_args "--json" "${CMAKE_BINARY_DIR}/${lint_target}.json")
+
+ set(qmllint_rsp_path ${qmllint_dir}/${target}_json.rsp)
+
+ file(GENERATE
+ OUTPUT "${qmllint_rsp_path}"
+ CONTENT "$<JOIN:${qmllint_args},\n>\n"
+ )
+
+ set(cmd
+ ${tool_wrapper}
+ $<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qmllint>
+ @${qmllint_rsp_path}
+ )
+
+ add_custom_target(${lint_target_json}
+ COMMAND "$<${have_qmllint_files}:${cmd}>"
+ COMMAND_EXPAND_LISTS
+ DEPENDS
+ ${QT_CMAKE_EXPORT_NAMESPACE}::qmllint
+ ${qmllint_files}
+ ${qmllint_rsp_path}
+ $<TARGET_NAME_IF_EXISTS:all_qmltyperegistrations>
+ WORKING_DIRECTORY "$<TARGET_PROPERTY:${target},SOURCE_DIR>"
+ )
+ _qt_internal_assign_to_qmllint_targets_folder(${lint_target_json})
+
+ set_target_properties(${lint_target_json} PROPERTIES EXCLUDE_FROM_ALL TRUE)
+
+ get_target_property(module_uri ${target} QT_QML_MODULE_URI)
+
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+
+ set(qmllint_args
+ ${import_args}
+ ${qrc_args}
+ --module
+ ${module_uri}
+ )
+
+ set(qmllint_rsp_path ${qmllint_dir}/${target}_module.rsp)
+
+ file(GENERATE
+ OUTPUT "${qmllint_rsp_path}"
+ CONTENT "$<JOIN:${qmllint_args},\n>\n"
+ )
+
+ set(cmd
+ ${tool_wrapper}
+ $<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qmllint>
+ @${qmllint_rsp_path}
+ )
+
+ add_custom_target(${lint_target_module}
+ COMMAND ${cmd}
+ COMMAND_EXPAND_LISTS
+ DEPENDS
+ ${QT_CMAKE_EXPORT_NAMESPACE}::qmllint
+ ${qmllint_files}
+ ${qmllint_rsp_path}
+ $<TARGET_NAME_IF_EXISTS:all_qmltyperegistrations>
+ WORKING_DIRECTORY "$<TARGET_PROPERTY:${target},SOURCE_DIR>"
+ )
+ _qt_internal_assign_to_qmllint_targets_folder(${lint_target_module})
+
+ # Make the global linting target depend on the one we add here.
+ # Note that the caller is free to change the value of QT_QMLLINT_ALL_TARGET
+ # for different QML modules if they wish, which means they can implement
+ # their own grouping of the ${target}_qmllint targets.
+ _qt_internal_add_all_qmllint_target(QT_QMLLINT_ALL_TARGET
+ all_qmllint ${lint_target})
+ _qt_internal_add_all_qmllint_target(QT_QMLLINT_JSON_ALL_TARGET
+ all_qmllint_json ${lint_target_json})
+ _qt_internal_add_all_qmllint_target(QT_QMLLINT_MODULE_ALL_TARGET
+ all_qmllint_module ${lint_target_module})
+endfunction()
+
+# This is a modified version of __qt_propagate_generated_resource from qtbase.
+#
+# It uses a common __qt_internal_propagate_object_library function to link and propagate the object
+# library to the end-point executable.
+#
+# The reason for propagating the qmlcache target as a 'fake resource' from the build system
+# perspective is to ensure proper handling of the object files in generated qmake .prl files.
+function(_qt_internal_propagate_qmlcache_object_lib
+ target
+ generated_source_code
+ link_condition
+ output_generated_target)
+ set(resource_target "${target}_qmlcache")
+ qt6_add_library("${resource_target}" OBJECT "${generated_source_code}")
+
+ # Needed to trigger the handling of the object library for .prl generation.
+ set_property(TARGET ${resource_target} APPEND PROPERTY _qt_resource_name ${resource_target})
+
+ # Export info that this is a qmlcache target, in case if we ever need to detect such targets,
+ # similar how we need it for plugin initializers.
+ set_property(TARGET ${resource_target} PROPERTY _is_qt_qmlcache_target TRUE)
+ set_property(TARGET ${resource_target} APPEND PROPERTY
+ EXPORT_PROPERTIES _is_qt_qmlcache_target
+ )
+
+ # Save the path to the generated source file, relative to the the current build dir.
+ # The path will be used in static library prl file generation to ensure qmake links
+ # against the installed resource object files.
+ # Example saved path:
+ # .rcc/qrc_qprintdialog.cpp
+ file(RELATIVE_PATH generated_cpp_file_relative_path
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ "${generated_source_code}")
+ set_property(TARGET ${resource_target} APPEND PROPERTY
+ _qt_resource_generated_cpp_relative_path "${generated_cpp_file_relative_path}")
+
+ # Qml specific additions.
+ target_link_libraries(${resource_target} PRIVATE
+ ${QT_CMAKE_EXPORT_NAMESPACE}::QmlPrivate
+ ${QT_CMAKE_EXPORT_NAMESPACE}::Core
+ )
+
+ __qt_internal_propagate_object_library(${target} ${resource_target}
+ EXTRA_CONDITIONS "${link_condition}"
+ )
+
+ set(${output_generated_target} "${resource_target}" PARENT_SCOPE)
+endfunction()
+
+# Create an 'all_qmllint' target. The target's name can be user-controlled by ${target_var} with the
+# default name ${default_target_name}. The parameter ${lint_target} holds the name of the single
+# foo_qmllint target that should be triggered by the all_qmllint target.
+function(_qt_internal_add_all_qmllint_target target_var default_target_name lint_target)
+ set(target_name "${${target_var}}")
+ if("${target_name}" STREQUAL "")
+ set(target_name ${default_target_name})
+ endif()
+ _qt_internal_add_phony_target(${target_name}
+ WARNING_VARIABLE QT_NO_QMLLINT_CREATION_WARNING
+ TARGET_CREATED_HOOK _qt_internal_assign_to_qmllint_targets_folder
+ )
+ _qt_internal_add_phony_target_dependencies(${target_name} ${lint_target})
+endfunction()
+
+# Hack for the Visual Studio generator. Create the all_qmllint target named ${target} and work
+# around the lack of a working add_dependencies by calling 'cmake --build' for every dependency.
+function(_qt_internal_add_all_qmllint_target_deferred target)
+ get_property(target_dependencies GLOBAL PROPERTY _qt_target_${target}_dependencies)
+ set(target_commands "")
+ foreach(dependency IN LISTS target_dependencies)
+ list(APPEND target_commands
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" -t ${dependency}
+ )
+ endforeach()
+ add_custom_target(${target} ${target_commands})
+ _qt_internal_assign_to_qmllint_targets_folder(${target})
+endfunction()
+
+function(_qt_internal_target_enable_qmlcachegen target qmlcachegen)
+ set_target_properties(${target} PROPERTIES _qt_cachegen_set_up TRUE)
+
+ get_target_property(target_binary_dir ${target} BINARY_DIR)
+ set(qmlcache_dir ${target_binary_dir}/.rcc/qmlcache)
+ set(qmlcache_resource_name qmlcache_${target})
+
+ # Save the resource name in a property so we can reference it later in a qml plugin
+ # constructor, to avoid discarding the resource if it's in a static library.
+ __qt_internal_sanitize_resource_name(
+ sanitized_qmlcache_resource_name "${qmlcache_resource_name}")
+ set_target_properties(${target} PROPERTIES _qt_cachegen_sanitized_resource_name
+ "${sanitized_qmlcache_resource_name}")
+
+ # INTEGRITY_SYMBOL_UNIQUENESS
+ # The cache loader file name has to be unique, because the Integrity compiler uses the file name
+ # for the generation of the translation unit static constructor symbol name.
+ # e.g. __sti___19_qmlcache_loader_cpp_11acedbd
+ # For some reason the symbol is created with global visibility.
+ #
+ # When an application links against the Basic and Fusion static qml plugins, the linker
+ # fails with duplicate symbol errors because both of those plugins will contain the same symbol.
+ #
+ # With gcc on regular Linux, the symbol names are also the same, but it's not a problem because
+ # they have local (hidden) visbility.
+ #
+ # Make the file name unique by prepending the target name.
+ set(qmlcache_loader_cpp ${qmlcache_dir}/${target}_qmlcache_loader.cpp)
+
+ set(qmlcache_loader_list ${qmlcache_dir}/${target}_qml_loader_file_list.rsp)
+ set(qmlcache_resource_paths "$<TARGET_PROPERTY:${target},QT_QML_MODULE_RESOURCE_PATHS>")
+
+ _qt_internal_genex_getjoinedproperty(qrc_resource_args ${target}
+ _qt_generated_qrc_files "--resource$<SEMICOLON>" "$<SEMICOLON>"
+ )
+
+ if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.20")
+ set(qmlcachegen "$<COMMAND_CONFIG:${qmlcachegen}>")
+ endif()
+
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ set(cmd
+ ${tool_wrapper}
+ ${qmlcachegen}
+ --resource-name "${qmlcache_resource_name}"
+ -o "${qmlcache_loader_cpp}"
+ "@${qmlcache_loader_list}"
+ )
+
+ file(GENERATE
+ OUTPUT ${qmlcache_loader_list}
+ CONTENT "$<JOIN:${qrc_resource_args},\n>\n$<JOIN:${qmlcache_resource_paths},\n>\n"
+ )
+
+ add_custom_command(
+ OUTPUT ${qmlcache_loader_cpp}
+ COMMAND "${cmd}"
+ COMMAND_EXPAND_LISTS
+ DEPENDS
+ ${qmlcachegen}
+ ${qmlcache_loader_list}
+ $<TARGET_PROPERTY:${target},_qt_generated_qrc_files>
+ VERBATIM
+ )
+
+ # The current scope sees the file as generated automatically, but the
+ # target scope may not if it is different. Force it where we can.
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set_source_files_properties(
+ ${qmlcache_loader_cpp}
+ TARGET_DIRECTORY ${target}
+ PROPERTIES GENERATED TRUE
+ SKIP_AUTOGEN TRUE
+ )
+ endif()
+ get_target_property(target_source_dir ${target} SOURCE_DIR)
+ if(NOT target_source_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ add_custom_target(${target}_qmlcachegen DEPENDS ${qmlcache_loader_cpp})
+ add_dependencies(${target} ${target}_qmlcachegen)
+ endif()
+
+ # TODO: Probably need to reject ${target} being an object library as unsupported
+ target_sources(${target} PRIVATE "${qmlcache_loader_cpp}")
+ target_link_libraries(${target} PRIVATE
+ ${QT_CMAKE_EXPORT_NAMESPACE}::QmlPrivate
+ ${QT_CMAKE_EXPORT_NAMESPACE}::Core
+ )
+endfunction()
+
+# We cannot defer writing out the qmldir file to generation time because the
+# qmlimportscanner runs at configure time as part of target finalizers.
+# Therefore, the best we can do is defer writing the qmldir file if we are
+# using a recent enough CMake version, otherwise we write it out progressively
+# on each call that adds qml sources. The immediate progressive writes will
+# trigger some unnecessary rebuilds after reconfiguring due to the qmldir
+# file's timestamp being updated even though its contents might not change,
+# but that's the cost of not having deferred write capability.
+function(_qt_internal_target_generate_qmldir target)
+
+ macro(_qt_internal_qmldir_item prefix property)
+ get_target_property(_value ${target} ${property})
+ if(_value)
+ string(APPEND content "${prefix} ${_value}\n")
+ endif()
+ endmacro()
+
+ macro(_qt_internal_qmldir_item_list prefix property)
+ get_target_property(_values ${target} ${property})
+ if(_values)
+ foreach(_value IN LISTS _values)
+ string(APPEND content "${prefix} ${_value}\n")
+ endforeach()
+ endif()
+ endmacro()
+
+ get_target_property(uri ${target} QT_QML_MODULE_URI)
+ if(NOT uri)
+ message(FATAL_ERROR "Target ${target} has no URI set, cannot create qmldir")
+ endif()
+ set(content "module ${uri}\n")
+
+ _qt_internal_qmldir_item(linktarget QT_QML_MODULE_INSTALLED_PLUGIN_TARGET)
+
+ get_target_property(plugin_target ${target} QT_QML_MODULE_PLUGIN_TARGET)
+ if(plugin_target)
+ get_target_property(no_plugin_optional ${target} QT_QML_MODULE_NO_PLUGIN_OPTIONAL)
+ if(NOT no_plugin_optional MATCHES "NOTFOUND" AND NOT no_plugin_optional)
+ string(APPEND content "optional ")
+ endif()
+
+ get_target_property(target_path ${target} QT_QML_MODULE_TARGET_PATH)
+ _qt_internal_get_qml_plugin_output_name(plugin_output_name ${plugin_target}
+ TARGET_PATH "${target_path}"
+ URI "${uri}"
+ )
+ string(APPEND content "plugin ${plugin_output_name}\n")
+
+ _qt_internal_qmldir_item(classname QT_QML_MODULE_CLASS_NAME)
+ endif()
+
+ get_target_property(designer_supported ${target} QT_QML_MODULE_DESIGNER_SUPPORTED)
+ if(designer_supported)
+ string(APPEND content "designersupported\n")
+ endif()
+
+ get_target_property(static_module ${target} QT_QML_MODULE_IS_STATIC)
+ if (static_module)
+ string(APPEND content "static\n")
+ endif()
+
+ get_target_property(system_module ${target} QT_QML_MODULE_IS_SYSTEM)
+ if (system_module)
+ string(APPEND content "system\n")
+ endif()
+
+ _qt_internal_qmldir_item(typeinfo QT_QML_MODULE_TYPEINFO)
+
+ _qt_internal_qmldir_item_list(import QT_QML_MODULE_IMPORTS)
+ _qt_internal_qmldir_item_list("optional import" QT_QML_MODULE_OPTIONAL_IMPORTS)
+ _qt_internal_qmldir_item_list("default import" QT_QML_MODULE_DEFAULT_IMPORTS)
+
+ _qt_internal_qmldir_item_list(depends QT_QML_MODULE_DEPENDENCIES)
+
+ get_target_property(prefix ${target} QT_QML_MODULE_RESOURCE_PREFIX)
+ if(prefix)
+ # Ensure we use a path that ends with a "/", but handle the special case
+ # of "/" without anything after it
+ if(NOT prefix STREQUAL "/" AND NOT prefix MATCHES "/$")
+ string(APPEND prefix "/")
+ endif()
+ string(APPEND content "prefer :${prefix}\n")
+ endif()
+
+ # TODO: What about multi-config generators? Would we need per-config qmldir
+ # files (because we will have per-config plugin targets)?
+
+ # Record the contents but defer the actual write. We will write the file
+ # later, either at the end of qt6_add_qml_module() or the end of the
+ # directory scope (depending on the CMake version being used).
+ set_property(TARGET ${target} PROPERTY _qt_internal_qmldir_content "${content}")
+
+ # NOTE: qt6_target_qml_sources() may append further content later.
+endfunction()
+
+function(_qt_internal_write_deferred_qmldir_file target)
+ get_target_property(__qt_qmldir_content ${target} _qt_internal_qmldir_content)
+ get_target_property(out_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
+ set(qmldir_file "${out_dir}/qmldir")
+ configure_file(${__qt_qml_macros_module_base_dir}/Qt6qmldirTemplate.cmake.in ${qmldir_file} @ONLY)
+endfunction()
+
+# With a macOS framework Qt build, moc needs to be passed -F<qt-framework-path>
+# arguments to resolve framework style includes like #include <QtCore/qobject.h>
+# Extract the location of the Qt frameworks by querying the imported location of
+# the target (where target is a Qt library). Do not care about non-Qt targets.
+function(_qt_internal_qml_get_qt_framework_path target out_var)
+ set(value "")
+ # NOTE: only exercise IMPORTED_LOCATION of various flavors. this seems to be
+ # good enough in other places (e.g. when locating qmlimportscanner)
+ get_target_property(target_path ${target} IMPORTED_LOCATION)
+ if(NOT target_path)
+ set(configs "RELWITHDEBINFO;RELEASE;MINSIZEREL;DEBUG")
+ foreach(config ${configs})
+ get_target_property(target_path ${target} IMPORTED_LOCATION_${config})
+ # NOTE: to be fair, any location is good enough. the macro
+ # definitions we need must not vary between configurations
+ if(target_path)
+ break()
+ endif()
+ endforeach()
+ endif()
+ string(REGEX REPLACE "(.*)/Qt[^/]+\\.framework.*" "\\1" target_fw_path "${target_path}")
+ if(target_fw_path)
+ set(value "${target_fw_path}")
+ endif()
+ set(${out_var} "${value}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_qml_get_qt_framework_path_moc_option target out_var)
+ _qt_internal_qml_get_qt_framework_path(${target} target_fw_path)
+ if(target_fw_path)
+ set(${out_var} "-F${target_fw_path}" PARENT_SCOPE)
+ else()
+ set(${out_var} "" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# creates a QRC mapping between QML files in build directory and QML files in
+# source directory
+function(_qt_internal_qml_map_build_files target qml_module_prefix qrc_file_out_var)
+ get_target_property(output_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
+ if(NOT output_dir)
+ # TODO: we might want to support non-qml modules here (think QML
+ # language server) but it is unclear whether the below code would
+ # succeed, so just abort here until we have a proper test case
+ message(WARNING "Target ${target} is not a QML module. Cannot detect its output directory")
+ return()
+ endif()
+
+ set(qrcContents "")
+ string(APPEND qrcContents " <file alias=\"${qml_module_prefix}\">${output_dir}</file>\n")
+
+ # dump the contents into the .qrc file
+ set(template_file "${__qt_qml_macros_module_base_dir}/Qt6QmlModuleDirMappingTemplate.qrc.in")
+ set(generated_qrc_file "${output_dir}/${target}_qml_module_dir_map.qrc")
+ set(qt_qml_module_dir_mapping_contents "${qrcContents}")
+ configure_file(${template_file} ${generated_qrc_file})
+
+ set(${qrc_file_out_var} ${generated_qrc_file} PARENT_SCOPE)
+endfunction()
+
+# Creates a qrc file that maps QML file path to generated C++ header file name
+function(_qt_internal_qml_add_qmltc_file_mapping_resource qrc_file target qml_files)
+ get_target_property(output_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
+ set(qrcContents "")
+
+ # go over all QML_FILES, mapping QML files to generated C++ sources
+ foreach(qml_file IN LISTS qml_files)
+ get_filename_component(file_absolute ${qml_file} ABSOLUTE)
+ get_filename_component(file_basename ${file_absolute} NAME_WLE) # extension is always .qml
+ string(REGEX REPLACE "[$#?]+" "_" compiled_file ${file_basename})
+
+ # NB: use <lowercase(file_name)>.<extension> pattern. if
+ # lowercase(file_name) is already taken (e.g. project has main.qml and
+ # main.h/main.cpp), the compilation might fail. in this case, expect
+ # user to specify QT_QMLTC_FILE_BASENAME
+ string(TOLOWER ${compiled_file} file_name)
+
+ get_source_file_property(specified_file_name ${qml_file} QT_QMLTC_FILE_BASENAME)
+ if (specified_file_name)
+ get_filename_component(file_name ${specified_file_name} NAME_WLE)
+ endif()
+
+ # <file_name>.h is enough as corresponding .cpp is not interesting (and
+ # we can get it easily by replacing the extension)
+ string(APPEND qrcContents " <file alias=\"${file_name}.h\">${file_absolute}</file>\n")
+ endforeach()
+
+ # dump the contents into the .qrc file
+ set(template_file "${__qt_qml_macros_module_base_dir}/Qt6QmltcFileMappingTemplate.qrc.in")
+ set(generated_qrc_file "${output_dir}/.qmltc/${target}/${target}_qmltc_file_map.qrc")
+ set(qt_qml_qmltc_file_mapping_contents "${qrcContents}")
+ configure_file(${template_file} ${generated_qrc_file})
+
+ set(${qrc_file} ${generated_qrc_file} PARENT_SCOPE)
+endfunction()
+
+# Compile Qml files (.qml) to C++ source files with QML type compiler (qmltc).
+function(_qt_internal_target_enable_qmltc target)
+ set(args_option "")
+ set(args_single NAMESPACE EXPORT_MACRO_NAME EXPORT_FILE_NAME MODULE)
+ set(args_multi QML_FILES IMPORT_PATHS)
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${args_option}" "${args_single}" "${args_multi}"
+ )
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown/unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+
+ if (NOT arg_QML_FILES)
+ message(FATAL_ERROR "FILES option not given or contains empty list for target ${target}")
+ endif()
+
+ if(NOT TARGET "${target}")
+ message(FATAL_ERROR "\"${target}\" is not a known target")
+ endif()
+
+ get_target_property(target_source_dir ${target} SOURCE_DIR)
+ get_target_property(target_binary_dir ${target} BINARY_DIR)
+
+ set(generated_sources_other_scope)
+
+ set(compiled_files) # compiled files list to be used to generate MOC C++
+ set(qmltc_executable "$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qmltc>")
+ if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.20")
+ set(qmltc_executable "$<COMMAND_CONFIG:${qmltc_executable}>")
+ endif()
+
+ set(common_args "")
+ if(arg_NAMESPACE)
+ list(APPEND common_args --namespace "${arg_NAMESPACE}")
+ endif()
+ if(arg_MODULE)
+ list(APPEND common_args --module "${arg_MODULE}")
+ endif()
+ if(arg_EXPORT_MACRO_NAME)
+ list(APPEND common_args --export "${arg_EXPORT_MACRO_NAME}")
+ if(arg_EXPORT_FILE_NAME)
+ list(APPEND common_args --exportInclude "${arg_EXPORT_FILE_NAME}")
+ endif()
+ endif()
+
+ get_target_property(output_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
+ set(qmldir_file ${output_dir}/qmldir)
+ # TODO: we still need to specify the qmldir here for _explicit_ imports of
+ # own module. in theory this could be pushed to the user side
+ list(APPEND common_args "-i" ${qmldir_file})
+
+ foreach(import_path IN LISTS arg_IMPORT_PATHS)
+ list(APPEND common_args -I "${import_path}")
+ endforeach()
+
+ _qt_internal_extend_qml_import_paths(common_args)
+
+ # we explicitly depend on qmldir (due to `-i ${qmldir_file}`) but also
+ # implicitly on the generated qmltypes file, which is a part of qmldir
+ set(qml_module_files)
+ list(APPEND qml_module_files ${qmldir_file})
+ get_target_property(qmltypes_file ${target} QT_QML_MODULE_TYPEINFO)
+ if(qmltypes_file)
+ list(APPEND qml_module_files ${output_dir}/${qmltypes_file})
+ endif()
+
+ get_target_property(potential_qml_modules ${target} LINK_LIBRARIES)
+ foreach(lib ${potential_qml_modules})
+ if(NOT TARGET ${lib})
+ continue()
+ endif()
+
+ # if we have a versionless Qt lib, find the public one with a version
+ if(lib MATCHES "^Qt::(.*)")
+ set(lib "${CMAKE_MATCH_1}")
+ if(lib MATCHES "^(.*)Private") # remove "Private"
+ set(lib "${CMAKE_MATCH_1}")
+ endif()
+ set(lib ${QT_CMAKE_EXPORT_NAMESPACE}::${lib})
+ if(NOT TARGET ${lib})
+ continue()
+ endif()
+ endif()
+
+ # when we have a suitable lib, ignore INTERFACE_LIBRARY and IMPORTED
+ get_target_property(lib_type ${lib} TYPE)
+ get_target_property(lib_is_imported ${lib} IMPORTED)
+ if(lib_type STREQUAL "INTERFACE_LIBRARY" OR lib_is_imported)
+ continue()
+ endif()
+
+ # get any QT_QML_MODULE_ property, this way we can tell whether we deal
+ # with QML module target or not. use output dir as it's used later
+ get_target_property(external_output_dir ${lib} QT_QML_MODULE_OUTPUT_DIRECTORY)
+ if(NOT external_output_dir) # not a QML module, so not interesting
+ continue()
+ endif()
+
+ get_target_property(external_qmltypes_file ${lib} QT_QML_MODULE_TYPEINFO)
+ if(external_qmltypes)
+ # add linked module's qmltypes file to a list of target
+ # dependencies. unlike qmllint or other tooling, qmltc only cares
+ # about explicitly linked libraries. things like plugins are not
+ # supported by design and would result in C++ compilation errors
+ list(APPEND qml_module_files ${external_output_dir}/${external_qmltypes_file})
+ endif()
+ endforeach()
+
+ # ignore non-QML and to-be-skipped QML files
+ set(filtered_qml_files "")
+ foreach(qml_file_src IN LISTS arg_QML_FILES)
+ if(NOT qml_file_src MATCHES "\\.(qml)$")
+ continue()
+ endif()
+ get_source_file_property(skip_qmltc ${qml_file_src} QT_QML_SKIP_TYPE_COMPILER)
+ if(skip_qmltc)
+ continue()
+ endif()
+ list(APPEND filtered_qml_files ${qml_file_src})
+ endforeach()
+
+ # qmltc needs qrc files to supply to the QQmlJSResourceFileMapper
+ _qt_internal_genex_getjoinedproperty(qrc_args ${target}
+ _qt_generated_qrc_files "--resource$<SEMICOLON>" "$<SEMICOLON>"
+ )
+ # qmltc also needs meta data qrc files when importing types from own module
+ _qt_internal_genex_getjoinedproperty(metadata_qrc_args ${target}
+ _qt_qml_meta_qrc_files "--meta-resource$<SEMICOLON>" "$<SEMICOLON>"
+ )
+ list(APPEND qrc_args ${metadata_qrc_args})
+
+ # NB: pass qml files variable as string to preserve its list nature
+ # (otherwise we lose all but first element of the list inside a function)
+ _qt_internal_qml_add_qmltc_file_mapping_resource(
+ qmltc_file_map_qrc ${target} "${filtered_qml_files}")
+ # append --resource <qrc> to qmltc's command line
+ list(APPEND qrc_args --resource "${qmltc_file_map_qrc}")
+
+ list(APPEND common_args ${qrc_args})
+
+ foreach(qml_file_src IN LISTS filtered_qml_files)
+ get_filename_component(file_absolute ${qml_file_src} ABSOLUTE)
+
+ get_filename_component(file_basename ${file_absolute} NAME_WLE) # extension is always .qml
+ string(REGEX REPLACE "[$#?]+" "_" compiled_file ${file_basename})
+ string(TOLOWER ${compiled_file} file_name)
+
+ # NB: use <lowercase(file_name)>.<extension> pattern. if
+ # lowercase(file_name) is already taken (e.g. project has main.qml and
+ # main.h/main.cpp), the compilation might fail. in this case, expect
+ # user to specify QT_QMLTC_FILE_BASENAME
+ get_source_file_property(specified_file_name ${qml_file_src} QT_QMLTC_FILE_BASENAME)
+ if (specified_file_name)
+ get_filename_component(file_name ${specified_file_name} NAME_WLE)
+ endif()
+
+ # Note: add '${target}' to path to avoid potential conflicts where 2+
+ # distinct targets use the same ${target_binary_dir}/.qmltc/ output dir
+ set(compiled_header "${target_binary_dir}/.qmltc/${target}/${file_name}.h")
+ set(compiled_cpp "${target_binary_dir}/.qmltc/${target}/${file_name}.cpp")
+ get_filename_component(out_dir ${compiled_header} DIRECTORY)
+
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ add_custom_command(
+ OUTPUT ${compiled_header} ${compiled_cpp}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${out_dir}
+ COMMAND
+ ${tool_wrapper}
+ ${qmltc_executable}
+ --bare
+ --header "${compiled_header}"
+ --impl "${compiled_cpp}"
+ ${common_args}
+ ${file_absolute}
+ COMMAND_EXPAND_LISTS
+ DEPENDS
+ ${qmltc_executable}
+ "${file_absolute}"
+ ${qml_module_files}
+ $<TARGET_PROPERTY:${target},_qt_generated_qrc_files>
+ $<TARGET_PROPERTY:${target},_qt_qml_meta_qrc_files>
+ ${qmltc_file_map_qrc}
+ COMMENT "Compiling ${qml_file_src} with qmltc"
+ VERBATIM
+ )
+
+ set_source_files_properties(${compiled_header} ${compiled_cpp}
+ PROPERTIES SKIP_AUTOGEN ON
+ SKIP_UNITY_BUILD_INCLUSION ON)
+ target_sources(${target} PRIVATE ${compiled_header} ${compiled_cpp})
+ target_include_directories(${target} PUBLIC ${out_dir})
+ # The current scope automatically sees the file as generated, but the
+ # target scope may not if it is different. Force it where we can.
+ # We will also have to add the generated file to a target in this
+ # scope at the end to ensure correct dependencies.
+ if(NOT target_source_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ list(APPEND generated_sources_other_scope ${compiled_header} ${compiled_cpp})
+ endif()
+ endif()
+
+ list(APPEND compiled_files ${compiled_header})
+ endforeach()
+
+ set(extra_moc_options "")
+ if(APPLE AND QT_FEATURE_framework)
+ # this is a special case, where we need -F options passed to manual moc.
+ # since we're in qmltc code, we only ever need to check QtCore and QtQml
+ # for framework path
+ list(APPEND link_libs ${QT_CMAKE_EXPORT_NAMESPACE}::Core ${QT_CMAKE_EXPORT_NAMESPACE}::Qml)
+ foreach(lib ${link_libs})
+ _qt_internal_qml_get_qt_framework_path_moc_option(${lib} moc_option)
+ if(moc_option)
+ list(APPEND extra_moc_options ${moc_option})
+ endif()
+ endforeach()
+ endif()
+
+ # run MOC manually for the generated files
+ qt6_wrap_cpp(compiled_moc_files ${compiled_files} TARGET ${target} OPTIONS ${extra_moc_options})
+ set_source_files_properties(${compiled_moc_files} PROPERTIES SKIP_AUTOGEN ON
+ SKIP_UNITY_BUILD_INCLUSION ON)
+ target_sources(${target} PRIVATE ${compiled_moc_files})
+ if(NOT target_source_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set_source_files_properties(${generated_sources_other_scope} ${compiled_moc_files}
+ TARGET_DIRECTORY ${target}
+ PROPERTIES
+ SKIP_AUTOGEN TRUE
+ GENERATED TRUE
+ )
+ endif()
+
+ if(NOT TARGET ${target}_tooling)
+ message(FATAL_ERROR
+ "${target}_tooling is not found, although it should be in this function.")
+ endif()
+ # adding sources to ${target}_tooling would ensure that these sources
+ # become a dependency of ${target} in this weird case that we have.
+ # add_dependencies() for ${target} and ${target}_tooling must have been
+ # added as part of qt_add_qml_module() command run.
+ target_sources(${target}_tooling PRIVATE
+ ${generated_sources_other_scope} ${compiled_moc_files}
+ )
+ endif()
+
+endfunction()
+
+function(qt6_target_compile_qml_to_cpp target)
+ message(WARNING
+ "qt6_target_compile_qml_to_cpp() can no longer be used standalone and is planned to be "
+ "removed in a future Qt release. To enable qmltc compilation, use:\n"
+ "qt6_add_qml_module(${target} ... ENABLE_TYPE_COMPILER)"
+ )
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_target_compile_qml_to_cpp)
+ qt6_target_compile_qml_to_cpp(${ARGV})
+ endfunction()
+endif()
+
+# Get extern declaration for types registration function.
+function(_qt_internal_qml_get_types_extern_declaration register_types_function_name out_var)
+ set(with_ending_semicolon FALSE)
+ _qt_internal_genex_get_list_joined_with_macro(
+ content
+ "${register_types_function_name}"
+ "QT_DECLARE_EXTERN_SYMBOL_VOID"
+ ${with_ending_semicolon}
+ )
+
+ string(PREPEND content "\n")
+ set(${out_var} "${content}" PARENT_SCOPE)
+endfunction()
+
+# Get code block that should reference the types registration function in the plugin constructor.
+# Ensures the symbol is not discarded when linking.
+function(_qt_internal_qml_get_types_keep_reference register_types_function_name out_var)
+ set(with_ending_semicolon FALSE)
+ _qt_internal_genex_get_list_joined_with_macro(
+ content
+ "${register_types_function_name}"
+ "QT_KEEP_SYMBOL"
+ ${with_ending_semicolon}
+ )
+
+ string(PREPEND content "\n")
+ set(${out_var} "${content}" PARENT_SCOPE)
+endfunction()
+
+# Get extern declaration for cachegen resource.
+function(_qt_internal_qml_get_cachegen_extern_resource_declaration target out_var)
+ set(with_ending_semicolon FALSE)
+ _qt_internal_genex_get_property_joined_with_macro(
+ content
+ "${target}"
+ "_qt_cachegen_sanitized_resource_name"
+ "QT_DECLARE_EXTERN_RESOURCE"
+ ${with_ending_semicolon}
+ )
+
+ string(PREPEND content "\n")
+ set(${out_var} "${content}" PARENT_SCOPE)
+endfunction()
+
+# Get code block that should reference the cachegen resource in the plugin constructor.
+# Ensures the resource is not discarded when linking.
+function(_qt_internal_qml_get_cachegen_resource_keep_reference target out_var)
+ set(with_ending_semicolon FALSE)
+ _qt_internal_genex_get_property_joined_with_macro(
+ content
+ "${target}"
+ "_qt_cachegen_sanitized_resource_name"
+ "QT_KEEP_RESOURCE"
+ ${with_ending_semicolon}
+ )
+
+ string(PREPEND content "\n")
+ set(${out_var} "${content}" PARENT_SCOPE)
+endfunction()
+
+# Get extern declaration for a regular resource.
+function(_qt_internal_qml_get_resource_extern_declarations target out_var)
+ set(with_ending_semicolon FALSE)
+ _qt_internal_genex_get_property_joined_with_macro(
+ content
+ "${target}"
+ "_qt_qml_module_sanitized_resource_names"
+ "QT_DECLARE_EXTERN_RESOURCE"
+ ${with_ending_semicolon}
+ )
+
+ string(PREPEND content "\n")
+ set(${out_var} "${content}" PARENT_SCOPE)
+endfunction()
+
+# Get code block that should reference regular resources in the plugin constructor.
+# Ensures the resources are not discarded when linking.
+function(_qt_internal_qml_get_resource_keep_references target out_var)
+ set(with_ending_semicolon FALSE)
+ _qt_internal_genex_get_property_joined_with_macro(
+ content
+ "${target}"
+ "_qt_qml_module_sanitized_resource_names"
+ "QT_KEEP_RESOURCE"
+ ${with_ending_semicolon}
+ )
+
+ string(PREPEND content "\n")
+ set(${out_var} "${content}" PARENT_SCOPE)
+endfunction()
+
+# Get 3 different code blocks that should be inserted into various locations of the generated
+# qml plugin cpp file. The code blocks ensure that if a target links to a plugin backed by a static
+# library and initializes the plugin using Q_IMPORT_PLUGIN, none of the resources or type
+# registration functions in the backing library are discarded by the linker.
+function(_qt_internal_qml_get_symbols_to_keep
+ target
+ backing_target_type
+ register_types_function_name
+ out_var_intro
+ out_var_intro_namespaced
+ out_var_constructor)
+ set(intro_content "")
+ set(intro_namespaced_content "")
+
+ # External symbol declarations.
+ _qt_internal_qml_get_types_extern_declaration("${register_types_function_name}" output)
+ string(APPEND intro_namespaced_content "${output}")
+
+ if(backing_target_type STREQUAL "STATIC_LIBRARY")
+ _qt_internal_qml_get_cachegen_extern_resource_declaration(${target} output)
+ string(APPEND intro_content "${output}")
+
+ _qt_internal_qml_get_resource_extern_declarations(${target} output)
+ string(APPEND intro_content "${output}")
+ endif()
+
+
+ # Reference the external symbols in the plugin constructor to prevent the linker from
+ # discarding the symbols.
+ # The types symbol is an exported symbol, so we always reference it.
+ set(constructor_content "")
+
+ _qt_internal_qml_get_types_keep_reference("${register_types_function_name}" output)
+ string(APPEND constructor_content "${output}")
+
+ # Only reference the resources if the backing library is static.
+ # If the backing library is shared, the symbols will not be found at link time because they
+ # are not exported symbols.
+ if(backing_target_type STREQUAL "STATIC_LIBRARY")
+ _qt_internal_qml_get_cachegen_resource_keep_reference(${target} output)
+ string(APPEND constructor_content "${output}")
+
+ _qt_internal_qml_get_resource_keep_references(${target} output)
+ string(APPEND constructor_content "${output}")
+ endif()
+
+ set(${out_var_intro} "${intro_content}" PARENT_SCOPE)
+ set(${out_var_intro_namespaced} "${intro_namespaced_content}" PARENT_SCOPE)
+ set(${out_var_constructor} "${constructor_content}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_set_qml_target_multi_config_output_directory target output_directory)
+ # In multi-config builds we need to make sure that at least one configuration has the dynamic
+ # plugin that is located next to qmldir file, otherwise QML engine won't be able to load the
+ # plugin.
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi_config)
+ # We don't care about static plugins here since, they are linked at build time and
+ # their location doesn't affect the runtime.
+ get_target_property(target_type ${target} TYPE)
+ if(target_type STREQUAL "SHARED_LIBRARY" OR target_type STREQUAL "MODULE_LIBRARY")
+ if(NOT "${output_directory}")
+ set(output_directory "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+
+ list(GET CMAKE_CONFIGURATION_TYPES 0 default_config)
+ string(JOIN "" output_directory_with_default_config
+ "$<IF:$<CONFIG:${default_config}>,"
+ "${output_directory},"
+ "${output_directory}/$<CONFIG>"
+ ">"
+ )
+ set_target_properties(${target} PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY "${output_directory_with_default_config}"
+ LIBRARY_OUTPUT_DIRECTORY "${output_directory_with_default_config}"
+ )
+ endif()
+ endif()
+endfunction()
+
+function(qt6_add_qml_plugin target)
+ set(args_option
+ STATIC
+ SHARED
+ NO_GENERATE_PLUGIN_SOURCE
+ )
+
+ set(args_single
+ OUTPUT_DIRECTORY
+ URI
+ BACKING_TARGET
+ CLASS_NAME
+ NAMESPACE
+ # The following is only needed on Android, and even then, only if the
+ # default conversion from the URI is not applicable. It is an internal
+ # option, it may be removed.
+ TARGET_PATH
+ )
+
+ set(args_multi "")
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${args_option}"
+ "${args_single}"
+ "${args_multi}"
+ )
+
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+
+ if(NOT arg_URI)
+ if(NOT arg_BACKING_TARGET)
+ message(FATAL_ERROR "No URI or BACKING_TARGET provided")
+ endif()
+ if(NOT TARGET ${arg_BACKING_TARGET})
+ if(arg_BACKING_TARGET STREQUAL target)
+ message(FATAL_ERROR
+ "Plugin ${target} is its own backing target, URI must be provided"
+ )
+ else()
+ message(FATAL_ERROR
+ "No URI provided and unable to obtain it from the BACKING_TARGET "
+ "(${arg_BACKING_TARGET}) because no such target exists"
+ )
+ endif()
+ endif()
+ get_target_property(arg_URI ${arg_BACKING_TARGET} QT_QML_MODULE_URI)
+ if(NOT arg_URI)
+ message(FATAL_ERROR
+ "No URI provided and the BACKING_TARGET (${arg_BACKING_TARGET}) "
+ "does not have one set either"
+ )
+ endif()
+ endif()
+
+ # TODO: Probably should remove TARGET_PATH as a supported keyword now
+ if(NOT arg_TARGET_PATH AND TARGET "${arg_BACKING_TARGET}")
+ get_target_property(arg_TARGET_PATH ${arg_BACKING_TARGET} QT_QML_MODULE_TARGET_PATH)
+ endif()
+ if(NOT arg_TARGET_PATH)
+ string(REPLACE "." "/" arg_TARGET_PATH "${arg_URI}")
+ endif()
+
+ _qt_internal_get_escaped_uri("${arg_URI}" escaped_uri)
+
+ if(NOT arg_CLASS_NAME)
+ if(NOT "${arg_BACKING_TARGET}" STREQUAL "")
+ get_target_property(arg_CLASS_NAME ${arg_BACKING_TARGET} QT_QML_MODULE_CLASS_NAME)
+ endif()
+ if(NOT arg_CLASS_NAME)
+ _qt_internal_compute_qml_plugin_class_name_from_uri("${arg_URI}" arg_CLASS_NAME)
+ endif()
+ endif()
+
+ if(arg_BACKING_TARGET AND TARGET "${arg_BACKING_TARGET}")
+ get_target_property(backing_type ${arg_BACKING_TARGET} TYPE)
+ endif()
+
+ if(TARGET ${target})
+ # Plugin target already exists. Perform a few sanity checks, but we
+ # otherwise trust that the target is appropriate for use as a plugin.
+ get_target_property(target_type ${target} TYPE)
+ if(target_type STREQUAL "EXECUTABLE")
+ message(FATAL_ERROR "Plugins cannot be executables (target: ${target})")
+ endif()
+ foreach(arg IN ITEMS STATIC SHARED)
+ if(arg_${arg})
+ message(FATAL_ERROR
+ "Cannot specify ${arg} keyword, target ${target} already exists"
+ )
+ endif()
+ endforeach()
+
+ get_target_property(existing_class_name ${target} QT_PLUGIN_CLASS_NAME)
+ if(existing_class_name)
+ if(NOT existing_class_name STREQUAL arg_CLASS_NAME)
+ message(FATAL_ERROR
+ "An existing plugin target was given, but it has a different class name "
+ "(${existing_class_name}) to that being used here (${arg_CLASS_NAME})"
+ )
+ endif()
+ elseif(arg_CLASS_NAME)
+ set_property(TARGET ${target} PROPERTY QT_PLUGIN_CLASS_NAME "${arg_CLASS_NAME}")
+ else()
+ message(FATAL_ERROR
+ "An existing '${target}' plugin target was given, but it has no class name set "
+ "and no new class name was provided."
+ )
+ endif()
+ else()
+ if(arg_STATIC AND arg_SHARED)
+ message(FATAL_ERROR
+ "Cannot specify both STATIC and SHARED for target ${target}"
+ )
+ endif()
+ set(lib_type "")
+ if(arg_STATIC)
+ set(lib_type STATIC)
+ elseif(arg_SHARED)
+ set(lib_type SHARED)
+ endif()
+
+ if(TARGET "${arg_BACKING_TARGET}")
+ # Ensure that the plugin type we create will be compatible with the
+ # type of backing target we were given
+ if(backing_type STREQUAL "STATIC_LIBRARY")
+ if(lib_type STREQUAL "")
+ set(lib_type STATIC)
+ elseif(lib_type STREQUAL "SHARED")
+ message(FATAL_ERROR
+ "Mixing a static backing library with a non-static plugin "
+ "is not supported"
+ )
+ endif()
+ elseif(backing_type STREQUAL "SHARED_LIBRARY")
+ if(lib_type STREQUAL "")
+ set(lib_type SHARED)
+ elseif(lib_type STREQUAL "STATIC")
+ message(FATAL_ERROR
+ "Mixing a non-static backing library with a static plugin "
+ "is not supported"
+ )
+ endif()
+ elseif(backing_type STREQUAL "EXECUTABLE")
+ message(FATAL_ERROR
+ "A separate plugin should not be needed when the backing target "
+ "is an executable. Pre-create the plugin target before calling "
+ "this command if you really must have a separate plugin."
+ )
+ else()
+ # Object libraries, utility/custom targets
+ message(FATAL_ERROR "Unsupported backing target type: ${backing_type}")
+ endif()
+ endif()
+
+ qt6_add_plugin(${target} ${lib_type}
+ PLUGIN_TYPE qml_plugin
+ CLASS_NAME ${arg_CLASS_NAME}
+ )
+ endif()
+
+ get_target_property(install_rpath ${target} INSTALL_RPATH)
+ # Ignore any CMAKE_INSTALL_RPATH and set a better default RPATH on platforms
+ # that support it, if allowed. Projects will often set CMAKE_INSTALL_RPATH
+ # for executables or backing libraries, but forget about plugins. Because
+ # the path for QML plugins depends on their URI, it is unlikely that
+ # CMAKE_INSTALL_RPATH would ever be intended for use with QML plugins.
+ #
+ # Avoid setting INSTALL_RPATH if it was set before. This is mostly
+ # applicable for the Qml plugins built in Qt tree, that got INSTALL_RPATH
+ # from the qt_internal_add_plugin function, but also can be the case for the
+ # user Qml plugins created manually.
+ if(NOT WIN32 AND NOT QT_NO_QML_PLUGIN_RPATH AND NOT install_rpath)
+ # Construct a relative path from a default install location (assumed to
+ # be qml/target-path) to ${CMAKE_INSTALL_LIBDIR}. This would be
+ # applicable for Apple too (although unusual) if this is a bare install
+ # (i.e. not part of an app bundle).
+ string(REPLACE "/" ";" path "qml/${arg_TARGET_PATH}")
+ list(LENGTH path path_count)
+ string(REPEAT "../" ${path_count} rel_path)
+ string(APPEND rel_path "${CMAKE_INSTALL_LIBDIR}")
+ if(APPLE)
+ set(install_rpath
+ # If embedded in an app bundle, search in a bundle-local path
+ # first. This path should always be the same for every app
+ # bundle because plugin binaries should live in the PlugIns
+ # directory, not a subdirectory of it or anywhere else.
+ # Similarly, frameworks and bare shared libraries should always
+ # be in the bundle's Frameworks directory.
+ "@loader_path/../Frameworks"
+
+ # This will be needed if the plugin is not installed as part of
+ # an app bundle, such as when used by a command-line tool.
+ "@loader_path/${rel_path}"
+ )
+ else()
+ set(install_rpath "$ORIGIN/${rel_path}")
+ endif()
+ set_target_properties(${target} PROPERTIES INSTALL_RPATH "${install_rpath}")
+ endif()
+
+ get_target_property(moc_opts ${target} AUTOMOC_MOC_OPTIONS)
+ set(already_set FALSE)
+ if(moc_opts)
+ foreach(opt IN LISTS moc_opts)
+ if("${opt}" MATCHES "^-Muri=")
+ set(already_set TRUE)
+ break()
+ endif()
+ endforeach()
+ endif()
+ if(NOT already_set)
+ # Insert the plugin's URI into its meta data to enable usage
+ # of static plugins in QtDeclarative (like in mkspecs/features/qml_plugin.prf).
+ set_property(TARGET ${target} APPEND PROPERTY
+ AUTOMOC_MOC_OPTIONS "-Muri=${arg_URI}"
+ )
+ endif()
+
+ # Work around QTBUG-115152.
+ # Assign / duplicate the backing library's metatypes file to the qml plugin.
+ # This ensures that the metatypes are passed as foreign types to qmltyperegistrar when
+ # a consumer links against the plugin, but not the backing library.
+ # This is needed because the plugin links PRIVATEly to the backing library and thus the
+ # backing library's INTERFACE_SOURCES don't end up in the final consumer's SOURCES.
+ # Arguably doing this is cleaner than changing the linkage to PUBLIC, because that will
+ # propagate not only the INTERFACE_SOURCES, but also other link dependencies, which might
+ # be unwanted.
+ # In general this is a workaround due to CMake's limitations around support for propagating
+ # custom properties across targets to a final consumer target.
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/20416
+ if(arg_BACKING_TARGET
+ AND TARGET "${arg_BACKING_TARGET}" AND NOT arg_BACKING_TARGET STREQUAL target)
+ get_target_property(plugin_meta_types_file "${target}" INTERFACE_QT_META_TYPES_BUILD_FILE)
+ get_target_property(
+ backing_meta_types_file "${arg_BACKING_TARGET}" INTERFACE_QT_META_TYPES_BUILD_FILE)
+ get_target_property(
+ backing_meta_types_file_name
+ "${arg_BACKING_TARGET}" INTERFACE_QT_META_TYPES_FILE_NAME)
+ get_target_property(backing_has_qmltypes "${arg_BACKING_TARGET}" _qt_internal_has_qmltypes)
+ if(backing_has_qmltypes AND NOT plugin_meta_types_file)
+ _qt_internal_assign_build_metatypes_files_and_properties(
+ "${target}"
+ METATYPES_FILE_NAME "${backing_meta_types_file_name}"
+ METATYPES_FILE_PATH "${backing_meta_types_file}"
+ )
+ endif()
+ endif()
+
+ if(ANDROID)
+ _qt_internal_get_qml_plugin_output_name(plugin_output_name ${target}
+ BACKING_TARGET "${arg_BACKING_TARGET}"
+ TARGET_PATH "${arg_TARGET_PATH}"
+ URI "${arg_URI}"
+ )
+ set_target_properties(${target}
+ PROPERTIES
+ LIBRARY_OUTPUT_NAME "${plugin_output_name}"
+ )
+ set_property(TARGET "${target}"
+ PROPERTY _qt_android_apply_arch_suffix_called_from_qt_impl TRUE)
+ qt6_android_apply_arch_suffix(${target})
+ endif()
+
+ if(NOT arg_OUTPUT_DIRECTORY AND arg_BACKING_TARGET AND TARGET ${arg_BACKING_TARGET})
+ get_target_property(arg_OUTPUT_DIRECTORY ${arg_BACKING_TARGET} QT_QML_MODULE_OUTPUT_DIRECTORY)
+ endif()
+ if(arg_OUTPUT_DIRECTORY)
+ # Plugin target must be in the output directory. The backing target,
+ # if it is different to the plugin target, can be anywhere.
+ set_target_properties(${target} PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
+ LIBRARY_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
+ ARCHIVE_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
+ )
+ endif()
+
+ _qt_internal_set_qml_target_multi_config_output_directory(${target} "${arg_OUTPUT_DIRECTORY}")
+
+ if(NOT arg_NO_GENERATE_PLUGIN_SOURCE)
+ set(generated_cpp_file_name_base "${target}_${arg_CLASS_NAME}")
+ set(register_types_function_name "qml_register_types_${escaped_uri}")
+
+ # These are all substituted in the template file used further below
+ set(qt_qml_plugin_class_name "${arg_CLASS_NAME}")
+ set(qt_qml_plugin_moc_include_name "${generated_cpp_file_name_base}.moc")
+ set(qt_qml_plugin_intro "")
+ set(qt_qml_plugin_outro "")
+ set(qt_qml_plugin_constructor_content "")
+
+ # Get the target that contains the resource names.
+ set(target_with_prop "${target}")
+ if(NOT arg_BACKING_TARGET STREQUAL "" AND TARGET "${arg_BACKING_TARGET}")
+ set(target_with_prop "${arg_BACKING_TARGET}")
+ endif()
+
+ _qt_internal_qml_get_symbols_to_keep(
+ "${target_with_prop}"
+ "${backing_type}"
+ "${register_types_function_name}"
+ extra_intro_content
+ extra_intro_namespaced_content
+ extra_costructor_content
+ )
+
+ string(APPEND qt_qml_plugin_intro "${extra_intro_content}\n\n")
+
+ if (arg_NAMESPACE)
+ string(APPEND qt_qml_plugin_intro "namespace ${arg_NAMESPACE} {\n")
+ string(APPEND qt_qml_plugin_outro "} // namespace ${arg_NAMESPACE}")
+ endif()
+
+ string(APPEND qt_qml_plugin_intro "${extra_intro_namespaced_content}")
+
+ string(APPEND qt_qml_plugin_constructor_content "${extra_costructor_content}")
+
+ # Configure file from the template.
+ set(generated_cpp_file_in
+ "${CMAKE_CURRENT_BINARY_DIR}/${generated_cpp_file_name_base}_in.cpp"
+ )
+ configure_file(
+ "${__qt_qml_macros_module_base_dir}/Qt6QmlPluginTemplate.cpp.in"
+ "${generated_cpp_file_in}"
+ @ONLY
+ )
+
+ get_target_property(template_generated ${target} _qt_qml_plugin_template_generated)
+
+ if(NOT template_generated)
+ # Generate the file to allow adding generator expressions.
+ set(generated_cpp_file
+ "${CMAKE_CURRENT_BINARY_DIR}/${generated_cpp_file_name_base}.cpp"
+ )
+ file(GENERATE OUTPUT "${generated_cpp_file}"
+ INPUT "${generated_cpp_file_in}"
+ )
+
+ # We can't rely on policy CMP0118 since user project controls it
+ set(scope_args)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(scope_args TARGET_DIRECTORY ${target})
+ endif()
+ set_source_files_properties("${generated_cpp_file}" ${scope_args}
+ PROPERTIES GENERATED TRUE
+ )
+
+ # Because the add_qml_plugin function might be called multiple times on the same target,
+ # Only generate and add the cpp file once.
+ set_target_properties(${target} PROPERTIES _qt_qml_plugin_template_generated TRUE)
+ target_sources(${target} PRIVATE "${generated_cpp_file}")
+ endif()
+
+ # The generated cpp file expects to include its moc-ed output file.
+ set_target_properties(${target} PROPERTIES AUTOMOC TRUE)
+ endif()
+
+ target_link_libraries(${target} PRIVATE ${QT_CMAKE_EXPORT_NAMESPACE}::Qml)
+
+ # Link plugin against its backing lib if it has one.
+ if(NOT arg_BACKING_TARGET STREQUAL "" AND NOT arg_BACKING_TARGET STREQUAL target)
+ target_link_libraries(${target} PRIVATE ${arg_BACKING_TARGET})
+ endif()
+
+ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.19.0")
+ # Defer the collection of plugin dependencies until after any extra target_link_libraries
+ # calls that a user project might do.
+ # We wrap the deferred call with EVAL CODE
+ # so that ${target} is evaluated now rather than the end of the scope.
+ cmake_language(EVAL CODE
+ "cmake_language(DEFER CALL _qt_internal_add_static_qml_plugin_dependencies \"${target}\" \"${arg_BACKING_TARGET}\")"
+ )
+ else()
+ # Can't defer, have to do it now.
+ _qt_internal_add_static_qml_plugin_dependencies("${target}" "${arg_BACKING_TARGET}")
+ endif()
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_add_qml_plugin)
+ qt6_add_qml_plugin(${ARGV})
+ endfunction()
+endif()
+
+function(qt6_target_qml_sources target)
+
+ get_target_property(uri ${target} QT_QML_MODULE_URI)
+ get_target_property(output_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
+ if(NOT uri OR NOT output_dir)
+ message(FATAL_ERROR "Target ${target} is not a QML module")
+ endif()
+
+ set(args_option
+ NO_LINT
+ NO_CACHEGEN
+ NO_QMLDIR_TYPES
+ __QT_INTERNAL_FORCE_DEFER_QMLDIR # Used only by qt6_add_qml_module()
+ )
+
+ set(args_single
+ PREFIX
+ OUTPUT_TARGETS
+ )
+
+ set(args_multi
+ QML_FILES
+ RESOURCES
+ )
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${args_option}" "${args_single}" "${args_multi}"
+ )
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown/unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+
+ get_target_property(no_lint ${target} QT_QML_MODULE_NO_LINT)
+ if(NOT arg_QML_FILES AND NOT arg_RESOURCES)
+ if(NOT arg_NO_LINT AND NOT no_lint)
+ _qt_internal_target_enable_qmllint(${target})
+ endif()
+
+ if(arg_OUTPUT_TARGETS)
+ set(${arg_OUTPUT_TARGETS} "" PARENT_SCOPE)
+ endif()
+ return()
+ endif()
+
+ if(NOT arg___QT_INTERNAL_FORCE_DEFER_QMLDIR AND ${CMAKE_VERSION} VERSION_LESS "3.19.0")
+ message(FATAL_ERROR
+ "You are using CMake ${CMAKE_VERSION}, but CMake 3.19 or later "
+ "is required to add qml files with this function. Either pass "
+ "the qml files to qt6_add_qml_module() instead or update to "
+ "CMake 3.19 or later."
+ )
+ endif()
+
+ get_target_property(no_cachegen ${target} QT_QML_MODULE_NO_CACHEGEN)
+ get_target_property(no_qmldir ${target} QT_QML_MODULE_NO_GENERATE_QMLDIR)
+ get_target_property(resource_prefix ${target} QT_QML_MODULE_RESOURCE_PREFIX)
+ get_target_property(qml_module_version ${target} QT_QML_MODULE_VERSION)
+ get_target_property(past_major_versions ${target} QT_QML_MODULE_PAST_MAJOR_VERSIONS)
+
+ if(NOT output_dir)
+ # Probably not a qml module. We still want to support tooling for this
+ # scenario, it's just that we will be relying solely on the implicit
+ # imports to find things.
+ set(output_dir ${CMAKE_CURRENT_BINARY_DIR})
+ set(no_qmldir TRUE)
+ endif()
+
+ if(NOT arg_PREFIX)
+ if(resource_prefix)
+ set(arg_PREFIX ${resource_prefix})
+ else()
+ message(FATAL_ERROR
+ "PREFIX option not given and target ${target} does not have a "
+ "QT_QML_MODULE_RESOURCE_PREFIX property set."
+ )
+ endif()
+ endif()
+ _qt_internal_canonicalize_resource_path("${arg_PREFIX}" arg_PREFIX)
+ if(arg_PREFIX STREQUAL resource_prefix)
+ set(prefix_override "")
+ else()
+ set(prefix_override "${arg_PREFIX}")
+ endif()
+ if(NOT arg_PREFIX STREQUAL "/")
+ string(APPEND arg_PREFIX "/")
+ endif()
+
+ if (qml_module_version MATCHES "^([0-9]+)\\.")
+ set(qml_module_files_versions "${CMAKE_MATCH_1}.0")
+ else()
+ message(FATAL_ERROR
+ "No major version found in '${qml_module_version}'."
+ )
+ endif()
+ if (past_major_versions OR past_major_versions STREQUAL "0")
+ foreach (past_major_version ${past_major_versions})
+ list(APPEND qml_module_files_versions "${past_major_version}.0")
+ endforeach()
+ endif()
+
+ # Linting and cachegen can still occur for a target that isn't a qml module,
+ # but for such targets, there is no qmldir file to update.
+ if(arg_NO_LINT)
+ set(no_lint TRUE)
+ endif()
+ if(arg_NO_CACHEGEN)
+ set(no_cachegen TRUE)
+ endif()
+ if(no_qmldir MATCHES "NOTFOUND" OR arg_NO_QMLDIR_TYPES)
+ set(no_qmldir TRUE)
+ endif()
+
+ if(NOT no_cachegen AND arg_QML_FILES)
+
+ # Even if we don't generate a qmldir file, it still should be here, manually written.
+ # We can pass it unconditionally. If it's not there, qmlcachegen or qmlsc might warn,
+ # but that's not fatal.
+ set(qmldir_file ${output_dir}/qmldir)
+
+ _qt_internal_genex_getproperty(qmltypes_file ${target} QT_QML_MODULE_PLUGIN_TYPES_FILE)
+ _qt_internal_genex_getproperty(qmlcachegen ${target} QT_QMLCACHEGEN_EXECUTABLE)
+ _qt_internal_genex_getproperty(direct_calls ${target} QT_QMLCACHEGEN_DIRECT_CALLS)
+ _qt_internal_genex_getjoinedproperty(arguments ${target}
+ QT_QMLCACHEGEN_ARGUMENTS "$<SEMICOLON>" "$<SEMICOLON>"
+ )
+ _qt_internal_genex_getjoinedproperty(import_paths ${target}
+ QT_QML_IMPORT_PATH "-I$<SEMICOLON>" "$<SEMICOLON>"
+ )
+ _qt_internal_genex_getjoinedproperty(qrc_resource_args ${target}
+ _qt_generated_qrc_files "--resource$<SEMICOLON>" "$<SEMICOLON>"
+ )
+ get_target_property(target_type ${target} TYPE)
+ get_target_property(is_android_executable ${target} _qt_is_android_executable)
+ if(target_type STREQUAL "EXECUTABLE" OR is_android_executable)
+ # The application binary directory is part of the default import path.
+ list(APPEND import_paths -I "$<TARGET_PROPERTY:${target},BINARY_DIR>")
+ else()
+ string(REPLACE "." "/" uri_path "${uri}")
+ string(FIND "${output_dir}" "${uri_path}" position REVERSE)
+ string(LENGTH "${output_dir}" output_dir_length)
+ string(LENGTH "${uri_path}" uri_path_length)
+ math(EXPR import_path_length "${output_dir_length} - ${uri_path_length}")
+ if("${position}" EQUAL "${import_path_length}")
+ string(SUBSTRING "${output_dir}" "0" "${import_path_length}" import_path)
+ list(APPEND import_paths -I "${import_path}")
+ endif()
+ endif()
+ _qt_internal_extend_qml_import_paths(import_paths)
+ set(cachegen_args
+ ${import_paths}
+ -i "${qmldir_file}"
+ "$<${have_direct_calls}:--direct-calls>"
+ "$<${have_arguments}:${arguments}>"
+ ${qrc_resource_args}
+ )
+
+ # For direct evaluation in if() below
+ get_target_property(cachegen_prop ${target} QT_QMLCACHEGEN_EXECUTABLE)
+ if(cachegen_prop)
+ if(cachegen_prop STREQUAL "qmlcachegen" OR cachegen_prop STREQUAL "qmlsc")
+ # If it's qmlcachegen or qmlsc, don't go looking for other programs of that name
+ set(qmlcachegen "$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::${cachegen_prop}>")
+ else()
+ find_program(${target}_QMLCACHEGEN ${cachegen_prop})
+ if(${target}_QMLCACHEGEN)
+ set(qmlcachegen "${${target}_QMLCACHEGEN}")
+ else()
+ message(FATAL_ERROR "Invalid qmlcachegen binary ${cachegen_prop} for ${target}")
+ endif()
+ endif()
+ else()
+ set(have_qmlsc "$<TARGET_EXISTS:${QT_CMAKE_EXPORT_NAMESPACE}::qmlsc>")
+ set(cachegen_name "$<IF:${have_qmlsc},qmlsc,qmlcachegen>")
+ set(qmlcachegen "$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::${cachegen_name}>")
+ endif()
+ endif()
+
+ set(non_qml_cpp_files "")
+ set(non_qml_files "")
+ set(output_targets "")
+ set(copied_files "")
+
+ # We want to set source file properties in the target's own scope if we can.
+ # That's the canonical place the properties will be read from.
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.18)
+ set(scope_option TARGET_DIRECTORY ${target})
+ else()
+ set(scope_option "")
+ endif()
+
+ foreach(file_set IN ITEMS QML_FILES RESOURCES)
+ foreach(file_src IN LISTS arg_${file_set})
+ get_filename_component(file_absolute ${file_src} ABSOLUTE)
+
+ # Store the original files so the project can query them later.
+ set_property(TARGET ${target} APPEND PROPERTY
+ QT_QML_MODULE_${file_set} ${file_absolute}
+ )
+ if(prefix_override)
+ set_source_files_properties(${file_absolute} ${scope_option}
+ PROPERTIES
+ QT_QML_MODULE_PREFIX_OVERRIDE "${prefix_override}"
+ )
+ endif()
+
+ # We need to copy the file to the build directory now so that when
+ # qmlimportscanner is run in qt6_import_qml_plugins() as part of
+ # target finalizers, the files will be there. We need to do this
+ # in a way that CMake doesn't create a dependency on the source or it
+ # will re-run CMake every time the file is modified. We also don't
+ # want to update the file's timestamp if its contents won't change.
+ # We still enforce the dependency on the source file by adding a
+ # build-time rule. This avoids having to re-run CMake just to re-copy
+ # the file.
+ __qt_get_relative_resource_path_for_file(file_resource_path ${file_src})
+ set(file_out ${output_dir}/${file_resource_path})
+
+ # Don't generate or copy the file in an in-source build if the source
+ # and destination paths are the same, it will cause a ninja dependency
+ # cycle at build time.
+ if(NOT file_out STREQUAL file_absolute)
+ get_filename_component(file_out_dir ${file_out} DIRECTORY)
+ file(MAKE_DIRECTORY ${file_out_dir})
+
+ if(EXISTS "${file_absolute}")
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.21")
+ # Significantly increases copying speed according to profiling, presumably
+ # because we bypass process creation.
+ file(COPY_FILE "${file_absolute}" "${file_out}" ONLY_IF_DIFFERENT)
+ else()
+ execute_process(COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different ${file_absolute} ${file_out}
+ )
+ endif()
+ endif()
+
+ add_custom_command(OUTPUT ${file_out}
+ COMMAND ${CMAKE_COMMAND} -E copy ${file_absolute} ${file_out}
+ DEPENDS ${file_absolute}
+ WORKING_DIRECTORY $<TARGET_PROPERTY:${target},SOURCE_DIR>
+ VERBATIM
+ COMMENT "Copying ${file_src} to ${file_out}"
+ )
+ list(APPEND copied_files ${file_out})
+ endif()
+ endforeach()
+ endforeach()
+
+ set(generated_sources_other_scope)
+ set(extra_qmldirs)
+ foreach(qml_file_src IN LISTS arg_QML_FILES)
+ # This is to facilitate updating code that used the earlier tech preview
+ # API function qt6_target_qml_files()
+ if(NOT qml_file_src MATCHES "\\.(js|mjs|qml)$")
+ if(qml_file_src MATCHES "\\.(cpp|cxx|cc|c|c\\+\\+|h|hh|hxx|hpp|h\\+\\+)")
+ list(APPEND non_qml_cpp_files "${qml_file_src}")
+ else()
+ list(APPEND non_qml_files "${qml_file_src}")
+ endif()
+ continue()
+ endif()
+
+ # Mark QML files as source files, so that they do not appear in <Other Locations> in Creator
+ # or other IDEs
+ set_source_files_properties(${qml_file_src} HEADER_FILE_ONLY ON)
+ target_sources(${target} PRIVATE ${qml_file_src})
+
+ get_filename_component(file_absolute ${qml_file_src} ABSOLUTE)
+ __qt_get_relative_resource_path_for_file(file_resource_path ${qml_file_src})
+
+ get_filename_component(qml_file_resource_dir ${file_resource_path} DIRECTORY)
+ if(qml_file_resource_dir)
+ list(APPEND extra_qmldirs "${output_dir}/${qml_file_resource_dir}/qmldir")
+ endif()
+
+ # For the tooling steps below, run the tools on the copied qml file in
+ # the build directory, not the source directory. This is required
+ # because the tools may need to reference imported modules from
+ # subdirectories, which would require those subdirectories to have
+ # their generated qmldir files present. They also need to use the right
+ # resource paths and the source locations might be structured quite
+ # differently.
+
+ # Add file to those processed by qmllint
+ get_source_file_property(skip_qmllint ${qml_file_src} QT_QML_SKIP_QMLLINT)
+ if(NOT no_lint AND NOT skip_qmllint)
+ # The set of qml files to run qmllint on may be a subset of the
+ # full set of files, so record these in a separate property.
+ _qt_internal_target_enable_qmllint(${target})
+ set_property(TARGET ${target} APPEND PROPERTY QT_QML_LINT_FILES ${file_absolute})
+ endif()
+
+ # Add qml file's type to qmldir
+ get_source_file_property(skip_qmldir ${qml_file_src} QT_QML_SKIP_QMLDIR_ENTRY)
+ if(NOT no_qmldir AND NOT skip_qmldir)
+ get_source_file_property(qml_file_typename ${qml_file_src} QT_QML_SOURCE_TYPENAME)
+ if (NOT qml_file_typename)
+ get_filename_component(qml_file_ext ${qml_file_src} EXT)
+ get_filename_component(qml_file_typename ${qml_file_src} NAME_WE)
+ endif()
+
+ # Do not add qmldir entries for lowercase names. Those are not components.
+ if (qml_file_typename AND qml_file_typename MATCHES "^[A-Z]")
+ if (qml_file_ext AND NOT qml_file_ext STREQUAL ".qml" AND NOT qml_file_ext STREQUAL ".ui.qml"
+ AND NOT qml_file_ext STREQUAL ".js" AND NOT qml_file_ext STREQUAL ".mjs")
+ message(AUTHOR_WARNING
+ "${qml_file_src} has a file extension different from .qml, .ui.qml, .js, "
+ "and .mjs. This leads to unexpected component names."
+ )
+ endif()
+
+ # We previously accepted the singular form of this property name
+ # during tech preview. Issue a warning for that, but still
+ # honor it. The plural form will override it if both are set.
+ get_property(have_singular_property SOURCE ${qml_file_src}
+ PROPERTY QT_QML_SOURCE_VERSION SET
+ )
+ if(have_singular_property)
+ message(AUTHOR_WARNING
+ "The QT_QML_SOURCE_VERSION source file property has been replaced "
+ "by QT_QML_SOURCE_VERSIONS (i.e. plural rather than singular). "
+ "The singular form will eventually be removed, please update "
+ "the project to use the plural form instead for the file at:\n"
+ " ${qml_file_src}"
+ )
+ endif()
+ get_source_file_property(qml_file_versions ${qml_file_src} QT_QML_SOURCE_VERSIONS)
+ if(NOT qml_file_versions AND have_singular_property)
+ get_source_file_property(qml_file_versions ${qml_file_src} QT_QML_SOURCE_VERSION)
+ endif()
+
+ get_source_file_property(qml_file_singleton ${qml_file_src} QT_QML_SINGLETON_TYPE)
+ get_source_file_property(qml_file_internal ${qml_file_src} QT_QML_INTERNAL_TYPE)
+
+ if (qml_file_singleton AND qml_file_internal)
+ message(FATAL_ERROR
+ "${qml_file_src} is marked as both internal and as a "
+ "singleton, but singletons cannot be internal!")
+ endif()
+
+ if (NOT qml_file_versions)
+ set(qml_file_versions ${qml_module_files_versions})
+ endif()
+
+ set(qmldir_file_contents "")
+ foreach(qml_file_version IN LISTS qml_file_versions)
+ if (qml_file_singleton)
+ string(APPEND qmldir_file_contents "singleton ")
+ elseif (qml_file_internal)
+ continue()
+ endif()
+ string(APPEND qmldir_file_contents "${qml_file_typename} ${qml_file_version} ${file_resource_path}\n")
+ endforeach()
+
+ if (qml_file_internal)
+ # TODO: Remove when all qmldir parsers can parse internal types with versions.
+ # Instead handle internal types like singletons above.
+ # See QTCREATORBUG-28755
+ string(APPEND qmldir_file_contents "internal ${qml_file_typename} ${file_resource_path}\n")
+ endif()
+
+ set_property(TARGET ${target} APPEND_STRING PROPERTY
+ _qt_internal_qmldir_content "${qmldir_file_contents}"
+ )
+ endif()
+ endif()
+
+ # Run cachegen on the qml file, or if disabled, store the raw qml file in the resources
+ get_source_file_property(skip_cachegen ${qml_file_src} QT_QML_SKIP_CACHEGEN)
+ if(NOT no_cachegen AND NOT skip_cachegen)
+ # We delay this to here to ensure that we only ever enable cachegen
+ # after we know there will be at least one file to compile.
+ get_target_property(is_cachegen_set_up ${target} _qt_cachegen_set_up)
+ if(NOT is_cachegen_set_up)
+ _qt_internal_target_enable_qmlcachegen(${target} ${qmlcachegen})
+ endif()
+
+ # We ensured earlier that arg_PREFIX always ends with "/"
+ file(TO_CMAKE_PATH "${arg_PREFIX}${file_resource_path}" file_resource_path)
+
+ set_property(TARGET ${target} APPEND PROPERTY
+ QT_QML_MODULE_RESOURCE_PATHS ${file_resource_path}
+ )
+
+ file(RELATIVE_PATH file_relative ${CMAKE_CURRENT_SOURCE_DIR} ${file_absolute})
+ string(REGEX REPLACE "\\.(js|mjs|qml)$" "_\\1" compiled_file ${file_relative})
+ string(REGEX REPLACE "[$#?]+" "_" compiled_file ${compiled_file})
+
+ # The file name needs to be unique to work around an Integrity compiler issue.
+ # Search for INTEGRITY_SYMBOL_UNIQUENESS in this file for details.
+ set(compiled_file
+ "${CMAKE_CURRENT_BINARY_DIR}/.rcc/qmlcache/${target}_${compiled_file}.cpp")
+ get_filename_component(out_dir ${compiled_file} DIRECTORY)
+
+ if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.20")
+ set(qmlcachegen_cmd "$<COMMAND_CONFIG:${qmlcachegen}>")
+ else()
+ set(qmlcachegen_cmd "${qmlcachegen}")
+ endif()
+
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ add_custom_command(
+ OUTPUT ${compiled_file}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${out_dir}
+ COMMAND
+ ${tool_wrapper}
+ ${qmlcachegen_cmd}
+ --bare
+ --resource-path "${file_resource_path}"
+ ${cachegen_args}
+ -o "${compiled_file}"
+ "${file_absolute}"
+ COMMAND_EXPAND_LISTS
+ DEPENDS
+ ${qmlcachegen_cmd}
+ "${file_absolute}"
+ $<TARGET_PROPERTY:${target},_qt_generated_qrc_files>
+ "$<$<BOOL:${qmltypes_file}>:${qmltypes_file}>"
+ "${qmldir_file}"
+ VERBATIM
+ )
+
+ target_sources(${target} PRIVATE ${compiled_file})
+ set_source_files_properties(${compiled_file} PROPERTIES
+ SKIP_AUTOGEN ON
+ )
+ # The current scope automatically sees the file as generated, but the
+ # target scope may not if it is different. Force it where we can.
+ # We will also have to add the generated file to a target in this
+ # scope at the end to ensure correct dependencies.
+ get_target_property(target_source_dir ${target} SOURCE_DIR)
+ if(NOT target_source_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ list(APPEND generated_sources_other_scope ${compiled_file})
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set_source_files_properties(
+ ${compiled_file}
+ TARGET_DIRECTORY ${target}
+ PROPERTIES
+ SKIP_AUTOGEN TRUE
+ GENERATED TRUE
+ )
+ endif()
+ endif()
+ endif()
+ endforeach()
+
+ if(ANDROID)
+ _qt_internal_collect_qml_root_paths("${target}" ${arg_QML_FILES})
+ endif()
+
+ if(non_qml_files OR non_qml_cpp_files)
+ if(non_qml_cpp_files)
+ list(JOIN non_qml_cpp_files "\n " file_list)
+ set(wrong_sources "\nwith SOURCES:\n ${file_list}"
+ )
+ endif()
+ if(non_qml_files)
+ list(JOIN non_qml_files "\n " file_list)
+ set(wrong_resources "\nwith RESOURCES:\n ${file_list}")
+ endif()
+
+ message(WARNING "Only .qml, .js or .mjs files should be added with QML_FILES. "
+ "The following files should be added${wrong_sources}${wrong_resources}")
+ endif()
+
+ if(copied_files OR generated_sources_other_scope)
+ if(CMAKE_VERSION VERSION_LESS 3.19)
+ # Called from qt6_add_qml_module() and we know there can only be
+ # this one call. With those constraints, we can use a custom target
+ # to implement the necessary dependencies to get files copied to the
+ # build directory when their source files change.
+ add_custom_target(${target}_tooling ALL
+ DEPENDS
+ ${copied_files}
+ ${generated_sources_other_scope}
+ )
+ add_dependencies(${target} ${target}_tooling)
+ else()
+ # We could be called multiple times and a custom target can only
+ # have file-level dependencies added at the time the target is
+ # created. Use an interface library instead, since we can add
+ # private sources to those and have the library act as a build
+ # system target from CMake 3.19 onward, and we can add the sources
+ # progressively over multiple calls.
+ if(NOT TARGET ${target}_tooling)
+ add_library(${target}_tooling INTERFACE)
+ add_dependencies(${target} ${target}_tooling)
+ endif()
+ target_sources(${target}_tooling PRIVATE
+ ${copied_files}
+ ${generated_sources_other_scope}
+ )
+ endif()
+ _qt_internal_assign_to_internal_targets_folder(${target}_tooling)
+ endif()
+
+ # Batch all the non-compiled qml sources into a single resource for this
+ # call. Subsequent calls for the same target will be in their own separate
+ # resource file.
+ get_target_property(counter ${target} QT_QML_MODULE_RAW_QML_SETS)
+ if(NOT counter)
+ set(counter 0)
+ endif()
+ set(resource_name ${target}_raw_qml_${counter})
+ set(resource_targets)
+ qt6_add_resources(${target} ${resource_name}
+ PREFIX ${arg_PREFIX}
+ FILES ${arg_QML_FILES} ${arg_RESOURCES}
+ OUTPUT_TARGETS resource_targets
+ )
+ list(APPEND output_targets ${resource_targets})
+
+ # Save the resource name in a property so we can reference it later in a qml plugin
+ # constructor, to avoid discarding the resource if it's in a static library.
+ __qt_internal_sanitize_resource_name(
+ sanitized_resource_name "${resource_name}")
+ set_property(TARGET ${target}
+ APPEND PROPERTY _qt_qml_module_sanitized_resource_names "${sanitized_resource_name}")
+
+ if(extra_qmldirs)
+ list(REMOVE_DUPLICATES extra_qmldirs)
+ __qt_internal_setup_policy(QTP0004 "6.8.0"
+"You need qmldir files for each extra directory that contains .qml files for your module. \
+Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0004.html for policy details."
+ )
+ qt6_policy(GET QTP0004 generate_extra_qmldirs_policy)
+ if ("${generate_extra_qmldirs_policy}" STREQUAL "NEW")
+ foreach(extra_qmldir IN LISTS extra_qmldirs)
+ set(__qt_qmldir_content "prefer :${arg_PREFIX}")
+ configure_file(
+ ${__qt_qml_macros_module_base_dir}/Qt6qmldirTemplate.cmake.in
+ "${extra_qmldir}"
+ @ONLY
+ )
+
+ set_source_files_properties("${extra_qmldir}"
+ PROPERTIES GENERATED TRUE
+ )
+ endforeach()
+
+ set(extra_qmldirs_targets)
+ qt6_add_resources(${target} "${resource_name}_extra_qmldirs"
+ PREFIX ${arg_PREFIX}
+ FILES ${extra_qmldirs}
+ BASE ${output_dir}
+ OUTPUT_TARGETS extra_qmldirs_targets
+ )
+ list(APPEND output_targets ${extra_qmldirs_targets})
+
+ set_property(TARGET ${target} PROPERTY _qt_internal_extra_qmldirs ${extra_qmldirs})
+
+ # Save the resource name in a property so we can reference it later in a qml plugin
+ # constructor, to avoid discarding the resource if it's in a static library.
+ __qt_internal_sanitize_resource_name(
+ sanitized_extra_qmldirs_resource_name "${resource_name}_extra_qmldirs")
+ set_property(TARGET ${target}
+ APPEND PROPERTY _qt_qml_module_sanitized_resource_names
+ "${sanitized_extra_qmldirs_resource_name}")
+ endif()
+ endif()
+
+ math(EXPR counter "${counter} + 1")
+ set_target_properties(${target} PROPERTIES QT_QML_MODULE_RAW_QML_SETS ${counter})
+
+ if(arg_OUTPUT_TARGETS)
+ set(${arg_OUTPUT_TARGETS} ${output_targets} PARENT_SCOPE)
+ endif()
+
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_target_qml_sources)
+ qt6_target_qml_sources(${ARGV})
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "OUTPUT_TARGETS" "")
+ if(arg_OUTPUT_TARGETS)
+ set(${arg_OUTPUT_TARGETS} ${${arg_OUTPUT_TARGETS}} PARENT_SCOPE)
+ endif()
+ endfunction()
+endif()
+
+function(qt6_generate_foreign_qml_types source_target destination_qml_target)
+ qt6_extract_metatypes(${source_target})
+ get_target_property(target_metatypes_json_file ${source_target}
+ INTERFACE_QT_META_TYPES_BUILD_FILE)
+ if (NOT target_metatypes_json_file)
+ message(FATAL_ERROR "Need target metatypes.json file")
+ endif()
+
+ get_target_property(automoc_enabled ${destination_qml_target} AUTOMOC)
+ if(NOT automoc_enabled)
+ message(FATAL_ERROR "qt6_generate_foreign_qml_types requires AUTOMOC to be enabled "
+ "on target '${destination_qml_target}'.")
+ endif()
+
+ set(registration_files_base ${source_target}_${destination_qml_target})
+ set(additional_sources
+ "${CMAKE_CURRENT_BINARY_DIR}/${registration_files_base}.cpp"
+ "${CMAKE_CURRENT_BINARY_DIR}/${registration_files_base}.h"
+ )
+
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ add_custom_command(
+ OUTPUT
+ ${additional_sources}
+ DEPENDS
+ ${source_target}
+ ${target_metatypes_json_file}
+ ${QT_CMAKE_EXPORT_NAMESPACE}::qmltyperegistrar
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qmltyperegistrar>
+ "--extract"
+ -o ${registration_files_base}
+ ${target_metatypes_json_file}
+ COMMENT "Generate QML registration code for target ${source_target}"
+ VERBATIM
+ )
+
+ target_sources(${destination_qml_target} PRIVATE ${additional_sources})
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ function(qt_generate_foreign_qml_types)
+ qt6_generate_foreign_qml_types(${ARGV})
+ endfunction()
+ else()
+ message(FATAL_ERROR "qt_generate_foreign_qml_types() is only available in Qt 6.")
+ endif()
+endif()
+
+# target: Expected to be the backing target for a qml module. Certain target
+# properties normally set by qt6_add_qml_module() will be retrieved from this
+# target. (REQUIRED)
+#
+# MANUAL_MOC_JSON_FILES: Specifies a list of json files, generated by a manual
+# moc call, to extract metatypes. (OPTIONAL)
+#
+# NAMESPACE: Specifies a namespace the type registration function shall be
+# generated into. (OPTIONAL)
+#
+# REGISTRATIONS_TARGET: Specifies a separate target the generated .cpp file
+# shall be added to. If not given, the main backing target is used. (OPTIONAL)
+#
+function(_qt_internal_qml_type_registration target)
+ set(args_option)
+ set(args_single NAMESPACE REGISTRATIONS_TARGET)
+ set(args_multi MANUAL_MOC_JSON_FILES)
+
+ get_target_property(skipped ${target} _qt_is_skipped_test)
+ if(skipped)
+ return()
+ endif()
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${args_option}" "${args_single}" "${args_multi}"
+ )
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown/unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+
+ get_target_property(import_name ${target} QT_QML_MODULE_URI)
+ if (NOT import_name)
+ message(FATAL_ERROR "Target ${target} is not a QML module")
+ endif()
+ get_target_property(qmltypes_output_name ${target} QT_QML_MODULE_TYPEINFO)
+ if (NOT qmltypes_output_name)
+ get_target_property(compile_definitions_list ${target} COMPILE_DEFINITIONS)
+ list(FIND compile_definitions_list QT_PLUGIN is_a_plugin)
+ if (is_a_plugin GREATER_EQUAL 0)
+ set(qmltypes_output_name "plugins.qmltypes")
+ else()
+ set(qmltypes_output_name ${target}.qmltypes)
+ endif()
+ endif()
+
+ set(meta_types_json_args "")
+ if(arg_MANUAL_MOC_JSON_FILES)
+ list(APPEND meta_types_json_args "MANUAL_MOC_JSON_FILES" ${arg_MANUAL_MOC_JSON_FILES})
+ endif()
+ qt6_extract_metatypes(${target} ${meta_types_json_args})
+
+ get_target_property(import_version ${target} QT_QML_MODULE_VERSION)
+ get_target_property(output_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
+ get_target_property(target_source_dir ${target} SOURCE_DIR)
+ get_target_property(target_binary_dir ${target} BINARY_DIR)
+ get_target_property(target_metatypes_file ${target} INTERFACE_QT_META_TYPES_BUILD_FILE)
+ if (NOT target_metatypes_file)
+ message(FATAL_ERROR "Target ${target} does not have a meta types file")
+ endif()
+
+ # Extract major and minor version (could also have patch part, but we don't
+ # need that here)
+ if (import_version MATCHES "^([0-9]+)\\.([0-9]+)")
+ set(major_version ${CMAKE_MATCH_1})
+ set(minor_version ${CMAKE_MATCH_2})
+ else()
+ message(FATAL_ERROR
+ "Invalid module version number '${import_version}'. "
+ "Expected VersionMajor.VersionMinor."
+ )
+ endif()
+
+ # check if plugins.qmltypes is already defined
+ get_target_property(target_plugin_qmltypes ${target} QT_QML_MODULE_PLUGIN_TYPES_FILE)
+ if (target_plugin_qmltypes)
+ message(FATAL_ERROR "Target ${target} already has a qmltypes file set.")
+ endif()
+
+ set(cmd_args)
+ set(plugin_types_file "${output_dir}/${qmltypes_output_name}")
+ set(generated_marker_file "${target_binary_dir}/.qt/qmltypes/${qmltypes_output_name}")
+ get_filename_component(generated_marker_dir "${generated_marker_file}" DIRECTORY)
+ set_target_properties(${target} PROPERTIES
+ QT_QML_MODULE_PLUGIN_TYPES_FILE ${plugin_types_file}
+ )
+
+ if (arg_NAMESPACE)
+ list(APPEND cmd_args
+ --namespace=${arg_NAMESPACE}
+ )
+ endif()
+
+ list(APPEND cmd_args
+ --generate-qmltypes=${plugin_types_file}
+ --import-name=${import_name}
+ --major-version=${major_version}
+ --minor-version=${minor_version}
+ )
+
+
+ # Add --follow-foreign-versioning if requested
+ get_target_property(follow_foreign_versioning ${target}
+ _qt_qml_module_follow_foreign_versioning)
+
+ if (follow_foreign_versioning)
+ list(APPEND cmd_args
+ --follow-foreign-versioning
+ )
+ endif()
+
+ # Add past minor versions
+ get_target_property(past_major_versions ${target} QT_QML_MODULE_PAST_MAJOR_VERSIONS)
+
+ if (past_major_versions OR past_major_versions STREQUAL "0")
+ foreach (past_major_version ${past_major_versions})
+ list(APPEND cmd_args
+ --past-major-version ${past_major_version}
+ )
+ endforeach()
+ endif()
+
+ # Run a script to recursively evaluate all the metatypes.json files in order
+ # to collect all foreign types.
+ string(TOLOWER "${target}_qmltyperegistrations.cpp" type_registration_cpp_file_name)
+ set(foreign_types_file "${target_binary_dir}/qmltypes/${target}_foreign_types.txt")
+ set(type_registration_cpp_file "${target_binary_dir}/${type_registration_cpp_file_name}")
+
+ # Enable evaluation of metatypes.json source interfaces
+ set_target_properties(${target} PROPERTIES QT_CONSUMES_METATYPES TRUE)
+ set(genex_list "$<REMOVE_DUPLICATES:$<FILTER:$<TARGET_PROPERTY:${target},SOURCES>,INCLUDE,metatypes.json$>>")
+ set(genex_main "$<JOIN:${genex_list},$<COMMA>>")
+ file(GENERATE OUTPUT "${foreign_types_file}"
+ CONTENT "$<IF:$<BOOL:${genex_list}>,--foreign-types=${genex_main},\n>"
+ )
+
+ list(APPEND cmd_args
+ "@${foreign_types_file}"
+ )
+
+ if (TARGET ${target}Private)
+ list(APPEND cmd_args --private-includes)
+ else()
+ string(REGEX MATCH "Private$" privateSuffix ${target})
+ if (privateSuffix)
+ list(APPEND cmd_args --private-includes)
+ endif()
+ endif()
+
+ get_target_property(target_metatypes_json_file ${target} INTERFACE_QT_META_TYPES_BUILD_FILE)
+ if (NOT target_metatypes_json_file)
+ message(FATAL_ERROR "Need target metatypes.json file")
+ endif()
+
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ add_custom_command(
+ OUTPUT
+ ${type_registration_cpp_file}
+ ${plugin_types_file}
+ DEPENDS
+ ${foreign_types_file}
+ ${target_metatypes_json_file}
+ ${QT_CMAKE_EXPORT_NAMESPACE}::qmltyperegistrar
+ "$<$<BOOL:${genex_list}>:${genex_list}>"
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qmltyperegistrar>
+ ${cmd_args}
+ -o ${type_registration_cpp_file}
+ ${target_metatypes_json_file}
+ COMMAND
+ ${CMAKE_COMMAND} -E make_directory "${generated_marker_dir}"
+ COMMAND
+ ${CMAKE_COMMAND} -E touch "${generated_marker_file}"
+ COMMENT "Automatic QML type registration for target ${target}"
+ VERBATIM
+ )
+
+ # The ${target}_qmllint targets need to depend on the generation of all
+ # *.qmltypes files in the build. We have no way of reliably working out
+ # which QML modules a given target depends on at configure time, so we
+ # have to be conservative and make ${target}_qmllint targets depend on all
+ # *.qmltypes files. We need to provide a target for those dependencies
+ # here. Note that we can't use ${target} itself for those dependencies
+ # because the user might want to run qmllint without having to build the
+ # QML module.
+ add_custom_target(${target}_qmltyperegistration
+ DEPENDS
+ ${type_registration_cpp_file}
+ ${plugin_types_file}
+ )
+ _qt_internal_assign_to_internal_targets_folder(${target}_qmltyperegistration)
+ if(NOT TARGET all_qmltyperegistrations)
+ add_custom_target(all_qmltyperegistrations)
+ _qt_internal_assign_to_internal_targets_folder(all_qmltyperegistrations)
+ endif()
+ add_dependencies(all_qmltyperegistrations ${target}_qmltyperegistration)
+
+ set(effective_target ${target})
+ if(arg_REGISTRATIONS_TARGET)
+ set(effective_target ${arg_REGISTRATIONS_TARGET})
+ endif()
+
+ # Both ${effective_target} (via target_sources) and ${target}_qmltyperegistration (via
+ # add_custom_target DEPENDS option) depend on ${type_registration_cpp_file}.
+ # The new Xcode build system requires a common target to drive the generation of files,
+ # otherwise project configuration fails.
+ # Make ${effective_target} the common target, by adding it as a dependency for
+ # ${target}_qmltyperegistration.
+ # The consequence is that the ${target}_qmllint target will now first build ${effective_target}
+ # when using the Xcode generator (mostly only relevant for projects using Qt for iOS).
+ # See QTBUG-95763.
+ if(CMAKE_GENERATOR STREQUAL "Xcode")
+ add_dependencies(${target}_qmltyperegistration ${effective_target})
+ endif()
+
+ target_sources(${effective_target} PRIVATE ${type_registration_cpp_file})
+
+ # FIXME: The generated .cpp file has usually lost the path information for
+ # the headers it #include's. Since these generated .cpp files are in
+ # the build directory away from those headers, the header search path
+ # has to be augmented to ensure they can be found. We don't know what
+ # paths are needed, but add the source directory to at least handle
+ # the common case of headers in the same directory as the target.
+ # See QTBUG-93443.
+ target_include_directories(${effective_target} PRIVATE ${target_source_dir})
+
+ # Circumvent "too many sections" error when doing a 32 bit debug build on Windows with
+ # MinGW.
+ set(additional_source_files_properties "")
+ if(MINGW)
+ set(additional_source_files_properties "COMPILE_OPTIONS" "-Wa,-mbig-obj")
+ elseif(MSVC)
+ set(additional_source_files_properties "COMPILE_OPTIONS" "/bigobj")
+ endif()
+ set_source_files_properties(${type_registration_cpp_file} PROPERTIES
+ SKIP_AUTOGEN ON
+ ${additional_source_files_properties}
+ )
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set_source_files_properties(
+ ${type_registration_cpp_file}
+ TARGET_DIRECTORY ${effective_target}
+ PROPERTIES
+ SKIP_AUTOGEN TRUE
+ GENERATED TRUE
+ ${additional_source_files_properties}
+ )
+ endif()
+
+ target_include_directories(${effective_target} PRIVATE
+ $<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::QmlPrivate,INTERFACE_INCLUDE_DIRECTORIES>
+ )
+endfunction()
+
+function(qt6_qml_type_registration)
+ message(FATAL_ERROR
+ "This function, previously available under Technical Preview, has been removed. "
+ "Please use qt6_add_qml_module() instead."
+ )
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_qml_type_registration)
+ message(FATAL_ERROR
+ "This function, previously available under Technical Preview, has been removed. "
+ "Please use qt_add_qml_module() instead."
+ )
+ endfunction()
+endif()
+
+# Get Qt provided QML import paths.
+# The appending order is important. Build dirs are preferred over install dirs.
+function(_qt_internal_get_main_qt_qml_import_paths out_var)
+ set(qml_import_paths "")
+
+ # When building a qml module as part of a prefix Qt build that is not yet installed, add an
+ # extra import path which is the current module's build dir: we need
+ # this to ensure correct importing of QML modules when having a prefix-build
+ # with QLibraryInfo::path(QLibraryInfo::QmlImportsPath) pointing to the
+ # install location.
+ if(QT_BUILDING_QT AND QT_WILL_INSTALL)
+ set(build_dir_import_path "${QT_BUILD_DIR}/${INSTALL_QMLDIR}")
+ if(IS_DIRECTORY "${build_dir_import_path}")
+ list(APPEND qml_import_paths "${build_dir_import_path}")
+ endif()
+ endif()
+
+ # We could have multiple additional installation prefixes: one per Qt repository (conan).
+ # Or just extra ones, that might be needed during cross-compilation or example building.
+ # Add those that have a "qml" subdirectory.
+ # The additional prefixes have priority over the main Qt prefix, so they come first.
+ if(NOT "${_qt_additional_packages_prefix_paths}" STREQUAL "")
+ __qt_internal_prefix_paths_to_roots(
+ additional_root_paths "${_qt_additional_packages_prefix_paths}")
+ foreach(root IN ITEMS ${additional_root_paths})
+ set(candidate "${root}/${QT6_INSTALL_QML}")
+ if(IS_DIRECTORY "${candidate}")
+ list(APPEND qml_import_paths "${candidate}")
+ endif()
+ endforeach()
+ endif()
+
+ # Add the main Qt "<prefix>/qml" import path.
+ if(QT6_INSTALL_PREFIX)
+ set(main_import_path "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_QML}")
+ if(IS_DIRECTORY "${main_import_path}")
+ list(APPEND qml_import_paths "${main_import_path}")
+ endif()
+ endif()
+
+ set(${out_var} "${qml_import_paths}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_collect_target_qml_import_paths out_var target)
+ set(qml_import_paths "")
+ # Get custom import paths provided during qt_add_qml_module call.
+ get_target_property(qml_import_path ${target} QT_QML_IMPORT_PATH)
+ if(qml_import_path)
+ list(APPEND qml_import_paths ${qml_import_path})
+ endif()
+
+ # Facilitate self-import so we can find the qmldir file
+ get_target_property(module_out_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
+ if(module_out_dir)
+ list(APPEND qml_import_paths "${module_out_dir}")
+ endif()
+
+ # Find qmldir files we copied to the build directory
+ if(NOT "${QT_QML_OUTPUT_DIRECTORY}" STREQUAL "")
+ if(EXISTS "${QT_QML_OUTPUT_DIRECTORY}")
+ list(APPEND qml_import_paths "${QT_QML_OUTPUT_DIRECTORY}")
+ endif()
+ else()
+ list(APPEND qml_import_paths "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+
+ set(${out_var} "${qml_import_paths}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_collect_qml_import_paths out_var target)
+ _qt_internal_collect_target_qml_import_paths(qml_import_paths ${target})
+
+ # Add the Qt import paths last.
+ _qt_internal_get_main_qt_qml_import_paths(qt_main_import_paths)
+ list(APPEND qml_import_paths ${qt_main_import_paths})
+
+ set(${out_var} "${qml_import_paths}" PARENT_SCOPE)
+endfunction()
+
+# This function returns the path to the qmlimportscanner executable.
+# The are a few cases to handle:
+# When used in a user project, the tool should already be built and we can find the path
+# via the imported target.
+# When used in an example that is built as part of the qtdeclarative build (or top-level build),
+# there is no imported target yet. Here we have to differentiate whether the tool will be run at
+# build time or configure time.
+# If at configure time, we show an error, there is nothing to run yet. Such a setup is currently not
+# supported.
+# If at build time, we return the path where the built tool will be located after it is built.
+function(_qt_internal_find_qmlimportscanner_path out_path scan_at_configure_time)
+ # Find location of qmlimportscanner via the imported target.
+ set(tool_path "")
+ set(tool_name "qmlimportscanner")
+ set(import_scanner_target "${QT_CMAKE_EXPORT_NAMESPACE}::${tool_name}")
+ if(TARGET "${import_scanner_target}")
+ get_target_property(tool_path "${import_scanner_target}" IMPORTED_LOCATION)
+ if(NOT tool_path)
+ set(configs "RELWITHDEBINFO;RELEASE;MINSIZEREL;DEBUG")
+ foreach(config ${configs})
+ get_target_property(tool_path
+ "${import_scanner_target}" IMPORTED_LOCATION_${config})
+ if(tool_path)
+ break()
+ endif()
+ endforeach()
+ endif()
+ endif()
+
+ if(NOT QT_BUILDING_QT)
+ set(building_user_project TRUE)
+ else()
+ set(building_user_project FALSE)
+ endif()
+
+ if(NOT EXISTS "${tool_path}"
+ AND (building_user_project OR scan_at_configure_time))
+ message(FATAL_ERROR "The qmlimportscanner tool could not be found.
+Possible reasons include:
+* The file was deleted, renamed, or moved to another location.
+* An install or uninstall procedure did not complete successfully.
+* The installation was faulty.
+")
+ endif()
+
+ # We are building Qt, the tool is not built yet and we need to run it at build time.
+ if(NOT tool_path)
+ qt_path_join(tool_path
+ "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}"
+ "${tool_name}${CMAKE_EXECUTABLE_SUFFIX}")
+ endif()
+
+ set(${out_path} "${tool_path}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_scan_qml_imports target imports_file_var when_to_scan)
+ if(NOT "${ARGN}" STREQUAL "")
+ message(FATAL_ERROR "Unknown/unexpected arguments: ${ARGN}")
+ endif()
+
+ if(when_to_scan STREQUAL "BUILD_PHASE")
+ set(scan_at_build_time TRUE)
+ set(scan_at_configure_time FALSE)
+ set(imports_file_infix "build")
+ elseif(when_to_scan STREQUAL "IMMEDIATELY")
+ set(scan_at_build_time FALSE)
+ set(scan_at_configure_time TRUE)
+ set(imports_file_infix "conf")
+ else()
+ message(FATAL_ERROR "Unexpected value for when_to_scan: ${when_to_scan}")
+ endif()
+
+ _qt_internal_find_qmlimportscanner_path(tool_path "${scan_at_configure_time}")
+
+ get_target_property(target_source_dir ${target} SOURCE_DIR)
+ get_target_property(target_binary_dir ${target} BINARY_DIR)
+ set(out_dir "${target_binary_dir}/.qt/qml_imports")
+
+ # Create separate files for scanning at build time vs configure time. Otherwise calling
+ # ninja clean will re-run qmlimportscanner directly after the clean, which is
+ # both weird and sometimes prints warnings due to the tool not finding qml files that were
+ # cleaned from the build dir.
+ set(file_base_name "${target}_${imports_file_infix}")
+
+ set(imports_file "${out_dir}/${file_base_name}.cmake")
+ set(${imports_file_var} "${imports_file}" PARENT_SCOPE)
+ file(MAKE_DIRECTORY ${out_dir})
+
+ set(cmd_args
+ -rootPath "${target_source_dir}"
+ -cmake-output
+ -output-file "${imports_file}"
+ )
+
+ _qt_internal_collect_qml_import_paths(qml_import_paths ${target})
+ list(REMOVE_DUPLICATES qml_import_paths)
+
+ # Construct the -importPath arguments.
+ set(import_path_arguments)
+ foreach(path IN LISTS qml_import_paths)
+ if(EXISTS "${path}" OR scan_at_build_time)
+ list(APPEND import_path_arguments -importPath ${path})
+ else()
+ message(DEBUG "The import path ${path} is mentioned for ${target}, but it doesn't"
+ " exists.")
+ endif()
+ endforeach()
+
+ list(APPEND cmd_args ${import_path_arguments})
+
+ # All of the module's .qml files will be listed in one of the generated
+ # .qrc files, so there's no need to list the files individually. We provide
+ # the .qrc files instead because they have the additional information for
+ # each file's resource alias.
+ get_property(qrc_files TARGET ${target} PROPERTY _qt_generated_qrc_files)
+ if (qrc_files)
+ list(APPEND cmd_args "-qrcFiles" ${qrc_files})
+ endif()
+
+ # Use a response file to avoid command line length issues if we have a lot
+ # of arguments on the command line
+ string(LENGTH "${cmd_args}" length)
+ if(length GREATER 240)
+ set(rsp_file "${out_dir}/${file_base_name}.rsp")
+ list(JOIN cmd_args "\n" rsp_file_content)
+ file(WRITE ${rsp_file} "${rsp_file_content}")
+ set(cmd_args "@${rsp_file}")
+ endif()
+
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ set(import_scanner_args ${tool_wrapper} ${tool_path} ${cmd_args})
+
+ # Run qmlimportscanner to generate the cmake file that records the import entries
+ if(scan_at_build_time)
+ add_custom_command(
+ OUTPUT "${imports_file}"
+ COMMENT "Running qmlimportscanner for ${target}"
+ COMMAND ${import_scanner_args}
+ WORKING_DIRECTORY ${target_source_dir}
+ DEPENDS
+ ${tool_path}
+ ${qrc_files}
+ $<TARGET_PROPERTY:${target},QT_QML_MODULE_QML_FILES>
+ VERBATIM
+ )
+ add_custom_target(${target}_qmlimportscan DEPENDS "${imports_file}")
+ _qt_internal_assign_to_internal_targets_folder(${target}_qmlimportscan)
+ add_dependencies(${target} ${target}_qmlimportscan)
+ else()
+ message(VERBOSE "Running qmlimportscanner for ${target}.")
+ list(JOIN import_scanner_args " " import_scanner_args_string)
+ message(DEBUG "qmlimportscanner command: ${import_scanner_args_string}")
+ execute_process(
+ COMMAND ${import_scanner_args}
+ WORKING_DIRECTORY ${target_source_dir}
+ RESULT_VARIABLE result
+ )
+ if(result)
+ message(FATAL_ERROR
+ "Failed to scan target ${target} for QML imports: ${result}"
+ )
+ endif()
+ endif()
+endfunction()
+
+# Parse the entry at the specified index, assuming the caller already included
+# the file generated by a call to _qt_internal_scan_qml_imports()
+macro(_qt_internal_parse_qml_imports_entry prefix index)
+ cmake_parse_arguments("${prefix}"
+ ""
+ "CLASSNAME;NAME;PATH;PLUGIN;RELATIVEPATH;TYPE;VERSION;LINKTARGET;PREFER"
+ "COMPONENTS;SCRIPTS"
+ ${qml_import_scanner_import_${index}}
+ )
+endmacro()
+
+
+# This function is called as a finalizer in qt6_finalize_executable() for any
+# target that links against the Qml library.
+function(qt6_import_qml_plugins target)
+ if(NOT TARGET ${QT_CMAKE_EXPORT_NAMESPACE}::qmlimportscanner)
+ return()
+ endif()
+
+ get_target_property(is_imported ${QT_CMAKE_EXPORT_NAMESPACE}::qmlimportscanner IMPORTED)
+ if(NOT is_imported)
+ message(DEBUG "qt6_import_qml_plugins is called before qmlimportscanner is built."
+ " Skip calling qmlimportscanner because it doesn't yet exist.")
+ return()
+ endif()
+
+ # Protect against being called multiple times in case we are being called
+ # explicitly before the finalizer is invoked.
+ get_target_property(already_imported ${target} _QT_QML_PLUGINS_IMPORTED)
+ get_target_property(no_import_scan ${target} QT_QML_MODULE_NO_IMPORT_SCAN)
+ if(already_imported OR no_import_scan)
+ return()
+ endif()
+ set_target_properties(${target} PROPERTIES _QT_QML_PLUGINS_IMPORTED TRUE)
+
+ _qt_internal_scan_qml_imports(${target} imports_file IMMEDIATELY)
+ include("${imports_file}")
+
+ # Parse the generated cmake file.
+ # It is possible for the scanner to find no usage of QML, in which case the import count is 0.
+ if(qml_import_scanner_imports_count GREATER 0)
+ set(added_plugins "")
+ set(plugins_to_link "")
+ set(plugin_inits_to_link "")
+
+ math(EXPR last_index "${qml_import_scanner_imports_count} - 1")
+ foreach(index RANGE 0 ${last_index})
+ _qt_internal_parse_qml_imports_entry(entry ${index})
+ if(entry_PATH)
+ if(NOT entry_PLUGIN)
+ # Check if qml module is built within the build tree, and should have a plugin
+ # target, but its qmldir file is not generated yet.
+ get_property(dirs GLOBAL PROPERTY _qt_all_qml_output_dirs)
+ if(dirs)
+ list(FIND dirs "${entry_PATH}" index)
+ if(NOT index EQUAL -1)
+ get_property(qml_targets GLOBAL PROPERTY _qt_all_qml_targets)
+ list(GET qml_targets ${index} qml_module)
+ if(qml_module AND TARGET ${qml_module})
+ get_target_property(entry_LINKTARGET
+ ${qml_module} QT_QML_MODULE_PLUGIN_TARGET)
+ if(entry_LINKTARGET AND TARGET ${entry_LINKTARGET})
+ get_target_property(entry_PLUGIN ${entry_LINKTARGET}
+ OUTPUT_NAME)
+ endif()
+ endif()
+ endif()
+ endif()
+ endif()
+
+ if(entry_PLUGIN)
+ # Sometimes a plugin appears multiple times with different versions.
+ # Make sure to process it only once.
+ list(FIND added_plugins "${entry_PLUGIN}" _index)
+ if(NOT _index EQUAL -1)
+ continue()
+ endif()
+ list(APPEND added_plugins "${entry_PLUGIN}")
+
+ # Link against the Qml plugin.
+ # For plugins provided by Qt, we assume those plugin targets are already defined
+ # (typically brought in via find_package(Qt6...) ).
+ # For other plugins, the targets can come from the project itself.
+ #
+ if(entry_LINKTARGET)
+ if(TARGET ${entry_LINKTARGET})
+ get_target_property(target_type ${entry_LINKTARGET} TYPE)
+ if(target_type STREQUAL "STATIC_LIBRARY")
+ list(APPEND plugins_to_link "${entry_LINKTARGET}")
+ endif()
+ else()
+ message(WARNING
+ "The qml plugin '${entry_PLUGIN}' is a dependency of '${target}', "
+ "but the link target it defines (${entry_LINKTARGET}) does not "
+ "exist in the current scope. The plugin will not be linked."
+ )
+ endif()
+ elseif(TARGET ${entry_PLUGIN})
+ get_target_property(target_type ${entry_PLUGIN} TYPE)
+ if(target_type STREQUAL "STATIC_LIBRARY")
+ list(APPEND plugins_to_link "${entry_PLUGIN}")
+ endif()
+ else()
+ # TODO: QTBUG-94605 Figure out if this is a reasonable scenario to support
+ message(WARNING
+ "The qml plugin '${entry_PLUGIN}' is a dependency of '${target}', "
+ "but there is no target by that name in the current scope. The plugin "
+ "will not be linked."
+ )
+ endif()
+ endif()
+ endif()
+ endforeach()
+
+ if(plugins_to_link)
+ # If ${target} is an executable or a shared library, link the plugins directly to
+ # the target.
+ # If ${target} is a static or INTERFACE library, the plugins should be propagated
+ # across those libraries to the end target (executable or shared library).
+ # The plugin initializers will be linked via usage requirements from the plugin target.
+ get_target_property(target_type ${target} TYPE)
+ if(target_type STREQUAL "EXECUTABLE" OR target_type STREQUAL "SHARED_LIBRARY"
+ OR target_type STREQUAL "MODULE_LIBRARY")
+ set(link_type "PRIVATE")
+ else()
+ set(link_type "INTERFACE")
+ endif()
+ target_link_libraries("${target}" ${link_type} ${plugins_to_link})
+ endif()
+ endif()
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_import_qml_plugins)
+ if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
+ qt5_import_qml_plugins(${ARGV})
+ elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ qt6_import_qml_plugins(${ARGV})
+ endif()
+ endfunction()
+endif()
+
+function(_qt_internal_add_qml_deploy_info_finalizer target)
+ get_property(finalizer_added TARGET ${target} PROPERTY _qt_qml_deploy_finalizer_added)
+ if(NOT finalizer_added)
+ set_property(TARGET ${target} APPEND PROPERTY
+ INTERFACE_QT_EXECUTABLE_FINALIZERS
+ _qt_internal_generate_deploy_qml_imports_script
+ )
+ set_property(TARGET ${target} PROPERTY _qt_qml_deploy_finalizer_added TRUE)
+ endif()
+endfunction()
+
+# This function may be called as a finalizer in qt6_finalize_executable() for any
+# target that links against the Qml library for a shared Qt.
+function(_qt_internal_generate_deploy_qml_imports_script target)
+ if(NOT QT6_IS_SHARED_LIBS_BUILD)
+ return()
+ endif()
+ get_target_property(target_type ${target} TYPE)
+ # TODO: Handle Android where executables are module libraries instead
+ if(NOT target_type STREQUAL "EXECUTABLE")
+ return()
+ endif()
+
+ # Protect against being called multiple times in case we are being called
+ # explicitly before the finalizer is invoked.
+ get_target_property(already_generated ${target} _QT_QML_PLUGIN_SCAN_GENERATED)
+ get_target_property(no_import_scan ${target} QT_QML_MODULE_NO_IMPORT_SCAN)
+ if(already_generated OR no_import_scan)
+ return()
+ endif()
+ set_target_properties(${target} PROPERTIES _QT_QML_PLUGIN_SCAN_GENERATED TRUE)
+
+ # Defer actually running qmlimportscanner until build time. This keeps the
+ # configure step fast and takes advantage of the build step supporting
+ # parallel execution if there are multiple targets that need scanning.
+ _qt_internal_scan_qml_imports(${target} imports_file BUILD_PHASE)
+
+ set(is_bundle FALSE)
+ if(APPLE)
+ if(IOS)
+ message(FATAL_ERROR "Install support not available for iOS builds")
+ endif()
+ get_target_property(is_bundle ${target} MACOSX_BUNDLE)
+ endif()
+ set(is_bundle "$<BOOL:${is_bundle}>")
+
+ # For macOS app bundles, the directory layout must conform to Apple's
+ # requirements, so we hard-code the required structure. This assumes the
+ # app bundle is installed to the base dir with an install command like:
+ # install(TARGETS ${target} BUNDLE DESTINATION .)
+ set(bundle_qml_dir "$<TARGET_FILE_NAME:${target}>.app/Contents/Resources/qml")
+ set(bundle_plugins_dir "$<TARGET_FILE_NAME:${target}>.app/Contents/PlugIns")
+
+ _qt_internal_get_deploy_impl_dir(deploy_impl_dir)
+ string(MAKE_C_IDENTIFIER "${target}" target_id)
+ set(filename "${deploy_impl_dir}/deploy_qml_imports/${target_id}")
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi_config)
+ string(APPEND filename "-$<CONFIG>")
+ endif()
+ string(APPEND filename ".cmake")
+
+ # TODO: Fix macOS multi-config bundles to work.
+ file(GENERATE OUTPUT "${filename}" CONTENT
+"# Auto-generated deploy QML imports script for target \"${target}\".
+# Do not edit, all changes will be lost.
+# This file should only be included by qt6_deploy_qml_imports().
+
+set(__qt_opts $<${is_bundle}:BUNDLE>)
+if(arg_NO_QT_IMPORTS)
+ list(APPEND __qt_opts NO_QT_IMPORTS)
+endif()
+
+_qt_internal_deploy_qml_imports_for_target(
+ \${__qt_opts}
+ IMPORTS_FILE \"${imports_file}\"
+ PLUGINS_FOUND __qt_internal_plugins_found
+ QML_DIR \"$<IF:${is_bundle},${bundle_qml_dir},\${arg_QML_DIR}>\"
+ PLUGINS_DIR \"$<IF:${is_bundle},${bundle_plugins_dir},\${arg_PLUGINS_DIR}>\"
+)
+
+if(arg_PLUGINS_FOUND)
+ set(\${arg_PLUGINS_FOUND} \"\${__qt_internal_plugins_found}\" PARENT_SCOPE)
+endif()
+")
+
+endfunction()
+
+function(qt6_generate_deploy_qml_app_script)
+ # We take the target using a TARGET keyword instead of as the first
+ # positional argument so that we have a consistent signature with the
+ # qt6_generate_deploy_app_script() from qtbase. That function might accept
+ # an executable instead of a target in the future, but we can't because we
+ # need information associated with the target (scanning all its .qml files
+ # for imported QML modules).
+ set(no_value_options
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ NO_TRANSLATIONS
+ NO_COMPILER_RUNTIME
+ MACOS_BUNDLE_POST_BUILD
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
+ )
+ set(single_value_options
+ TARGET
+ OUTPUT_SCRIPT
+
+ # TODO: For backward compatibility / transitional use only,
+ # remove at some point
+ FILENAME_VARIABLE
+ )
+ set(qt_deploy_runtime_dependencies_options
+ # These options are forwarded as is to qt_deploy_runtime_dependencies.
+ PRE_INCLUDE_REGEXES
+ PRE_EXCLUDE_REGEXES
+ POST_INCLUDE_REGEXES
+ POST_EXCLUDE_REGEXES
+ POST_INCLUDE_FILES
+ POST_EXCLUDE_FILES
+ DEPLOY_TOOL_OPTIONS
+ )
+ set(multi_value_options
+ ${qt_deploy_runtime_dependencies_options}
+ )
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+ if(NOT arg_TARGET)
+ message(FATAL_ERROR "TARGET must be specified")
+ endif()
+
+ # TODO: Remove when FILENAME_VARIABLE is fully removed
+ # Handle the slow deprecation of FILENAME_VARIABLE
+ if(arg_FILENAME_VARIABLE)
+ if(arg_OUTPUT_SCRIPT AND NOT arg_FILENAME_VARIABLE STREQUAL arg_OUTPUT_SCRIPT)
+ message(FATAL_ERROR
+ "Both FILENAME_VARIABLE and OUTPUT_SCRIPT were given and were different. "
+ "Only one of the two should be used."
+ )
+ endif()
+ message(AUTHOR_WARNING
+ "The FILENAME_VARIABLE keyword is deprecated and will be removed soon. "
+ "Please use OUTPUT_SCRIPT instead.")
+ set(arg_OUTPUT_SCRIPT "${arg_FILENAME_VARIABLE}")
+ unset(arg_FILENAME_VARIABLE)
+ endif()
+
+ if(NOT arg_OUTPUT_SCRIPT)
+ message(FATAL_ERROR "OUTPUT_SCRIPT must be specified")
+ endif()
+
+ # Check that the target was defer-finalized, and not immediately finalized when using
+ # CMake < 3.19. This is important because if it's immediately finalized, Qt::Qml is likely
+ # not in the dependency list, and thus _qt_internal_generate_deploy_qml_imports_script will
+ # not be executed, leading to an error at install time
+ # 'No QML imports information recorded for target X'.
+ # _qt_is_immediately_finalized is set by qt6_add_executable.
+ # TODO: Remove once minimum required CMAKE_VERSION is 3.19+.
+ get_target_property(is_immediately_finalized "${arg_TARGET}" _qt_is_immediately_finalized)
+ if(is_immediately_finalized)
+ message(FATAL_ERROR
+ "QML app deployment requires CMake version 3.19, or later, or manual executable "
+ "finalization. For manual finalization, pass the MANUAL_FINALIZATION option to "
+ "qt_add_executable() and then call qt_finalize_target(${arg_TARGET}) just before
+ calling qt_generate_deploy_qml_app_script().")
+ endif()
+
+ # Generate a descriptive deploy script name.
+ string(MAKE_C_IDENTIFIER "${arg_TARGET}" target_id)
+ set(deploy_script_name "qml_app_${target_id}")
+
+ get_target_property(is_bundle ${arg_TARGET} MACOSX_BUNDLE)
+
+ set(unsupported_platform_extra_message "")
+ if(QT6_IS_SHARED_LIBS_BUILD)
+ set(qt_build_type_string "shared Qt libs")
+ else()
+ set(qt_build_type_string "static Qt libs")
+ endif()
+
+ if(CMAKE_CROSSCOMPILING)
+ string(APPEND qt_build_type_string ", cross-compiled")
+ endif()
+
+ if(NOT is_bundle)
+ string(APPEND qt_build_type_string ", non-bundle app")
+ set(unsupported_platform_extra_message
+ "Executable targets have to be app bundles to use this command on Apple platforms.")
+ endif()
+
+ set(skip_message
+ "_qt_internal_show_skip_runtime_deploy_message(\"${qt_build_type_string}\"")
+ if(unsupported_platform_extra_message)
+ string(APPEND skip_message
+ "\n EXTRA_MESSAGE \"${unsupported_platform_extra_message}\"")
+ endif()
+ string(APPEND skip_message "\n)")
+
+ set(common_deploy_args "")
+ if(arg_NO_TRANSLATIONS)
+ string(APPEND common_deploy_args " NO_TRANSLATIONS\n")
+ endif()
+ if(arg_NO_COMPILER_RUNTIME)
+ string(APPEND common_deploy_args " NO_COMPILER_RUNTIME\n")
+ endif()
+
+ # Forward the arguments that are exactly the same for qt_deploy_runtime_dependencies.
+ foreach(var IN LISTS qt_deploy_runtime_dependencies_options)
+ if(NOT "${arg_${var}}" STREQUAL "")
+ list(APPEND common_deploy_args ${var} ${arg_${var}})
+ endif()
+ endforeach()
+
+ _qt_internal_should_skip_deployment_api(skip_deployment skip_reason)
+ _qt_internal_should_skip_post_build_deployment_api(skip_post_build_deployment
+ post_build_skip_reason)
+
+ if(APPLE AND NOT IOS AND QT6_IS_SHARED_LIBS_BUILD AND is_bundle)
+ # TODO: Consider handling non-bundle applications in the future using the generic cmake
+ # runtime dependency feature.
+
+ set(should_post_build FALSE)
+ if(arg_MACOS_BUNDLE_POST_BUILD AND NOT skip_post_build_deployment)
+ set(should_post_build TRUE)
+ endif()
+
+ # Generate the real deployment script when both post build step either deployment are
+ # enabled.
+ # If we skip deployment, but not the POST_BUILD step, we still need to generate the
+ # regular deploy script to run it during POST_BUILD time.
+ if(NOT skip_deployment OR should_post_build)
+ qt6_generate_deploy_script(
+ TARGET ${arg_TARGET}
+ NAME ${deploy_script_name}
+ OUTPUT_SCRIPT real_deploy_script
+ CONTENT "
+qt6_deploy_qml_imports(TARGET ${arg_TARGET} PLUGINS_FOUND plugins_found)
+if(NOT DEFINED __QT_DEPLOY_POST_BUILD)
+ qt6_deploy_runtime_dependencies(
+ EXECUTABLE $<TARGET_FILE_NAME:${arg_TARGET}>.app
+ ADDITIONAL_MODULES \${plugins_found}
+ ${common_deploy_args})
+endif()")
+ endif()
+
+ # Generate a no-op script either if we skip deployment or the post build step.
+ if(skip_deployment)
+ _qt_internal_generate_no_op_deploy_script(
+ FUNCTION_NAME "qt6_generate_deploy_qml_app_script"
+ SKIP_REASON "${skip_reason}"
+ TARGET ${arg_TARGET}
+ NAME ${deploy_script_name}
+ OUTPUT_SCRIPT no_op_deploy_script
+ )
+ endif()
+
+ if(skip_post_build_deployment)
+ _qt_internal_generate_no_op_deploy_script(
+ FUNCTION_NAME "qt6_generate_deploy_qml_app_script"
+ SKIP_REASON "${post_build_skip_reason}"
+ TARGET ${arg_TARGET}
+ NAME ${deploy_script_name}
+ OUTPUT_SCRIPT no_op_post_build_script
+ )
+ endif()
+
+ # Choose which deployment script to use during installation.
+ if(skip_deployment)
+ set(deploy_script "${no_op_deploy_script}")
+ else()
+ set(deploy_script "${real_deploy_script}")
+ endif()
+
+ # Choose which deployment script to use during the post build step.
+ if(should_post_build)
+ set(post_build_deploy_script "${real_deploy_script}")
+ elseif(skip_post_build_deployment)
+ # Explicitly asked to skip post build, show a no-op message.
+ set(post_build_deploy_script "${no_op_post_build_script}")
+ endif()
+
+ if(should_post_build OR skip_post_build_deployment)
+ # We must not deploy the runtime dependencies, otherwise we interfere
+ # with CMake's RPATH rewriting at install time. We only need the QML
+ # imports deployed to the bundle anyway, the build RPATHs will allow
+ # the regular libraries, frameworks and non-QML plugins to still be
+ # found, even if they are outside the app bundle.
+ add_custom_command(TARGET ${arg_TARGET} POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -D "QT_DEPLOY_PREFIX=$<TARGET_PROPERTY:${arg_TARGET},BINARY_DIR>"
+ -D "__QT_DEPLOY_IMPL_DIR=${deploy_impl_dir}"
+ -D "__QT_DEPLOY_POST_BUILD=TRUE"
+ -P "${post_build_deploy_script}"
+ VERBATIM
+ )
+ endif()
+ elseif(skip_deployment)
+ _qt_internal_generate_no_op_deploy_script(
+ FUNCTION_NAME "qt6_generate_deploy_qml_app_script"
+ SKIP_REASON "${skip_reason}"
+ TARGET ${arg_TARGET}
+ NAME ${deploy_script_name}
+ OUTPUT_SCRIPT deploy_script
+ )
+ elseif(WIN32 AND QT6_IS_SHARED_LIBS_BUILD)
+ qt6_generate_deploy_script(
+ TARGET ${arg_TARGET}
+ NAME ${deploy_script_name}
+ OUTPUT_SCRIPT deploy_script
+ CONTENT "
+qt6_deploy_qml_imports(TARGET ${arg_TARGET} PLUGINS_FOUND plugins_found)
+qt6_deploy_runtime_dependencies(
+ EXECUTABLE $<TARGET_FILE:${arg_TARGET}>
+ ADDITIONAL_MODULES \${plugins_found}
+ GENERATE_QT_CONF
+${common_deploy_args})")
+ elseif(UNIX AND NOT APPLE AND NOT ANDROID AND NOT CMAKE_CROSSCOMPILING
+ AND QT6_IS_SHARED_LIBS_BUILD)
+ qt6_generate_deploy_script(
+ TARGET ${arg_TARGET}
+ NAME ${deploy_script_name}
+ OUTPUT_SCRIPT deploy_script
+ CONTENT "
+qt6_deploy_qml_imports(TARGET ${arg_TARGET} PLUGINS_FOUND plugins_found)
+qt6_deploy_runtime_dependencies(
+ EXECUTABLE $<TARGET_FILE:${arg_TARGET}>
+ ADDITIONAL_MODULES \${plugins_found}
+ GENERATE_QT_CONF
+${common_deploy_args})")
+ elseif((arg_NO_UNSUPPORTED_PLATFORM_ERROR OR
+ QT_INTERNAL_NO_UNSUPPORTED_PLATFORM_ERROR)
+ AND (arg_DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
+ OR QT_INTERNAL_DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM)
+ AND QT6_IS_SHARED_LIBS_BUILD)
+ # User project explicitly requested to deploy only user QML modules on a shared Qt libs
+ # platform where qt_deploy_runtime_dependencies does not work.
+ # This is useful for projects that will deploy the Qt QML and runtime libraries manually.
+ # This also offers a migration path to enable qt_deploy_runtime_dependencies for
+ # unsupported platforms without breaking projects that already handle runtime libs manually.
+ # But for it to work cleanly, projects will have to enable both
+ # NO_UNSUPPORTED_PLATFORM_ERROR and DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
+ # conditionally per platform.
+ qt6_generate_deploy_script(
+ TARGET ${arg_TARGET}
+ NAME ${deploy_script_name}
+ OUTPUT_SCRIPT deploy_script
+ CONTENT "
+${skip_message}
+qt6_deploy_qml_imports(TARGET ${arg_TARGET} NO_QT_IMPORTS)
+")
+ elseif(NOT arg_NO_UNSUPPORTED_PLATFORM_ERROR AND NOT QT_INTERNAL_NO_UNSUPPORTED_PLATFORM_ERROR)
+ # Currently we don't deploy runtime dependencies if cross-compiling or using a static Qt.
+ # Error out by default unless the project opted out of the error.
+ # This provides us a migration path in the future without breaking compatibility promises.
+ message(FATAL_ERROR
+ "Support for installing runtime dependencies is not implemented for "
+ "this target platform (${CMAKE_SYSTEM_NAME}, ${qt_build_type_string}). "
+ ${unsupported_platform_extra_message}
+ )
+ else()
+ qt6_generate_deploy_script(
+ TARGET ${arg_TARGET}
+ NAME ${deploy_script_name}
+ OUTPUT_SCRIPT deploy_script
+ CONTENT "
+${skip_message}
+_qt_internal_show_skip_qml_runtime_deploy_message()
+")
+ endif()
+
+ set(${arg_OUTPUT_SCRIPT} ${deploy_script} PARENT_SCOPE)
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ macro(qt_generate_deploy_qml_app_script)
+ qt6_generate_deploy_qml_app_script(${ARGV})
+ endmacro()
+endif()
+
+function(qt6_query_qml_module target)
+
+ if(NOT TARGET ${target})
+ message(FATAL_ERROR "\"${target}\" is not a target")
+ endif()
+
+ get_target_property(is_imported ${target} IMPORTED)
+ if(is_imported)
+ message(FATAL_ERROR
+ "Only targets built by the project can be used with this command, "
+ "but target \"${target}\" is imported."
+ )
+ endif()
+
+ get_target_property(uri ${target} QT_QML_MODULE_URI)
+ if(NOT uri)
+ message(FATAL_ERROR
+ "Target \"${target}\" does not appear to be a QML module"
+ )
+ endif()
+
+ set(no_value_options "")
+ set(single_value_options
+ URI
+ VERSION
+ PLUGIN_TARGET
+ MODULE_RESOURCE_PATH
+ TARGET_PATH
+ QMLDIR
+ TYPEINFO
+ QML_FILES
+ QML_FILES_DEPLOY_PATHS # relative to target path
+ QML_FILES_PREFIX_OVERRIDES
+ RESOURCES
+ RESOURCES_DEPLOY_PATHS # relative to target path
+ RESOURCES_PREFIX_OVERRIDES
+ )
+ set(multi_value_options "")
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+
+ if(arg_URI)
+ set(${arg_URI} "${uri}" PARENT_SCOPE)
+ endif()
+
+ if(arg_VERSION)
+ get_property(version TARGET ${target} PROPERTY QT_QML_MODULE_VERSION)
+ set(${arg_VERSION} "${version}" PARENT_SCOPE)
+ endif()
+
+ if(arg_PLUGIN_TARGET)
+ # There might not be a plugin target, so return an empty string for that
+ get_property(plugin_target TARGET ${target} PROPERTY QT_QML_MODULE_PLUGIN_TARGET)
+ set(${arg_PLUGIN_TARGET} "${plugin_target}" PARENT_SCOPE)
+ endif()
+
+ if(arg_MODULE_RESOURCE_PATH)
+ # Note that QT_QML_MODULE_RESOURCE_PREFIX is not the RESOURCE_PREFIX
+ # passed to qt6_add_qml_module(). It is that plus the target path, which
+ # corresponds to what we mean by the MODULE_RESOURCE_PATH.
+ get_property(prefix TARGET ${target} PROPERTY QT_QML_MODULE_RESOURCE_PREFIX)
+ set(${arg_MODULE_RESOURCE_PATH} "${prefix}" PARENT_SCOPE)
+ endif()
+
+ string(REPLACE "." "/" target_path "${uri}")
+ if(arg_TARGET_PATH)
+ set(${arg_TARGET_PATH} "${target_path}" PARENT_SCOPE)
+ endif()
+
+ get_target_property(output_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
+
+ if(arg_QMLDIR)
+ set(${arg_QMLDIR} "${output_dir}/qmldir" PARENT_SCOPE)
+ endif()
+
+ # This should always be set to something non-empty
+ # unless we've explicitly said NO_GENERATE_QMLTYPES
+ get_target_property(typeinfo ${target} QT_QML_MODULE_TYPEINFO)
+ if(arg_TYPEINFO AND typeinfo)
+ set(${arg_TYPEINFO} "${output_dir}/${typeinfo}" PARENT_SCOPE)
+ endif()
+
+ get_target_property(target_source_dir ${target} SOURCE_DIR)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.18)
+ set(scope_option TARGET_DIRECTORY ${target})
+ else()
+ set(scope_option "")
+ if(NOT target_source_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR AND
+ (arg_QML_FILES_DEPLOY_PATHS OR arg_RESOURCES_DEPLOY_PATHS))
+ # This isn't a fatal error because it will only be a problem if any
+ # qml or resource files actually have source file properties set.
+ message(WARNING
+ "Calling qt6_query_qml_module() from a different directory scope "
+ "to the one in which target \"${target}\" was created. "
+ "This requires CMake 3.18 or later to be robust, but you are using "
+ "CMake ${CMAKE_VERSION}. Deployment paths may not be correct."
+ )
+ endif()
+ endif()
+
+ # Because of how CMake lists work, in particular appending empty strings,
+ # we have to use a placeholder to represent empty values and then replace
+ # them at the end. If we don't do this, any list that starts with an empty
+ # value ends up discarding that empty value because it is indistinguishable
+ # from an empty list.
+ set(empty_placeholder "__qt_empty_placeholder__")
+
+ foreach(file_set IN ITEMS QML_FILES RESOURCES)
+ # NOTE: We converted these files to absolute paths already when storing them
+ get_target_property(files ${target} QT_QML_MODULE_${file_set})
+
+ if(arg_${file_set})
+ set(${arg_${file_set}} "${files}" PARENT_SCOPE)
+ endif()
+
+ if(arg_${file_set}_DEPLOY_PATHS OR arg_${file_set}_PREFIX_OVERRIDES)
+ set(deploy_paths "")
+ set(prefix_overrides "")
+ foreach(abs_file IN LISTS files)
+ # The QT_QML_MODULE_PREFIX_OVERRIDE is the PREFIX value that was passed to
+ # qt_target_qml_sources. It has no relation to the QT_QML_MODULE_RESOURCE_PREFIX
+ # property or the computed MODULE_RESOURCE_PATH variable above.
+ get_property(prefix_override SOURCE ${abs_file} ${scope_option}
+ PROPERTY QT_QML_MODULE_PREFIX_OVERRIDE
+ )
+ if("${prefix_override}" STREQUAL "")
+ list(APPEND prefix_overrides "${empty_placeholder}")
+ else()
+ list(APPEND prefix_overrides "${prefix_override}")
+ endif()
+
+ # We can't provide a deploy path when the resource prefix is
+ # overridden. We still need to store an empty deploy path for it
+ # though so that the file lists all line up correctly.
+ if(NOT "${prefix_override}" STREQUAL "")
+ list(APPEND deploy_paths "${empty_placeholder}")
+ else()
+ # Careful how we check whether this property is set. Projects might
+ # use a resource alias that matches one of CMake's false constants,
+ # so we must use get_property(), not get_source_file_property(),
+ # then compare the result with an empty string.
+ get_property(alias
+ SOURCE ${abs_file} ${scope_option} PROPERTY QT_RESOURCE_ALIAS)
+ if(NOT "${alias}" STREQUAL "")
+ list(APPEND deploy_paths "${alias}")
+ else()
+ file(RELATIVE_PATH rel_file ${target_source_dir} ${abs_file})
+ list(APPEND deploy_paths "${rel_file}")
+ endif()
+ endif()
+ endforeach()
+ string(REPLACE "${empty_placeholder}" "" deploy_paths "${deploy_paths}")
+ string(REPLACE "${empty_placeholder}" "" prefix_overrides "${prefix_overrides}")
+ if(arg_${file_set}_DEPLOY_PATHS)
+ set(${arg_${file_set}_DEPLOY_PATHS} "${deploy_paths}" PARENT_SCOPE)
+ endif()
+ if(arg_${file_set}_PREFIX_OVERRIDES)
+ set(${arg_${file_set}_PREFIX_OVERRIDES} "${prefix_overrides}" PARENT_SCOPE)
+ endif()
+ endif()
+ endforeach()
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ macro(qt_query_qml_module)
+ qt6_query_qml_module(${ARGV})
+ endmacro()
+endif()
+
+
+function(_qt_internal_add_static_qml_plugin_dependencies plugin_target backing_target)
+ # Protect against multiple calls of qt_add_qml_plugin.
+ get_target_property(plugin_deps_added "${plugin_target}" _qt_extra_static_qml_plugin_deps_added)
+ if(plugin_deps_added)
+ return()
+ endif()
+ set_target_properties("${plugin_target}" PROPERTIES _qt_extra_static_qml_plugin_deps_added TRUE)
+
+ # Get the install plugin target name, which we will need for filtering later on.
+ if(TARGET "${backing_target}")
+ get_target_property(installed_plugin_target
+ "${backing_target}" _qt_qml_module_installed_plugin_target)
+ endif()
+
+ if(NOT backing_target STREQUAL plugin_target AND TARGET "${backing_target}")
+ set(has_backing_lib TRUE)
+ else()
+ set(has_backing_lib FALSE)
+ endif()
+
+ get_target_property(plugin_type ${plugin_target} TYPE)
+ set(skip_prl_marker "$<BOOL:QT_IS_PLUGIN_GENEX>")
+
+ # If ${plugin_target} is a static qml plugin, recursively get its private dependencies (and its
+ # backing lib private deps), identify which of those are qml modules, extract any associated qml
+ # plugin target from those qml modules and make them dependencies of ${plugin_target}.
+ #
+ # E.g. this ensures that if a user project links directly to the static qtquick2plugin plugin
+ # target (note the plugin target, not the backing lib) it will automatically also link to
+ # Quick's transitive plugin dependencies: qmlplugin, modelsplugin and workerscriptplugin, in
+ # addition to the the Qml, QmlModels and QmlWorkerScript backing libraries.
+ #
+ # Note this logic is not specific to qtquick2plugin, it applies to all static qml plugins.
+ #
+ # This eliminates the needed boilerplate to link to the full transitive closure of qml plugins
+ # in user projects that don't want to use qmlimportscanner / qt_import_qml_plugins.
+ set(additional_plugin_deps "")
+
+ if(plugin_type STREQUAL "STATIC_LIBRARY")
+ set(all_private_deps "")
+
+ # We walk both plugin_target and backing_lib private deps because they can have differing
+ # dependencies and we want to consider all of them.
+ __qt_internal_collect_all_target_dependencies(
+ "${plugin_target}" plugin_private_deps)
+ if(plugin_private_deps)
+ list(APPEND all_private_deps ${plugin_private_deps})
+ endif()
+
+ if(has_backing_lib)
+ __qt_internal_collect_all_target_dependencies(
+ "${backing_target}" backing_lib_private_deps)
+ if(backing_lib_private_deps)
+ list(APPEND all_private_deps ${backing_lib_private_deps})
+ endif()
+ endif()
+
+ foreach(dep IN LISTS all_private_deps)
+ if(NOT TARGET "${dep}")
+ continue()
+ endif()
+ get_target_property(dep_type ${dep} TYPE)
+ if(dep_type STREQUAL "STATIC_LIBRARY")
+ set(associated_qml_plugin "")
+
+ # Check if the target has an associated imported qml plugin (like a Qt-provided
+ # one).
+ get_target_property(associated_qml_plugin_candidate ${dep}
+ _qt_qml_module_installed_plugin_target)
+
+ if(associated_qml_plugin_candidate AND TARGET "${associated_qml_plugin_candidate}")
+ set(associated_qml_plugin "${associated_qml_plugin_candidate}")
+ endif()
+
+ # Check if the target has an associated qml plugin that's built as part of the
+ # current project (non-installed one, so without a target namespace prefix).
+ get_target_property(associated_qml_plugin_candidate ${dep}
+ _qt_qml_module_plugin_target)
+
+ if(NOT associated_qml_plugin AND
+ associated_qml_plugin_candidate
+ AND TARGET "${associated_qml_plugin_candidate}")
+ set(associated_qml_plugin "${associated_qml_plugin_candidate}")
+ endif()
+
+ # We need to filter out adding the plugin_target as a dependency to itself,
+ # when walking the backing lib of the plugin_target.
+ if(associated_qml_plugin
+ AND NOT associated_qml_plugin STREQUAL plugin_target
+ AND NOT associated_qml_plugin STREQUAL installed_plugin_target)
+ # Abuse a genex marker, to skip the dependency to be added into prl files.
+ # TODO: Introduce a more generic marker name in qtbase specifically
+ # for skipping deps in prl file deps generation.
+ set(wrapped_associated_qml_plugin
+ "$<${skip_prl_marker}:$<TARGET_NAME:${associated_qml_plugin}>>")
+
+ if(NOT wrapped_associated_qml_plugin IN_LIST additional_plugin_deps)
+ list(APPEND additional_plugin_deps "${wrapped_associated_qml_plugin}")
+ endif()
+ endif()
+ endif()
+ endforeach()
+ endif()
+
+ if(additional_plugin_deps)
+ target_link_libraries(${plugin_target} PRIVATE ${additional_plugin_deps})
+ endif()
+endfunction()
+
+# The function returns the output name of a qml plugin that will be used as library output
+# name and in a qmldir file as the 'plugin <plugin_output_name>' record.
+function(_qt_internal_get_qml_plugin_output_name out_var plugin_target)
+ cmake_parse_arguments(arg
+ ""
+ "BACKING_TARGET;TARGET_PATH;URI"
+ ""
+ ${ARGN}
+ )
+ set(plugin_name)
+ if(TARGET ${plugin_target})
+ get_target_property(plugin_name ${plugin_target} OUTPUT_NAME)
+ endif()
+ if(NOT plugin_name)
+ set(plugin_name "${plugin_target}")
+ endif()
+
+ if(ANDROID)
+ # In Android all plugins are stored in directly the /libs directory. This means that plugin
+ # names must be unique in scope of apk. To make this work we prepend uri-based prefix to
+ # each qml plugin in case if users don't use the manually written qmldir files.
+ get_target_property(no_generate_qmldir ${target} QT_QML_MODULE_NO_GENERATE_QMLDIR)
+ if(TARGET "${arg_BACKING_TARGET}")
+ get_target_property(no_generate_qmldir ${arg_BACKING_TARGET}
+ QT_QML_MODULE_NO_GENERATE_QMLDIR)
+
+ # Adjust Qml plugin names on Android similar to qml_plugin.prf which calls
+ # $$qt5LibraryTarget($$TARGET, "qml/$$TARGETPATH/").
+ # Example plugin names:
+ # qtdeclarative
+ # TARGET_PATH: QtQml/Models
+ # file name: libqml_QtQml_Models_modelsplugin_x86_64.so
+ # qtquickcontrols2
+ # TARGET_PATH: QtQuick/Controls.2/Material
+ # file name:
+ # libqml_QtQuick_Controls.2_Material_qtquickcontrols2materialstyleplugin_x86_64.so
+ if(NOT arg_TARGET_PATH)
+ get_target_property(arg_TARGET_PATH ${arg_BACKING_TARGET}
+ QT_QML_MODULE_TARGET_PATH)
+ endif()
+ endif()
+ if(arg_TARGET_PATH)
+ string(REPLACE "/" "_" android_plugin_name_infix_name "${arg_TARGET_PATH}")
+ else()
+ string(REPLACE "." "_" android_plugin_name_infix_name "${arg_URI}")
+ endif()
+
+ # If plugin supposed to use manually written qmldir file we don't prepend the uri-based
+ # prefix to the plugin output name. User should keep the file name of a QML plugin in
+ # qmldir the same as the name of plugin on a file system. Exception is the
+ # ABI-/platform-specific suffix that has the separate processing and should not be
+ # a part of plugin name in qmldir.
+ if(NOT no_generate_qmldir)
+ set(plugin_name
+ "qml_${android_plugin_name_infix_name}_${plugin_name}")
+ endif()
+ endif()
+
+ set(${out_var} "${plugin_name}" PARENT_SCOPE)
+endfunction()
+
+# Used to add extra dependencies between ${target} and ${dep_target} qml plugins in a static
+# Qt build, without creating a dependency in the genereated qmake .prl files.
+# These dependencies make manual linking to static plugins a nicer experience for users that don't
+# want to use qt_import_qml_plugins.
+function(_qt_internal_add_qml_static_plugin_dependency target dep_target)
+ if(NOT BUILD_SHARED_LIBS)
+ # Abuse a genex marker, to skip the dependency to be added into prl files.
+ # TODO: Introduce a more generic marker name in qtbase specifically
+ # for skipping deps in prl file deps generation.
+ set(skip_prl_marker "$<BOOL:QT_IS_PLUGIN_GENEX>")
+ target_link_libraries("${target}" PRIVATE
+ "$<${skip_prl_marker}:$<TARGET_NAME:${dep_target}>>")
+ endif()
+endfunction()
+
+function(_qt_internal_collect_qml_module_dependencies target)
+ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.19.0")
+ cmake_language(EVAL CODE
+ "cmake_language(DEFER CALL _qt_internal_collect_qml_module_dependencies_deferred \"${target}\")"
+ )
+ else()
+ _qt_internal_collect_qml_module_dependencies_deferred("${target}")
+ endif()
+endfunction()
+
+function(_qt_internal_collect_qml_module_dependencies_deferred target)
+ get_target_property(deps ${target} QT_QML_MODULE_DEPENDENCIES)
+ if(NOT deps)
+ return()
+ endif()
+ foreach(dep IN LISTS deps)
+ string(REPLACE " " ";" dep "${dep}")
+ list(GET dep 0 dep_module_uri)
+ get_property(qml_uris GLOBAL PROPERTY _qt_all_qml_uris)
+ list(FIND qml_uris "${dep_module_uri}" index)
+ if(index LESS 0)
+ continue()
+ endif()
+ get_property(qml_targets GLOBAL PROPERTY _qt_all_qml_targets)
+ list(GET qml_targets ${index} dep_module)
+ # Make the module target dependent on its non-imported QML dependencies.
+ if(TARGET "${dep_module}")
+ get_target_property(is_imported ${dep_module} IMPORTED)
+ if(NOT is_imported)
+ add_dependencies(${target} ${dep_module})
+ endif()
+ endif()
+ endforeach()
+endfunction()
diff --git a/src/qml/Qt6QmlModuleDirMappingTemplate.qrc.in b/src/qml/Qt6QmlModuleDirMappingTemplate.qrc.in
new file mode 100644
index 0000000000..e7e376bcb2
--- /dev/null
+++ b/src/qml/Qt6QmlModuleDirMappingTemplate.qrc.in
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+@qt_qml_module_dir_mapping_contents@
+ </qresource>
+</RCC>
diff --git a/src/qml/Qt6QmlPluginTemplate.cpp.in b/src/qml/Qt6QmlPluginTemplate.cpp.in
new file mode 100644
index 0000000000..f49aceb8d1
--- /dev/null
+++ b/src/qml/Qt6QmlPluginTemplate.cpp.in
@@ -0,0 +1,22 @@
+// This file is autogenerated by CMake. Do not edit.
+
+#include <QtCore/qtsymbolmacros.h>
+#include <QtQml/qqmlextensionplugin.h>
+
+@qt_qml_plugin_intro@
+
+class @qt_qml_plugin_class_name@ : public QQmlEngineExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid)
+
+public:
+ @qt_qml_plugin_class_name@(QObject *parent = nullptr) : QQmlEngineExtensionPlugin(parent)
+ {
+@qt_qml_plugin_constructor_content@
+ }
+};
+
+@qt_qml_plugin_outro@
+
+#include "@qt_qml_plugin_moc_include_name@"
diff --git a/src/qml/Qt6QmltcFileMappingTemplate.qrc.in b/src/qml/Qt6QmltcFileMappingTemplate.qrc.in
new file mode 100644
index 0000000000..d845d3526d
--- /dev/null
+++ b/src/qml/Qt6QmltcFileMappingTemplate.qrc.in
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource>
+@qt_qml_qmltc_file_mapping_contents@
+ </qresource>
+</RCC>
diff --git a/src/qml/Qt6qmldirTemplate.cmake.in b/src/qml/Qt6qmldirTemplate.cmake.in
new file mode 100644
index 0000000000..7155d2fec2
--- /dev/null
+++ b/src/qml/Qt6qmldirTemplate.cmake.in
@@ -0,0 +1 @@
+@__qt_qmldir_content@
diff --git a/src/qml/animations/animations.pri b/src/qml/animations/animations.pri
deleted file mode 100644
index a379692567..0000000000
--- a/src/qml/animations/animations.pri
+++ /dev/null
@@ -1,18 +0,0 @@
-INCLUDEPATH += $$PWD
-
-HEADERS += \
- $$PWD/qabstractanimationjob_p.h \
- $$PWD/qanimationgroupjob_p.h \
- $$PWD/qsequentialanimationgroupjob_p.h \
- $$PWD/qparallelanimationgroupjob_p.h \
- $$PWD/qcontinuinganimationgroupjob_p.h \
- $$PWD/qpauseanimationjob_p.h \
- $$PWD/qanimationjobutil_p.h
-
-SOURCES += \
- $$PWD/qabstractanimationjob.cpp \
- $$PWD/qanimationgroupjob.cpp \
- $$PWD/qsequentialanimationgroupjob.cpp \
- $$PWD/qparallelanimationgroupjob.cpp \
- $$PWD/qcontinuinganimationgroupjob.cpp \
- $$PWD/qpauseanimationjob.cpp
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index c6ace05b8f..a50685ba50 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qthreadstorage.h>
@@ -44,8 +8,7 @@
#include "private/qanimationjobutil_p.h"
#include "private/qqmlengine_p.h"
#include "private/qqmlglobal_p.h"
-
-#define DEFAULT_TIMER_INTERVAL 16
+#include "private/qdoubleendedlist_p.h"
QT_BEGIN_NAMESPACE
@@ -67,6 +30,35 @@ QQmlAnimationTimer::QQmlAnimationTimer() :
{
}
+void QQmlAnimationTimer::unsetJobTimer(QAbstractAnimationJob *animation)
+{
+ if (!animation)
+ return;
+ if (animation->m_timer == this)
+ animation->m_timer = nullptr;
+
+ if (animation->m_isPause)
+ runningPauseAnimations.removeOne(animation);
+
+ if (animation->isGroup()) {
+ QAnimationGroupJob *group = static_cast<QAnimationGroupJob *>(animation);
+ if (const auto children = group->children()) {
+ for (auto *child : *children)
+ unsetJobTimer(child);
+ }
+ }
+}
+
+QQmlAnimationTimer::~QQmlAnimationTimer()
+{
+ for (const auto &animation : std::as_const(animations))
+ unsetJobTimer(animation);
+ for (const auto &animation : std::as_const(animationsToStart))
+ unsetJobTimer(animation);
+ for (const auto &animation : std::as_const(runningPauseAnimations))
+ unsetJobTimer(animation);
+}
+
QQmlAnimationTimer *QQmlAnimationTimer::instance(bool create)
{
QQmlAnimationTimer *inst;
@@ -88,7 +80,7 @@ void QQmlAnimationTimer::ensureTimerUpdate()
{
QUnifiedTimer *instU = QUnifiedTimer::instance(false);
if (instU && isPaused)
- instU->updateAnimationTimers(-1);
+ instU->updateAnimationTimers();
}
void QQmlAnimationTimer::updateAnimationsTime(qint64 delta)
@@ -104,7 +96,7 @@ void QQmlAnimationTimer::updateAnimationsTime(qint64 delta)
//when the CPU load is high
if (delta) {
insideTick = true;
- for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) {
+ for (currentAnimationIdx = 0; currentAnimationIdx < animations.size(); ++currentAnimationIdx) {
QAbstractAnimationJob *animation = animations.at(currentAnimationIdx);
int elapsed = animation->m_totalCurrentTime
+ (animation->direction() == QAbstractAnimationJob::Forward ? delta : -delta);
@@ -112,7 +104,7 @@ void QQmlAnimationTimer::updateAnimationsTime(qint64 delta)
}
if (animationTickDump()) {
qDebug() << "***** Dumping Animation Tree ***** ( tick:" << lastTick << "delta:" << delta << ")";
- for (int i = 0; i < animations.count(); ++i)
+ for (int i = 0; i < animations.size(); ++i)
qDebug() << animations.at(i);
}
insideTick = false;
@@ -218,16 +210,16 @@ void QQmlAnimationTimer::registerRunningAnimation(QAbstractAnimationJob *animati
void QQmlAnimationTimer::unregisterRunningAnimation(QAbstractAnimationJob *animation)
{
+ unsetJobTimer(animation);
if (animation->userControlDisabled())
return;
if (animation->m_isGroup)
return;
- if (animation->m_isPause)
- runningPauseAnimations.removeOne(animation);
- else
+ if (!animation->m_isPause)
runningLeafAnimations--;
+
Q_ASSERT(runningLeafAnimations >= 0);
}
@@ -261,8 +253,6 @@ QAbstractAnimationJob::QAbstractAnimationJob()
, m_currentLoop(0)
, m_uncontrolledFinishTime(-1)
, m_currentLoopStartTime(0)
- , m_nextSibling(nullptr)
- , m_previousSibling(nullptr)
, m_hasRegisteredTimer(false)
, m_isPause(false)
, m_isGroup(false)
@@ -284,8 +274,10 @@ QAbstractAnimationJob::~QAbstractAnimationJob()
Q_ASSERT(m_state == Stopped);
if (oldState == Running) {
- Q_ASSERT(QQmlAnimationTimer::instance() == m_timer);
- m_timer->unregisterAnimation(this);
+ if (m_timer) {
+ Q_ASSERT(QQmlAnimationTimer::instance(false) == m_timer);
+ m_timer->unregisterAnimation(this);
+ }
}
Q_ASSERT(!m_hasRegisteredTimer);
}
@@ -310,8 +302,9 @@ void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
if (m_loopCount == 0)
return;
- if (!m_timer)
- m_timer = QQmlAnimationTimer::instance();
+ if (!m_timer) // don't create a timer just to stop the animation
+ m_timer = QQmlAnimationTimer::instance(newState != Stopped);
+ Q_ASSERT(m_timer || newState == Stopped);
State oldState = m_state;
int oldCurrentTime = m_currentTime;
@@ -339,8 +332,9 @@ void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
if (oldState == Running) {
if (newState == Paused && m_hasRegisteredTimer)
m_timer->ensureTimerUpdate();
- //the animation, is not running any more
- m_timer->unregisterAnimation(this);
+ // the animation is not running any more
+ if (m_timer)
+ m_timer->unregisterAnimation(this);
} else if (newState == Running) {
m_timer->registerAnimation(this, isTopLevel);
}
@@ -418,7 +412,10 @@ void QAbstractAnimationJob::setDirection(Direction direction)
void QAbstractAnimationJob::setLoopCount(int loopCount)
{
+ if (m_loopCount == loopCount)
+ return;
m_loopCount = loopCount;
+ updateLoopCount(loopCount);
}
int QAbstractAnimationJob::totalDuration() const
@@ -483,8 +480,11 @@ void QAbstractAnimationJob::setCurrentTime(int msecs)
RETURN_IF_DELETED(updateCurrentTime(m_currentTime));
- if (m_currentLoop != oldLoop)
- currentLoopChanged();
+ if (m_currentLoop != oldLoop) {
+ // CurrentLoop listeners may restart the job if e.g. from has changed. Stopping a job will
+ // destroy it, so account for that here.
+ RETURN_IF_DELETED(currentLoopChanged());
+ }
// All animations are responsible for stopping the animation when their
// own end state is reached; in this case the animation is time driven,
@@ -522,6 +522,14 @@ void QAbstractAnimationJob::stop()
setState(Stopped);
}
+void QAbstractAnimationJob::complete()
+{
+ // Simulate the full animation cycle
+ setState(Running);
+ setCurrentTime(m_direction == Forward ? duration() : 0);
+ setState(Stopped);
+}
+
void QAbstractAnimationJob::pause()
{
if (m_state == Stopped) {
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
index d046ce9def..04b47e3ae5 100644
--- a/src/qml/animations/qabstractanimationjob_p.h
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QABSTRACTANIMATIONJOB_P_H
#define QABSTRACTANIMATIONJOB_P_H
@@ -53,6 +17,7 @@
#include <private/qtqmlglobal_p.h>
#include <private/qanimationjobutil_p.h>
+#include <private/qdoubleendedlist_p.h>
#include <QtCore/QObject>
#include <QtCore/private/qabstractanimation_p.h>
#include <vector>
@@ -65,7 +30,7 @@ class QAnimationGroupJob;
class QAnimationJobChangeListener;
class QQmlAnimationTimer;
-class Q_QML_PRIVATE_EXPORT QAbstractAnimationJob
+class Q_QML_EXPORT QAbstractAnimationJob : public QInheritedListNode
{
Q_DISABLE_COPY(QAbstractAnimationJob)
public:
@@ -113,6 +78,7 @@ public:
void pause();
void resume();
void stop();
+ void complete();
enum ChangeType {
Completion = 0x01,
@@ -124,8 +90,6 @@ public:
void addAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes);
void removeAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes);
- QAbstractAnimationJob *nextSibling() const { return m_nextSibling; }
- QAbstractAnimationJob *previousSibling() const { return m_previousSibling; }
bool isGroup() const { return m_isGroup; }
bool isRenderThreadJob() const { return m_isRenderThreadJob; }
@@ -134,6 +98,7 @@ public:
SelfDeletable m_selfDeletable;
protected:
virtual void updateCurrentTime(int) {}
+ virtual void updateLoopCount(int) {}
virtual void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);
virtual void updateDirection(QAbstractAnimationJob::Direction direction);
virtual void topLevelAnimationLoopChanged() {}
@@ -172,8 +137,6 @@ protected:
};
std::vector<ChangeListener> changeListeners;
- QAbstractAnimationJob *m_nextSibling;
- QAbstractAnimationJob *m_previousSibling;
QQmlAnimationTimer *m_timer = nullptr;
bool m_hasRegisteredTimer:1;
@@ -186,10 +149,10 @@ protected:
friend class QQmlAnimationTimer;
friend class QAnimationGroupJob;
- friend Q_QML_PRIVATE_EXPORT QDebug operator<<(QDebug, const QAbstractAnimationJob *job);
+ friend Q_QML_EXPORT QDebug operator<<(QDebug, const QAbstractAnimationJob *job);
};
-class Q_QML_PRIVATE_EXPORT QAnimationJobChangeListener
+class Q_QML_EXPORT QAnimationJobChangeListener
{
public:
virtual ~QAnimationJobChangeListener();
@@ -199,13 +162,15 @@ public:
virtual void animationCurrentTimeChanged(QAbstractAnimationJob *, int) {}
};
-class Q_QML_PRIVATE_EXPORT QQmlAnimationTimer : public QAbstractAnimationTimer
+class Q_QML_EXPORT QQmlAnimationTimer : public QAbstractAnimationTimer
{
Q_OBJECT
private:
QQmlAnimationTimer();
public:
+ ~QQmlAnimationTimer(); // must be destructible by QThreadStorage
+
static QQmlAnimationTimer *instance();
static QQmlAnimationTimer *instance(bool create);
@@ -228,7 +193,7 @@ public:
void updateAnimationsTime(qint64 timeStep) override;
//useful for profiling/debugging
- int runningAnimationCount() override { return animations.count(); }
+ int runningAnimationCount() override { return animations.size(); }
bool hasStartAnimationPending() const { return startAnimationPending; }
@@ -251,13 +216,14 @@ private:
void registerRunningAnimation(QAbstractAnimationJob *animation);
void unregisterRunningAnimation(QAbstractAnimationJob *animation);
+ void unsetJobTimer(QAbstractAnimationJob *animation);
int closestPauseAnimationTimeToFinish();
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractAnimationJob::ChangeTypes)
-Q_QML_PRIVATE_EXPORT QDebug operator<<(QDebug, const QAbstractAnimationJob *job);
+Q_QML_EXPORT QDebug operator<<(QDebug, const QAbstractAnimationJob *job);
QT_END_NAMESPACE
diff --git a/src/qml/animations/qanimationgroupjob.cpp b/src/qml/animations/qanimationgroupjob.cpp
index 66599561fc..d9b7e3f78d 100644
--- a/src/qml/animations/qanimationgroupjob.cpp
+++ b/src/qml/animations/qanimationgroupjob.cpp
@@ -1,60 +1,44 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qanimationgroupjob_p.h"
QT_BEGIN_NAMESPACE
QAnimationGroupJob::QAnimationGroupJob()
- : QAbstractAnimationJob(), m_firstChild(nullptr), m_lastChild(nullptr)
{
m_isGroup = true;
}
+void QAnimationGroupJob::ungroupChild(QAbstractAnimationJob *animation)
+{
+ Q_ASSERT(animation);
+ Q_ASSERT(animation->m_group == this);
+ m_children.remove(animation);
+ animation->m_group = nullptr;
+}
+
+void QAnimationGroupJob::handleAnimationRemoved(QAbstractAnimationJob *animation)
+{
+ resetUncontrolledAnimationFinishTime(animation);
+ if (m_children.isEmpty()) {
+ m_currentTime = 0;
+ stop();
+ }
+}
+
QAnimationGroupJob::~QAnimationGroupJob()
{
- clear();
+ while (QAbstractAnimationJob *animation = m_children.first()) {
+ ungroupChild(animation);
+ handleAnimationRemoved(animation);
+ delete animation;
+ }
}
void QAnimationGroupJob::topLevelAnimationLoopChanged()
{
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ for (QAbstractAnimationJob *animation : m_children)
animation->fireTopLevelAnimationLoopChanged();
}
@@ -63,15 +47,9 @@ void QAnimationGroupJob::appendAnimation(QAbstractAnimationJob *animation)
if (QAnimationGroupJob *oldGroup = animation->m_group)
oldGroup->removeAnimation(animation);
- Q_ASSERT(!animation->previousSibling() && !animation->nextSibling());
-
- if (m_lastChild)
- m_lastChild->m_nextSibling = animation;
- else
- m_firstChild = animation;
- animation->m_previousSibling = m_lastChild;
- m_lastChild = animation;
+ Q_ASSERT(!animation->isInList());
+ m_children.append(animation);
animation->m_group = this;
animationInserted(animation);
}
@@ -81,56 +59,34 @@ void QAnimationGroupJob::prependAnimation(QAbstractAnimationJob *animation)
if (QAnimationGroupJob *oldGroup = animation->m_group)
oldGroup->removeAnimation(animation);
- Q_ASSERT(!previousSibling() && !nextSibling());
-
- if (m_firstChild)
- m_firstChild->m_previousSibling = animation;
- else
- m_lastChild = animation;
- animation->m_nextSibling = m_firstChild;
- m_firstChild = animation;
+ Q_ASSERT(!animation->isInList());
+ m_children.prepend(animation);
animation->m_group = this;
animationInserted(animation);
}
void QAnimationGroupJob::removeAnimation(QAbstractAnimationJob *animation)
{
- Q_ASSERT(animation);
- Q_ASSERT(animation->m_group == this);
- QAbstractAnimationJob *prev = animation->previousSibling();
- QAbstractAnimationJob *next = animation->nextSibling();
-
- if (prev)
- prev->m_nextSibling = next;
- else
- m_firstChild = next;
-
- if (next)
- next->m_previousSibling = prev;
- else
- m_lastChild = prev;
-
- animation->m_previousSibling = nullptr;
- animation->m_nextSibling = nullptr;
-
- animation->m_group = nullptr;
+ QAbstractAnimationJob *prev = m_children.prev(animation);
+ QAbstractAnimationJob *next = m_children.next(animation);
+ ungroupChild(animation);
animationRemoved(animation, prev, next);
}
void QAnimationGroupJob::clear()
{
- while (QAbstractAnimationJob *child = firstChild()) {
+ while (QAbstractAnimationJob *child = m_children.first()) {
removeAnimation(child);
delete child;
}
- m_firstChild = nullptr;
- m_lastChild = nullptr;
+
+ Q_ASSERT(m_children.isEmpty());
}
void QAnimationGroupJob::resetUncontrolledAnimationsFinishTime()
{
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
if (animation->duration() == -1 || animation->loopCount() < 0) {
resetUncontrolledAnimationFinishTime(animation);
}
@@ -154,11 +110,7 @@ void QAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimationJob *an
void QAnimationGroupJob::animationRemoved(QAbstractAnimationJob* anim, QAbstractAnimationJob* , QAbstractAnimationJob* )
{
- resetUncontrolledAnimationFinishTime(anim);
- if (!firstChild()) {
- m_currentTime = 0;
- stop();
- }
+ handleAnimationRemoved(anim);
}
void QAnimationGroupJob::debugChildren(QDebug d) const
@@ -169,7 +121,7 @@ void QAnimationGroupJob::debugChildren(QDebug d) const
++indentLevel;
QByteArray ind(indentLevel, ' ');
- for (QAbstractAnimationJob *child = firstChild(); child; child = child->nextSibling())
+ for (const QAbstractAnimationJob *child : m_children)
d << "\n" << ind.constData() << child;
}
diff --git a/src/qml/animations/qanimationgroupjob_p.h b/src/qml/animations/qanimationgroupjob_p.h
index a27c9195dd..d276f63868 100644
--- a/src/qml/animations/qanimationgroupjob_p.h
+++ b/src/qml/animations/qanimationgroupjob_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANIMATIONGROUPJOB_P_H
#define QANIMATIONGROUPJOB_P_H
@@ -51,17 +15,20 @@
// We mean it.
//
-#include "private/qabstractanimationjob_p.h"
+#include <QtQml/private/qabstractanimationjob_p.h>
+#include <QtQml/private/qdoubleendedlist_p.h>
#include <QtCore/qdebug.h>
QT_REQUIRE_CONFIG(qml_animation);
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QAnimationGroupJob : public QAbstractAnimationJob
+class Q_QML_EXPORT QAnimationGroupJob : public QAbstractAnimationJob
{
Q_DISABLE_COPY(QAnimationGroupJob)
public:
+ using Children = QDoubleEndedList<QAbstractAnimationJob>;
+
QAnimationGroupJob();
~QAnimationGroupJob() override;
@@ -69,8 +36,8 @@ public:
void prependAnimation(QAbstractAnimationJob *animation);
void removeAnimation(QAbstractAnimationJob *animation);
- QAbstractAnimationJob *firstChild() const { return m_firstChild; }
- QAbstractAnimationJob *lastChild() const { return m_lastChild; }
+ Children *children() { return &m_children; }
+ const Children *children() const { return &m_children; }
virtual void clear();
@@ -85,15 +52,18 @@ protected:
//TODO: confirm location of these (should any be moved into QAbstractAnimationJob?)
void resetUncontrolledAnimationsFinishTime();
void resetUncontrolledAnimationFinishTime(QAbstractAnimationJob *anim);
- int uncontrolledAnimationFinishTime(QAbstractAnimationJob *anim) const { return anim->m_uncontrolledFinishTime; }
+ int uncontrolledAnimationFinishTime(const QAbstractAnimationJob *anim) const
+ {
+ return anim->m_uncontrolledFinishTime;
+ }
void setUncontrolledAnimationFinishTime(QAbstractAnimationJob *anim, int time);
void debugChildren(QDebug d) const;
-private:
- //definition
- QAbstractAnimationJob *m_firstChild = nullptr;
- QAbstractAnimationJob *m_lastChild = nullptr;
+ void ungroupChild(QAbstractAnimationJob *animation);
+ void handleAnimationRemoved(QAbstractAnimationJob *animation);
+
+ Children m_children;
};
QT_END_NAMESPACE
diff --git a/src/qml/animations/qanimationjobutil_p.h b/src/qml/animations/qanimationjobutil_p.h
index 83cf3b246f..fb323d7c89 100644
--- a/src/qml/animations/qanimationjobutil_p.h
+++ b/src/qml/animations/qanimationjobutil_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QANIMATIONJOBUTIL_P_H
#define QANIMATIONJOBUTIL_P_H
@@ -51,10 +15,19 @@
// We mean it.
//
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtconfigmacros.h>
+
#include <type_traits>
QT_REQUIRE_CONFIG(qml_animation);
+#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU_ONLY >= 1300
+# define ACTION_IF_DISABLE_DANGLING_POINTER_WARNING QT_WARNING_DISABLE_GCC("-Wdangling-pointer")
+#else
+# define ACTION_IF_DISABLE_DANGLING_POINTER_WARNING
+#endif
+
// SelfDeletable is used for self-destruction detection along with
// ACTION_IF_DELETED and RETURN_IF_DELETED macros. While using, the objects
// under test should have a member m_selfDeletable of type SelfDeletable
@@ -70,7 +43,9 @@ struct SelfDeletable {
// \param func statements or functions that to be executed under test.
// \param action post process if p was deleted under test.
#define ACTION_IF_DELETED(p, func, action) \
-{ \
+do { \
+ QT_WARNING_PUSH \
+ ACTION_IF_DISABLE_DANGLING_POINTER_WARNING \
static_assert(std::is_same<decltype((p)->m_selfDeletable), SelfDeletable>::value, "m_selfDeletable must be SelfDeletable");\
bool *prevWasDeleted = (p)->m_selfDeletable.m_wasDeleted; \
bool wasDeleted = false; \
@@ -82,7 +57,8 @@ struct SelfDeletable {
{action;} \
} \
(p)->m_selfDeletable.m_wasDeleted = prevWasDeleted; \
-}
+ QT_WARNING_POP \
+} while (false)
#define RETURN_IF_DELETED(func) \
ACTION_IF_DELETED(this, func, return)
diff --git a/src/qml/animations/qcontinuinganimationgroupjob.cpp b/src/qml/animations/qcontinuinganimationgroupjob.cpp
index 88c0e9e60e..892bfc6fdb 100644
--- a/src/qml/animations/qcontinuinganimationgroupjob.cpp
+++ b/src/qml/animations/qcontinuinganimationgroupjob.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Jolla Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qcontinuinganimationgroupjob_p.h"
#include "private/qanimationjobutil_p.h"
@@ -52,9 +16,8 @@ QContinuingAnimationGroupJob::~QContinuingAnimationGroupJob()
void QContinuingAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
{
- Q_ASSERT(firstChild());
-
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ Q_ASSERT(!m_children.isEmpty());
+ for (QAbstractAnimationJob *animation : m_children) {
if (animation->state() == state()) {
RETURN_IF_DELETED(animation->setCurrentTime(m_currentTime));
}
@@ -68,23 +31,23 @@ void QContinuingAnimationGroupJob::updateState(QAbstractAnimationJob::State newS
switch (newState) {
case Stopped:
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ for (QAbstractAnimationJob *animation : m_children)
animation->stop();
break;
case Paused:
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ for (QAbstractAnimationJob *animation : m_children)
if (animation->isRunning())
animation->pause();
break;
case Running:
- if (!firstChild()) {
+ if (m_children.isEmpty()) {
stop();
return;
}
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
- resetUncontrolledAnimationFinishTime(animation);
+ for (QAbstractAnimationJob *animation : m_children) {
+ RETURN_IF_DELETED(resetUncontrolledAnimationFinishTime(animation));
animation->setDirection(m_direction);
- animation->start();
+ RETURN_IF_DELETED(animation->start());
}
break;
}
@@ -93,9 +56,8 @@ void QContinuingAnimationGroupJob::updateState(QAbstractAnimationJob::State newS
void QContinuingAnimationGroupJob::updateDirection(QAbstractAnimationJob::Direction direction)
{
if (!isStopped()) {
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children)
animation->setDirection(direction);
- }
}
}
@@ -104,7 +66,7 @@ void QContinuingAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
Q_ASSERT(animation && (animation->duration() == -1));
int uncontrolledRunningCount = 0;
- for (QAbstractAnimationJob *child = firstChild(); child; child = child->nextSibling()) {
+ for (QAbstractAnimationJob *child : m_children) {
if (child == animation)
setUncontrolledAnimationFinishTime(animation, animation->currentTime());
else if (uncontrolledAnimationFinishTime(child) == -1)
diff --git a/src/qml/animations/qcontinuinganimationgroupjob_p.h b/src/qml/animations/qcontinuinganimationgroupjob_p.h
index c67b8d39ad..1112262d4b 100644
--- a/src/qml/animations/qcontinuinganimationgroupjob_p.h
+++ b/src/qml/animations/qcontinuinganimationgroupjob_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Jolla Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCONTINUINGANIMATIONGROUPJOB_P_H
#define QCONTINUINGANIMATIONGROUPJOB_P_H
@@ -57,7 +21,7 @@ QT_REQUIRE_CONFIG(qml_animation);
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QContinuingAnimationGroupJob : public QAnimationGroupJob
+class Q_QML_EXPORT QContinuingAnimationGroupJob : public QAnimationGroupJob
{
Q_DISABLE_COPY(QContinuingAnimationGroupJob)
public:
diff --git a/src/qml/animations/qparallelanimationgroupjob.cpp b/src/qml/animations/qparallelanimationgroupjob.cpp
index 420a934ba2..4cd63eb6d6 100644
--- a/src/qml/animations/qparallelanimationgroupjob.cpp
+++ b/src/qml/animations/qparallelanimationgroupjob.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qparallelanimationgroupjob_p.h"
#include "private/qanimationjobutil_p.h"
@@ -57,7 +21,7 @@ int QParallelAnimationGroupJob::duration() const
{
int ret = 0;
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (const QAbstractAnimationJob *animation : m_children) {
int currentDuration = animation->totalDuration();
if (currentDuration == -1)
return -1; // Undetermined length
@@ -69,7 +33,7 @@ int QParallelAnimationGroupJob::duration() const
void QParallelAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
{
- if (!firstChild())
+ if (m_children.isEmpty())
return;
if (m_currentLoop > m_previousLoop) {
@@ -79,21 +43,21 @@ void QParallelAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
// For an uncontrolled parallel group, we need to simulate the end of running animations.
// As uncontrolled animation finish time is already reset for this next loop, we pick the
// longest of the known stop times.
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
int currentDuration = animation->totalDuration();
if (currentDuration >= 0)
dura = qMax(dura, currentDuration);
}
}
if (dura > 0) {
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
if (!animation->isStopped())
RETURN_IF_DELETED(animation->setCurrentTime(dura)); // will stop
}
}
} else if (m_currentLoop < m_previousLoop) {
// simulate completion of the loop seeking backwards
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
//we need to make sure the animation is in the right state
//and then rewind it
applyGroupState(animation);
@@ -103,7 +67,7 @@ void QParallelAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
}
// finally move into the actual time of the current loop
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
const int dura = animation->totalDuration();
//if the loopcount is bigger we should always start all animations
if (m_currentLoop > m_previousLoop
@@ -130,24 +94,24 @@ void QParallelAnimationGroupJob::updateState(QAbstractAnimationJob::State newSta
switch (newState) {
case Stopped:
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ for (QAbstractAnimationJob *animation : m_children)
animation->stop();
break;
case Paused:
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
+ for (QAbstractAnimationJob *animation : m_children)
if (animation->isRunning())
animation->pause();
break;
case Running:
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
if (oldState == Stopped) {
animation->stop();
m_previousLoop = m_direction == Forward ? 0 : m_loopCount - 1;
}
- resetUncontrolledAnimationFinishTime(animation);
+ RETURN_IF_DELETED(resetUncontrolledAnimationFinishTime(animation));
animation->setDirection(m_direction);
if (shouldAnimationStart(animation, oldState == Stopped))
- animation->start();
+ RETURN_IF_DELETED(animation->start());
}
break;
}
@@ -188,7 +152,7 @@ void QParallelAnimationGroupJob::updateDirection(QAbstractAnimationJob::Directio
{
//we need to update the direction of the current animation
if (!isStopped()) {
- for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ for (QAbstractAnimationJob *animation : m_children) {
animation->setDirection(direction);
}
} else {
@@ -208,7 +172,7 @@ void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimatio
Q_ASSERT(animation && (animation->duration() == -1 || animation->loopCount() < 0));
int uncontrolledRunningCount = 0;
- for (QAbstractAnimationJob *child = firstChild(); child; child = child->nextSibling()) {
+ for (QAbstractAnimationJob *child : m_children) {
if (child == animation) {
setUncontrolledAnimationFinishTime(animation, animation->currentTime());
} else if (child->duration() == -1 || child->loopCount() < 0) {
@@ -222,7 +186,7 @@ void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimatio
int maxDuration = 0;
bool running = false;
- for (QAbstractAnimationJob *job = firstChild(); job; job = job->nextSibling()) {
+ for (QAbstractAnimationJob *job : m_children) {
if (job->state() == Running)
running = true;
maxDuration = qMax(maxDuration, job->totalDuration());
diff --git a/src/qml/animations/qparallelanimationgroupjob_p.h b/src/qml/animations/qparallelanimationgroupjob_p.h
index 0265fe3274..c4708a8e5d 100644
--- a/src/qml/animations/qparallelanimationgroupjob_p.h
+++ b/src/qml/animations/qparallelanimationgroupjob_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPARALLELANIMATIONGROUPJOB_P_H
#define QPARALLELANIMATIONGROUPJOB_P_H
@@ -57,7 +21,7 @@ QT_REQUIRE_CONFIG(qml_animation);
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QParallelAnimationGroupJob : public QAnimationGroupJob
+class Q_QML_EXPORT QParallelAnimationGroupJob : public QAnimationGroupJob
{
Q_DISABLE_COPY(QParallelAnimationGroupJob)
public:
diff --git a/src/qml/animations/qpauseanimationjob.cpp b/src/qml/animations/qpauseanimationjob.cpp
index aac04d2f8d..c088b0d351 100644
--- a/src/qml/animations/qpauseanimationjob.cpp
+++ b/src/qml/animations/qpauseanimationjob.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qpauseanimationjob_p.h"
diff --git a/src/qml/animations/qpauseanimationjob_p.h b/src/qml/animations/qpauseanimationjob_p.h
index 6c9bbf0dab..e08186e165 100644
--- a/src/qml/animations/qpauseanimationjob_p.h
+++ b/src/qml/animations/qpauseanimationjob_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAUSEANIMATIONJOB_P_H
#define QPAUSEANIMATIONJOB_P_H
@@ -57,7 +21,7 @@ QT_REQUIRE_CONFIG(qml_animation);
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QPauseAnimationJob : public QAbstractAnimationJob
+class Q_QML_EXPORT QPauseAnimationJob : public QAbstractAnimationJob
{
Q_DISABLE_COPY(QPauseAnimationJob)
public:
diff --git a/src/qml/animations/qsequentialanimationgroupjob.cpp b/src/qml/animations/qsequentialanimationgroupjob.cpp
index dc57444b32..cc2c535031 100644
--- a/src/qml/animations/qsequentialanimationgroupjob.cpp
+++ b/src/qml/animations/qsequentialanimationgroupjob.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qsequentialanimationgroupjob_p.h"
#include "private/qpauseanimationjob_p.h"
@@ -66,11 +30,12 @@ bool QSequentialAnimationGroupJob::atEnd() const
const int animTotalCurrentTime = m_currentAnimation->currentTime();
return (m_currentLoop == m_loopCount - 1
&& m_direction == Forward
- && !m_currentAnimation->nextSibling()
+ && !m_children.next(m_currentAnimation)
&& animTotalCurrentTime == animationActualTotalDuration(m_currentAnimation));
}
-int QSequentialAnimationGroupJob::animationActualTotalDuration(QAbstractAnimationJob *anim) const
+int QSequentialAnimationGroupJob::animationActualTotalDuration(
+ const QAbstractAnimationJob *anim) const
{
int ret = anim->totalDuration();
if (ret == -1) {
@@ -84,13 +49,12 @@ int QSequentialAnimationGroupJob::animationActualTotalDuration(QAbstractAnimatio
QSequentialAnimationGroupJob::AnimationIndex QSequentialAnimationGroupJob::indexForCurrentTime() const
{
- Q_ASSERT(firstChild());
+ Q_ASSERT(!m_children.isEmpty());
AnimationIndex ret;
- QAbstractAnimationJob *anim = nullptr;
int duration = 0;
- for (anim = firstChild(); anim; anim = anim->nextSibling()) {
+ for (const QAbstractAnimationJob *anim : m_children) {
duration = animationActualTotalDuration(anim);
// 'animation' is the current animation if one of these reasons is true:
@@ -116,7 +80,7 @@ QSequentialAnimationGroupJob::AnimationIndex QSequentialAnimationGroupJob::index
// 1. the duration of the group is undefined and we passed its actual duration
// 2. there are only 0-duration animations in the group
ret.timeOffset -= duration;
- ret.animation = lastChild();
+ ret.animation = m_children.last();
return ret;
}
@@ -125,17 +89,17 @@ void QSequentialAnimationGroupJob::restart()
// restarting the group by making the first/last animation the current one
if (m_direction == Forward) {
m_previousLoop = 0;
- if (m_currentAnimation == firstChild())
+ if (m_currentAnimation == m_children.first())
activateCurrentAnimation();
else
- setCurrentAnimation(firstChild());
+ setCurrentAnimation(m_children.first());
}
else { // direction == Backward
m_previousLoop = m_loopCount - 1;
- if (m_currentAnimation == lastChild())
+ if (m_currentAnimation == m_children.last())
activateCurrentAnimation();
else
- setCurrentAnimation(lastChild());
+ setCurrentAnimation(m_children.last());
}
}
@@ -143,21 +107,22 @@ void QSequentialAnimationGroupJob::advanceForwards(const AnimationIndex &newAnim
{
if (m_previousLoop < m_currentLoop) {
// we need to fast forward to the end
- for (QAbstractAnimationJob *anim = m_currentAnimation; anim; anim = anim->nextSibling()) {
+ for (QAbstractAnimationJob *anim = m_currentAnimation; anim; anim = m_children.next(anim)) {
RETURN_IF_DELETED(setCurrentAnimation(anim, true));
RETURN_IF_DELETED(anim->setCurrentTime(animationActualTotalDuration(anim)));
}
// this will make sure the current animation is reset to the beginning
- if (firstChild() && !firstChild()->nextSibling()) { //count == 1
+ if (m_children.count() == 1) {
// we need to force activation because setCurrentAnimation will have no effect
RETURN_IF_DELETED(activateCurrentAnimation());
} else {
- RETURN_IF_DELETED(setCurrentAnimation(firstChild(), true));
+ RETURN_IF_DELETED(setCurrentAnimation(m_children.first(), true));
}
}
// and now we need to fast forward from the current position to
- for (QAbstractAnimationJob *anim = m_currentAnimation; anim && anim != newAnimationIndex.animation; anim = anim->nextSibling()) { //### WRONG,
+ for (QAbstractAnimationJob *anim = m_currentAnimation;
+ anim && anim != newAnimationIndex.animation; anim = m_children.next(anim)) { //### WRONG,
RETURN_IF_DELETED(setCurrentAnimation(anim, true));
RETURN_IF_DELETED(anim->setCurrentTime(animationActualTotalDuration(anim)));
}
@@ -168,21 +133,23 @@ void QSequentialAnimationGroupJob::rewindForwards(const AnimationIndex &newAnima
{
if (m_previousLoop > m_currentLoop) {
// we need to fast rewind to the beginning
- for (QAbstractAnimationJob *anim = m_currentAnimation; anim; anim = anim->previousSibling()) {
+ for (QAbstractAnimationJob *anim = m_currentAnimation; anim;
+ anim = m_children.prev(anim)) {
RETURN_IF_DELETED(setCurrentAnimation(anim, true));
RETURN_IF_DELETED(anim->setCurrentTime(0));
}
// this will make sure the current animation is reset to the end
- if (lastChild() && !lastChild()->previousSibling()) { //count == 1
+ if (m_children.count() == 1) { //count == 1
// we need to force activation because setCurrentAnimation will have no effect
RETURN_IF_DELETED(activateCurrentAnimation());
} else {
- RETURN_IF_DELETED(setCurrentAnimation(lastChild(), true));
+ RETURN_IF_DELETED(setCurrentAnimation(m_children.last(), true));
}
}
// and now we need to fast rewind from the current position to
- for (QAbstractAnimationJob *anim = m_currentAnimation; anim && anim != newAnimationIndex.animation; anim = anim->previousSibling()) {
+ for (QAbstractAnimationJob *anim = m_currentAnimation;
+ anim && anim != newAnimationIndex.animation; anim = m_children.prev(anim)) {
RETURN_IF_DELETED(setCurrentAnimation(anim, true));
RETURN_IF_DELETED(anim->setCurrentTime(0));
}
@@ -193,7 +160,7 @@ int QSequentialAnimationGroupJob::duration() const
{
int ret = 0;
- for (QAbstractAnimationJob *anim = firstChild(); anim; anim = anim->nextSibling()) {
+ for (const QAbstractAnimationJob *anim : m_children) {
const int currentDuration = anim->totalDuration();
if (currentDuration == -1)
return -1; // Undetermined length
@@ -246,7 +213,7 @@ void QSequentialAnimationGroupJob::updateCurrentTime(int currentTime)
} else {
//the only case where currentAnimation could be null
//is when all animations have been removed
- Q_ASSERT(!firstChild());
+ Q_ASSERT(m_children.isEmpty());
m_currentTime = 0;
RETURN_IF_DELETED(stop());
}
@@ -288,10 +255,11 @@ void QSequentialAnimationGroupJob::updateDirection(QAbstractAnimationJob::Direct
m_currentAnimation->setDirection(direction);
}
-void QSequentialAnimationGroupJob::setCurrentAnimation(QAbstractAnimationJob *anim, bool intermediate)
+void QSequentialAnimationGroupJob::setCurrentAnimation(
+ const QAbstractAnimationJob *anim, bool intermediate)
{
if (!anim) {
- Q_ASSERT(!firstChild());
+ Q_ASSERT(m_children.isEmpty());
m_currentAnimation = nullptr;
return;
}
@@ -303,7 +271,12 @@ void QSequentialAnimationGroupJob::setCurrentAnimation(QAbstractAnimationJob *an
if (m_currentAnimation)
m_currentAnimation->stop();
- m_currentAnimation = anim;
+ // Assert that the animation passed as argument is actually part of this group ...
+ Q_ASSERT(m_children.contains(anim));
+
+ // ... as then this const_cast is just a shortcut for looking up the non-const
+ // pointer in the linked list of jobs.
+ m_currentAnimation = const_cast<QAbstractAnimationJob *>(anim);
activateCurrentAnimation(intermediate);
}
@@ -337,10 +310,10 @@ void QSequentialAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
int totalTime = currentTime();
if (m_direction == Forward) {
// set the current animation to be the next one
- if (m_currentAnimation->nextSibling())
- setCurrentAnimation(m_currentAnimation->nextSibling());
+ if (auto *anim = m_children.next(m_currentAnimation))
+ RETURN_IF_DELETED(setCurrentAnimation(anim));
- for (QAbstractAnimationJob *a = animation->nextSibling(); a; a = a->nextSibling()) {
+ for (QAbstractAnimationJob *a = m_children.next(animation); a; a = m_children.next(a)) {
int dur = a->duration();
if (dur == -1) {
totalTime = -1;
@@ -352,10 +325,10 @@ void QSequentialAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
} else {
// set the current animation to be the previous one
- if (m_currentAnimation->previousSibling())
- setCurrentAnimation(m_currentAnimation->previousSibling());
+ if (auto *anim = m_children.prev(m_currentAnimation))
+ RETURN_IF_DELETED(setCurrentAnimation(anim));
- for (QAbstractAnimationJob *a = animation->previousSibling(); a; a = a->previousSibling()) {
+ for (QAbstractAnimationJob *a = m_children.prev(animation); a; a = m_children.prev(a)) {
int dur = a->duration();
if (dur == -1) {
totalTime = -1;
@@ -374,12 +347,12 @@ void QSequentialAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
void QSequentialAnimationGroupJob::animationInserted(QAbstractAnimationJob *anim)
{
if (m_currentAnimation == nullptr)
- setCurrentAnimation(firstChild()); // initialize the current animation
+ RETURN_IF_DELETED(setCurrentAnimation(m_children.first())); // initialize the current animation
- if (m_currentAnimation == anim->nextSibling()
+ if (m_currentAnimation == m_children.next(anim)
&& m_currentAnimation->currentTime() == 0 && m_currentAnimation->currentLoop() == 0) {
//in this case we simply insert the animation before the current one has actually started
- setCurrentAnimation(anim);
+ RETURN_IF_DELETED(setCurrentAnimation(anim));
}
// TODO
@@ -398,16 +371,16 @@ void QSequentialAnimationGroupJob::animationRemoved(QAbstractAnimationJob *anim,
bool removingCurrent = anim == m_currentAnimation;
if (removingCurrent) {
if (next)
- setCurrentAnimation(next); //let's try to take the next one
+ RETURN_IF_DELETED(setCurrentAnimation(next)); //let's try to take the next one
else if (prev)
- setCurrentAnimation(prev);
+ RETURN_IF_DELETED(setCurrentAnimation(prev));
else// case all animations were removed
- setCurrentAnimation(nullptr);
+ RETURN_IF_DELETED(setCurrentAnimation(nullptr));
}
// duration of the previous animations up to the current animation
m_currentTime = 0;
- for (QAbstractAnimationJob *job = firstChild(); job; job = job->nextSibling()) {
+ for (QAbstractAnimationJob *job : m_children) {
if (job == m_currentAnimation)
break;
m_currentTime += animationActualTotalDuration(job);
diff --git a/src/qml/animations/qsequentialanimationgroupjob_p.h b/src/qml/animations/qsequentialanimationgroupjob_p.h
index 34e8fe1e08..c7d4319b4d 100644
--- a/src/qml/animations/qsequentialanimationgroupjob_p.h
+++ b/src/qml/animations/qsequentialanimationgroupjob_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSEQUENTIALANIMATIONGROUPJOB_P_H
#define QSEQUENTIALANIMATIONGROUPJOB_P_H
@@ -58,7 +22,7 @@ QT_REQUIRE_CONFIG(qml_animation);
QT_BEGIN_NAMESPACE
class QPauseAnimationJob;
-class Q_QML_PRIVATE_EXPORT QSequentialAnimationGroupJob : public QAnimationGroupJob
+class Q_QML_EXPORT QSequentialAnimationGroupJob : public QAnimationGroupJob
{
Q_DISABLE_COPY(QSequentialAnimationGroupJob)
public:
@@ -85,13 +49,13 @@ private:
// Note that the index semantic is slightly different depending on the direction.
bool afterCurrent = false; //whether animation is before or after m_currentAnimation //TODO: make enum Before/After/Same
int timeOffset = 0; // time offset when the animation at index starts.
- QAbstractAnimationJob *animation = nullptr; //points to the animation at timeOffset
+ const QAbstractAnimationJob *animation = nullptr; //points to the animation at timeOffset
};
- int animationActualTotalDuration(QAbstractAnimationJob *anim) const;
+ int animationActualTotalDuration(const QAbstractAnimationJob *anim) const;
AnimationIndex indexForCurrentTime() const;
- void setCurrentAnimation(QAbstractAnimationJob *anim, bool intermediate = false);
+ void setCurrentAnimation(const QAbstractAnimationJob *anim, bool intermediate = false);
void activateCurrentAnimation(bool intermediate = false);
void animationInserted(QAbstractAnimationJob *anim) override;
diff --git a/src/qml/common/common.pri b/src/qml/common/common.pri
deleted file mode 100644
index bcc3ea0fa0..0000000000
--- a/src/qml/common/common.pri
+++ /dev/null
@@ -1,35 +0,0 @@
-!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/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/qjsnumbercoercion.cpp b/src/qml/common/qjsnumbercoercion.cpp
new file mode 100644
index 0000000000..8cd96a4e25
--- /dev/null
+++ b/src/qml/common/qjsnumbercoercion.cpp
@@ -0,0 +1,62 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qjsnumbercoercion.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \since 6.1
+ \class QJSNumberCoercion
+ \internal
+
+ \brief Implements the JavaScript double-to-int coercion.
+ */
+
+/*!
+ \fn bool QJSNumberCoercion::isInteger(double d)
+ \internal
+ \deprecated 6.7
+ */
+
+/*!
+ \fn bool QJSNumberCoercion::isArrayIndex(double d)
+ \internal
+
+ Checks whether \a d contains a value that can serve as an index into an array.
+ For that, \a d must be a non-negative value representable as an unsigned 32bit int.
+ */
+
+/*!
+ \fn bool QJSNumberCoercion::isArrayIndex(qint64 i)
+ \internal
+
+ Checks whether \a i contains a value that can serve as an index into an array.
+ For that, \a d must be a non-negative value representable as an unsigned 32bit int.
+*/
+
+/*!
+ \fn bool QJSNumberCoercion::isArrayIndex(quint64 i)
+ \internal
+
+ Checks whether \a i contains a value that can serve as an index into an array.
+ For that, \a d must be a value representable as an unsigned 32bit int.
+*/
+
+/*!
+ \fn int QJSNumberCoercion::toInteger(double d)
+ \internal
+
+ Coerces the given \a d to a 32bit integer by JavaScript rules and returns
+ the result.
+ */
+
+/*!
+ \fn bool equals(double lhs, double rhs)
+ \internal
+
+ Compares \a lhs and \a rhs bit by bit without causing a compile warning.
+ Returns the \c true if they are equal, or \c false if not.
+ */
+
+QT_END_NAMESPACE
diff --git a/src/qml/common/qjsnumbercoercion.h b/src/qml/common/qjsnumbercoercion.h
new file mode 100644
index 0000000000..0023bff6e8
--- /dev/null
+++ b/src/qml/common/qjsnumbercoercion.h
@@ -0,0 +1,120 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QJSNUMBERCOERCION_H
+#define QJSNUMBERCOERCION_H
+
+#include <QtCore/qglobal.h>
+#include <cstring>
+
+QT_BEGIN_NAMESPACE
+
+class QJSNumberCoercion
+{
+public:
+
+ static constexpr bool isInteger(double d)
+ {
+ // Comparing d with itself checks for NaN and comparing d with the min and max values
+ // for int also covers infinities.
+ if (!equals(d, d) || d < (std::numeric_limits<int>::min)()
+ || d > (std::numeric_limits<int>::max)()) {
+ return false;
+ }
+
+ return equals(static_cast<int>(d), d);
+ }
+
+ static constexpr bool isArrayIndex(double d)
+ {
+ return d >= 0
+ && equals(d, d)
+ && d <= (std::numeric_limits<uint>::max)()
+ && equals(static_cast<uint>(d), d);
+ }
+
+ static constexpr bool isArrayIndex(qint64 i)
+ {
+ return i >= 0 && i <= (std::numeric_limits<uint>::max)();
+ }
+
+ static constexpr bool isArrayIndex(quint64 i)
+ {
+ return i <= (std::numeric_limits<uint>::max)();
+ }
+
+ static constexpr int toInteger(double d) {
+ // Check for NaN
+ if (!equals(d, d))
+ return 0;
+
+ if (d >= (std::numeric_limits<int>::min)() && d <= (std::numeric_limits<int>::max)()) {
+ const int i = static_cast<int>(d);
+ if (equals(i, d))
+ return i;
+ }
+
+ return QJSNumberCoercion(d).toInteger();
+ }
+
+ static constexpr bool equals(double lhs, double rhs)
+ {
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_FLOAT_COMPARE
+ return lhs == rhs;
+ QT_WARNING_POP
+ }
+
+private:
+ constexpr QJSNumberCoercion(double dbl)
+ {
+ // the dbl == 0 path is guaranteed constexpr. The other one may or may not be, depending
+ // on whether and how the compiler inlines the memcpy.
+ // In order to declare the ctor constexpr we need one guaranteed constexpr path.
+ if (!equals(dbl, 0))
+ memcpy(&d, &dbl, sizeof(double));
+ }
+
+ constexpr int sign() const
+ {
+ return (d >> 63) ? -1 : 1;
+ }
+
+ constexpr bool isDenormal() const
+ {
+ return static_cast<int>((d << 1) >> 53) == 0;
+ }
+
+ constexpr int exponent() const
+ {
+ return static_cast<int>((d << 1) >> 53) - 1023;
+ }
+
+ constexpr quint64 significant() const
+ {
+ quint64 m = (d << 12) >> 12;
+ if (!isDenormal())
+ m |= (static_cast<quint64>(1) << 52);
+ return m;
+ }
+
+ constexpr int toInteger()
+ {
+ int e = exponent() - 52;
+ if (e < 0) {
+ if (e <= -53)
+ return 0;
+ return sign() * static_cast<int>(significant() >> -e);
+ } else {
+ if (e > 31)
+ return 0;
+ return sign() * (static_cast<int>(significant()) << e);
+ }
+ }
+
+ quint64 d = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QJSNUMBERCOERCION_H
diff --git a/src/qml/common/qqmlapiversion_p.h b/src/qml/common/qqmlapiversion_p.h
deleted file mode 100644
index 576619c518..0000000000
--- a/src/qml/common/qqmlapiversion_p.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLAPIVERSION_P_H
-#define QQMLAPIVERSION_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.
-//
-
-#define Q_QML_PRIVATE_API_VERSION 6
-
-#endif // QQMLAPIVERSION_P_H
diff --git a/src/qml/common/qqmljsdiagnosticmessage_p.h b/src/qml/common/qqmljsdiagnosticmessage_p.h
index 763332ba76..0e7adbc3be 100644
--- a/src/qml/common/qqmljsdiagnosticmessage_p.h
+++ b/src/qml/common/qqmljsdiagnosticmessage_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSDIAGNOSTICMESSAGE_P_H
#define QQMLJSDIAGNOSTICMESSAGE_P_H
@@ -56,7 +20,8 @@
// Include the API version here, to avoid complications when querying it for the
// QQmlSourceLocation -> line/column change.
-#include <private/qqmlapiversion_p.h>
+
+#include "qqmljssourcelocation_p.h"
QT_BEGIN_NAMESPACE
@@ -65,8 +30,7 @@ struct DiagnosticMessage
{
QString message;
QtMsgType type = QtCriticalMsg;
- quint32 line = 0;
- quint32 column = 0;
+ SourceLocation loc;
bool isError() const
{
@@ -85,7 +49,7 @@ struct DiagnosticMessage
};
} // namespace QQmlJS
-Q_DECLARE_TYPEINFO(QQmlJS::DiagnosticMessage, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QQmlJS::DiagnosticMessage, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/qml/common/qqmljsfixedpoolarray_p.h b/src/qml/common/qqmljsfixedpoolarray_p.h
index b65b994d6c..e946b1ecfd 100644
--- a/src/qml/common/qqmljsfixedpoolarray_p.h
+++ b/src/qml/common/qqmljsfixedpoolarray_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSFIXEDPOOLARRAY_P_H
#define QQMLJSFIXEDPOOLARRAY_P_H
@@ -80,13 +44,13 @@ public:
void allocate(MemoryPool *pool, const QVector<T> &vector)
{
- count = vector.count();
+ count = vector.size();
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 {
+ } else if (count) {
memcpy(data, static_cast<const void*>(vector.constData()), count * sizeof(T));
}
}
@@ -94,7 +58,7 @@ public:
template <typename Container>
void allocate(MemoryPool *pool, const Container &container)
{
- count = container.count();
+ count = container.size();
data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
typename Container::ConstIterator it = container.constBegin();
for (int i = 0; i < count; ++i)
diff --git a/src/qml/common/qqmljsmemorypool_p.h b/src/qml/common/qqmljsmemorypool_p.h
index 0cf7ea84e6..6f0f8ed491 100644
--- a/src/qml/common/qqmljsmemorypool_p.h
+++ b/src/qml/common/qqmljsmemorypool_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSMEMORYPOOL_P_H
#define QQMLJSMEMORYPOOL_P_H
@@ -51,11 +15,11 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
-#include <QtCore/qshareddata.h>
-#include <QtCore/qdebug.h>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qvector.h>
-#include <cstring>
+#include <cstdlib>
QT_BEGIN_NAMESPACE
@@ -63,14 +27,12 @@ namespace QQmlJS {
class Managed;
-class MemoryPool : public QSharedData
+class MemoryPool
{
- MemoryPool(const MemoryPool &other);
- void operator =(const MemoryPool &other);
+ Q_DISABLE_COPY_MOVE(MemoryPool);
public:
- MemoryPool() {}
-
+ MemoryPool() = default;
~MemoryPool()
{
if (_blocks) {
@@ -81,13 +43,12 @@ public:
free(_blocks);
}
- qDeleteAll(strings);
}
inline void *allocate(size_t size)
{
size = (size + 7) & ~size_t(7);
- if (Q_LIKELY(_ptr && (_ptr + size < _end))) {
+ if (Q_LIKELY(_ptr && size < size_t(_end - _ptr))) {
void *addr = _ptr;
_ptr += size;
return addr;
@@ -105,9 +66,8 @@ public:
template <typename Tp, typename... Ta> Tp *New(Ta... args)
{ return new (this->allocate(sizeof(Tp))) Tp(args...); }
- QStringRef newString(const QString &string) {
- strings.append(new QString(string));
- return QStringRef(strings.last());
+ QStringView newString(QString string) {
+ return strings.emplace_back(std::move(string));
}
private:
@@ -151,7 +111,7 @@ private:
int _blockCount = -1;
char *_ptr = nullptr;
char *_end = nullptr;
- QVector<QString*> strings;
+ QStringList strings;
enum
{
diff --git a/src/qml/common/qqmljssourcelocation_p.h b/src/qml/common/qqmljssourcelocation_p.h
new file mode 100644
index 0000000000..9a007e4ac5
--- /dev/null
+++ b/src/qml/common/qqmljssourcelocation_p.h
@@ -0,0 +1,107 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLJSSOURCELOCATION_P_H
+#define QQMLJSSOURCELOCATION_P_H
+
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qhashfunctions.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class SourceLocation
+{
+public:
+ explicit SourceLocation(quint32 offset = 0, quint32 length = 0, quint32 line = 0, quint32 column = 0)
+ : offset(offset), length(length),
+ startLine(line), startColumn(column)
+ { }
+
+ bool isValid() const { return *this != SourceLocation(); }
+
+ quint32 begin() const { return offset; }
+ quint32 end() const { return offset + length; }
+
+ // Returns a zero length location at the start of the current one.
+ SourceLocation startZeroLengthLocation() const
+ {
+ return SourceLocation(offset, 0, startLine, startColumn);
+ }
+ // Returns a zero length location at the end of the current one.
+ SourceLocation endZeroLengthLocation(QStringView text) const
+ {
+ quint32 i = offset;
+ quint32 endLine = startLine;
+ quint32 endColumn = startColumn;
+ while (i < end()) {
+ QChar c = text.at(i);
+ switch (c.unicode()) {
+ case '\n':
+ if (i + 1 < end() && text.at(i + 1) == QLatin1Char('\r'))
+ ++i;
+ Q_FALLTHROUGH();
+ case '\r':
+ ++endLine;
+ endColumn = 1;
+ break;
+ default:
+ ++endColumn;
+ }
+ ++i;
+ }
+ return SourceLocation(offset + length, 0, endLine, endColumn);
+ }
+
+// attributes
+ // ### encode
+ quint32 offset;
+ quint32 length;
+ quint32 startLine;
+ quint32 startColumn;
+
+ friend size_t qHash(const SourceLocation &location, size_t seed = 0)
+ {
+ return qHashMulti(seed, location.offset, location.length,
+ location.startLine, location.startColumn);
+ }
+
+ friend bool operator==(const SourceLocation &a, const SourceLocation &b)
+ {
+ return a.offset == b.offset && a.length == b.length
+ && a.startLine == b.startLine && a.startColumn == b.startColumn;
+ }
+
+ friend bool operator!=(const SourceLocation &a, const SourceLocation &b) { return !(a == b); }
+
+ // Returns a source location starting at the beginning of l1, l2 and ending at the end of them.
+ // Ignores invalid source locations.
+ friend SourceLocation combine(const SourceLocation &l1, const SourceLocation &l2) {
+ quint32 e = qMax(l1.end(), l2.end());
+ SourceLocation res;
+ if (l1.offset <= l2.offset)
+ res = (l1.isValid() ? l1 : l2);
+ else
+ res = (l2.isValid() ? l2 : l1);
+ res.length = e - res.offset;
+ return res;
+ }
+};
+
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/common/qqmlsignalnames.cpp b/src/qml/common/qqmlsignalnames.cpp
new file mode 100644
index 0000000000..d2a23205a6
--- /dev/null
+++ b/src/qml/common/qqmlsignalnames.cpp
@@ -0,0 +1,257 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmlsignalnames_p.h"
+#include <iterator>
+#include <algorithm>
+#include <optional>
+#include <string>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::Literals;
+
+static constexpr const QLatin1String On("on");
+static constexpr const QLatin1String Changed("Changed");
+
+static constexpr const qsizetype StrlenOn = On.length();
+static constexpr const qsizetype StrlenChanged = Changed.length();
+
+static std::optional<qsizetype> firstLetterIdx(QStringView name, qsizetype removePrefix = 0,
+ qsizetype removeSuffix = 0)
+{
+ auto end = std::prev(name.cend(), removeSuffix);
+ auto result = std::find_if(std::next(name.cbegin(), removePrefix), end,
+ [](const QChar &c) { return c.isLetter(); });
+ if (result != end)
+ return std::distance(name.begin(), result);
+
+ return {};
+}
+
+static std::optional<QChar> firstLetter(QStringView name, qsizetype removePrefix = 0,
+ qsizetype removeSuffix = 0)
+{
+ if (auto idx = firstLetterIdx(name, removePrefix, removeSuffix))
+ return name[*idx];
+ return {};
+}
+
+enum ChangeCase { ToUpper, ToLower };
+static void changeCaseOfFirstLetter(QString &name, ChangeCase option, qsizetype removePrefix = 0,
+ qsizetype removeSuffix = 0)
+{
+ auto idx = firstLetterIdx(name, removePrefix, removeSuffix);
+ if (!idx)
+ return;
+
+ QChar &changeMe = name[*idx];
+ changeMe = option == ToUpper ? changeMe.toUpper() : changeMe.toLower();
+};
+
+static std::optional<QString> toQStringData(std::optional<QStringView> view)
+{
+ if (view)
+ return view->toString();
+ return std::nullopt;
+}
+
+static QByteArray toUtf8Data(QUtf8StringView view)
+{
+ return QByteArray(view.data(), view.size());
+}
+
+static std::optional<QByteArray> toUtf8Data(std::optional<QUtf8StringView> view)
+{
+ if (view)
+ return toUtf8Data(*view);
+ return std::nullopt;
+}
+
+/*!
+\internal
+\class QQmlSignalNames
+
+QQmlSignalNames contains a list of helper methods to manipulate signal names.
+Always try to use the most specific one, as combining them might lead to incorrect
+results like wrong upper/lower case, for example.
+*/
+
+/*!
+\internal
+Concatenate a prefix to a property name and uppercases the first letter of the property name.
+*/
+QString QQmlSignalNames::addPrefixToPropertyName(QStringView prefix, QStringView propertyName)
+{
+ QString result = prefix.toString().append(propertyName);
+ changeCaseOfFirstLetter(result, ToUpper, prefix.size());
+ return result;
+}
+
+QString QQmlSignalNames::propertyNameToChangedSignalName(QStringView property)
+{
+ return property.toString().append(Changed);
+}
+
+QByteArray QQmlSignalNames::propertyNameToChangedSignalName(QUtf8StringView property)
+{
+ return toUtf8Data(property).append(QByteArrayView(Changed));
+}
+
+QString QQmlSignalNames::propertyNameToChangedHandlerName(QStringView property)
+{
+ return propertyNameToChangedSignalName(signalNameToHandlerName(property));
+}
+
+template<typename View>
+std::optional<View> changedSignalNameToPropertyNameTemplate(View changeSignal)
+{
+ const qsizetype changeSignalSize = changeSignal.size();
+ if (changeSignalSize < StrlenChanged || changeSignal.last(StrlenChanged).compare(Changed) != 0)
+ return std::nullopt;
+
+ const View result = changeSignal.sliced(0, changeSignalSize - StrlenChanged);
+ if (!result.isEmpty())
+ return result;
+
+ return {};
+}
+
+/*!
+\internal
+Obtain a propertyName from its changed signal handler.
+Do not call this on a value obtained from handlerNameToSignalName! Instead use
+changedHandlerNameToPropertyName() directly. Otherwise you might end up with a wrong
+capitalization of _Changed for "on_Changed", for example.
+*/
+
+std::optional<QString> QQmlSignalNames::changedSignalNameToPropertyName(QStringView signalName)
+{
+ return toQStringData(changedSignalNameToPropertyNameTemplate(signalName));
+}
+std::optional<QByteArray>
+QQmlSignalNames::changedSignalNameToPropertyName(QUtf8StringView signalName)
+{
+ return toUtf8Data(changedSignalNameToPropertyNameTemplate(signalName));
+}
+
+/*!
+\internal
+Returns a property name from \a changedHandler.
+This fails for property names starting with an upper-case letter, as it will lower-case it in the
+process.
+*/
+std::optional<QString> QQmlSignalNames::changedHandlerNameToPropertyName(QStringView handler)
+{
+ if (!isChangedHandlerName(handler))
+ return {};
+
+ if (auto withoutChangedSuffix = changedSignalNameToPropertyName(handler)) {
+ return handlerNameToSignalName(*withoutChangedSuffix);
+ }
+ return {};
+}
+
+QString QQmlSignalNames::signalNameToHandlerName(QAnyStringView signal)
+{
+ QString handlerName;
+ handlerName.reserve(StrlenOn + signal.length());
+ handlerName.append(On);
+
+ signal.visit([&handlerName](auto &&s) { handlerName.append(s); });
+
+ changeCaseOfFirstLetter(handlerName, ToUpper, StrlenOn);
+ return handlerName;
+}
+
+enum HandlerType { ChangedHandler, Handler };
+
+template<HandlerType type>
+static std::optional<QString> handlerNameToSignalNameHelper(QStringView handler)
+{
+ if (!QQmlSignalNames::isHandlerName(handler))
+ return {};
+
+ QString signalName = handler.sliced(StrlenOn).toString();
+ Q_ASSERT(!signalName.isEmpty());
+
+ changeCaseOfFirstLetter(signalName, ToLower, 0, type == ChangedHandler ? StrlenChanged : 0);
+ return signalName;
+}
+
+/*!
+\internal
+Returns a signal name from \a handlerName string. Do not use it on changed handlers, see
+changedHandlerNameToSignalName for that!
+*/
+std::optional<QString> QQmlSignalNames::handlerNameToSignalName(QStringView handler)
+{
+ return handlerNameToSignalNameHelper<Handler>(handler);
+}
+
+/*!
+\internal
+Returns a signal name from \a handlerName string. Do not use it on changed handlers, see
+changedHandlerNameToSignalName for that! Accepts improperly capitalized handler names and
+incorrectly resolves signal names that start with '_' or '$'.
+*/
+std::optional<QString> QQmlSignalNames::badHandlerNameToSignalName(QStringView handler)
+{
+ if (handler.size() <= StrlenOn || !handler.startsWith(On))
+ return {};
+
+ QString signalName = handler.sliced(StrlenOn).toString();
+
+ // This is quite wrong. But we need it for backwards compatibility.
+ signalName.front() = signalName.front().toLower();
+
+ return signalName;
+}
+
+/*!
+\internal
+Returns a signal name from \a changedHandlerName string. Makes sure not to lowercase the 'C' from
+Changed.
+*/
+std::optional<QString> QQmlSignalNames::changedHandlerNameToSignalName(QStringView handler)
+{
+ return handlerNameToSignalNameHelper<ChangedHandler>(handler);
+}
+
+bool QQmlSignalNames::isChangedSignalName(QStringView signalName)
+{
+ if (signalName.size() <= StrlenChanged || !signalName.endsWith(Changed))
+ return false;
+
+ if (auto letter = firstLetter(signalName, 0, StrlenChanged))
+ return letter->isLower();
+
+ return true;
+}
+
+bool QQmlSignalNames::isChangedHandlerName(QStringView signalName)
+{
+ if (signalName.size() <= (StrlenOn + StrlenChanged)
+ || !signalName.startsWith(On)
+ || !signalName.endsWith(Changed)) {
+ return false;
+ }
+
+ if (auto letter = firstLetter(signalName, StrlenOn, StrlenChanged))
+ return letter->isUpper();
+
+ return true;
+}
+
+bool QQmlSignalNames::isHandlerName(QStringView signalName)
+{
+ if (signalName.size() <= StrlenOn || !signalName.startsWith(On))
+ return false;
+
+ if (auto letter = firstLetter(signalName, StrlenOn))
+ return letter->isUpper();
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/common/qqmlsignalnames_p.h b/src/qml/common/qqmlsignalnames_p.h
new file mode 100644
index 0000000000..9c3d192666
--- /dev/null
+++ b/src/qml/common/qqmlsignalnames_p.h
@@ -0,0 +1,59 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLSIGNALANDPROPERTYNAMES_P_H
+#define QQMLSIGNALANDPROPERTYNAMES_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 <cstddef>
+#include <optional>
+
+#include <QtQml/private/qtqmlglobal_p.h>
+#include <QtCore/qstringview.h>
+#include <QtCore/qstring.h>
+#include <type_traits>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_EXPORT QQmlSignalNames
+{
+public:
+ static QString propertyNameToChangedSignalName(QStringView property);
+ static QByteArray propertyNameToChangedSignalName(QUtf8StringView property);
+
+ static QString propertyNameToChangedHandlerName(QStringView property);
+
+ static QString signalNameToHandlerName(QAnyStringView signal);
+
+ static std::optional<QString> changedSignalNameToPropertyName(QStringView changeSignal);
+ static std::optional<QByteArray> changedSignalNameToPropertyName(QUtf8StringView changeSignal);
+
+ static std::optional<QString> changedHandlerNameToPropertyName(QStringView handler);
+ static std::optional<QByteArray> changedHandlerNameToPropertyName(QUtf8StringView handler);
+
+ static std::optional<QString> handlerNameToSignalName(QStringView handler);
+ static std::optional<QString> changedHandlerNameToSignalName(QStringView changedHandler);
+
+ static bool isChangedHandlerName(QStringView signalName);
+ static bool isChangedSignalName(QStringView signalName);
+ static bool isHandlerName(QStringView signalName);
+
+ static QString addPrefixToPropertyName(QStringView prefix, QStringView propertyName);
+
+ // ### Qt7: remove this
+ static std::optional<QString> badHandlerNameToSignalName(QStringView handler);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLSIGNALANDPROPERTYNAMES_P_H
diff --git a/src/qml/common/qqmltranslation.cpp b/src/qml/common/qqmltranslation.cpp
new file mode 100644
index 0000000000..7120071b1a
--- /dev/null
+++ b/src/qml/common/qqmltranslation.cpp
@@ -0,0 +1,125 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "private/qqmltranslation_p.h"
+
+QQmlTranslation::QQmlTranslation(const Data &d) : data(d) { }
+QQmlTranslation::QQmlTranslation() : data(nullptr) { }
+
+QString QQmlTranslation::translate() const
+{
+ return std::visit(
+ [](auto &&arg) -> QString {
+ using T = std::decay_t<decltype(arg)>;
+ if constexpr (!std::is_same_v<T, std::nullptr_t>)
+ return arg.translate();
+ else {
+ Q_ASSERT_X(false, "QQmlTranslation", "Uninitialized Translation");
+ return {};
+ }
+ },
+ data);
+}
+
+QString QQmlTranslation::serializeForQmltc() const
+{
+ return std::visit(
+ [](auto &&arg) -> QString {
+ using T = std::decay_t<decltype(arg)>;
+ if constexpr (!std::is_same_v<T, std::nullptr_t>)
+ return arg.serializeForQmltc();
+ else {
+ Q_ASSERT_X(false, "QQmlTranslation", "Uninitialized Translation");
+ return {};
+ }
+ },
+ data);
+}
+
+QString QQmlTranslation::idForQmlDebug() const
+{
+ return std::visit(
+ [](auto &&arg) -> QString {
+ using T = std::decay_t<decltype(arg)>;
+ if constexpr (!std::is_same_v<T, std::nullptr_t>)
+ return arg.idForQmlDebug();
+ else {
+ Q_ASSERT_X(false, "QQmlTranslation", "Uninitialized Translation");
+ return {};
+ }
+ },
+ data);
+}
+
+QQmlTranslation::QsTrData::QsTrData(const QString &context, const QString &text,
+ const QString &comment, int number)
+ : context(context.toUtf8()), text(text.toUtf8()), comment(comment.toUtf8()), number(number)
+{
+}
+
+QString QQmlTranslation::contextFromQmlFilename(const QString &qmlFilename)
+{
+ int lastSlash = qmlFilename.lastIndexOf(QLatin1Char('/'));
+ QStringView contextView = (lastSlash > -1)
+ ? QStringView{ qmlFilename }.mid(lastSlash + 1, qmlFilename.size() - lastSlash - 5)
+ : QStringView();
+ return contextView.toString();
+}
+
+QString QQmlTranslation::QsTrData::translate() const
+{
+#if !QT_CONFIG(translation)
+ return QString();
+#else
+ return QCoreApplication::translate(context, text, comment, number);
+#endif
+}
+
+QString QQmlTranslation::QsTrData::idForQmlDebug() const
+{
+ return QString::fromUtf8(text);
+}
+
+QString QQmlTranslation::QsTrData::serializeForQmltc() const
+{
+ QString result = QStringLiteral(R"(QQmlTranslation(QQmlTranslation::QsTrData(
+ QStringLiteral("%1"),
+ QStringLiteral("%2"),
+ QStringLiteral("%3"),
+ %4)))")
+ .arg(QString::fromUtf8(context), QString::fromUtf8(text),
+ QString::fromUtf8(comment))
+ .arg(number);
+
+ return result;
+}
+
+QQmlTranslation::QsTrIdData::QsTrIdData(const QString &id, int number)
+ : id(id.toUtf8()), number(number)
+{
+}
+
+QString QQmlTranslation::QsTrIdData::translate() const
+{
+#if !QT_CONFIG(translation)
+ return QString();
+#else
+ return qtTrId(id, number);
+#endif
+}
+
+QString QQmlTranslation::QsTrIdData::serializeForQmltc() const
+{
+ QString result = QStringLiteral(R"(QQmlTranslation(QQmlTranslation::QsTrIdData(
+ QStringLiteral("%1"),
+ %4)))")
+ .arg(QString::fromUtf8(id))
+ .arg(number);
+
+ return result;
+}
+
+QString QQmlTranslation::QsTrIdData::idForQmlDebug() const
+{
+ return QString::fromUtf8(id);
+}
diff --git a/src/qml/common/qqmltranslation_p.h b/src/qml/common/qqmltranslation_p.h
new file mode 100644
index 0000000000..9849203abe
--- /dev/null
+++ b/src/qml/common/qqmltranslation_p.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLTRANSLATION_P_H
+#define QQMLTRANSLATION_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/qstring.h>
+
+#include <private/qv4qmlcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_EXPORT QQmlTranslation
+{
+public:
+ class Q_QML_EXPORT QsTrData
+ {
+ QByteArray context;
+ QByteArray text;
+ QByteArray comment;
+ int number;
+
+ public:
+ QsTrData(const QString &fileNameForContext, const QString &text, const QString &comment,
+ int number);
+ QString translate() const;
+ QString serializeForQmltc() const;
+ QString idForQmlDebug() const;
+ };
+
+ class Q_QML_EXPORT QsTrIdData
+ {
+ QByteArray id;
+ int number;
+
+ public:
+ QsTrIdData(const QString &id, int number);
+ QString translate() const;
+ QString serializeForQmltc() const;
+ QString idForQmlDebug() const;
+ };
+
+ // The static analyzer hates std::monostate in std::variant because
+ // that results in various uninitialized memory "problems". Just use
+ // std::nullptr_t to indicate "empty".
+ using Data = std::variant<std::nullptr_t, QsTrData, QsTrIdData>;
+
+private:
+ Data data;
+
+public:
+ QQmlTranslation(const Data &d);
+ QQmlTranslation();
+ QString translate() const;
+ QString serializeForQmltc() const;
+ QString idForQmlDebug() const;
+
+ static QString contextFromQmlFilename(const QString &qmlFilename);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTRANSLATION_P_H
diff --git a/src/qml/common/qv4alloca_p.h b/src/qml/common/qv4alloca_p.h
index 65c3e4d65a..c1d1e6e87d 100644
--- a/src/qml/common/qv4alloca_p.h
+++ b/src/qml/common/qv4alloca_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4_ALLOCA_H
#define QV4_ALLOCA_H
@@ -100,8 +64,10 @@ QT_END_NAMESPACE
type *name = nullptr
#define Q_ALLOCA_ASSIGN(type, name, size) \
- _qt_alloca_##name.allocate(size); \
- name = static_cast<type*>(_qt_alloca_##name.data())
+ do { \
+ _qt_alloca_##name.allocate(size); \
+ name = static_cast<type*>(_qt_alloca_##name.data()); \
+ } while (false)
#endif
diff --git a/src/qml/common/qv4calldata_p.h b/src/qml/common/qv4calldata_p.h
index 5a5280cb86..8d193bae4d 100644
--- a/src/qml/common/qv4calldata_p.h
+++ b/src/qml/common/qv4calldata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4CALLDATA_P_H
#define QV4CALLDATA_P_H
@@ -95,7 +59,7 @@ struct CallData
StaticValue args[1];
- static Q_DECL_CONSTEXPR int HeaderSize()
+ static constexpr int HeaderSize()
{
return offsetof(CallData, args) / sizeof(QV4::StaticValue);
}
diff --git a/src/qml/common/qv4compileddata.cpp b/src/qml/common/qv4compileddata.cpp
new file mode 100644
index 0000000000..9dee91f713
--- /dev/null
+++ b/src/qml/common/qv4compileddata.cpp
@@ -0,0 +1,431 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qv4compileddata_p.h"
+
+#include <private/inlinecomponentutils_p.h>
+#include <private/qml_compile_hash_p.h>
+#include <private/qqmlscriptdata_p.h>
+#include <private/qqmltypenamecache_p.h>
+#include <private/qv4resolvedtypereference_p.h>
+
+#include <QtQml/qqmlfile.h>
+
+#include <QtCore/qdir.h>
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qstandardpaths.h>
+
+static_assert(QV4::CompiledData::QmlCompileHashSpace > QML_COMPILE_HASH_LENGTH);
+
+#if defined(QML_COMPILE_HASH) && defined(QML_COMPILE_HASH_LENGTH) && QML_COMPILE_HASH_LENGTH > 0
+# ifdef Q_OS_LINUX
+// Place on a separate section on Linux so it's easier to check from outside
+// what the hash version is.
+__attribute__((section(".qml_compile_hash")))
+# endif
+const char qml_compile_hash[QV4::CompiledData::QmlCompileHashSpace] = QML_COMPILE_HASH;
+static_assert(sizeof(QV4::CompiledData::Unit::libraryVersionHash) > QML_COMPILE_HASH_LENGTH,
+ "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version");
+#else
+# error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+namespace CompiledData {
+
+
+bool Unit::verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const
+{
+ if (strncmp(magic, CompiledData::magic_str, sizeof(magic))) {
+ *errorString = QStringLiteral("Magic bytes in the header do not match");
+ return false;
+ }
+
+ if (version != quint32(QV4_DATA_STRUCTURE_VERSION)) {
+ *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2")
+ .arg(version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16);
+ return false;
+ }
+
+ if (qtVersion != quint32(QT_VERSION)) {
+ *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2")
+ .arg(qtVersion, 0, 16).arg(QT_VERSION, 0, 16);
+ return false;
+ }
+
+ if (sourceTimeStamp) {
+ // Files from the resource system do not have any time stamps, so fall back to the application
+ // executable.
+ if (!expectedSourceTimeStamp.isValid())
+ expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
+
+ if (expectedSourceTimeStamp.isValid()
+ && expectedSourceTimeStamp.toMSecsSinceEpoch() != sourceTimeStamp) {
+ *errorString = QStringLiteral("QML source file has a different time stamp than cached file.");
+ return false;
+ }
+ }
+
+#if defined(QML_COMPILE_HASH) && defined(QML_COMPILE_HASH_LENGTH) && QML_COMPILE_HASH_LENGTH > 0
+ if (qstrncmp(qml_compile_hash, libraryVersionHash, QML_COMPILE_HASH_LENGTH) != 0) {
+ *errorString = QStringLiteral("QML compile hashes don't match. Found %1 expected %2")
+ .arg(QString::fromLatin1(
+ QByteArray(libraryVersionHash, QML_COMPILE_HASH_LENGTH)
+ .toPercentEncoding()),
+ QString::fromLatin1(
+ QByteArray(qml_compile_hash, QML_COMPILE_HASH_LENGTH)
+ .toPercentEncoding()));
+ return false;
+ }
+#else
+#error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
+#endif
+ return true;
+}
+
+/*!
+ \internal
+ This function creates a temporary key vector and sorts it to guarantuee a stable
+ hash. This is used to calculate a check-sum on dependent meta-objects.
+ */
+bool ResolvedTypeReferenceMap::addToHash(
+ QCryptographicHash *hash, QHash<quintptr, QByteArray> *checksums) const
+{
+ std::vector<int> keys (size());
+ int i = 0;
+ for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
+ keys[i] = it.key();
+ ++i;
+ }
+ std::sort(keys.begin(), keys.end());
+ for (int key: keys) {
+ if (!this->operator[](key)->addToHash(hash, checksums))
+ return false;
+ }
+
+ return true;
+}
+
+CompilationUnit::CompilationUnit(
+ const Unit *unitData, const QString &fileName, const QString &finalUrlString)
+{
+ setUnitData(unitData, nullptr, fileName, finalUrlString);
+}
+
+CompilationUnit::~CompilationUnit()
+{
+ qDeleteAll(resolvedTypes);
+
+ if (data) {
+ if (data->qmlUnit() != qmlData)
+ free(const_cast<QmlUnit *>(qmlData));
+ qmlData = nullptr;
+
+ if (!(data->flags & QV4::CompiledData::Unit::StaticData))
+ free(const_cast<Unit *>(data));
+ }
+ data = nullptr;
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ delete [] constants;
+ constants = nullptr;
+#endif
+}
+
+QString CompilationUnit::localCacheFilePath(const QUrl &url)
+{
+ static const QByteArray envCachePath = qgetenv("QML_DISK_CACHE_PATH");
+
+ const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
+ const QString cacheFileSuffix
+ = QFileInfo(localSourcePath + QLatin1Char('c')).completeSuffix();
+ QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
+ fileNameHash.addData(localSourcePath.toUtf8());
+ QString directory = envCachePath.isEmpty()
+ ? QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
+ + QLatin1String("/qmlcache/")
+ : QString::fromLocal8Bit(envCachePath) + QLatin1String("/");
+ QDir::root().mkpath(directory);
+ return directory + QString::fromUtf8(fileNameHash.result().toHex())
+ + QLatin1Char('.') + cacheFileSuffix;
+}
+
+bool CompilationUnit::loadFromDisk(
+ const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString)
+{
+ if (!QQmlFile::isLocalFile(url)) {
+ *errorString = QStringLiteral("File has to be a local file.");
+ return false;
+ }
+
+ const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
+ auto cacheFile = std::make_unique<CompilationUnitMapper>();
+
+ const QStringList cachePaths = { sourcePath + QLatin1Char('c'), localCacheFilePath(url) };
+ for (const QString &cachePath : cachePaths) {
+ Unit *mappedUnit = cacheFile->get(cachePath, sourceTimeStamp, errorString);
+ if (!mappedUnit)
+ continue;
+
+ const Unit *oldData = unitData();
+ const Unit * const oldDataPtr
+ = (oldData && !(oldData->flags & Unit::StaticData))
+ ? oldData
+ : nullptr;
+
+ auto dataPtrRevert = qScopeGuard([this, oldData](){
+ setUnitData(oldData);
+ });
+ setUnitData(mappedUnit);
+
+ if (mappedUnit->sourceFileIndex != 0) {
+ if (mappedUnit->sourceFileIndex >=
+ mappedUnit->stringTableSize + dynamicStrings.size()) {
+ *errorString = QStringLiteral("QML source file index is invalid.");
+ continue;
+ }
+ if (sourcePath !=
+ QQmlFile::urlToLocalFileOrQrc(stringAt(mappedUnit->sourceFileIndex))) {
+ *errorString = QStringLiteral("QML source file has moved to a different location.");
+ continue;
+ }
+ }
+
+ dataPtrRevert.dismiss();
+ free(const_cast<Unit*>(oldDataPtr));
+ backingFile = std::move(cacheFile);
+ return true;
+ }
+
+ return false;
+}
+
+bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
+{
+ if (unitData()->sourceTimeStamp == 0) {
+ *errorString = QStringLiteral("Missing time stamp for source file");
+ return false;
+ }
+
+ if (!QQmlFile::isLocalFile(unitUrl)) {
+ *errorString = QStringLiteral("File has to be a local file.");
+ return false;
+ }
+
+ return SaveableUnitPointer(unitData()).saveToDisk<char>(
+ [&unitUrl, errorString](const char *data, quint32 size) {
+ const QString cachePath = localCacheFilePath(unitUrl);
+ if (SaveableUnitPointer::writeDataToFile(
+ cachePath, data, size, errorString)) {
+ CompilationUnitMapper::invalidate(cachePath);
+ return true;
+ }
+
+ return false;
+ });
+}
+
+QStringList CompilationUnit::moduleRequests() const
+{
+ QStringList requests;
+ requests.reserve(data->moduleRequestTableSize);
+ for (uint i = 0; i < data->moduleRequestTableSize; ++i)
+ requests << stringAt(data->moduleRequestTable()[i]);
+ return requests;
+}
+
+ResolvedTypeReference *CompilationUnit::resolvedType(QMetaType type) const
+{
+ for (ResolvedTypeReference *ref : std::as_const(resolvedTypes)) {
+ if (ref->type().typeId() == type)
+ return ref;
+ }
+ return nullptr;
+
+}
+
+int CompilationUnit::totalBindingsCount() const
+{
+ if (!icRootName)
+ return m_totalBindingsCount;
+ return inlineComponentData[*icRootName].totalBindingCount;
+}
+
+int CompilationUnit::totalObjectCount() const
+{
+ if (!icRootName)
+ return m_totalObjectCount;
+ return inlineComponentData[*icRootName].totalObjectCount;
+}
+
+template<typename F>
+void processInlinComponentType(
+ const QQmlType &type,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit,
+ F &&populateIcData)
+{
+ if (type.isInlineComponentType()) {
+ QString icRootName;
+ if (compilationUnit->icRootName) {
+ icRootName = type.elementName();
+ std::swap(*compilationUnit->icRootName, icRootName);
+ } else {
+ compilationUnit->icRootName = std::make_unique<QString>(type.elementName());
+ }
+
+ populateIcData();
+
+ if (icRootName.isEmpty())
+ compilationUnit->icRootName.reset();
+ else
+ std::swap(*compilationUnit->icRootName, icRootName);
+ } else {
+ populateIcData();
+ }
+}
+
+void CompiledData::CompilationUnit::finalizeCompositeType(const QQmlType &type)
+{
+ // Add to type registry of composites
+ if (propertyCaches.needsVMEMetaObject(/*root object*/0)) {
+ // qmlType is only valid for types that have references to themselves.
+ if (type.isValid()) {
+ qmlType = type;
+ } else {
+ qmlType = QQmlMetaType::findCompositeType(
+ finalUrl(), this, (unitData()->flags & CompiledData::Unit::IsSingleton)
+ ? QQmlMetaType::Singleton
+ : QQmlMetaType::NonSingleton);
+ }
+
+ QQmlMetaType::registerInternalCompositeType(this);
+ } else {
+ const QV4::CompiledData::Object *obj = objectAt(/*root object*/0);
+ auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
+ Q_ASSERT(typeRef);
+ if (const auto compilationUnit = typeRef->compilationUnit())
+ qmlType = compilationUnit->qmlType;
+ else
+ qmlType = typeRef->type();
+ }
+
+ // Collect some data for instantiation later.
+ using namespace icutils;
+ std::vector<QV4::CompiledData::InlineComponent> allICs {};
+ for (int i=0; i != objectCount(); ++i) {
+ const CompiledObject *obj = objectAt(i);
+ for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
+ allICs.push_back(*it);
+ }
+ }
+ NodeList nodes;
+ nodes.resize(allICs.size());
+ std::iota(nodes.begin(), nodes.end(), 0);
+ AdjacencyList adjacencyList;
+ adjacencyList.resize(nodes.size());
+ fillAdjacencyListForInlineComponents(this, adjacencyList, nodes, allICs);
+ bool hasCycle = false;
+ auto nodesSorted = topoSort(nodes, adjacencyList, hasCycle);
+ Q_ASSERT(!hasCycle); // would have already been discovered by qqmlpropertycachcecreator
+
+ // We need to first iterate over all inline components,
+ // as the containing component might create instances of them
+ // and in that case we need to add its object count
+ for (auto nodeIt = nodesSorted.rbegin(); nodeIt != nodesSorted.rend(); ++nodeIt) {
+ const auto &ic = allICs.at(nodeIt->index());
+ const int lastICRoot = ic.objectIndex;
+ for (int i = ic.objectIndex; i<objectCount(); ++i) {
+ const QV4::CompiledData::Object *obj = objectAt(i);
+ bool leftCurrentInlineComponent
+ = (i != lastICRoot
+ && obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot))
+ || !obj->hasFlag(QV4::CompiledData::Object::IsPartOfInlineComponent);
+ if (leftCurrentInlineComponent)
+ break;
+ const QString lastICRootName = stringAt(ic.nameIndex);
+ inlineComponentData[lastICRootName].totalBindingCount
+ += obj->nBindings;
+
+ if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
+ const auto type = typeRef->type();
+ if (type.isValid() && type.parserStatusCast() != -1)
+ ++inlineComponentData[lastICRootName].totalParserStatusCount;
+
+ ++inlineComponentData[lastICRootName].totalObjectCount;
+ if (const auto compilationUnit = typeRef->compilationUnit()) {
+ // if the type is an inline component type, we have to extract the information
+ // from it.
+ // This requires that inline components are visited in the correct order.
+ processInlinComponentType(type, compilationUnit, [&]() {
+ auto &icData = inlineComponentData[lastICRootName];
+ icData.totalBindingCount += compilationUnit->totalBindingsCount();
+ icData.totalParserStatusCount += compilationUnit->totalParserStatusCount();
+ icData.totalObjectCount += compilationUnit->totalObjectCount();
+ });
+ }
+ }
+ }
+ }
+ int bindingCount = 0;
+ int parserStatusCount = 0;
+ int objectCount = 0;
+ for (quint32 i = 0, count = this->objectCount(); i < count; ++i) {
+ const QV4::CompiledData::Object *obj = objectAt(i);
+ if (obj->hasFlag(QV4::CompiledData::Object::IsPartOfInlineComponent))
+ continue;
+
+ bindingCount += obj->nBindings;
+ if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
+ const auto type = typeRef->type();
+ if (type.isValid() && type.parserStatusCast() != -1)
+ ++parserStatusCount;
+ ++objectCount;
+ if (const auto compilationUnit = typeRef->compilationUnit()) {
+ processInlinComponentType(type, compilationUnit, [&](){
+ bindingCount += compilationUnit->totalBindingsCount();
+ parserStatusCount += compilationUnit->totalParserStatusCount();
+ objectCount += compilationUnit->totalObjectCount();
+ });
+ }
+ }
+ }
+
+ m_totalBindingsCount = bindingCount;
+ m_totalParserStatusCount = parserStatusCount;
+ m_totalObjectCount = objectCount;
+}
+
+int CompilationUnit::totalParserStatusCount() const
+{
+ if (!icRootName)
+ return m_totalParserStatusCount;
+ return inlineComponentData[*icRootName].totalParserStatusCount;
+}
+
+bool CompilationUnit::verifyChecksum(const DependentTypesHasher &dependencyHasher) const
+{
+ if (!dependencyHasher) {
+ for (size_t i = 0; i < sizeof(data->dependencyMD5Checksum); ++i) {
+ if (data->dependencyMD5Checksum[i] != 0)
+ return false;
+ }
+ return true;
+ }
+ const QByteArray checksum = dependencyHasher();
+ return checksum.size() == sizeof(data->dependencyMD5Checksum)
+ && memcmp(data->dependencyMD5Checksum, checksum.constData(),
+ sizeof(data->dependencyMD5Checksum)) == 0;
+}
+
+QQmlType CompilationUnit::qmlTypeForComponent(const QString &inlineComponentName) const
+{
+ if (inlineComponentName.isEmpty())
+ return qmlType;
+ return inlineComponentData[inlineComponentName].qmlType;
+}
+
+} // namespace CompiledData
+} // namespace QV4
+
+QT_END_NAMESPACE
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index 11de506a53..79df230872 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4COMPILEDDATA_P_H
#define QV4COMPILEDDATA_P_H
@@ -52,19 +16,31 @@
#include <functional>
-#include <QtCore/qstring.h>
+#include <QtCore/qcryptographichash.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qhashfunctions.h>
+#include <QtCore/qlocale.h>
#include <QtCore/qscopeguard.h>
-#include <QtCore/qvector.h>
+#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
-#include <QtCore/qhash.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qversionnumber.h>
#if QT_CONFIG(temporaryfile)
#include <QtCore/qsavefile.h>
#endif
#include <private/qendian_p.h>
+#include <private/qqmlnullablevalue_p.h>
+#include <private/qqmlpropertycachevector_p.h>
+#include <private/qqmlrefcount_p.h>
+#include <private/qqmltype_p.h>
+#include <private/qv4compilationunitmapper_p.h>
#include <private/qv4staticvalue_p.h>
+
#include <functional>
+#include <limits.h>
QT_BEGIN_NAMESPACE
@@ -75,12 +51,18 @@ QT_BEGIN_NAMESPACE
// Also change the comment behind the number to describe the latest change. This has the added
// benefit that if another patch changes the version too, it will result in a merge conflict, and
// not get removed silently.
-#define QV4_DATA_STRUCTURE_VERSION 0x26// support required properties
+#define QV4_DATA_STRUCTURE_VERSION 0x42 // Change metatype computation of AOT-compiled functions
class QIODevice;
class QQmlTypeNameCache;
class QQmlType;
class QQmlEngine;
+class QQmlPropertyData;
+class QQmlScriptData;
+
+namespace QQmlPrivate {
+struct AOTCompiledFunction;
+}
namespace QmlIR {
struct Document;
@@ -95,9 +77,19 @@ struct InternalClass;
struct Function;
class EvalISelFactory;
+class ResolvedTypeReference;
namespace CompiledData {
+// index is per-object binding index
+using BindingPropertyData = QVector<const QQmlPropertyData *>;
+
+// map from name index
+struct ResolvedTypeReferenceMap: public QHash<int, ResolvedTypeReference*>
+{
+ bool addToHash(QCryptographicHash *hash, QHash<quintptr, QByteArray> *checksums) const;
+};
+
struct String;
struct Function;
struct Lookup;
@@ -112,6 +104,7 @@ struct TableIterator
int index;
const ItemType *operator->() { return (container->*IndexedGetter)(index); }
+ ItemType operator*() {return *operator->();}
void operator++() { ++index; }
bool operator==(const TableIterator &rhs) const { return index == rhs.index; }
bool operator!=(const TableIterator &rhs) const { return index != rhs.index; }
@@ -119,18 +112,45 @@ struct TableIterator
struct Location
{
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 20> line;
- quint32_le_bitfield<20, 12> column;
- };
-
- Location() : _dummy(0) { }
+ Location() : m_data(QSpecialIntegerBitfieldZero) {}
+ Location(quint32 l, quint32 c) : Location()
+ {
+ m_data.set<LineField>(l);
+ m_data.set<ColumnField>(c);
+ Q_ASSERT(m_data.get<LineField>() == l);
+ Q_ASSERT(m_data.get<ColumnField>() == c);
+ }
inline bool operator<(const Location &other) const {
- return line < other.line ||
- (line == other.line && column < other.column);
+ return m_data.get<LineField>() < other.m_data.get<LineField>()
+ || (m_data.get<LineField>() == other.m_data.get<LineField>()
+ && m_data.get<ColumnField>() < other.m_data.get<ColumnField>());
+ }
+
+ friend size_t qHash(const Location &location, size_t seed = 0)
+ {
+ return QT_PREPEND_NAMESPACE(qHash)(location.m_data.data(), seed);
}
+
+ friend bool operator==(const Location &a, const Location &b)
+ {
+ return a.m_data.data()== b.m_data.data();
+ }
+
+ void set(quint32 line, quint32 column)
+ {
+ m_data.set<LineField>(line);
+ m_data.set<ColumnField>(column);
+ }
+
+ quint32 line() const { return m_data.get<LineField>(); }
+ quint32 column() const { return m_data.get<ColumnField>(); }
+
+private:
+ using LineField = quint32_le_bitfield_member<0, 20>;
+ using ColumnField = quint32_le_bitfield_member<20, 12>;
+
+ quint32_le_bitfield_union<LineField, ColumnField> m_data;
};
static_assert(sizeof(Location) == 4, "Location structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -141,16 +161,24 @@ struct RegExp
RegExp_Global = 0x01,
RegExp_IgnoreCase = 0x02,
RegExp_Multiline = 0x04,
- RegExp_Unicode = 0x08,
- RegExp_Sticky = 0x10
- };
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 5> flags;
- quint32_le_bitfield<5, 27> stringIndex;
+ RegExp_Sticky = 0x08,
+ RegExp_Unicode = 0x10,
};
- RegExp() : _dummy(0) { }
+ RegExp() : m_data(QSpecialIntegerBitfieldZero) {}
+ RegExp(quint32 flags, quint32 stringIndex) : RegExp()
+ {
+ m_data.set<FlagsField>(flags);
+ m_data.set<StringIndexField>(stringIndex);
+ }
+
+ quint32 flags() const { return m_data.get<FlagsField>(); }
+ quint32 stringIndex() const { return m_data.get<StringIndexField>(); }
+
+private:
+ using FlagsField = quint32_le_bitfield_member<0, 5>;
+ using StringIndexField = quint32_le_bitfield_member<5, 27>;
+ quint32_le_bitfield_union<FlagsField, StringIndexField> m_data;
};
static_assert(sizeof(RegExp) == 4, "RegExp structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -163,25 +191,49 @@ struct Lookup
Type_QmlContextPropertyGetter = 3
};
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 4> type_and_flags;
- quint32_le_bitfield<4, 28> nameIndex;
+ enum Mode : unsigned int {
+ Mode_ForStorage = 0,
+ Mode_ForCall = 1
};
- Lookup() : _dummy(0) { }
+ quint32 type() const { return m_data.get<TypeField>(); }
+ quint32 nameIndex() const { return m_data.get<NameIndexField>(); }
+ quint32 mode() const { return m_data.get<ModeField>(); }
+
+ Lookup() : m_data(QSpecialIntegerBitfieldZero) {}
+ Lookup(Type type, Mode mode, quint32 nameIndex) : Lookup()
+ {
+ m_data.set<TypeField>(type);
+ m_data.set<ModeField>(mode);
+ m_data.set<NameIndexField>(nameIndex);
+ }
+
+private:
+ using TypeField = quint32_le_bitfield_member<0, 2>;
+ using ModeField = quint32_le_bitfield_member<2, 1>;
+ // 1 bit left
+ using NameIndexField = quint32_le_bitfield_member<4, 28>;
+ quint32_le_bitfield_union<TypeField, ModeField, NameIndexField> m_data;
};
static_assert(sizeof(Lookup) == 4, "Lookup structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct JSClassMember
{
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 31> nameOffset;
- quint32_le_bitfield<31, 1> isAccessor;
- };
+ JSClassMember() : m_data(QSpecialIntegerBitfieldZero) {}
- JSClassMember() : _dummy(0) { }
+ void set(quint32 nameOffset, bool isAccessor)
+ {
+ m_data.set<NameOffsetField>(nameOffset);
+ m_data.set<IsAccessorField>(isAccessor ? 1 : 0);
+ }
+
+ quint32 nameOffset() const { return m_data.get<NameOffsetField>(); }
+ bool isAccessor() const { return m_data.get<IsAccessorField>() != 0; }
+
+private:
+ using NameOffsetField = quint32_le_bitfield_member<0, 31>;
+ using IsAccessorField = quint32_le_bitfield_member<31, 1>;
+ quint32_le_bitfield_union<NameOffsetField, IsAccessorField> m_data;
};
static_assert(sizeof(JSClassMember) == 4, "JSClassMember structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -194,45 +246,25 @@ struct JSClass
};
static_assert(sizeof(JSClass) == 4, "JSClass structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-// This data structure is intended to be binary compatible with QStringData/QStaticStringData on
-// 64-bit and 32-bit little-endian architectures, in all directions. So the same structure mapped
-// from a file must be castable to a QStringData regardless of the pointer size. With the first
-// few fields that's easy, they're always 32-bit. However the offset field of QArrayData is a
-// ptrdiff_t and thus variable in size.
-// On 64-bit systems compilers enforce an 8-byte alignment and thus place it at offset 16, while
-// on 32-bit systems offset 12 is sufficient. Therefore the two values don't overlap and contain
-// the same value.
struct String
{
- qint32_le refcount; // -1
qint32_le size;
- quint32_le allocAndCapacityReservedFlag; // 0
- quint32_le offsetOn32Bit;
- quint64_le offsetOn64Bit;
- // uint16 strdata[]
static int calculateSize(const QString &str) {
- return (sizeof(String) + (str.length() + 1) * sizeof(quint16) + 7) & ~0x7;
+ // we cannot enconuter strings larger than INT_MAX anyway, as such a string
+ // would already break in other parts of the compilation process
+ return (sizeof(String) + (int(str.size()) + 1) * sizeof(quint16) + 7) & ~0x7;
}
};
-static_assert(sizeof(String) == 24, "String structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
-
-// Ensure compatibility with QString
-static_assert(offsetof(QArrayData, ref) == offsetof(String, refcount), "refcount must be at the same location");
-static_assert(offsetof(QArrayData, size) == offsetof(String, size), "size must be at the same location");
-static_assert(offsetof(String, offsetOn64Bit) == 16, "offset must be at 8-byte aligned location");
-static_assert(offsetof(String, offsetOn32Bit) == 12, "offset must be at 4-byte aligned location");
-#if QT_POINTER_SIZE == 8
-static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn64Bit), "offset must be at the same location");
-#else
-static_assert(offsetof(QArrayData, offset) == offsetof(String, offsetOn32Bit), "offset must be at the same location");
-#endif
-struct CodeOffsetToLine {
+static_assert (sizeof (String) == 4, "String structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+
+struct CodeOffsetToLineAndStatement {
quint32_le codeOffset;
- quint32_le line;
+ qint32_le line; // signed because debug instructions get negative line numbers
+ quint32_le statement;
};
-static_assert(sizeof(CodeOffsetToLine) == 8, "CodeOffsetToLine 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(CodeOffsetToLineAndStatement) == 12, "CodeOffsetToLineAndStatement structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Block
{
@@ -256,19 +288,65 @@ 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
+enum class NamedBuiltin: unsigned int {
+ Void, Var, Int, Bool, Real, String, Url, DateTime, RegExp
+};
+
+enum class CommonType : unsigned int {
+ // Actual named builtins
+ Void = uint(NamedBuiltin::Void),
+ Var = uint(NamedBuiltin::Var),
+ Int = uint(NamedBuiltin::Int),
+ Bool = uint(NamedBuiltin::Bool),
+ Real = uint(NamedBuiltin::Real),
+ String = uint(NamedBuiltin::String),
+ Url = uint(NamedBuiltin::Url),
+ DateTime = uint(NamedBuiltin::DateTime),
+ RegExp = uint(NamedBuiltin::RegExp),
+
+ // Optimization for very common other types
+ Time, Date, Rect, Point, Size,
+
+ // No type specified or not recognized
+ Invalid
};
struct ParameterType
{
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 1> indexIsBuiltinType;
- quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType;
+ enum Flag {
+ NoFlag = 0x0,
+ Common = 0x1,
+ List = 0x2,
};
+ Q_DECLARE_FLAGS(Flags, Flag);
+
+ void set(Flags flags, quint32 typeNameIndexOrCommonType)
+ {
+ m_data.set<IsListField>(flags.testFlag(List) ? 1 : 0);
+ m_data.set<IndexIsCommonTypeField>(flags.testFlag(Common) ? 1 : 0);
+ m_data.set<TypeNameIndexOrCommonTypeField>(typeNameIndexOrCommonType);
+ }
+
+ bool indexIsCommonType() const
+ {
+ return m_data.get<IndexIsCommonTypeField>() != 0;
+ }
+
+ bool isList() const
+ {
+ return m_data.get<IsListField>() != 0;
+ }
+
+ quint32 typeNameIndexOrCommonType() const
+ {
+ return m_data.get<TypeNameIndexOrCommonTypeField>();
+ }
+
+private:
+ using IndexIsCommonTypeField = quint32_le_bitfield_member<0, 1>;
+ using IsListField = quint32_le_bitfield_member<1, 1>;
+ using TypeNameIndexOrCommonTypeField = quint32_le_bitfield_member<2, 30>;
+ quint32_le_bitfield_union<IndexIsCommonTypeField, IsListField, TypeNameIndexOrCommonTypeField> m_data;
};
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");
@@ -286,7 +364,8 @@ struct Function
enum Flags : unsigned int {
IsStrict = 0x1,
IsArrowFunction = 0x2,
- IsGenerator = 0x4
+ IsGenerator = 0x4,
+ IsClosureWrapper = 0x8,
};
// Absolute offset into file where the code for this function is located.
@@ -300,17 +379,22 @@ struct Function
ParameterType returnType;
quint32_le localsOffset;
quint16_le nLocals;
- quint16_le nLineNumbers;
- size_t lineNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); }
+ quint16_le nLineAndStatementNumbers;
+ size_t lineAndStatementNumberOffset() const { return localsOffset + nLocals * sizeof(quint32); }
quint32_le nestedFunctionIndex; // for functions that only return a single closure, used in signal handlers
+
+ quint32_le nRegisters;
+ Location location;
+ quint32_le nLabelInfos;
+
quint16_le sizeOfLocalTemporalDeadZone;
quint16_le firstTemporalDeadZoneRegister;
quint16_le sizeOfRegisterTemporalDeadZone;
- quint16_le nRegisters;
- Location location;
- quint32_le nLabelInfos;
- size_t labelInfosOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); }
+ size_t labelInfosOffset() const
+ {
+ return lineAndStatementNumberOffset() + nLineAndStatementNumbers * sizeof(CodeOffsetToLineAndStatement);
+ }
// Keep all unaligned data at the end
quint8 flags;
@@ -319,9 +403,21 @@ struct Function
// quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals]
- 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()); }
+ 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 CodeOffsetToLineAndStatement *lineAndStatementNumberTable() const
+ {
+ return reinterpret_cast<const CodeOffsetToLineAndStatement *>(
+ reinterpret_cast<const char *>(this) + lineAndStatementNumberOffset());
+ }
// --- QQmlPropertyCacheCreator interface
const Parameter *formalsBegin() const { return formalsTable(); }
@@ -332,9 +428,13 @@ 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 * sizeof(Parameter) + (nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32)
- + nLines*sizeof(CodeOffsetToLine);
+ static int calculateSize(
+ int nFormals, int nLocals, int nLinesAndStatements, int nInnerfunctions,
+ int labelInfoSize, int codeSize)
+ {
+ int trailingData = nFormals * sizeof(Parameter)
+ + (nLocals + nInnerfunctions + labelInfoSize) * sizeof (quint32)
+ + nLinesAndStatements * sizeof(CodeOffsetToLineAndStatement);
size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize);
Q_ASSERT(size < INT_MAX);
return int(size);
@@ -434,10 +534,11 @@ static_assert(sizeof(ImportEntry) == 16, "ImportEntry structure needs to have th
struct TranslationData
{
+ enum { NoContextIndex = std::numeric_limits<quint32>::max() };
quint32_le stringIndex;
quint32_le commentIndex;
qint32_le number;
- quint32_le padding;
+ quint32_le contextIndex;
};
static_assert(sizeof(TranslationData) == 16, "TranslationData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -445,7 +546,7 @@ struct Binding
{
quint32_le propertyNameIndex;
- enum ValueType : unsigned int {
+ enum Type : unsigned int {
Type_Invalid,
Type_Boolean,
Type_Number,
@@ -459,7 +560,7 @@ struct Binding
Type_GroupProperty
};
- enum Flags : unsigned int {
+ enum Flag : unsigned int {
IsSignalHandlerExpression = 0x1,
IsSignalHandlerObject = 0x2,
IsOnAssignment = 0x4,
@@ -469,13 +570,23 @@ struct Binding
IsBindingToAlias = 0x40,
IsDeferredBinding = 0x80,
IsCustomParserBinding = 0x100,
- IsFunctionExpression = 0x200
+ IsFunctionExpression = 0x200,
+ IsPropertyObserver = 0x400
};
+ Q_DECLARE_FLAGS(Flags, Flag);
+
+ using FlagsField = quint32_le_bitfield_member<0, 16>;
+ using TypeField = quint32_le_bitfield_member<16, 16>;
+ quint32_le_bitfield_union<FlagsField, TypeField> flagsAndType;
+
+ void clearFlags() { flagsAndType.set<FlagsField>(0); }
+ void setFlag(Flag flag) { flagsAndType.set<FlagsField>(flagsAndType.get<FlagsField>() | flag); }
+ bool hasFlag(Flag flag) const { return Flags(flagsAndType.get<FlagsField>()) & flag; }
+ Flags flags() const { return Flags(flagsAndType.get<FlagsField>()); }
+
+ void setType(Type type) { flagsAndType.set<TypeField>(type); }
+ Type type() const { return Type(flagsAndType.get<TypeField>()); }
- union {
- quint32_le_bitfield<0, 16> flags;
- quint32_le_bitfield<16, 16> type;
- };
union {
bool b;
quint32_le constantValueIndex;
@@ -489,23 +600,31 @@ struct Binding
Location location;
Location valueLocation;
+ bool hasSignalHandlerBindingFlag() const
+ {
+ const Flags bindingFlags = flags();
+ return bindingFlags & IsSignalHandlerExpression
+ || bindingFlags & IsSignalHandlerObject
+ || bindingFlags & IsPropertyObserver;
+ }
+
bool isValueBinding() const
{
- if (type == Type_AttachedProperty
- || type == Type_GroupProperty)
+ switch (type()) {
+ case Type_AttachedProperty:
+ case Type_GroupProperty:
return false;
- if (flags & IsSignalHandlerExpression
- || flags & IsSignalHandlerObject)
- return false;
- return true;
+ default:
+ return !hasSignalHandlerBindingFlag();
+ }
}
- bool isValueBindingNoAlias() const { return isValueBinding() && !(flags & IsBindingToAlias); }
- bool isValueBindingToAlias() const { return isValueBinding() && (flags & IsBindingToAlias); }
+ bool isValueBindingNoAlias() const { return isValueBinding() && !hasFlag(IsBindingToAlias); }
+ bool isValueBindingToAlias() const { return isValueBinding() && hasFlag(IsBindingToAlias); }
bool isSignalHandler() const
{
- if (flags & IsSignalHandlerExpression || flags & IsSignalHandlerObject) {
+ if (hasSignalHandlerBindingFlag()) {
Q_ASSERT(!isValueBinding());
Q_ASSERT(!isAttachedProperty());
Q_ASSERT(!isGroupProperty());
@@ -516,7 +635,7 @@ struct Binding
bool isAttachedProperty() const
{
- if (type == Type_AttachedProperty) {
+ if (type() == Type_AttachedProperty) {
Q_ASSERT(!isValueBinding());
Q_ASSERT(!isSignalHandler());
Q_ASSERT(!isGroupProperty());
@@ -527,7 +646,7 @@ struct Binding
bool isGroupProperty() const
{
- if (type == Type_GroupProperty) {
+ if (type() == Type_GroupProperty) {
Q_ASSERT(!isValueBinding());
Q_ASSERT(!isSignalHandler());
Q_ASSERT(!isAttachedProperty());
@@ -536,13 +655,13 @@ struct Binding
return false;
}
- bool isFunctionExpression() const { return (flags & IsFunctionExpression); }
+ bool isFunctionExpression() const { return hasFlag(IsFunctionExpression); }
//reverse of Lexer::singleEscape()
static QString escapedString(const QString &string)
{
QString tmp = QLatin1String("\"");
- for (int i = 0; i < string.length(); ++i) {
+ for (int i = 0; i < string.size(); ++i) {
const QChar &c = string.at(i);
switch (c.unicode()) {
case 0x08:
@@ -581,20 +700,34 @@ struct Binding
return tmp;
}
- bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; }
- bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); }
+ bool isTranslationBinding() const
+ {
+ const Binding::Type bindingType = type();
+ return bindingType == Type_Translation || bindingType == Type_TranslationById;
+ }
+ bool evaluatesToString() const { return type() == Type_String || isTranslationBinding(); }
+
+ bool isNumberBinding() const { return type() == Type_Number; }
bool valueAsBoolean() const
{
- if (type == Type_Boolean)
+ if (type() == Type_Boolean)
return value.b;
return false;
}
-
};
static_assert(sizeof(Binding) == 24, "Binding structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+struct InlineComponent
+{
+ quint32_le objectIndex;
+ quint32_le nameIndex;
+ Location location;
+};
+
+static_assert(sizeof(InlineComponent) == 12, "InlineComponent structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+
struct EnumValue
{
quint32_le nameIndex;
@@ -654,50 +787,89 @@ static_assert(sizeof(Signal) == 12, "Signal structure needs to have the expected
struct Property
{
- quint32_le nameIndex;
- union {
- quint32_le_bitfield<0, 28> builtinTypeOrTypeNameIndex;
- quint32_le_bitfield<28, 1> isRequired;
- quint32_le_bitfield<29, 1> isBuiltinType;
- quint32_le_bitfield<30, 1> isList;
- quint32_le_bitfield<31, 1> isReadOnly;
- };
+private:
+ using CommonTypeOrTypeNameIndexField = quint32_le_bitfield_member<0, 28>;
+ using IsRequiredField = quint32_le_bitfield_member<28, 1>;
+ using IsCommonTypeField = quint32_le_bitfield_member<29, 1>;
+ using IsListField = quint32_le_bitfield_member<30, 1>;
+ using IsReadOnlyField = quint32_le_bitfield_member<31, 1>;
+public:
+ quint32_le nameIndex;
+ quint32_le_bitfield_union<
+ CommonTypeOrTypeNameIndexField,
+ IsRequiredField,
+ IsCommonTypeField,
+ IsListField,
+ IsReadOnlyField> data;
Location location;
- void setBuiltinType(BuiltinType t)
+ void setCommonType(CommonType t)
{
- builtinTypeOrTypeNameIndex = static_cast<quint32>(t);
- isBuiltinType = true;
+ data.set<CommonTypeOrTypeNameIndexField>(static_cast<quint32>(t));
+ data.set<IsCommonTypeField>(true);
}
- BuiltinType builtinType() const {
- if (isBuiltinType)
- return static_cast<BuiltinType>(quint32(builtinTypeOrTypeNameIndex));
- return BuiltinType::InvalidBuiltin;
+
+ CommonType commonType() const {
+ if (data.get<IsCommonTypeField>() != 0)
+ return CommonType(data.get<CommonTypeOrTypeNameIndexField>());
+ return CommonType::Invalid;
+ }
+
+ void setTypeNameIndex(int nameIndex)
+ {
+ data.set<CommonTypeOrTypeNameIndexField>(nameIndex);
+ data.set<IsCommonTypeField>(false);
}
- void setCustomType(int nameIndex)
+
+ int typeNameIndex() const
{
- builtinTypeOrTypeNameIndex = nameIndex;
- isBuiltinType = false;
+ return data.get<IsCommonTypeField>() ? -1 : data.get<CommonTypeOrTypeNameIndexField>();
}
+
+ bool isCommonType() const { return data.get<IsCommonTypeField>(); }
+ uint commonTypeOrTypeNameIndex() const { return data.get<CommonTypeOrTypeNameIndexField>(); }
+
+ bool isList() const { return data.get<IsListField>(); }
+ void setIsList(bool isList) { data.set<IsListField>(isList); }
+
+ bool isRequired() const { return data.get<IsRequiredField>(); }
+ void setIsRequired(bool isRequired) { data.set<IsRequiredField>(isRequired); }
+
+ bool isReadOnly() const { return data.get<IsReadOnlyField>(); }
+ void setIsReadOnly(bool isReadOnly) { data.set<IsReadOnlyField>(isReadOnly); }
};
static_assert(sizeof(Property) == 12, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+struct RequiredPropertyExtraData {
+ quint32_le nameIndex;
+};
+
+static_assert (sizeof(RequiredPropertyExtraData) == 4, "RequiredPropertyExtraData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+
struct Alias {
- enum Flags : unsigned int {
+private:
+ using NameIndexField = quint32_le_bitfield_member<0, 29>;
+ using FlagsField = quint32_le_bitfield_member<29, 3>;
+
+ // object id index (in QQmlContextData::idValues)
+ using TargetObjectIdField = quint32_le_bitfield_member<0, 31>;
+ using AliasToLocalAliasField = quint32_le_bitfield_member<31, 1>;
+ using IdIndexField = quint32_le_bitfield_member<0, 32>;
+
+public:
+
+ enum Flag : unsigned int {
IsReadOnly = 0x1,
Resolved = 0x2,
AliasPointsToPointerObject = 0x4
};
- union {
- quint32_le_bitfield<0, 29> nameIndex;
- quint32_le_bitfield<29, 3> flags;
- };
- union {
- quint32_le idIndex; // string index
- quint32_le_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues)
- quint32_le_bitfield<31, 1> aliasToLocalAlias;
- };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ quint32_le_bitfield_union<NameIndexField, FlagsField> nameIndexAndFlags;
+ quint32_le_bitfield_union<IdIndexField, TargetObjectIdField, AliasToLocalAliasField>
+ idIndexAndTargetObjectIdAndAliasToLocalAlias;
+
union {
quint32_le propertyNameIndex; // string index
qint32_le encodedMetaPropertyIndex;
@@ -706,32 +878,94 @@ struct Alias {
Location location;
Location referenceLocation;
- bool isObjectAlias() const {
- Q_ASSERT(flags & Resolved);
+ bool hasFlag(Flag flag) const
+ {
+ return nameIndexAndFlags.get<FlagsField>() & flag;
+ }
+
+ void setFlag(Flag flag)
+ {
+ nameIndexAndFlags.set<FlagsField>(nameIndexAndFlags.get<FlagsField>() | flag);
+ }
+
+ void clearFlags()
+ {
+ nameIndexAndFlags.set<FlagsField>(0);
+ }
+
+ quint32 nameIndex() const
+ {
+ return nameIndexAndFlags.get<NameIndexField>();
+ }
+
+ void setNameIndex(quint32 nameIndex)
+ {
+ nameIndexAndFlags.set<NameIndexField>(nameIndex);
+ }
+
+ bool isObjectAlias() const
+ {
+ Q_ASSERT(hasFlag(Resolved));
return encodedMetaPropertyIndex == -1;
}
+
+ quint32 idIndex() const
+ {
+ return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<IdIndexField>();
+ }
+
+ void setIdIndex(quint32 idIndex)
+ {
+ idIndexAndTargetObjectIdAndAliasToLocalAlias.set<IdIndexField>(idIndex);
+ }
+
+
+ bool isAliasToLocalAlias() const
+ {
+ return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<AliasToLocalAliasField>();
+ }
+
+ void setIsAliasToLocalAlias(bool isAliasToLocalAlias)
+ {
+ idIndexAndTargetObjectIdAndAliasToLocalAlias.set<AliasToLocalAliasField>(isAliasToLocalAlias);
+ }
+
+ quint32 targetObjectId() const
+ {
+ return idIndexAndTargetObjectIdAndAliasToLocalAlias.get<TargetObjectIdField>();
+ }
+
+ void setTargetObjectId(quint32 targetObjectId)
+ {
+ idIndexAndTargetObjectIdAndAliasToLocalAlias.set<TargetObjectIdField>(targetObjectId);
+ }
};
static_assert(sizeof(Alias) == 20, "Alias structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Object
{
- enum Flags : unsigned int {
+private:
+ using FlagsField = quint32_le_bitfield_member<0, 15>;
+ using DefaultPropertyIsAliasField = quint32_le_bitfield_member<15, 1>;
+ using IdField = quint32_le_bitfield_member<16, 16, qint32>;
+public:
+ enum Flag : unsigned int {
NoFlag = 0x0,
IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
HasDeferredBindings = 0x2, // any of the bindings are deferred
- HasCustomParserBindings = 0x4
+ HasCustomParserBindings = 0x4,
+ IsInlineComponentRoot = 0x8,
+ IsPartOfInlineComponent = 0x10
};
+ Q_DECLARE_FLAGS(Flags, Flag);
// Depending on the use, this may be the type name to instantiate before instantiating this
// object. For grouped properties the type name will be empty and for attached properties
// it will be the name of the attached type.
quint32_le inheritedTypeNameIndex;
quint32_le idNameIndex;
- union {
- quint32_le_bitfield<0, 15> flags;
- quint32_le_bitfield<15, 1> defaultPropertyIsAlias;
- qint32_le_bitfield<16, 16> id;
- };
+ quint32_le_bitfield_union<FlagsField, DefaultPropertyIsAliasField, IdField>
+ flagsAndDefaultPropertyIsAliasAndId;
qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
quint16_le nFunctions;
quint16_le nProperties;
@@ -749,12 +983,60 @@ struct Object
quint32_le offsetToNamedObjectsInComponent;
Location location;
Location locationOfIdProperty;
+ quint32_le offsetToInlineComponents;
+ quint16_le nInlineComponents;
+ quint32_le offsetToRequiredPropertyExtraData;
+ quint16_le nRequiredPropertyExtraData;
// Function[]
// Property[]
// Signal[]
// Binding[]
+// InlineComponent[]
+// RequiredPropertyExtraData[]
+
+ Flags flags() const
+ {
+ return Flags(flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>());
+ }
+
+ bool hasFlag(Flag flag) const
+ {
+ return flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() & flag;
+ }
+
+ void setFlag(Flag flag)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(
+ flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() | flag);
+ }
- static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent)
+ void setFlags(Flags flags)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(flags);
+ }
+
+ bool hasAliasAsDefaultProperty() const
+ {
+ return flagsAndDefaultPropertyIsAliasAndId.get<DefaultPropertyIsAliasField>();
+ }
+
+ void setHasAliasAsDefaultProperty(bool defaultAlias)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<DefaultPropertyIsAliasField>(defaultAlias);
+ }
+
+ qint32 objectId() const
+ {
+ return flagsAndDefaultPropertyIsAliasAndId.get<IdField>();
+ }
+
+ void setObjectId(qint32 id)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<IdField>(id);
+ }
+
+
+ static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int nRequiredPropertyExtraData)
{
return ( sizeof(Object)
+ nFunctions * sizeof(quint32)
@@ -764,6 +1046,8 @@ struct Object
+ nSignals * sizeof(quint32)
+ nBindings * sizeof(Binding)
+ nNamedObjectsInComponent * sizeof(int)
+ + nInlineComponents * sizeof(InlineComponent)
+ + nRequiredPropertyExtraData * sizeof(RequiredPropertyExtraData)
+ 0x7
) & ~0x7;
}
@@ -802,11 +1086,31 @@ struct Object
return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
}
+ const InlineComponent *inlineComponentAt(int idx) const
+ {
+ return inlineComponentTable() + idx;
+ }
+
const quint32_le *namedObjectsInComponentTable() const
{
return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
}
+ const InlineComponent *inlineComponentTable() const
+ {
+ return reinterpret_cast<const InlineComponent*>(reinterpret_cast<const char *>(this) + offsetToInlineComponents);
+ }
+
+ const RequiredPropertyExtraData *requiredPropertyExtraDataAt(int idx) const
+ {
+ return requiredPropertyExtraDataTable() + idx;
+ }
+
+ const RequiredPropertyExtraData *requiredPropertyExtraDataTable() const
+ {
+ return reinterpret_cast<const RequiredPropertyExtraData*>(reinterpret_cast<const char *>(this) + offsetToRequiredPropertyExtraData);
+ }
+
// --- QQmlPropertyCacheCreator interface
int propertyCount() const { return nProperties; }
int aliasCount() const { return nAliases; }
@@ -816,6 +1120,7 @@ struct Object
const Binding *bindingsBegin() const { return bindingTable(); }
const Binding *bindingsEnd() const { return bindingTable() + nBindings; }
+ int bindingCount() const { return nBindings; }
const Property *propertiesBegin() const { return propertyTable(); }
const Property *propertiesEnd() const { return propertyTable() + nProperties; }
@@ -831,31 +1136,42 @@ struct Object
SignalIterator signalsBegin() const { return SignalIterator(this, 0); }
SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); }
+ typedef TableIterator<InlineComponent, Object, &Object::inlineComponentAt> InlineComponentIterator;
+ InlineComponentIterator inlineComponentsBegin() const {return InlineComponentIterator(this, 0);}
+ InlineComponentIterator inlineComponentsEnd() const {return InlineComponentIterator(this, nInlineComponents);}
+
+ typedef TableIterator<RequiredPropertyExtraData, Object, &Object::requiredPropertyExtraDataAt> RequiredPropertyExtraDataIterator;
+ RequiredPropertyExtraDataIterator requiredPropertyExtraDataBegin() const {return RequiredPropertyExtraDataIterator(this, 0); }
+ RequiredPropertyExtraDataIterator requiredPropertyExtraDataEnd() const {return RequiredPropertyExtraDataIterator(this, nRequiredPropertyExtraData); }
+
int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
// ---
};
-static_assert(sizeof(Object) == 68, "Object 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(Object) == 84, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Import
{
enum ImportType : unsigned int {
ImportLibrary = 0x1,
ImportFile = 0x2,
- ImportScript = 0x3
+ ImportScript = 0x3,
+ ImportInlineComponent = 0x4
};
quint32_le type;
quint32_le uriIndex;
quint32_le qualifierIndex;
- qint32_le majorVersion;
- qint32_le minorVersion;
-
Location location;
+ QTypeRevision version;
+ quint16_le reserved;
- Import() { type = 0; uriIndex = 0; qualifierIndex = 0; majorVersion = 0; minorVersion = 0; }
+ Import()
+ {
+ type = 0; uriIndex = 0; qualifierIndex = 0; version = QTypeRevision::zero(); reserved = 0;
+ }
};
-static_assert(sizeof(Import) == 24, "Import 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(Import) == 20, "Import structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct QmlUnit
{
@@ -900,7 +1216,17 @@ struct Unit
IsSingleton = 0x4,
IsSharedLibrary = 0x8, // .pragma shared?
IsESModule = 0x10,
- PendingTypeCompilation = 0x20 // the QML data structures present are incomplete and require type compilation
+ PendingTypeCompilation = 0x20, // the QML data structures present are incomplete and require type compilation
+ IsStrict = 0x40,
+ ListPropertyAssignReplaceIfDefault = 0x80,
+ ListPropertyAssignReplaceIfNotDefault = 0x100,
+ ListPropertyAssignReplace
+ = ListPropertyAssignReplaceIfDefault | ListPropertyAssignReplaceIfNotDefault,
+ ComponentsBound = 0x200,
+ FunctionSignaturesIgnored = 0x400,
+ NativeMethodsAcceptThisObject = 0x800,
+ ValueTypesCopied = 0x1000,
+ ValueTypesAddressable = 0x2000,
};
quint32_le flags;
quint32_le stringTableSize;
@@ -954,19 +1280,18 @@ struct Unit
}
/* end QML specific fields*/
- QString stringAtInternal(int idx) const {
- Q_ASSERT(idx < int(stringTableSize));
+ QString stringAtInternal(uint idx) const {
+ Q_ASSERT(idx < stringTableSize);
const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
const quint32_le offset = offsetTable[idx];
const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
+ Q_ASSERT(str->size >= 0);
if (str->size == 0)
return QString();
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- if (flags & StaticData) {
- const QStringDataPtr holder = { const_cast<QStringData *>(reinterpret_cast<const QStringData*>(str)) };
- return QString(holder);
- }
const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
+ if (flags & StaticData)
+ return QString::fromRawData(characters, str->size);
return QString(characters, str->size);
#else
const quint16_le *characters = reinterpret_cast<const quint16_le *>(str + 1);
@@ -1028,12 +1353,28 @@ struct Unit
return reinterpret_cast<const TranslationData *>(reinterpret_cast<const char *>(this) + offsetToTranslationTable);
}
+ const quint32_le *translationContextIndex() const{
+ if ( translationTableSize == 0)
+ return nullptr;
+ return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this))
+ + offsetToTranslationTable
+ + translationTableSize * sizeof(CompiledData::TranslationData)); }
+
+ quint32_le *translationContextIndex() {
+ if ( translationTableSize == 0)
+ return nullptr;
+ return reinterpret_cast<quint32_le*>((reinterpret_cast<char *>(this))
+ + offsetToTranslationTable
+ + translationTableSize * sizeof(CompiledData::TranslationData)); }
+
const ImportEntry *importEntryTable() const { return reinterpret_cast<const ImportEntry *>(reinterpret_cast<const char *>(this) + offsetToImportEntryTable); }
const ExportEntry *localExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToLocalExportEntryTable); }
const ExportEntry *indirectExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToIndirectExportEntryTable); }
const ExportEntry *starExportEntryTable() const { return reinterpret_cast<const ExportEntry *>(reinterpret_cast<const char *>(this) + offsetToStarExportEntryTable); }
const quint32_le *moduleRequestTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToModuleRequestTable); }
+
+ bool verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const;
};
static_assert(sizeof(Unit) == 248, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -1070,20 +1411,26 @@ struct TypeReferenceMap : QHash<int, TypeReference>
}
auto prop = obj->propertiesBegin();
- auto propEnd = obj->propertiesEnd();
+ auto const propEnd = obj->propertiesEnd();
for ( ; prop != propEnd; ++prop) {
- if (!prop->isBuiltinType) {
- TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex, prop->location);
+ if (!prop->isCommonType()) {
+ TypeReference &r = this->add(prop->commonTypeOrTypeNameIndex(), prop->location);
r.errorWhenNotFound = true;
}
}
auto binding = obj->bindingsBegin();
- auto bindingEnd = obj->bindingsEnd();
+ auto const bindingEnd = obj->bindingsEnd();
for ( ; binding != bindingEnd; ++binding) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
+ if (binding->type() == QV4::CompiledData::Binding::Type_AttachedProperty)
this->add(binding->propertyNameIndex, binding->location);
}
+
+ auto ic = obj->inlineComponentsBegin();
+ auto const icEnd = obj->inlineComponentsEnd();
+ for (; ic != icEnd; ++ic) {
+ this->add(ic->nameIndex, ic->location);
+ }
}
template <typename Iterator>
@@ -1096,110 +1443,93 @@ struct TypeReferenceMap : QHash<int, TypeReference>
using DependentTypesHasher = std::function<QByteArray()>;
-// This is how this hooks into the existing structures:
-
-struct CompilationUnitBase
-{
- Q_DISABLE_COPY(CompilationUnitBase)
-
- CompilationUnitBase() = default;
- ~CompilationUnitBase() = default;
-
- CompilationUnitBase(CompilationUnitBase &&other) noexcept { *this = std::move(other); }
-
- CompilationUnitBase &operator=(CompilationUnitBase &&other) noexcept
- {
- if (this != &other) {
- runtimeStrings = other.runtimeStrings;
- other.runtimeStrings = nullptr;
- constants = other.constants;
- other.constants = nullptr;
- runtimeRegularExpressions = other.runtimeRegularExpressions;
- other.runtimeRegularExpressions = nullptr;
- runtimeClasses = other.runtimeClasses;
- other.runtimeClasses = nullptr;
- imports = other.imports;
- other.imports = nullptr;
- }
- return *this;
- }
+struct InlineComponentData {
+
+ InlineComponentData() = default;
+ InlineComponentData(
+ const QQmlType &qmlType, int objectIndex, int nameIndex, int totalObjectCount,
+ int totalBindingCount, int totalParserStatusCount)
+ : qmlType(qmlType)
+ , objectIndex(objectIndex)
+ , nameIndex(nameIndex)
+ , totalObjectCount(totalObjectCount)
+ , totalBindingCount(totalBindingCount)
+ , totalParserStatusCount(totalParserStatusCount)
+ {}
- // pointers either to data->constants() or little-endian memory copy.
- Heap::String **runtimeStrings = nullptr; // Array
- const StaticValue* constants = nullptr;
- QV4::StaticValue *runtimeRegularExpressions = nullptr;
- Heap::InternalClass **runtimeClasses = nullptr;
- const StaticValue** imports = nullptr;
+ QQmlType qmlType;
+ int objectIndex = -1;
+ int nameIndex = -1;
+ int totalObjectCount = 0;
+ int totalBindingCount = 0;
+ int totalParserStatusCount = 0;
};
-Q_STATIC_ASSERT(std::is_standard_layout<CompilationUnitBase>::value);
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeStrings) == 0);
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, constants) == sizeof(QV4::Heap::String **));
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offsetof(CompilationUnitBase, constants) + sizeof(const StaticValue *));
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const StaticValue *));
-Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const StaticValue *));
-
-struct CompilationUnit : public CompilationUnitBase
+struct CompilationUnit final : public QQmlRefCounted<CompilationUnit>
{
- Q_DISABLE_COPY(CompilationUnit)
+ Q_DISABLE_COPY_MOVE(CompilationUnit)
const Unit *data = nullptr;
const QmlUnit *qmlData = nullptr;
QStringList dynamicStrings;
-public:
- using CompiledObject = CompiledData::Object;
+ const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions = nullptr;
- CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(),
- const QString &finalUrlString = QString())
- {
- setUnitData(unitData, nullptr, fileName, finalUrlString);
- }
+ // pointers either to data->constants() or little-endian memory copy.
+ const StaticValue *constants = nullptr;
- ~CompilationUnit()
- {
- if (data) {
- if (data->qmlUnit() != qmlData)
- free(const_cast<QmlUnit *>(qmlData));
- qmlData = nullptr;
+ std::unique_ptr<CompilationUnitMapper> backingFile;
- if (!(data->flags & QV4::CompiledData::Unit::StaticData))
- free(const_cast<Unit *>(data));
- }
- data = nullptr;
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- delete [] constants;
- constants = nullptr;
-#endif
+ int m_totalBindingsCount = 0; // Number of bindings used in this type
+ int m_totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
+ int m_totalObjectCount = 0; // Number of objects explicitly instantiated
- delete [] imports;
- imports = nullptr;
- }
+ std::unique_ptr<QString> icRootName;
+ QHash<QString, InlineComponentData> inlineComponentData;
+
+ // index is object index. This allows fast access to the
+ // property data when initializing bindings, avoiding expensive
+ // lookups by string (property name).
+ QVector<BindingPropertyData> bindingPropertyDataPerObject;
- CompilationUnit(CompilationUnit &&other) noexcept
+ ResolvedTypeReferenceMap resolvedTypes;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
+
+ QQmlPropertyCacheVector propertyCaches;
+
+ QQmlType qmlType;
+
+ QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts;
+
+public:
+ // --- interface for QQmlPropertyCacheCreator
+ using CompiledObject = const CompiledData::Object;
+ using CompiledFunction = const CompiledData::Function;
+ using CompiledBinding = const CompiledData::Binding;
+
+ // Empty dummy. We don't need to do this when loading from cache.
+ class IdToObjectMap
{
- *this = std::move(other);
- }
+ public:
+ void insert(int, int) {}
+ void clear() {}
+
+ // We have already checked uniqueness of IDs when creating the CU
+ bool contains(int) { return false; }
+ };
- CompilationUnit &operator=(CompilationUnit &&other) noexcept
+ explicit CompilationUnit(const Unit *unitData, const QQmlPrivate::AOTCompiledFunction *aotCompiledFunctions,
+ const QString &fileName = QString(), const QString &finalUrlString = QString())
+ : CompilationUnit(unitData, fileName, finalUrlString)
{
- if (this != &other) {
- data = other.data;
- other.data = nullptr;
- qmlData = other.qmlData;
- other.qmlData = nullptr;
- dynamicStrings = std::move(other.dynamicStrings);
- other.dynamicStrings.clear();
- m_fileName = std::move(other.m_fileName);
- other.m_fileName.clear();
- m_finalUrlString = std::move(other.m_finalUrlString);
- other.m_finalUrlString.clear();
- m_module = other.m_module;
- other.m_module = nullptr;
- CompilationUnitBase::operator=(std::move(other));
- }
- return *this;
+ this->aotCompiledFunctions = aotCompiledFunctions;
}
+ Q_QML_EXPORT CompilationUnit(
+ const Unit *unitData = nullptr, const QString &fileName = QString(),
+ const QString &finalUrlString = QString());
+
+ Q_QML_EXPORT ~CompilationUnit();
+
const Unit *unitData() const { return data; }
void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr,
@@ -1232,24 +1562,202 @@ public:
m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex);
}
- QString stringAt(int index) const
+ QString stringAt(uint index) const
{
- if (uint(index) >= data->stringTableSize)
- return dynamicStrings.at(index - data->stringTableSize);
- return data->stringAtInternal(index);
+ if (index < data->stringTableSize)
+ return data->stringAtInternal(index);
+
+ const qsizetype dynamicIndex = index - data->stringTableSize;
+ Q_ASSERT(dynamicIndex < dynamicStrings.size());
+ return dynamicStrings.at(dynamicIndex);
}
QString fileName() const { return m_fileName; }
QString finalUrlString() const { return m_finalUrlString; }
- Heap::Module *module() const { return m_module; }
- void setModule(Heap::Module *module) { m_module = module; }
+ QString bindingValueAsString(const CompiledData::Binding *binding) const
+ {
+ using namespace CompiledData;
+ switch (binding->type()) {
+ case Binding::Type_Script:
+ case Binding::Type_String:
+ return stringAt(binding->stringIndex);
+ case Binding::Type_Null:
+ return QStringLiteral("null");
+ case Binding::Type_Boolean:
+ return binding->value.b ? QStringLiteral("true") : QStringLiteral("false");
+ case Binding::Type_Number:
+ return QString::number(bindingValueAsNumber(binding), 'g', QLocale::FloatingPointShortest);
+ case Binding::Type_Invalid:
+ return QString();
+ case Binding::Type_TranslationById:
+ case Binding::Type_Translation:
+ return stringAt(data->translations()[binding->value.translationDataIndex].stringIndex);
+ default:
+ break;
+ }
+ return QString();
+ }
+
+ QString bindingValueAsScriptString(const CompiledData::Binding *binding) const
+ {
+ return (binding->type() == CompiledData::Binding::Type_String)
+ ? CompiledData::Binding::escapedString(stringAt(binding->stringIndex))
+ : bindingValueAsString(binding);
+ }
+
+ double bindingValueAsNumber(const CompiledData::Binding *binding) const
+ {
+ if (binding->type() != CompiledData::Binding::Type_Number)
+ return 0.0;
+ return constants[binding->value.constantValueIndex].doubleValue();
+ }
+
+ Q_QML_EXPORT static QString localCacheFilePath(const QUrl &url);
+ Q_QML_EXPORT bool loadFromDisk(
+ const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString);
+ Q_QML_EXPORT bool saveToDisk(const QUrl &unitUrl, QString *errorString);
+
+ int importCount() const { return qmlData->nImports; }
+ const CompiledData::Import *importAt(int index) const { return qmlData->importAt(index); }
+
+ Q_QML_EXPORT QStringList moduleRequests() const;
+
+ // url() and fileName() shall be used to load the actual QML/JS code or to show errors or
+ // warnings about that code. They include any potential URL interceptions and thus represent the
+ // "physical" location of the code.
+ //
+ // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code
+ // They are _not_ intercepted and thus represent the "logical" name for the code.
+
+ QUrl url() const
+ {
+ if (!m_url.isValid())
+ m_url = QUrl(fileName());
+ return m_url;
+ }
+
+ QUrl finalUrl() const
+ {
+ if (!m_finalUrl.isValid())
+ m_finalUrl = QUrl(finalUrlString());
+ return m_finalUrl;
+ }
+
+ ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); }
+ ResolvedTypeReference *resolvedType(QMetaType type) const;
+
+ QQmlPropertyCache::ConstPtr rootPropertyCache() const
+ {
+ return propertyCaches.at(/*root object*/0);
+ }
+
+ int objectCount() const { return qmlData->nObjects; }
+ const CompiledObject *objectAt(int index) const { return qmlData->objectAt(index); }
+
+ int totalBindingsCount() const;
+ int totalParserStatusCount() const;
+ int totalObjectCount() const;
+
+ int inlineComponentId(const QString &inlineComponentName) const
+ {
+ for (uint i = 0; i < qmlData->nObjects; ++i) {
+ auto *object = qmlData->objectAt(i);
+ for (auto it = object->inlineComponentsBegin(), end = object->inlineComponentsEnd();
+ it != end; ++it) {
+ if (stringAt(it->nameIndex) == inlineComponentName)
+ return it->objectIndex;
+ }
+ }
+ return -1;
+ }
+
+ void finalizeCompositeType(const QQmlType &type);
+
+ bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
+
+ enum class ListPropertyAssignBehavior { Append, Replace, ReplaceIfNotDefault };
+ ListPropertyAssignBehavior listPropertyAssignBehavior() const
+ {
+ if (unitData()->flags & CompiledData::Unit::ListPropertyAssignReplace)
+ return ListPropertyAssignBehavior::Replace;
+ if (unitData()->flags & CompiledData::Unit::ListPropertyAssignReplaceIfNotDefault)
+ return ListPropertyAssignBehavior::ReplaceIfNotDefault;
+ return ListPropertyAssignBehavior::Append;
+ }
+
+ bool ignoresFunctionSignature() const
+ {
+ return unitData()->flags & CompiledData::Unit::FunctionSignaturesIgnored;
+ }
+
+ bool nativeMethodsAcceptThisObjects() const
+ {
+ return unitData()->flags & CompiledData::Unit::NativeMethodsAcceptThisObject;
+ }
+
+ bool valueTypesAreCopied() const
+ {
+ return unitData()->flags & CompiledData::Unit::ValueTypesCopied;
+ }
+
+ bool valueTypesAreAddressable() const
+ {
+ return unitData()->flags & CompiledData::Unit::ValueTypesAddressable;
+ }
+
+ bool componentsAreBound() const
+ {
+ return unitData()->flags & CompiledData::Unit::ComponentsBound;
+ }
+
+ bool isESModule() const
+ {
+ return unitData()->flags & CompiledData::Unit::IsESModule;
+ }
+
+ bool isSharedLibrary() const
+ {
+ return unitData()->flags & CompiledData::Unit::IsSharedLibrary;
+ }
+
+ struct FunctionIterator
+ {
+ FunctionIterator(const CompiledData::Unit *unit, const CompiledObject *object, int index)
+ : unit(unit), object(object), index(index) {}
+ const CompiledData::Unit *unit;
+ const CompiledObject *object;
+ int index;
+
+ const CompiledFunction *operator->() const
+ {
+ return unit->functionAt(object->functionOffsetTable()[index]);
+ }
+
+ void operator++() { ++index; }
+ bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; }
+ bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; }
+ };
+
+ FunctionIterator objectFunctionsBegin(const CompiledObject *object) const
+ {
+ return FunctionIterator(unitData(), object, 0);
+ }
+
+ FunctionIterator objectFunctionsEnd(const CompiledObject *object) const
+ {
+ return FunctionIterator(unitData(), object, object->nFunctions);
+ }
+
+ QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const;
+ QMetaType metaType() const { return qmlType.typeId(); }
private:
QString m_fileName; // initialized from data->sourceFileIndex
QString m_finalUrlString; // initialized from data->finalUrlIndex
- Heap::Module *m_module = nullptr;
+ mutable QQmlNullableValue<QUrl> m_url;
+ mutable QQmlNullableValue<QUrl> m_finalUrl;
};
class SaveableUnitPointer
@@ -1267,7 +1775,8 @@ public:
template<typename Char>
bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const
{
- auto cleanup = qScopeGuard([this]() { mutableFlags() ^= temporaryFlags; });
+ const quint32_le oldFlags = mutableFlags();
+ auto cleanup = qScopeGuard([this, oldFlags]() { mutableFlags() = oldFlags; });
mutableFlags() |= temporaryFlags;
return writer(data<Char>(), size());
}
@@ -1287,7 +1796,7 @@ public:
errorString->clear();
return true;
#else
- Q_UNUSED(outputFileName)
+ Q_UNUSED(outputFileName);
*errorString = QStringLiteral("features.temporaryfile is disabled.");
return false;
#endif
@@ -1321,6 +1830,7 @@ private:
} // CompiledData namespace
} // QV4 namespace
+Q_DECLARE_OPERATORS_FOR_FLAGS(QV4::CompiledData::ParameterType::Flags);
Q_DECLARE_TYPEINFO(QV4::CompiledData::JSClassMember, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
diff --git a/src/qml/common/qv4staticvalue_p.h b/src/qml/common/qv4staticvalue_p.h
index 0716f7ea20..e887cdc674 100644
--- a/src/qml/common/qv4staticvalue_p.h
+++ b/src/qml/common/qv4staticvalue_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4STATICVALUE_P_H
#define QV4STATICVALUE_P_H
@@ -50,7 +14,11 @@
// We mean it.
//
+#include <qjsnumbercoercion.h>
+
#include <QtCore/private/qnumeric_p.h>
+#include <private/qtqmlglobal_p.h>
+
#include <cstring>
#ifdef QT_NO_DEBUG
@@ -69,55 +37,14 @@ namespace QV4 {
// It will be returned in rax on x64, [eax,edx] on x86 and [r0,r1] on arm
typedef quint64 ReturnedValue;
-struct Double {
- quint64 d;
-
- Double(double dbl) {
- memcpy(&d, &dbl, sizeof(double));
- }
-
- int sign() const {
- return (d >> 63) ? -1 : 1;
- }
-
- bool isDenormal() const {
- return static_cast<int>((d << 1) >> 53) == 0;
- }
-
- int exponent() const {
- return static_cast<int>((d << 1) >> 53) - 1023;
- }
-
- quint64 significant() const {
- quint64 m = (d << 12) >> 12;
- if (!isDenormal())
- m |= (static_cast<quint64>(1) << 52);
- return m;
- }
-
- static int toInt32(double d) {
- int i = static_cast<int>(d);
- if (i == d)
- return i;
- return Double(d).toInt32();
- }
-
- int toInt32() {
- int e = exponent() - 52;
- if (e < 0) {
- if (e <= -53)
- return 0;
- return sign() * static_cast<int>(significant() >> -e);
- } else {
- if (e > 31)
- return 0;
- return sign() * (static_cast<int>(significant()) << e);
- }
- }
-};
+namespace Heap {
+struct Base;
+}
struct StaticValue
{
+ using HeapBasePtr = Heap::Base *;
+
StaticValue() = default;
constexpr StaticValue(quint64 val) : _val(val) {}
@@ -137,21 +64,31 @@ struct StaticValue
Value &asValue();
/*
- We use 8 bytes for a value and a different variant of NaN boxing. A Double
- NaN (actually -qNaN) is indicated by a number that has the top 13 bits set, and for a
- signalling NaN it is the top 14 bits. The other values are usually set to 0 by the
- processor, and are thus free for us to store other data. We keep pointers in there for
- managed objects, and encode the other types using the free space given to use by the unused
- bits for NaN values. This also works for pointers on 64 bit systems, as they all currently
- only have 48 bits of addressable memory. (Note: we do leave the lower 49 bits available for
- pointers.)
-
- We xor Doubles with (0xffff8000 << 32). That has the effect that no doubles will
- get encoded with bits 63-49 all set to 0. We then use bit 48 to distinguish between
- managed/undefined (0), or Null/Int/Bool/Empty (1). So, storing a 49 bit pointer will leave
- the top 15 bits 0, which is exactly the 'natural' representation of pointers. If bit 49 is
- set, bit 48 indicates Empty (0) or integer-convertible (1). Then the 3 bit below that are
- used to encode Null/Int/Bool.
+ We use 8 bytes for a value. In order to store all possible values we employ a variant of NaN
+ boxing. A "special" Double is indicated by a number that has the 11 exponent bits set to 1.
+ Those can be NaN, positive or negative infinity. We only store one variant of NaN: The sign
+ bit has to be off and the bit after the exponent ("quiet bit") has to be on. However, since
+ the exponent bits are enough to identify special doubles, we can use a different bit as
+ discriminator to tell us how the rest of the bits (including quiet and sign) are to be
+ interpreted. This bit is bit 48. If set, we have an unmanaged value, which includes the
+ special doubles and various other values. If unset, we have a managed value, and all of the
+ other bits can be used to assemble a pointer.
+
+ On 32bit systems the pointer can just live in the lower 4 bytes. On 64 bit systems the lower
+ 48 bits can be used for verbatim pointer bits. However, since all our heap objects are
+ aligned to 32 bytes, we can use the 5 least significant bits of the pointer to store, e.g.
+ pointer tags on android. The same holds for the 3 bits between the double exponent and
+ bit 48.
+
+ With that out of the way, we can use the other bits to store different values.
+
+ We xor Doubles with (0x7ff48000 << 32). That has the effect that any double with all the
+ exponent bits set to 0 is one of our special doubles. Those special doubles then get the
+ other two bits in the mask (Special and Number) set to 1, as they cannot have 1s in those
+ positions to begin with.
+
+ We dedicate further bits to integer-convertible and bool-or-int. With those bits we can
+ describe all values we need to store.
Undefined is encoded as a managed pointer with value 0. This is the same as a nullptr.
@@ -159,41 +96,38 @@ struct StaticValue
0 = always 0
1 = always 1
x = stored value
- a,b,c,d = specific bit values, see notes
+ y = stored value, shifted to different position
+ a = xor-ed bits, where at least one bit is set
+ b = xor-ed bits
32109876 54321098 76543210 98765432 10987654 32109876 54321098 76543210 |
66665555 55555544 44444444 33333333 33222222 22221111 11111100 00000000 | JS Value
------------------------------------------------------------------------+--------------
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | Undefined
- 00000000 0000000x xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Managed (heap pointer)
- a0000000 0000bc00 00000000 00000000 00000000 00000000 00000000 00000000 | NaN/Inf
- dddddddd ddddddxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double
- 00000000 00000010 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole)
- 00000000 00000010 10000000 00000000 00000000 00000000 00000000 00000000 | Null
- 00000000 00000011 00000000 00000000 00000000 00000000 00000000 0000000x | Bool
- 00000000 00000011 10000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int
-
- Notes:
- - a: xor-ed signbit, always 1 for NaN
- - bc, xor-ed values: 11 = inf, 10 = sNaN, 01 = qNaN, 00 = boxed value
- - d: xor-ed bits, where at least one bit is set, so: (val >> (64-14)) > 0
- - Undefined maps to C++ nullptr, so the "default" initialization is the same for both C++
- and JS
- - Managed has the left 15 bits set to 0, so: (val >> (64-15)) == 0
- - empty, Null, Bool, and Int have the left 14 bits set to 0, and bit 49 set to 1,
- so: (val >> (64-15)) == 1
- - Null, Bool, and Int have bit 48 set, indicating integer-convertible
- - xoring _val with NaNEncodeMask will convert to a double in "natural" representation, where
- any non double results in a NaN
- - on 32bit we can use the fact that addresses are 32bits wide, so the tag part (bits 32 to
- 63) are zero. No need to shift.
+ y0000000 0000yyy0 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxyyyyy | Managed (heap pointer)
+ 00000000 00001101 10000000 00000000 00000000 00000000 00000000 00000000 | NaN
+ 00000000 00000101 10000000 00000000 00000000 00000000 00000000 00000000 | +Inf
+ 10000000 00000101 10000000 00000000 00000000 00000000 00000000 00000000 | -Inf
+ xaaaaaaa aaaaxbxb bxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | double
+ 00000000 00000001 00000000 00000000 00000000 00000000 00000000 00000000 | empty (non-sparse array hole)
+ 00000000 00000011 00000000 00000000 00000000 00000000 00000000 00000000 | Null
+ 00000000 00000011 10000000 00000000 00000000 00000000 00000000 0000000x | Bool
+ 00000000 00000011 11000000 00000000 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx | Int
+ ^ ^^^ ^^
+ | ||| ||
+ | ||| |+-> Number
+ | ||| +--> Int or Bool
+ | ||+----> Unmanaged
+ | |+-----> Integer compatible
+ | +------> Special double
+ +--------------------> Double sign, also used for special doubles
*/
quint64 _val;
- 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; }
+ QV4_NEARLY_ALWAYS_INLINE constexpr quint64 &rawValueRef() { return _val; }
+ QV4_NEARLY_ALWAYS_INLINE constexpr quint64 rawValue() const { return _val; }
+ QV4_NEARLY_ALWAYS_INLINE constexpr void setRawValue(quint64 raw) { _val = raw; }
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
static inline int valueOffset() { return 0; }
@@ -202,108 +136,145 @@ struct StaticValue
static inline int valueOffset() { return 4; }
static inline int tagOffset() { return 0; }
#endif
- static inline constexpr quint64 tagValue(quint32 tag, quint32 value) { return quint64(tag) << 32 | value; }
- QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << 32 | value; }
+ static inline constexpr quint64 tagValue(quint32 tag, quint32 value) { return quint64(tag) << Tag_Shift | value; }
+ QV4_NEARLY_ALWAYS_INLINE constexpr void setTagValue(quint32 tag, quint32 value) { _val = quint64(tag) << Tag_Shift | 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()); }
+ QV4_NEARLY_ALWAYS_INLINE constexpr quint32 tag() const { return _val >> Tag_Shift; }
+ QV4_NEARLY_ALWAYS_INLINE constexpr void setTag(quint32 tag) { setTagValue(tag, value()); }
QV4_NEARLY_ALWAYS_INLINE constexpr int int_32() const
{
return int(value());
}
- QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setInt_32(int i)
+ QV4_NEARLY_ALWAYS_INLINE constexpr void setInt_32(int i)
{
- setTagValue(quint32(ValueTypeInternal::Integer), quint32(i));
+ setTagValue(quint32(QuickType::Integer), quint32(i));
}
QV4_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); }
- QV4_NEARLY_ALWAYS_INLINE Q_DECL_RELAXED_CONSTEXPR void setEmpty()
+ QV4_NEARLY_ALWAYS_INLINE constexpr void setEmpty()
{
- setTagValue(quint32(ValueTypeInternal::Empty), 0);
- }
-
- // ### Fix for 32 bit (easiest solution is to set highest bit to 1 for mananged/undefined/integercompatible
- // and use negative numbers here
- enum QuickType {
- QT_ManagedOrUndefined = 0,
- QT_ManagedOrUndefined1 = 1,
- QT_ManagedOrUndefined2 = 2,
- QT_ManagedOrUndefined3 = 3,
- QT_Empty = 4,
- QT_Null = 5,
- QT_Bool = 6,
- QT_Int = 7
- // all other values are doubles
- };
-
- enum Type {
- Undefined_Type = 0,
- Managed_Type = 1,
- Empty_Type = 4,
- Null_Type = 5,
- Boolean_Type = 6,
- Integer_Type = 7,
- Double_Type = 8
+ setTagValue(quint32(QuickType::Empty), 0);
+ }
+
+ enum class TagBit {
+ // s: sign bit
+ // e: double exponent bit
+ // u: upper 3 bits if managed
+ // m: bit 48, denotes "unmanaged" if 1
+ // p: significant pointer bits (some re-used for non-managed)
+ // seeeeeeeeeeeuuumpppp
+ SpecialNegative = 0b10000000000000000000 << 12,
+ SpecialQNaN = 0b00000000000010000000 << 12,
+ Special = 0b00000000000001000000 << 12,
+ IntCompat = 0b00000000000000100000 << 12,
+ Unmanaged = 0b00000000000000010000 << 12,
+ IntOrBool = 0b00000000000000001000 << 12,
+ Number = 0b00000000000000000100 << 12,
};
- inline Type type() const {
- int t = quickType();
- if (t < QT_Empty)
- return _val ? Managed_Type : Undefined_Type;
- if (t > QT_Int)
- return Double_Type;
- return static_cast<Type>(t);
- }
+ static inline constexpr quint64 tagBitMask(TagBit bit) { return quint64(bit) << Tag_Shift; }
- // Shared between 32-bit and 64-bit encoding
- enum {
- Tag_Shift = 32
+ enum Type {
+ // Managed, Double and undefined are not directly encoded
+ Managed_Type = 0,
+ Double_Type = 1,
+ Undefined_Type = 2,
+
+ Empty_Type = quint32(TagBit::Unmanaged),
+ Null_Type = Empty_Type | quint32(TagBit::IntCompat),
+ Boolean_Type = Null_Type | quint32(TagBit::IntOrBool),
+ Integer_Type = Boolean_Type | quint32(TagBit::Number)
};
- // Used only by 64-bit encoding
- static const quint64 NaNEncodeMask = 0xfffc000000000000ull;
enum {
- IsDouble_Shift = 64-14,
- IsManagedOrUndefined_Shift = 64-15,
- IsIntegerConvertible_Shift = 64-15,
- IsIntegerOrBool_Shift = 64-16,
- QuickType_Shift = 64 - 17,
- IsPositiveIntShift = 31
- };
-
- static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
+ Tag_Shift = 32,
- enum class ValueTypeInternal_64 {
- Empty = Immediate_Mask_64 | 0,
- Null = Immediate_Mask_64 | 0x08000u,
- Boolean = Immediate_Mask_64 | 0x10000u,
- Integer = Immediate_Mask_64 | 0x18000u
- };
+ IsIntegerConvertible_Shift = 48,
+ IsIntegerConvertible_Value = 3, // Unmanaged | IntCompat after shifting
- // Used only by 32-bit encoding
- enum Masks {
- SilentNaNBit = 0x00040000,
- NotDouble_Mask = 0x7ffa0000,
+ IsIntegerOrBool_Shift = 47,
+ IsIntegerOrBool_Value = 7, // Unmanaged | IntCompat | IntOrBool after shifting
};
- static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit;
- enum class ValueTypeInternal_32 {
- Empty = Immediate_Mask_32 | 0,
- Null = Immediate_Mask_32 | 0x08000u,
- Boolean = Immediate_Mask_32 | 0x10000u,
- Integer = Immediate_Mask_32 | 0x18000u
+ static_assert(IsIntegerConvertible_Value ==
+ (quint32(TagBit::IntCompat) | quint32(TagBit::Unmanaged))
+ >> (IsIntegerConvertible_Shift - Tag_Shift));
+
+ static_assert(IsIntegerOrBool_Value ==
+ (quint32(TagBit::IntOrBool) | quint32(TagBit::IntCompat) | quint32(TagBit::Unmanaged))
+ >> (IsIntegerOrBool_Shift - Tag_Shift));
+
+ static constexpr quint64 ExponentMask = 0b0111111111110000ull << 48;
+
+ static constexpr quint64 Top1Mask = 0b1000000000000000ull << 48;
+ static constexpr quint64 Upper3Mask = 0b0000000000001110ull << 48;
+ static constexpr quint64 Lower5Mask = 0b0000000000011111ull;
+
+ static constexpr quint64 ManagedMask = ExponentMask | quint64(TagBit::Unmanaged) << Tag_Shift;
+ static constexpr quint64 DoubleMask = ManagedMask | quint64(TagBit::Special) << Tag_Shift;
+ static constexpr quint64 NumberMask = ManagedMask | quint64(TagBit::Number) << Tag_Shift;
+ static constexpr quint64 IntOrBoolMask = ManagedMask | quint64(TagBit::IntOrBool) << Tag_Shift;
+ static constexpr quint64 IntCompatMask = ManagedMask | quint64(TagBit::IntCompat) << Tag_Shift;
+
+ static constexpr quint64 EncodeMask = DoubleMask | NumberMask;
+
+ static constexpr quint64 DoubleDiscriminator
+ = ((quint64(TagBit::Unmanaged) | quint64(TagBit::Special)) << Tag_Shift);
+ static constexpr quint64 NumberDiscriminator
+ = ((quint64(TagBit::Unmanaged) | quint64(TagBit::Number)) << Tag_Shift);
+
+ // Things we can immediately determine by just looking at the upper 4 bytes.
+ enum class QuickType : quint32 {
+ // Managed takes precedence over all others. That is, other bits may be set if it's managed.
+ // However, since all others include the Unmanaged bit, we can still check them with simple
+ // equality operations.
+ Managed = Managed_Type,
+
+ Empty = Empty_Type,
+ Null = Null_Type,
+ Boolean = Boolean_Type,
+ Integer = Integer_Type,
+
+ PlusInf = quint32(TagBit::Number) | quint32(TagBit::Special) | quint32(TagBit::Unmanaged),
+ MinusInf = PlusInf | quint32(TagBit::SpecialNegative),
+ NaN = PlusInf | quint32(TagBit::SpecialQNaN),
+ MinusNaN = NaN | quint32(TagBit::SpecialNegative), // Can happen with UMinus on NaN
+ // All other values are doubles
};
+ // Aliases for easier porting. Remove those when possible
+ using ValueTypeInternal = QuickType;
enum {
- Managed_Type_Internal = 0
+ QT_Empty = Empty_Type,
+ QT_Null = Null_Type,
+ QT_Bool = Boolean_Type,
+ QT_Int = Integer_Type,
+ QuickType_Shift = Tag_Shift,
};
- using ValueTypeInternal = ValueTypeInternal_64;
+ inline Type type() const
+ {
+ const quint64 masked = _val & DoubleMask;
+ if (masked >= DoubleDiscriminator)
+ return Double_Type;
- enum {
- NaN_Mask = 0x7ff80000,
- };
+ // Any bit set in the exponent would have been caught above, as well as both bits being set.
+ // None of them being set as well as only Special being set means "managed".
+ // Only Unmanaged being set means "unmanaged". That's all remaining options.
+ if (masked != tagBitMask(TagBit::Unmanaged)) {
+ Q_ASSERT((_val & tagBitMask(TagBit::Unmanaged)) == 0);
+ return isUndefined() ? Undefined_Type : Managed_Type;
+ }
+
+ const Type ret = Type(tag());
+ Q_ASSERT(
+ ret == Empty_Type ||
+ ret == Null_Type ||
+ ret == Boolean_Type ||
+ ret == Integer_Type);
+ return ret;
+ }
inline quint64 quickType() const { return (_val >> QuickType_Shift); }
@@ -313,34 +284,52 @@ struct StaticValue
inline bool isBoolean() const { return tag() == quint32(ValueTypeInternal::Boolean); }
inline bool isInteger() const { return tag() == quint32(ValueTypeInternal::Integer); }
inline bool isNullOrUndefined() const { return isNull() || isUndefined(); }
- inline bool isNumber() const { return quickType() >= QT_Int; }
-
inline bool isUndefined() const { return _val == 0; }
- inline bool isDouble() const { return (_val >> IsDouble_Shift); }
- inline bool isManaged() const
+
+ inline bool isDouble() const
{
-#if QT_POINTER_SIZE == 4
- return value() && tag() == Managed_Type_Internal;
-#else
- return _val && ((_val >> IsManagedOrUndefined_Shift) == 0);
-#endif
+ // If any of the flipped exponent bits are 1, it's a regular double, and the masked tag is
+ // larger than Unmanaged | Special.
+ //
+ // If all (flipped) exponent bits are 0:
+ // 1. If Unmanaged bit is 0, it's managed
+ // 2. If the Unmanaged bit it is 1, and the Special bit is 0, it's not a special double
+ // 3. If both are 1, it is a special double and the masked tag equals Unmanaged | Special.
+
+ return (_val & DoubleMask) >= DoubleDiscriminator;
}
- inline bool isManagedOrUndefined() const
+
+ inline bool isNumber() const
{
-#if QT_POINTER_SIZE == 4
- return tag() == Managed_Type_Internal;
-#else
- return ((_val >> IsManagedOrUndefined_Shift) == 0);
-#endif
+ // If any of the flipped exponent bits are 1, it's a regular double, and the masked tag is
+ // larger than Unmanaged | Number.
+ //
+ // If all (flipped) exponent bits are 0:
+ // 1. If Unmanaged bit is 0, it's managed
+ // 2. If the Unmanaged bit it is 1, and the Number bit is 0, it's not number
+ // 3. If both are 1, it is a number and masked tag equals Unmanaged | Number.
+
+ return (_val & NumberMask) >= NumberDiscriminator;
}
- inline bool isIntOrBool() const {
- return (_val >> IsIntegerOrBool_Shift) == 3;
+ inline bool isManagedOrUndefined() const { return (_val & ManagedMask) == 0; }
+
+ // If any other bit is set in addition to the managed mask, it's not undefined.
+ inline bool isManaged() const
+ {
+ return isManagedOrUndefined() && !isUndefined();
+ }
+
+ inline bool isIntOrBool() const
+ {
+ // It's an int or bool if all the exponent bits are 0,
+ // and the "int or bool" bit as well as the "umanaged" bit are set,
+ return (_val >> IsIntegerOrBool_Shift) == IsIntegerOrBool_Value;
}
inline bool integerCompatible() const {
Q_ASSERT(!isEmpty());
- return (_val >> IsIntegerConvertible_Shift) == 1;
+ return (_val >> IsIntegerConvertible_Shift) == IsIntegerConvertible_Value;
}
static inline bool integerCompatible(StaticValue a, StaticValue b) {
@@ -353,36 +342,45 @@ struct StaticValue
inline bool isNaN() const
{
- return (tag() & 0x7ffc0000 ) == 0x00040000;
+ switch (QuickType(tag())) {
+ case QuickType::NaN:
+ case QuickType::MinusNaN:
+ return true;
+ default:
+ return false;
+ }
}
inline bool isPositiveInt() const {
-#if QT_POINTER_SIZE == 4
return isInteger() && int_32() >= 0;
-#else
- return (_val >> IsPositiveIntShift) == (quint64(ValueTypeInternal::Integer) << 1);
-#endif
}
QV4_NEARLY_ALWAYS_INLINE double doubleValue() const {
Q_ASSERT(isDouble());
double d;
- StaticValue v = *this;
- v._val ^= NaNEncodeMask;
- memcpy(&d, &v._val, 8);
+ const quint64 unmasked = _val ^ EncodeMask;
+ memcpy(&d, &unmasked, 8);
return d;
}
QV4_NEARLY_ALWAYS_INLINE void setDouble(double d) {
- if (qt_is_nan(d))
- d = qt_qnan();
- memcpy(&_val, &d, 8);
- _val ^= NaNEncodeMask;
+ if (qt_is_nan(d)) {
+ // We cannot store just any NaN. It has to be a NaN with only the quiet bit
+ // set in the upper bits of the mantissa and the sign bit off.
+ // qt_qnan() happens to produce such a thing via std::numeric_limits,
+ // but this is actually not guaranteed. Therefore, we make our own.
+ _val = (quint64(QuickType::NaN) << Tag_Shift);
+ Q_ASSERT(isNaN());
+ } else {
+ memcpy(&_val, &d, 8);
+ _val ^= EncodeMask;
+ }
+
Q_ASSERT(isDouble());
}
inline bool isInt32() {
- if (tag() == quint32(ValueTypeInternal::Integer))
+ if (tag() == quint32(QuickType::Integer))
return true;
if (isDouble()) {
double d = doubleValue();
@@ -395,12 +393,12 @@ struct StaticValue
}
QV4_NEARLY_ALWAYS_INLINE static bool isInt32(double d) {
- int i = int(d);
+ int i = QJSNumberCoercion::toInteger(d);
return (i == d && !(d == 0 && std::signbit(d)));
}
double asDouble() const {
- if (tag() == quint32(ValueTypeInternal::Integer))
+ if (tag() == quint32(QuickType::Integer))
return int_32();
return doubleValue();
}
@@ -416,7 +414,7 @@ struct StaticValue
inline bool tryIntegerConversion() {
bool b = integerCompatible();
if (b)
- setTagValue(quint32(ValueTypeInternal::Integer), value());
+ setTagValue(quint32(QuickType::Integer), value());
return b;
}
@@ -440,24 +438,25 @@ struct StaticValue
case Integer_Type:
return int_32();
case Double_Type:
- return Double::toInt32(doubleValue());
+ return QJSNumberCoercion::toInteger(doubleValue());
case Empty_Type:
case Undefined_Type:
case Managed_Type:
- break;
+ return 0; // Coercion of NaN to int, results in 0;
}
- return Double::toInt32(std::numeric_limits<double>::quiet_NaN());
+
+ Q_UNREACHABLE_RETURN(0);
}
ReturnedValue *data_ptr() { return &_val; }
constexpr ReturnedValue asReturnedValue() const { return _val; }
constexpr static StaticValue fromReturnedValue(ReturnedValue val) { return {val}; }
- inline static constexpr StaticValue emptyValue() { return { tagValue(quint32(ValueTypeInternal::Empty), 0) }; }
- static inline constexpr StaticValue fromBoolean(bool b) { return { tagValue(quint32(ValueTypeInternal::Boolean), b) }; }
- static inline constexpr StaticValue fromInt32(int i) { return { tagValue(quint32(ValueTypeInternal::Integer), quint32(i)) }; }
+ inline static constexpr StaticValue emptyValue() { return { tagValue(quint32(QuickType::Empty), 0) }; }
+ static inline constexpr StaticValue fromBoolean(bool b) { return { tagValue(quint32(QuickType::Boolean), b) }; }
+ static inline constexpr StaticValue fromInt32(int i) { return { tagValue(quint32(QuickType::Integer), quint32(i)) }; }
inline static constexpr StaticValue undefinedValue() { return { 0 }; }
- static inline constexpr StaticValue nullValue() { return { tagValue(quint32(ValueTypeInternal::Null), 0) }; }
+ static inline constexpr StaticValue nullValue() { return { tagValue(quint32(QuickType::Null), 0) }; }
static inline StaticValue fromDouble(double d)
{
@@ -470,7 +469,7 @@ struct StaticValue
{
StaticValue v;
if (i < uint(std::numeric_limits<int>::max())) {
- v.setTagValue(quint32(ValueTypeInternal::Integer), i);
+ v.setTagValue(quint32(QuickType::Integer), i);
} else {
v.setDouble(i);
}
@@ -488,15 +487,140 @@ struct StaticValue
static int toInt32(double d)
{
- return Double::toInt32(d);
+ return QJSNumberCoercion::toInteger(d);
}
static unsigned int toUInt32(double d)
{
return static_cast<uint>(toInt32(d));
}
+
+ // While a value containing a Heap::Base* is not actually static, we still implement
+ // the setting and retrieving of heap pointers here in order to have the encoding
+ // scheme completely in one place.
+
+#if QT_POINTER_SIZE == 8
+
+ // All pointer shifts are from more significant to less significant bits.
+ // When encoding, we shift right by that amount. When decoding, we shift left.
+ // Negative numbers mean shifting the other direction. 0 means no shifting.
+ //
+ // The IA64 and Sparc64 cases are mostly there to demonstrate the idea. Sparc64
+ // and IA64 are not officially supported, but we can expect more platforms with
+ // similar "problems" in the future.
+ enum PointerShift {
+#if 0 && defined(Q_OS_ANDROID) && defined(Q_PROCESSOR_ARM_64)
+ // We used to assume that Android on arm64 uses the top byte to store pointer tags.
+ // However, at least currently, the pointer tags are only applied on new/malloc and
+ // delete/free, not on mmap() and munmap(). We manage the JS heap directly using
+ // mmap, so we don't have to preserve any tags.
+ //
+ // If this ever changes, here is how to preserve the top byte:
+ // Move it to Upper3 and Lower5.
+ Top1Shift = 0,
+ Upper3Shift = 12,
+ Lower5Shift = 56,
+#elif defined(Q_PROCESSOR_IA64)
+ // On ia64, bits 63-61 in a 64-bit pointer are used to store the virtual region
+ // number. We can move those to Upper3.
+ Top1Shift = 0,
+ Upper3Shift = 12,
+ Lower5Shift = 0,
+#elif defined(Q_PROCESSOR_SPARC_64)
+ // Sparc64 wants to use 52 bits for pointers.
+ // Upper3 can stay where it is, bit48 moves to the top bit.
+ Top1Shift = -15,
+ Upper3Shift = 0,
+ Lower5Shift = 0,
+#elif 0 // TODO: Once we need 5-level page tables, add the appropriate check here.
+ // With 5-level page tables (as possible on linux) we need 57 address bits.
+ // Upper3 can stay where it is, bit48 moves to the top bit, the rest moves to Lower5.
+ Top1Shift = -15,
+ Upper3Shift = 0,
+ Lower5Shift = 52,
+#else
+ Top1Shift = 0,
+ Upper3Shift = 0,
+ Lower5Shift = 0
+#endif
+ };
+
+ template<int Offset, quint64 Mask>
+ static constexpr quint64 movePointerBits(quint64 val)
+ {
+ if constexpr (Offset > 0)
+ return (val & ~Mask) | ((val & Mask) >> Offset);
+ if constexpr (Offset < 0)
+ return (val & ~Mask) | ((val & Mask) << -Offset);
+ return val;
+ }
+
+ template<int Offset, quint64 Mask>
+ static constexpr quint64 storePointerBits(quint64 val)
+ {
+ constexpr quint64 OriginMask = movePointerBits<-Offset, Mask>(Mask);
+ return movePointerBits<Offset, OriginMask>(val);
+ }
+
+ template<int Offset, quint64 Mask>
+ static constexpr quint64 retrievePointerBits(quint64 val)
+ {
+ return movePointerBits<-Offset, Mask>(val);
+ }
+
+ QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
+ {
+ Q_ASSERT(!(_val & ManagedMask));
+
+ // Re-assemble the pointer from its fragments.
+ const quint64 tmp = retrievePointerBits<Top1Shift, Top1Mask>(
+ retrievePointerBits<Upper3Shift, Upper3Mask>(
+ retrievePointerBits<Lower5Shift, Lower5Mask>(_val)));
+
+ HeapBasePtr b;
+ memcpy(&b, &tmp, 8);
+ return b;
+ }
+ QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b)
+ {
+ quint64 tmp;
+ memcpy(&tmp, &b, 8);
+
+ // Has to be aligned to 32 bytes
+ Q_ASSERT(!(tmp & Lower5Mask));
+
+ // MinGW produces a bogus warning about array bounds.
+ // There is no array access here.
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_GCC("-Warray-bounds")
+
+ // Encode the pointer.
+ _val = storePointerBits<Top1Shift, Top1Mask>(
+ storePointerBits<Upper3Shift, Upper3Mask>(
+ storePointerBits<Lower5Shift, Lower5Mask>(tmp)));
+
+ QT_WARNING_POP
+ }
+#elif QT_POINTER_SIZE == 4
+ QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
+ {
+ Q_STATIC_ASSERT(sizeof(HeapBasePtr) == sizeof(quint32));
+ HeapBasePtr b;
+ quint32 v = value();
+ memcpy(&b, &v, 4);
+ return b;
+ }
+ QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b)
+ {
+ quint32 v;
+ memcpy(&v, &b, 4);
+ setTagValue(quint32(QuickType::Managed), v);
+ }
+#else
+# error "unsupported pointer size"
+#endif
};
-Q_STATIC_ASSERT(std::is_trivial<StaticValue>::value);
+Q_STATIC_ASSERT(std::is_trivial_v<StaticValue>);
struct Encode {
static constexpr ReturnedValue undefined() {
diff --git a/src/qml/common/qv4stringtoarrayindex_p.h b/src/qml/common/qv4stringtoarrayindex_p.h
index 61bd988d1e..7bdabd4f3f 100644
--- a/src/qml/common/qv4stringtoarrayindex_p.h
+++ b/src/qml/common/qv4stringtoarrayindex_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4STRINGTOARRAYINDEX_P_H
#define QV4STRINGTOARRAYINDEX_P_H
@@ -65,6 +29,8 @@ inline uint charToUInt(const char *ch) { return static_cast<unsigned char>(*ch);
template <typename T>
uint stringToArrayIndex(const T *ch, const T *end)
{
+ if (ch == end)
+ return std::numeric_limits<uint>::max();
uint i = charToUInt(ch) - '0';
if (i > 9)
return std::numeric_limits<uint>::max();
@@ -77,7 +43,7 @@ uint stringToArrayIndex(const T *ch, const T *end)
uint x = charToUInt(ch) - '0';
if (x > 9)
return std::numeric_limits<uint>::max();
- if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i)) // i = i * 10 + x
+ if (qMulOverflow(i, uint(10), &i) || qAddOverflow(i, x, &i)) // i = i * 10 + x
return std::numeric_limits<uint>::max();
++ch;
}
@@ -86,7 +52,7 @@ uint stringToArrayIndex(const T *ch, const T *end)
inline uint stringToArrayIndex(const QString &str)
{
- return stringToArrayIndex(str.constData(), str.constData() + str.length());
+ return stringToArrayIndex(str.constData(), str.constData() + str.size());
}
} // namespace QV4
diff --git a/src/qml/compat/removed_api.cpp b/src/qml/compat/removed_api.cpp
new file mode 100644
index 0000000000..fe16b7f462
--- /dev/null
+++ b/src/qml/compat/removed_api.cpp
@@ -0,0 +1,42 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#define QT_QML_BUILD_REMOVED_API
+
+#include "qtqmlglobal.h"
+
+QT_USE_NAMESPACE
+
+#if QT_QML_REMOVED_SINCE(6, 5)
+
+#include <QtQml/qjsengine.h>
+
+QJSValue QJSEngine::create(int typeId, const void *ptr)
+{
+ QMetaType type(typeId);
+ return create(type, ptr);
+}
+
+bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
+{
+ return convertV2(value, QMetaType(type), ptr);
+}
+
+#endif
+
+#if QT_QML_REMOVED_SINCE(6, 6)
+#include <QtQml/qqmlprivate.h>
+#include <QtQml/private/qv4executablecompilationunit_p.h>
+#include <QtQml/private/qv4lookup_p.h>
+
+bool QQmlPrivate::AOTCompiledContext::getEnumLookup(uint index, int *target) const
+{
+ using namespace QQmlPrivate;
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ auto mt = QMetaType(l->qmlEnumValueLookup.metaType);
+ QVariant buffer(mt);
+ getEnumLookup(index, buffer.data());
+ *target = buffer.toInt();
+ return true;
+}
+#endif
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
deleted file mode 100644
index 4d6926d420..0000000000
--- a/src/qml/compiler/compiler.pri
+++ /dev/null
@@ -1,29 +0,0 @@
-INCLUDEPATH += $$PWD
-INCLUDEPATH += $$OUT_PWD
-
-HEADERS += \
- $$PWD/qv4bytecodegenerator_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/qv4util_p.h
-
-SOURCES += \
- $$PWD/qv4bytecodegenerator.cpp \
- $$PWD/qv4compiler.cpp \
- $$PWD/qv4compilercontext.cpp \
- $$PWD/qv4compilerscanfunctions.cpp \
- $$PWD/qv4codegen.cpp \
- $$PWD/qqmlirbuilder.cpp \
- $$PWD/qv4instr_moth.cpp \
- $$PWD/qv4bytecodehandler.cpp
-
-gcc {
- equals(QT_GCC_MAJOR_VERSION, 5): QMAKE_CXXFLAGS += -fno-strict-aliasing
-}
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 940d61ba97..a81f8fb1d8 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlirbuilder_p.h"
@@ -48,12 +12,10 @@
#include <QCryptographicHash>
#include <cmath>
-#ifdef CONST
-#undef CONST
-#endif
-
QT_USE_NAMESPACE
+using namespace Qt::StringLiterals;
+
static const quint32 emptyStringIndex = 0;
using namespace QmlIR;
using namespace QQmlJS;
@@ -64,71 +26,75 @@ using namespace QQmlJS;
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);
+void Object::simplifyRequiredProperties() {
+ // if a property of the current object was marked as required
+ // do not store that information in the ExtraData
+ // but rather mark the property as required
+ QSet<int> required;
+ for (auto it = this->requiredPropertyExtraDataBegin(); it != this->requiredPropertyExtraDataEnd(); ++it)
+ required.insert(it->nameIndex);
+ if (required.isEmpty())
+ return;
+ for (auto it = this->propertiesBegin(); it != this->propertiesEnd(); ++it) {
+ auto requiredIt = required.find(it->nameIndex);
+ if (requiredIt != required.end()) {
+ it->setIsRequired(true);
+ required.erase(requiredIt);
+ }
+ }
+ QmlIR::RequiredPropertyExtraData *prev = nullptr;
+ auto current = this->requiredPropertyExtraDatas->first;
+ while (current) {
+ if (required.contains(current->nameIndex))
+ prev = current;
+ else
+ requiredPropertyExtraDatas->unlink(prev, current);
+ current = current->next;
+ }
}
-bool Parameter::initType(QV4::CompiledData::ParameterType *paramType, const QV4::Compiler::JSUnitGenerator *stringGenerator, int typeNameIndex)
+bool Parameter::initType(
+ QV4::CompiledData::ParameterType *paramType,
+ const QString &typeName, int typeNameIndex,
+ QV4::CompiledData::ParameterType::Flag listFlag)
{
- 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())
+ if (builtinType == QV4::CompiledData::CommonType::Invalid) {
+ if (typeName.isEmpty()) {
+ paramType->set(listFlag, 0);
return false;
- paramType->indexIsBuiltinType = false;
- paramType->typeNameIndexOrBuiltinType = typeNameIndex;
+ }
Q_ASSERT(quint32(typeNameIndex) < (1u << 31));
+ paramType->set(listFlag, typeNameIndex);
} else {
- paramType->indexIsBuiltinType = true;
- paramType->typeNameIndexOrBuiltinType = static_cast<quint32>(builtinType);
Q_ASSERT(quint32(builtinType) < (1u << 31));
+ paramType->set(listFlag | QV4::CompiledData::ParameterType::Common,
+ static_cast<quint32>(builtinType));
}
return true;
}
-QV4::CompiledData::BuiltinType Parameter::stringToBuiltinType(const QString &typeName)
+QV4::CompiledData::CommonType Parameter::stringToBuiltinType(const QString &typeName)
{
static const struct TypeNameToType {
const char *name;
size_t nameLength;
- QV4::CompiledData::BuiltinType type;
+ QV4::CompiledData::CommonType 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 }
+ { "void", strlen("void"), QV4::CompiledData::CommonType::Void },
+ { "int", strlen("int"), QV4::CompiledData::CommonType::Int },
+ { "bool", strlen("bool"), QV4::CompiledData::CommonType::Bool },
+ { "double", strlen("double"), QV4::CompiledData::CommonType::Real },
+ { "real", strlen("real"), QV4::CompiledData::CommonType::Real },
+ { "string", strlen("string"), QV4::CompiledData::CommonType::String },
+ { "url", strlen("url"), QV4::CompiledData::CommonType::Url },
+ { "date", strlen("date"), QV4::CompiledData::CommonType::DateTime },
+ { "regexp", strlen("regexp"), QV4::CompiledData::CommonType::RegExp },
+ { "rect", strlen("rect"), QV4::CompiledData::CommonType::Rect },
+ { "point", strlen("point"), QV4::CompiledData::CommonType::Point },
+ { "size", strlen("size"), QV4::CompiledData::CommonType::Size },
+ { "variant", strlen("variant"), QV4::CompiledData::CommonType::Var },
+ { "var", strlen("var"), QV4::CompiledData::CommonType::Var }
};
static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
sizeof(propTypeNameToTypes[0]);
@@ -139,16 +105,15 @@ QV4::CompiledData::BuiltinType Parameter::stringToBuiltinType(const QString &typ
return t->type;
}
}
- return QV4::CompiledData::BuiltinType::InvalidBuiltin;
+ return QV4::CompiledData::CommonType::Invalid;
}
-void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &loc)
+void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex,
+ const QV4::CompiledData::Location &loc)
{
+ Q_ASSERT(loc.line() > 0 && loc.column() > 0);
inheritedTypeNameIndex = typeNameIndex;
-
- location.line = loc.startLine;
- location.column = loc.startColumn;
-
+ location = loc;
idNameIndex = idIndex;
id = -1;
indexOfDefaultPropertyOrAlias = -1;
@@ -161,16 +126,18 @@ void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, cons
bindings = pool->New<PoolList<Binding> >();
functions = pool->New<PoolList<Function> >();
functionsAndExpressions = pool->New<PoolList<CompiledFunctionOrExpression> >();
+ inlineComponents = pool->New<PoolList<InlineComponent>>();
+ requiredPropertyExtraDatas = pool->New<PoolList<RequiredPropertyExtraData>>();
declarationsOverride = nullptr;
}
-QString IRBuilder::sanityCheckFunctionNames(Object *obj, const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation)
+QString IRBuilder::sanityCheckFunctionNames(Object *obj, const QSet<QString> &illegalNames, QQmlJS::SourceLocation *errorLocation)
{
QSet<int> functionNames;
for (auto functionit = obj->functionsBegin(); functionit != obj->functionsEnd(); ++functionit) {
Function *f = functionit.ptr;
- errorLocation->startLine = f->location.line;
- errorLocation->startColumn = f->location.column;
+ errorLocation->startLine = f->location.line();
+ errorLocation->startColumn = f->location.column();
if (functionNames.contains(f->nameIndex))
return tr("Duplicate method name");
functionNames.insert(f->nameIndex);
@@ -220,7 +187,7 @@ QString Object::appendSignal(Signal *signal)
return QString(); // no error
}
-QString Object::appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation)
+QString Object::appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::SourceLocation &defaultToken, QQmlJS::SourceLocation *errorLocation)
{
Object *target = declarationsOverride;
if (!target)
@@ -230,6 +197,10 @@ QString Object::appendProperty(Property *prop, const QString &propertyName, bool
if (p->nameIndex == prop->nameIndex)
return tr("Duplicate property name");
+ for (Alias *a = target->aliases->first; a; a = a->next)
+ if (a->nameIndex() == prop->nameIndex)
+ return tr("Property duplicates alias name");
+
if (propertyName.constData()->isUpper())
return tr("Property names cannot begin with an upper case letter");
@@ -244,15 +215,24 @@ QString Object::appendProperty(Property *prop, const QString &propertyName, bool
return QString(); // no error
}
-QString Object::appendAlias(Alias *alias, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation)
+QString Object::appendAlias(Alias *alias, const QString &aliasName, bool isDefaultProperty, const QQmlJS::SourceLocation &defaultToken, QQmlJS::SourceLocation *errorLocation)
{
Object *target = declarationsOverride;
if (!target)
target = this;
- for (Alias *p = target->aliases->first; p; p = p->next)
- if (p->nameIndex == alias->nameIndex)
- return tr("Duplicate alias name");
+ const auto aliasWithSameName = std::find_if(target->aliases->begin(), target->aliases->end(), [&alias](const Alias &targetAlias){
+ return targetAlias.nameIndex() == alias->nameIndex();
+ });
+ if (aliasWithSameName != target->aliases->end())
+ return tr("Duplicate alias name");
+
+ const auto aliasSameAsProperty = std::find_if(target->properties->begin(), target->properties->end(), [&alias](const Property &targetProp){
+ return targetProp.nameIndex == alias->nameIndex();
+ });
+
+ if (aliasSameAsProperty != target->properties->end())
+ return tr("Alias has same name as existing property");
if (aliasName.constData()->isUpper())
return tr("Alias names cannot begin with an upper case letter");
@@ -273,22 +253,37 @@ QString Object::appendAlias(Alias *alias, const QString &aliasName, bool isDefau
void Object::appendFunction(QmlIR::Function *f)
{
- Object *target = declarationsOverride;
- if (!target)
- target = this;
- target->functions->append(f);
+ // Unlike properties, a function definition inside a grouped property does not go into
+ // the surrounding object. It's been broken since the Qt 5 era, and the semantics
+ // seems super confusing, so it wouldn't make sense to support that.
+ Q_ASSERT(!declarationsOverride);
+ functions->append(f);
+}
+
+void Object::appendInlineComponent(InlineComponent *ic)
+{
+ inlineComponents->append(ic);
+}
+
+void Object::appendRequiredPropertyExtraData(RequiredPropertyExtraData *extraData)
+{
+ requiredPropertyExtraDatas->append(extraData);
}
QString Object::appendBinding(Binding *b, bool isListBinding)
{
const bool bindingToDefaultProperty = (b->propertyNameIndex == quint32(0));
- if (!isListBinding && !bindingToDefaultProperty
- && b->type != QV4::CompiledData::Binding::Type_GroupProperty
- && b->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && !(b->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
+ if (!isListBinding
+ && !bindingToDefaultProperty
+ && b->type() != QV4::CompiledData::Binding::Type_GroupProperty
+ && b->type() != QV4::CompiledData::Binding::Type_AttachedProperty
+ && !b->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) {
Binding *existing = findBinding(b->propertyNameIndex);
- if (existing && existing->isValueBinding() == b->isValueBinding() && !(existing->flags & QV4::CompiledData::Binding::IsOnAssignment))
+ if (existing
+ && existing->isValueBinding() == b->isValueBinding()
+ && !existing->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) {
return tr("Property value set multiple times");
+ }
}
if (bindingToDefaultProperty)
insertSorted(b);
@@ -317,8 +312,8 @@ QString Object::bindingAsString(Document *doc, int scriptIndex) const
QQmlJS::AST::Node *node = foe->node;
if (QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(node))
node = exprStmt->expression;
- QQmlJS::AST::SourceLocation start = node->firstSourceLocation();
- QQmlJS::AST::SourceLocation end = node->lastSourceLocation();
+ QQmlJS::SourceLocation start = node->firstSourceLocation();
+ QQmlJS::SourceLocation end = node->lastSourceLocation();
return doc->code.mid(start.offset, end.offset + end.length - start.offset);
}
@@ -356,8 +351,7 @@ void ScriptDirectivesCollector::importFile(const QString &jsfile, const QString
import->type = QV4::CompiledData::Import::ImportScript;
import->uriIndex = jsGenerator->registerString(jsfile);
import->qualifierIndex = jsGenerator->registerString(module);
- import->location.line = lineNumber;
- import->location.column = column;
+ import->location.set(lineNumber, column);
document->imports << import;
}
@@ -366,14 +360,9 @@ void ScriptDirectivesCollector::importModule(const QString &uri, const QString &
QV4::CompiledData::Import *import = engine->pool()->New<QV4::CompiledData::Import>();
import->type = QV4::CompiledData::Import::ImportLibrary;
import->uriIndex = jsGenerator->registerString(uri);
- int vmaj;
- int vmin;
- IRBuilder::extractVersion(QStringRef(&version), &vmaj, &vmin);
- import->majorVersion = vmaj;
- import->minorVersion = vmin;
+ import->version = IRBuilder::extractVersion(version);
import->qualifierIndex = jsGenerator->registerString(module);
- import->location.line = lineNumber;
- import->location.column = column;
+ import->location.set(lineNumber, column);
document->imports << import;
}
@@ -401,13 +390,15 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, Documen
// Extract errors from the parser
for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
if (m.isWarning()) {
- qWarning("%s:%d : %s", qPrintable(url), m.line, qPrintable(m.message));
+ qWarning("%s:%d : %s", qPrintable(url), m.loc.startLine, qPrintable(m.message));
continue;
}
errors << m;
}
- return false;
+
+ if (!errors.isEmpty() || !parseResult)
+ return false;
}
program = parser.ast();
Q_ASSERT(program);
@@ -429,7 +420,7 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, Documen
accept(program->headers);
if (program->members->next) {
- QQmlJS::AST::SourceLocation loc = program->members->next->firstSourceLocation();
+ QQmlJS::SourceLocation loc = program->members->next->firstSourceLocation();
recordError(loc, QCoreApplication::translate("QQmlParser", "Unexpected object definition"));
return false;
}
@@ -444,21 +435,11 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, Documen
qSwap(_imports, output->imports);
qSwap(_pragmas, output->pragmas);
qSwap(_objects, output->objects);
- return errors.isEmpty();
-}
-bool IRBuilder::isSignalPropertyName(const QString &name)
-{
- if (name.length() < 3) return false;
- if (!name.startsWith(QLatin1String("on"))) return false;
- int ns = name.length();
- for (int i = 2; i < ns; ++i) {
- const QChar curr = name.at(i);
- if (curr.unicode() == '_') continue;
- if (curr.isUpper()) return true;
- return false;
- }
- return false; // consists solely of underscores - invalid.
+ for (auto object: output->objects)
+ object->simplifyRequiredProperties();
+
+ return errors.isEmpty();
}
bool IRBuilder::visit(QQmlJS::AST::UiArrayMemberList *ast)
@@ -485,27 +466,66 @@ bool IRBuilder::visit(QQmlJS::AST::UiObjectDefinition *node)
QQmlJS::AST::UiQualifiedId *lastId = node->qualifiedTypeNameId;
while (lastId->next)
lastId = lastId->next;
- bool isType = lastId->name.unicode()->isUpper();
+ bool isType = lastId->name.data()->isUpper();
if (isType) {
int idx = 0;
if (!defineQMLObject(&idx, node))
return false;
- const QQmlJS::AST::SourceLocation nameLocation = node->qualifiedTypeNameId->identifierToken;
+ const QQmlJS::SourceLocation nameLocation = node->qualifiedTypeNameId->identifierToken;
appendBinding(nameLocation, nameLocation, emptyStringIndex, idx);
} else {
int idx = 0;
- if (!defineQMLObject(&idx, /*qualfied type name id*/nullptr, node->qualifiedTypeNameId->firstSourceLocation(), node->initializer, /*declarations should go here*/_object))
+ const QQmlJS::SourceLocation location = node->qualifiedTypeNameId->firstSourceLocation();
+ if (!defineQMLObject(
+ &idx, /*qualfied type name id*/nullptr,
+ { location.startLine, location.startColumn }, node->initializer,
+ /*declarations should go here*/_object)) {
return false;
+ }
appendBinding(node->qualifiedTypeNameId, idx);
}
return false;
}
+bool IRBuilder::visit(QQmlJS::AST::UiInlineComponent *ast)
+{
+ int idx = -1;
+ if (insideInlineComponent) {
+ recordError(ast->firstSourceLocation(), QLatin1String("Nested inline components are not supported"));
+ return false;
+ }
+ if (inlineComponentsNames.contains(ast->name.toString())) {
+ recordError(ast->firstSourceLocation(), QLatin1String("Inline component names must be unique per file"));
+ return false;
+ } else {
+ inlineComponentsNames.insert(ast->name.toString());
+ }
+ {
+ QScopedValueRollback<bool> rollBack {insideInlineComponent, true};
+ if (!defineQMLObject(&idx, ast->component))
+ return false;
+ }
+ Q_ASSERT(idx > 0);
+ Object* definedObject = _objects.at(idx);
+ definedObject->flags |= QV4::CompiledData::Object::IsInlineComponentRoot;
+ definedObject->flags |= QV4::CompiledData::Object::IsPartOfInlineComponent;
+ auto inlineComponent = New<InlineComponent>();
+ inlineComponent->nameIndex = registerString(ast->name.toString());
+ inlineComponent->objectIndex = idx;
+ auto location = ast->firstSourceLocation();
+ inlineComponent->location.set(location.startLine, location.startColumn);
+ _object->appendInlineComponent(inlineComponent);
+ return false;
+}
+
bool IRBuilder::visit(QQmlJS::AST::UiObjectBinding *node)
{
int idx = 0;
- if (!defineQMLObject(&idx, node->qualifiedTypeNameId, node->qualifiedTypeNameId->firstSourceLocation(), node->initializer))
+ const QQmlJS::SourceLocation location = node->qualifiedTypeNameId->firstSourceLocation();
+ if (!defineQMLObject(&idx, node->qualifiedTypeNameId,
+ { location.startLine, location.startColumn }, node->initializer)) {
return false;
+ }
appendBinding(node->qualifiedId, idx, node->hasOnToken);
return false;
}
@@ -518,7 +538,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiScriptBinding *node)
bool IRBuilder::visit(QQmlJS::AST::UiArrayBinding *node)
{
- const QQmlJS::AST::SourceLocation qualifiedNameLocation = node->qualifiedId->identifierToken;
+ const QQmlJS::SourceLocation qualifiedNameLocation = node->qualifiedId->identifierToken;
Object *object = nullptr;
QQmlJS::AST::UiQualifiedId *name = node->qualifiedId;
if (!resolveQualifiedId(&name, &object))
@@ -539,7 +559,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiArrayBinding *node)
memberList.append(member);
member = member->next;
}
- for (int i = memberList.count() - 1; i >= 0; --i) {
+ for (int i = memberList.size() - 1; i >= 0; --i) {
member = memberList.at(i);
QQmlJS::AST::UiObjectDefinition *def = QQmlJS::AST::cast<QQmlJS::AST::UiObjectDefinition*>(member->member);
@@ -583,7 +603,10 @@ void IRBuilder::accept(QQmlJS::AST::Node *node)
QQmlJS::AST::Node::accept(node, this);
}
-bool IRBuilder::defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId, const QQmlJS::AST::SourceLocation &location, QQmlJS::AST::UiObjectInitializer *initializer, Object *declarationsOverride)
+bool IRBuilder::defineQMLObject(
+ int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId,
+ const QV4::CompiledData::Location &location, QQmlJS::AST::UiObjectInitializer *initializer,
+ Object *declarationsOverride)
{
if (QQmlJS::AST::UiQualifiedId *lastName = qualifiedTypeNameId) {
while (lastName->next)
@@ -595,12 +618,16 @@ bool IRBuilder::defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qu
}
Object *obj = New<Object>();
+
_objects.append(obj);
*objectIndex = _objects.size() - 1;
qSwap(_object, obj);
_object->init(pool, registerString(asString(qualifiedTypeNameId)), emptyStringIndex, location);
_object->declarationsOverride = declarationsOverride;
+ if (insideInlineComponent) {
+ _object->flags |= QV4::CompiledData::Object::IsPartOfInlineComponent;
+ }
// A new object is also a boundary for property declarations.
Property *declaration = nullptr;
@@ -615,7 +642,7 @@ bool IRBuilder::defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qu
if (!errors.isEmpty())
return false;
- QQmlJS::AST::SourceLocation loc;
+ QQmlJS::SourceLocation loc;
QString error = sanityCheckFunctionNames(obj, illegalNames, &loc);
if (!error.isEmpty()) {
recordError(loc, error);
@@ -660,7 +687,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
// Check for script qualifier clashes
bool isScript = import->type == QV4::CompiledData::Import::ImportScript;
- for (int ii = 0; ii < _imports.count(); ++ii) {
+ for (int ii = 0; ii < _imports.size(); ++ii) {
const QV4::CompiledData::Import *other = _imports.at(ii);
bool otherIsScript = other->type == QV4::CompiledData::Import::ImportScript;
@@ -676,20 +703,13 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
}
if (node->version) {
- import->majorVersion = node->version->majorVersion;
- import->minorVersion = node->version->minorVersion;
- } else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
- recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Library import requires a version"));
- return false;
+ import->version = node->version->version;
} else {
- // For backward compatibility in how the imports are loaded we
- // must otherwise initialize the major and minor version to -1.
- import->majorVersion = -1;
- import->minorVersion = -1;
+ // Otherwise initialize the major and minor version to invalid to signal "latest".
+ import->version = QTypeRevision();
}
- import->location.line = node->importToken.startLine;
- import->location.column = node->importToken.startColumn;
+ import->location.set(node->importToken.startLine, node->importToken.startColumn);
import->uriIndex = registerString(uri);
@@ -698,27 +718,225 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
return false;
}
+
+template<typename Argument>
+struct PragmaParser
+{
+ static bool run(IRBuilder *builder, QQmlJS::AST::UiPragma *node, Pragma *pragma)
+ {
+ Q_ASSERT(builder);
+ Q_ASSERT(node);
+ Q_ASSERT(pragma);
+
+ if (!isUnique(builder)) {
+ builder->recordError(
+ node->pragmaToken, QCoreApplication::translate(
+ "QQmlParser", "Multiple %1 pragmas found").arg(name()));
+ return false;
+ }
+
+ pragma->type = type();
+
+ if (QQmlJS::AST::UiPragmaValueList *bad = assign(pragma, node->values)) {
+ builder->recordError(
+ node->pragmaToken, QCoreApplication::translate(
+ "QQmlParser", "Unknown %1 '%2' in pragma").arg(name(), bad->value));
+ return false;
+ }
+
+ return true;
+ }
+
+private:
+ static constexpr Pragma::PragmaType type()
+ {
+ if constexpr (std::is_same_v<Argument, Pragma::ComponentBehaviorValue>) {
+ return Pragma::ComponentBehavior;
+ } else if constexpr (std::is_same_v<Argument, Pragma::ListPropertyAssignBehaviorValue>) {
+ return Pragma::ListPropertyAssignBehavior;
+ } else if constexpr (std::is_same_v<Argument, Pragma::FunctionSignatureBehaviorValue>) {
+ return Pragma::FunctionSignatureBehavior;
+ } else if constexpr (std::is_same_v<Argument, Pragma::NativeMethodBehaviorValue>) {
+ return Pragma::NativeMethodBehavior;
+ } else if constexpr (std::is_same_v<Argument, Pragma::ValueTypeBehaviorValue>) {
+ return Pragma::ValueTypeBehavior;
+ }
+
+ Q_UNREACHABLE_RETURN(Pragma::PragmaType(-1));
+ }
+
+ template<typename F>
+ static QQmlJS::AST::UiPragmaValueList *iterateValues(
+ QQmlJS::AST::UiPragmaValueList *input, F &&process)
+ {
+ for (QQmlJS::AST::UiPragmaValueList *i = input; i; i = i->next) {
+ if (!process(i->value))
+ return i;
+ }
+ return nullptr;
+ }
+
+ static QQmlJS::AST::UiPragmaValueList *assign(
+ Pragma *pragma, QQmlJS::AST::UiPragmaValueList *values)
+ {
+ // We could use QMetaEnum here to make the code more compact,
+ // but it's probably more expensive.
+
+ if constexpr (std::is_same_v<Argument, Pragma::ComponentBehaviorValue>) {
+ return iterateValues(values, [pragma](QStringView value) {
+ if (value == "Unbound"_L1) {
+ pragma->componentBehavior = Pragma::Unbound;
+ return true;
+ }
+ if (value == "Bound"_L1) {
+ pragma->componentBehavior = Pragma::Bound;
+ return true;
+ }
+ return false;
+ });
+ } else if constexpr (std::is_same_v<Argument, Pragma::ListPropertyAssignBehaviorValue>) {
+ return iterateValues(values, [pragma](QStringView value) {
+ if (value == "Append"_L1) {
+ pragma->listPropertyAssignBehavior = Pragma::Append;
+ return true;
+ }
+ if (value == "Replace"_L1) {
+ pragma->listPropertyAssignBehavior = Pragma::Replace;
+ return true;
+ }
+ if (value == "ReplaceIfNotDefault"_L1) {
+ pragma->listPropertyAssignBehavior = Pragma::ReplaceIfNotDefault;
+ return true;
+ }
+ return false;
+ });
+ } else if constexpr (std::is_same_v<Argument, Pragma::FunctionSignatureBehaviorValue>) {
+ return iterateValues(values, [pragma](QStringView value) {
+ if (value == "Ignored"_L1) {
+ pragma->functionSignatureBehavior = Pragma::Ignored;
+ return true;
+ }
+ if (value == "Enforced"_L1) {
+ pragma->functionSignatureBehavior = Pragma::Enforced;
+ return true;
+ }
+ return false;
+ });
+ } else if constexpr (std::is_same_v<Argument, Pragma::NativeMethodBehaviorValue>) {
+ return iterateValues(values, [pragma](QStringView value) {
+ if (value == "AcceptThisObject"_L1) {
+ pragma->nativeMethodBehavior = Pragma::AcceptThisObject;
+ return true;
+ }
+ if (value == "RejectThisObject"_L1) {
+ pragma->nativeMethodBehavior = Pragma::RejectThisObject;
+ return true;
+ }
+ return false;
+ });
+ } else if constexpr (std::is_same_v<Argument, Pragma::ValueTypeBehaviorValue>) {
+ pragma->valueTypeBehavior = Pragma::ValueTypeBehaviorValues().toInt();
+ return iterateValues(values, [pragma](QStringView value) {
+ const auto setFlag = [pragma](Pragma::ValueTypeBehaviorValue flag, bool value) {
+ pragma->valueTypeBehavior
+ = Pragma::ValueTypeBehaviorValues(pragma->valueTypeBehavior)
+ .setFlag(flag, value).toInt();
+ };
+
+ if (value == "Reference"_L1) {
+ setFlag(Pragma::Copy, false);
+ return true;
+ }
+ if (value == "Copy"_L1) {
+ setFlag(Pragma::Copy, true);
+ return true;
+ }
+
+ if (value == "Inaddressable"_L1) {
+ setFlag(Pragma::Addressable, false);
+ return true;
+ }
+ if (value == "Addressable"_L1) {
+ setFlag(Pragma::Addressable, true);
+ return true;
+ }
+
+ return false;
+ });
+ }
+
+ Q_UNREACHABLE_RETURN(nullptr);
+ }
+
+ static bool isUnique(IRBuilder *builder)
+ {
+ for (const Pragma *prev : builder->_pragmas) {
+ if (prev->type == type())
+ return false;
+ }
+ return true;
+ };
+
+ static QLatin1StringView name()
+ {
+ switch (type()) {
+ case Pragma::ListPropertyAssignBehavior:
+ return "list property assign behavior"_L1;
+ case Pragma::ComponentBehavior:
+ return "component behavior"_L1;
+ case Pragma::FunctionSignatureBehavior:
+ return "function signature behavior"_L1;
+ case Pragma::NativeMethodBehavior:
+ return "native method behavior"_L1;
+ case Pragma::ValueTypeBehavior:
+ return "value type behavior"_L1;
+ default:
+ break;
+ }
+ Q_UNREACHABLE_RETURN(QLatin1StringView());
+ }
+};
+
bool IRBuilder::visit(QQmlJS::AST::UiPragma *node)
{
Pragma *pragma = New<Pragma>();
- // For now the only valid pragma is Singleton, so lets validate the input
- if (!node->name.isNull())
- {
- if (QLatin1String("Singleton") == node->name)
- {
- pragma->type = Pragma::PragmaSingleton;
+ if (!node->name.isNull()) {
+ if (node->name == "Singleton"_L1) {
+ pragma->type = Pragma::Singleton;
+ } else if (node->name == "Strict"_L1) {
+ pragma->type = Pragma::Strict;
+ } else if (node->name == "ComponentBehavior"_L1) {
+ if (!PragmaParser<Pragma::ComponentBehaviorValue>::run(this, node, pragma))
+ return false;
+ } else if (node->name == "ListPropertyAssignBehavior"_L1) {
+ if (!PragmaParser<Pragma::ListPropertyAssignBehaviorValue>::run(this, node, pragma))
+ return false;
+ } else if (node->name == "FunctionSignatureBehavior"_L1) {
+ if (!PragmaParser<Pragma::FunctionSignatureBehaviorValue>::run(this, node, pragma))
+ return false;
+ } else if (node->name == "NativeMethodBehavior"_L1) {
+ if (!PragmaParser<Pragma::NativeMethodBehaviorValue>::run(this, node, pragma))
+ return false;
+ } else if (node->name == "ValueTypeBehavior"_L1) {
+ if (!PragmaParser<Pragma::ValueTypeBehaviorValue>::run(this, node, pragma))
+ return false;
+ } else if (node->name == "Translator"_L1) {
+ pragma->type = Pragma::Translator;
+ pragma->translationContextIndex = registerString(node->values->value.toString());
+
} else {
- recordError(node->pragmaToken, QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier"));
+ recordError(node->pragmaToken, QCoreApplication::translate(
+ "QQmlParser", "Unknown pragma '%1'").arg(node->name));
return false;
}
} else {
- recordError(node->pragmaToken, QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier"));
+ recordError(node->pragmaToken, QCoreApplication::translate(
+ "QQmlParser", "Empty pragma found"));
return false;
}
- pragma->location.line = node->pragmaToken.startLine;
- pragma->location.column = node->pragmaToken.startColumn;
+ pragma->location.set(node->pragmaToken.startLine, node->pragmaToken.startColumn);
_pragmas.append(pragma);
return false;
@@ -751,8 +969,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node)
if (enumName.at(0).isLower())
COMPILE_EXCEPTION(node->enumToken, tr("Scoped enum names must begin with an upper case letter"));
- enumeration->location.line = node->enumToken.startLine;
- enumeration->location.column = node->enumToken.startColumn;
+ enumeration->location.set(node->enumToken.startLine, node->enumToken.startColumn);
enumeration->enumValues = New<PoolList<EnumValue>>();
@@ -771,8 +988,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node)
COMPILE_EXCEPTION(e->valueToken, tr("Enum value out of range"));
enumValue->value = e->value;
- enumValue->location.line = e->memberToken.startLine;
- enumValue->location.column = e->memberToken.startColumn;
+ enumValue->location.set(e->memberToken.startLine, e->memberToken.startColumn);
enumeration->enumValues->append(enumValue);
e = e->next;
@@ -795,25 +1011,25 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
const QString signalName = node->name.toString();
signal->nameIndex = registerString(signalName);
- QQmlJS::AST::SourceLocation loc = node->typeToken;
- signal->location.line = loc.startLine;
- signal->location.column = loc.startColumn;
+ QQmlJS::SourceLocation loc = node->typeToken;
+ signal->location.set(loc.startLine, loc.startColumn);
signal->parameters = New<PoolList<Parameter> >();
QQmlJS::AST::UiParameterList *p = node->parameters;
while (p) {
- const QString memberType = asString(p->type);
-
- if (memberType.isEmpty()) {
+ if (!p->type) {
recordError(node->typeToken, QCoreApplication::translate("QQmlParser","Expected parameter type"));
return false;
}
Parameter *param = New<Parameter>();
- if (!param->init(jsGenerator, p->name.toString(), memberType)) {
+ param->nameIndex = registerString(p->name.toString());
+ if (!Parameter::initType(
+ &param->type, [this](const QString &str) { return registerString(str); },
+ p->type)) {
QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: ");
- errStr.append(memberType);
+ errStr.append(p->type->toString());
recordError(node->typeToken, errStr);
return false;
}
@@ -843,52 +1059,40 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
if (memberType == QLatin1String("alias")) {
return appendAlias(node);
} else {
- const QStringRef &name = node->name;
+ QStringView name = node->name;
Property *property = New<Property>();
- property->isReadOnly = node->isReadonlyMember;
- property->isRequired = node->isRequired;
-
- 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;
-
- property->setCustomType(registerString(memberType));
- if (typeModifier == QLatin1String("list")) {
- property->isList = true;
- } else if (!typeModifier.isEmpty()) {
- recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
- return false;
- }
- typeFound = true;
- } else if (!node->typeModifier.isNull()) {
- recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Unexpected property type modifier"));
- return false;
- }
+ property->setIsReadOnly(node->isReadonly());
+ property->setIsRequired(node->isRequired());
- if (!typeFound) {
- recordError(node->typeToken, QCoreApplication::translate("QQmlParser","Expected property type"));
+ const QV4::CompiledData::CommonType builtinPropertyType
+ = Parameter::stringToBuiltinType(memberType);
+ if (builtinPropertyType != QV4::CompiledData::CommonType::Invalid)
+ property->setCommonType(builtinPropertyType);
+ else
+ property->setTypeNameIndex(registerString(memberType));
+
+ QStringView typeModifier = node->typeModifier;
+ if (typeModifier == QLatin1String("list")) {
+ property->setIsList(true);
+ } else if (!typeModifier.isEmpty()) {
+ recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
return false;
}
const QString propName = name.toString();
property->nameIndex = registerString(propName);
- QQmlJS::AST::SourceLocation loc = node->firstSourceLocation();
- property->location.line = loc.startLine;
- property->location.column = loc.startColumn;
+ QQmlJS::SourceLocation loc = node->firstSourceLocation();
+ property->location.set(loc.startLine, loc.startColumn);
- QQmlJS::AST::SourceLocation errorLocation;
+ QQmlJS::SourceLocation errorLocation;
QString error;
if (illegalNames.contains(propName))
error = tr("Illegal property name");
else
- error = _object->appendProperty(property, propName, node->isDefaultMember, node->defaultToken, &errorLocation);
+ error = _object->appendProperty(property, propName, node->isDefaultMember(), node->defaultToken(), &errorLocation);
if (!error.isEmpty()) {
if (errorLocation.startLine == 0)
@@ -916,6 +1120,14 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
{
if (QQmlJS::AST::FunctionExpression *funDecl = node->sourceElement->asFunctionDefinition()) {
+ if (_object->declarationsOverride) {
+ // See Object::appendFunction() for why.
+ recordError(node->firstSourceLocation(),
+ QCoreApplication::translate(
+ "QQmlParser", "Function declaration inside grouped property"));
+ return false;
+ }
+
CompiledFunctionOrExpression *foe = New<CompiledFunctionOrExpression>();
foe->node = funDecl;
foe->parentNode = funDecl;
@@ -923,14 +1135,16 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
const int index = _object->functionsAndExpressions->append(foe);
Function *f = New<Function>();
- QQmlJS::AST::SourceLocation loc = funDecl->identifierToken;
- f->location.line = loc.startLine;
- f->location.column = loc.startColumn;
+ QQmlJS::SourceLocation loc = funDecl->identifierToken;
+ f->location.set(loc.startLine, loc.startColumn);
f->index = index;
f->nameIndex = registerString(funDecl->name.toString());
- QString returnTypeName = funDecl->typeAnnotation ? funDecl->typeAnnotation->type->toString() : QString();
- Parameter::initType(&f->returnType, jsGenerator, registerString(returnTypeName));
+ const auto idGenerator = [this](const QString &str) { return registerString(str); };
+
+ Parameter::initType(
+ &f->returnType, idGenerator,
+ funDecl->typeAnnotation ? funDecl->typeAnnotation->type : nullptr);
const QQmlJS::AST::BoundNames formals = funDecl->formals ? funDecl->formals->formals() : QQmlJS::AST::BoundNames();
int formalsCount = formals.size();
@@ -938,7 +1152,11 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
int i = 0;
for (const auto &arg : formals) {
- f->formals[i].init(jsGenerator, arg.id, arg.typeName());
+ Parameter *functionParameter = &f->formals[i];
+ functionParameter->nameIndex = registerString(arg.id);
+ Parameter::initType(
+ &functionParameter->type, idGenerator,
+ arg.typeAnnotation.isNull() ? nullptr : arg.typeAnnotation->type);
++i;
}
@@ -949,6 +1167,14 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
return false;
}
+bool IRBuilder::visit(AST::UiRequired *ast)
+{
+ auto extraData = New<RequiredPropertyExtraData>();
+ extraData->nameIndex = registerString(ast->name.toString());
+ _object->appendRequiredPropertyExtraData(extraData);
+ return false;
+}
+
QString IRBuilder::asString(QQmlJS::AST::UiQualifiedId *node)
{
QString s;
@@ -963,60 +1189,58 @@ QString IRBuilder::asString(QQmlJS::AST::UiQualifiedId *node)
return s;
}
-QStringRef IRBuilder::asStringRef(QQmlJS::AST::Node *node)
+QStringView IRBuilder::asStringRef(QQmlJS::AST::Node *node)
{
if (!node)
- return QStringRef();
+ return QStringView();
return textRefAt(node->firstSourceLocation(), node->lastSourceLocation());
}
-void IRBuilder::extractVersion(const QStringRef &string, int *maj, int *min)
+QTypeRevision IRBuilder::extractVersion(QStringView string)
{
- *maj = -1; *min = -1;
+ if (string.isEmpty())
+ return QTypeRevision();
- if (!string.isEmpty()) {
-
- int dot = string.indexOf(QLatin1Char('.'));
-
- if (dot < 0) {
- *maj = string.toInt();
- *min = 0;
- } else {
- *maj = string.left(dot).toInt();
- *min = string.mid(dot + 1).toInt();
- }
- }
+ const int dot = string.indexOf(QLatin1Char('.'));
+ return (dot < 0)
+ ? QTypeRevision::fromMajorVersion(string.toInt())
+ : QTypeRevision::fromVersion(string.left(dot).toInt(), string.mid(dot + 1).toInt());
}
-QStringRef IRBuilder::textRefAt(const QQmlJS::AST::SourceLocation &first, const QQmlJS::AST::SourceLocation &last) const
+QStringView IRBuilder::textRefAt(const QQmlJS::SourceLocation &first, const QQmlJS::SourceLocation &last) const
{
- return QStringRef(&sourceCode, first.offset, last.offset + last.length - first.offset);
+ return QStringView(sourceCode).mid(first.offset, last.offset + last.length - first.offset);
}
void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, QQmlJS::AST::Node *parentNode)
{
- QQmlJS::AST::SourceLocation loc = statement->firstSourceLocation();
- binding->valueLocation.line = loc.startLine;
- binding->valueLocation.column = loc.startColumn;
- binding->type = QV4::CompiledData::Binding::Type_Invalid;
- if (_propertyDeclaration && _propertyDeclaration->isReadOnly)
- binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
+ QQmlJS::SourceLocation loc = statement->firstSourceLocation();
+ binding->valueLocation.set(loc.startLine, loc.startColumn);
+ binding->setType(QV4::CompiledData::Binding::Type_Invalid);
+ if (_propertyDeclaration && _propertyDeclaration->isReadOnly())
+ binding->setFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration);
QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
if (exprStmt) {
QQmlJS::AST::ExpressionNode * const expr = exprStmt->expression;
if (QQmlJS::AST::StringLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(expr)) {
- binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->setType(QV4::CompiledData::Binding::Type_String);
binding->stringIndex = registerString(lit->value.toString());
+ } else if (QQmlJS::AST::TemplateLiteral *templateLit = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expr);
+ templateLit && templateLit->hasNoSubstitution) {
+ // A template literal without substitution is just a string.
+ // With substitution, it could however be an arbitrarily complex expression
+ binding->setType(QV4::CompiledData::Binding::Type_String);
+ binding->stringIndex = registerString(templateLit->value.toString());
} else if (expr->kind == QQmlJS::AST::Node::Kind_TrueLiteral) {
- binding->type = QV4::CompiledData::Binding::Type_Boolean;
+ binding->setType(QV4::CompiledData::Binding::Type_Boolean);
binding->value.b = true;
} else if (expr->kind == QQmlJS::AST::Node::Kind_FalseLiteral) {
- binding->type = QV4::CompiledData::Binding::Type_Boolean;
+ binding->setType(QV4::CompiledData::Binding::Type_Boolean);
binding->value.b = false;
} else if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(expr)) {
- binding->type = QV4::CompiledData::Binding::Type_Number;
+ binding->setType(QV4::CompiledData::Binding::Type_Number);
binding->value.constantValueIndex = jsGenerator->registerConstant(QV4::Encode(lit->value));
} else if (QQmlJS::AST::CallExpression *call = QQmlJS::AST::cast<QQmlJS::AST::CallExpression *>(expr)) {
if (QQmlJS::AST::IdentifierExpression *base = QQmlJS::AST::cast<QQmlJS::AST::IdentifierExpression *>(call->base)) {
@@ -1025,21 +1249,21 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
// below.
}
} else if (QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression *>(expr)) {
- binding->flags |= QV4::CompiledData::Binding::IsFunctionExpression;
+ binding->setFlag(QV4::CompiledData::Binding::IsFunctionExpression);
} else if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast<QQmlJS::AST::UnaryMinusExpression *>(expr)) {
if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression)) {
- binding->type = QV4::CompiledData::Binding::Type_Number;
+ binding->setType(QV4::CompiledData::Binding::Type_Number);
binding->value.constantValueIndex = jsGenerator->registerConstant(QV4::Encode(-lit->value));
}
} else if (QQmlJS::AST::cast<QQmlJS::AST::NullExpression *>(expr)) {
- binding->type = QV4::CompiledData::Binding::Type_Null;
+ binding->setType(QV4::CompiledData::Binding::Type_Null);
binding->value.nullMarker = 0;
}
}
// Do binding instead
- if (binding->type == QV4::CompiledData::Binding::Type_Invalid) {
- binding->type = QV4::CompiledData::Binding::Type_Script;
+ if (binding->type() == QV4::CompiledData::Binding::Type_Invalid) {
+ binding->setType(QV4::CompiledData::Binding::Type_Script);
CompiledFunctionOrExpression *expr = New<CompiledFunctionOrExpression>();
expr->node = statement;
@@ -1050,130 +1274,44 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
binding->value.compiledScriptIndex = index;
// We don't need to store the binding script as string, except for script strings
// and types with custom parsers. Those will be added later in the compilation phase.
- binding->stringIndex = emptyStringIndex;
+ // Except that we cannot recover the string when cachegen runs; we need to therefore retain
+ // "undefined". Any other "special" strings (for the various literals) are already handled above
+ QQmlJS::AST::Node *nodeForString = statement;
+ if (exprStmt)
+ nodeForString = exprStmt->expression;
+ if (asStringRef(nodeForString) == u"undefined")
+ binding->stringIndex = registerString(u"undefined"_s);
+ else
+ binding->stringIndex = emptyStringIndex;
}
}
-void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::ArgumentList *args, QV4::CompiledData::Binding *binding)
+void IRBuilder::tryGeneratingTranslationBinding(QStringView base, AST::ArgumentList *args, QV4::CompiledData::Binding *binding)
{
- if (base == QLatin1String("qsTr")) {
- QV4::CompiledData::TranslationData translationData;
- translationData.number = -1;
- translationData.commentIndex = 0; // empty string
- translationData.padding = 0;
-
- if (!args || !args->expression)
- return; // no arguments, stop
-
- QStringRef translation;
- if (QQmlJS::AST::StringLiteral *arg1 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) {
- translation = arg1->value;
- } else {
- return; // first argument is not a string, stop
- }
- translationData.stringIndex = jsGenerator->registerString(translation.toString());
-
- args = args->next;
-
- if (args) {
- QQmlJS::AST::StringLiteral *arg2 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression);
- if (!arg2)
- return; // second argument is not a string, stop
- translationData.commentIndex = jsGenerator->registerString(arg2->value.toString());
-
- args = args->next;
- if (args) {
- if (QQmlJS::AST::NumericLiteral *arg3 = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(args->expression)) {
- translationData.number = int(arg3->value);
- args = args->next;
- } else {
- return; // third argument is not a translation number, stop
- }
- }
- }
-
- if (args)
- return; // too many arguments, stop
-
- binding->type = QV4::CompiledData::Binding::Type_Translation;
- binding->value.translationDataIndex = jsGenerator->registerTranslation(translationData);
- } else if (base == QLatin1String("qsTrId")) {
- QV4::CompiledData::TranslationData translationData;
- translationData.number = -1;
- translationData.commentIndex = 0; // empty string, but unused
- translationData.padding = 0;
-
- if (!args || !args->expression)
- return; // no arguments, stop
-
- QStringRef id;
- if (QQmlJS::AST::StringLiteral *arg1 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) {
- id = arg1->value;
- } else {
- return; // first argument is not a string, stop
- }
- translationData.stringIndex = jsGenerator->registerString(id.toString());
-
- args = args->next;
-
- if (args) {
- if (QQmlJS::AST::NumericLiteral *arg3 = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(args->expression)) {
- translationData.number = int(arg3->value);
- args = args->next;
- } else {
- return; // third argument is not a translation number, stop
- }
- }
-
- if (args)
- return; // too many arguments, stop
-
- binding->type = QV4::CompiledData::Binding::Type_TranslationById;
- binding->value.translationDataIndex = jsGenerator->registerTranslation(translationData);
- } else if (base == QLatin1String("QT_TR_NOOP") || base == QLatin1String("QT_TRID_NOOP")) {
- if (!args || !args->expression)
- return; // no arguments, stop
+ const auto registerString = [&](QStringView string) {
+ return jsGenerator->registerString(string.toString()) ;
+ };
- QStringRef str;
- if (QQmlJS::AST::StringLiteral *arg1 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) {
- str = arg1->value;
- } else {
- return; // first argument is not a string, stop
+ const auto finalizeTranslationData = [&](
+ QV4::CompiledData::Binding::Type type,
+ QV4::CompiledData::TranslationData translationData) {
+ binding->setType(type);
+ if (type == QV4::CompiledData::Binding::Type_Translation
+ || type == QV4::CompiledData::Binding::Type_TranslationById) {
+ binding->value.translationDataIndex = jsGenerator->registerTranslation(translationData);
+ } else if (type == QV4::CompiledData::Binding::Type_String) {
+ binding->stringIndex = translationData.number;
}
+ };
- args = args->next;
- if (args)
- return; // too many arguments, stop
-
- binding->type = QV4::CompiledData::Binding::Type_String;
- binding->stringIndex = jsGenerator->registerString(str.toString());
- } else if (base == QLatin1String("QT_TRANSLATE_NOOP")) {
- if (!args || !args->expression)
- return; // no arguments, stop
-
- args = args->next;
- if (!args || !args->expression)
- return; // no second arguments, stop
-
- QStringRef str;
- if (QQmlJS::AST::StringLiteral *arg2 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) {
- str = arg2->value;
- } else {
- return; // first argument is not a string, stop
- }
-
- args = args->next;
- if (args)
- return; // too many arguments, stop
-
- binding->type = QV4::CompiledData::Binding::Type_String;
- binding->stringIndex = jsGenerator->registerString(str.toString());
- }
+ tryGeneratingTranslationBindingBase(
+ base, args,
+ registerString, registerString, registerString, finalizeTranslationData);
}
void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Statement *value, QQmlJS::AST::Node *parentNode)
{
- const QQmlJS::AST::SourceLocation qualifiedNameLocation = name->identifierToken;
+ const QQmlJS::SourceLocation qualifiedNameLocation = name->identifierToken;
Object *object = nullptr;
if (!resolveQualifiedId(&name, &object))
return;
@@ -1188,7 +1326,7 @@ void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Sta
void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, int objectIndex, bool isOnAssignment)
{
- const QQmlJS::AST::SourceLocation qualifiedNameLocation = name->identifierToken;
+ const QQmlJS::SourceLocation qualifiedNameLocation = name->identifierToken;
Object *object = nullptr;
if (!resolveQualifiedId(&name, &object, isOnAssignment))
return;
@@ -1197,15 +1335,14 @@ void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, int objectIndex,
qSwap(_object, object);
}
-void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex,
+void IRBuilder::appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocation, const QQmlJS::SourceLocation &nameLocation, quint32 propertyNameIndex,
QQmlJS::AST::Statement *value, QQmlJS::AST::Node *parentNode)
{
Binding *binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
binding->offset = nameLocation.offset;
- binding->location.line = nameLocation.startLine;
- binding->location.column = nameLocation.startColumn;
- binding->flags = 0;
+ binding->location.set(nameLocation.startLine, nameLocation.startColumn);
+ binding->clearFlags();
setBindingValue(binding, value, parentNode);
QString error = bindingsTarget()->appendBinding(binding, /*isListBinding*/false);
if (!error.isEmpty()) {
@@ -1213,7 +1350,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo
}
}
-void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem, bool isOnAssignment)
+void IRBuilder::appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocation, const QQmlJS::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem, bool isOnAssignment)
{
if (stringAt(propertyNameIndex) == QLatin1String("id")) {
recordError(nameLocation, tr("Invalid component id specification"));
@@ -1223,27 +1360,26 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo
Binding *binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
binding->offset = nameLocation.offset;
- binding->location.line = nameLocation.startLine;
- binding->location.column = nameLocation.startColumn;
+ binding->location.set(nameLocation.startLine, nameLocation.startColumn);
const Object *obj = _objects.at(objectIndex);
binding->valueLocation = obj->location;
- binding->flags = 0;
+ binding->clearFlags();
- if (_propertyDeclaration && _propertyDeclaration->isReadOnly)
- binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
+ if (_propertyDeclaration && _propertyDeclaration->isReadOnly())
+ binding->setFlag(Binding::InitializerForReadOnlyDeclaration);
// No type name on the initializer means it must be a group property
if (_objects.at(objectIndex)->inheritedTypeNameIndex == emptyStringIndex)
- binding->type = QV4::CompiledData::Binding::Type_GroupProperty;
+ binding->setType(Binding::Type_GroupProperty);
else
- binding->type = QV4::CompiledData::Binding::Type_Object;
+ binding->setType(Binding::Type_Object);
if (isOnAssignment)
- binding->flags |= QV4::CompiledData::Binding::IsOnAssignment;
+ binding->setFlag(Binding::IsOnAssignment);
if (isListItem)
- binding->flags |= QV4::CompiledData::Binding::IsListItem;
+ binding->setFlag(Binding::IsListItem);
binding->value.objectIndex = objectIndex;
QString error = bindingsTarget()->appendBinding(binding, isListItem);
@@ -1255,31 +1391,29 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo
bool IRBuilder::appendAlias(QQmlJS::AST::UiPublicMember *node)
{
Alias *alias = New<Alias>();
- alias->flags = 0;
- if (node->isReadonlyMember)
- alias->flags |= QV4::CompiledData::Alias::IsReadOnly;
+ alias->clearFlags();
+ if (node->isReadonly())
+ alias->setFlag(QV4::CompiledData::Alias::IsReadOnly);
const QString propName = node->name.toString();
- alias->nameIndex = registerString(propName);
+ alias->setNameIndex(registerString(propName));
- QQmlJS::AST::SourceLocation loc = node->firstSourceLocation();
- alias->location.line = loc.startLine;
- alias->location.column = loc.startColumn;
+ QQmlJS::SourceLocation loc = node->firstSourceLocation();
+ alias->location.set(loc.startLine, loc.startColumn);
alias->propertyNameIndex = emptyStringIndex;
if (!node->statement && !node->binding)
COMPILE_EXCEPTION(loc, tr("No property alias location"));
- QQmlJS::AST::SourceLocation rhsLoc;
+ QQmlJS::SourceLocation rhsLoc;
if (node->binding)
rhsLoc = node->binding->firstSourceLocation();
else if (node->statement)
rhsLoc = node->statement->firstSourceLocation();
else
rhsLoc = node->semicolonToken;
- alias->referenceLocation.line = rhsLoc.startLine;
- alias->referenceLocation.column = rhsLoc.startColumn;
+ alias->referenceLocation.set(rhsLoc.startLine, rhsLoc.startColumn);
QStringList aliasReference;
@@ -1296,23 +1430,23 @@ bool IRBuilder::appendAlias(QQmlJS::AST::UiPublicMember *node)
COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
}
- if (aliasReference.count() < 1 || aliasReference.count() > 3)
+ if (aliasReference.size() < 1 || aliasReference.size() > 3)
COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
- alias->idIndex = registerString(aliasReference.first());
+ alias->setIdIndex(registerString(aliasReference.first()));
QString propertyValue = aliasReference.value(1);
- if (aliasReference.count() == 3)
+ if (aliasReference.size() == 3)
propertyValue += QLatin1Char('.') + aliasReference.at(2);
alias->propertyNameIndex = registerString(propertyValue);
- QQmlJS::AST::SourceLocation errorLocation;
+ QQmlJS::SourceLocation errorLocation;
QString error;
if (illegalNames.contains(propName))
error = tr("Illegal property name");
else
- error = _object->appendAlias(alias, propName, node->isDefaultMember, node->defaultToken, &errorLocation);
+ error = _object->appendAlias(alias, propName, node->isDefaultMember(), node->defaultToken(), &errorLocation);
if (!error.isEmpty()) {
if (errorLocation.startLine == 0)
@@ -1332,10 +1466,10 @@ Object *IRBuilder::bindingsTarget() const
return _object;
}
-bool IRBuilder::setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST::Statement *value)
+bool IRBuilder::setId(const QQmlJS::SourceLocation &idLocation, QQmlJS::AST::Statement *value)
{
- QQmlJS::AST::SourceLocation loc = value->firstSourceLocation();
- QStringRef str;
+ QQmlJS::SourceLocation loc = value->firstSourceLocation();
+ QStringView str;
QQmlJS::AST::Node *node = value;
if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(node)) {
@@ -1360,7 +1494,7 @@ bool IRBuilder::setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST
if (!ch.isLetter() && ch != u)
COMPILE_EXCEPTION(loc, tr( "IDs must start with a letter or underscore"));
- for (int ii = 1; ii < str.count(); ++ii) {
+ for (int ii = 1; ii < str.size(); ++ii) {
ch = str.at(ii);
if (!ch.isLetterOrNumber() && ch != u)
COMPILE_EXCEPTION(loc, tr( "IDs must contain only letters, numbers, and underscores"));
@@ -1374,8 +1508,7 @@ bool IRBuilder::setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST
COMPILE_EXCEPTION(idLocation, tr("Property value set multiple times"));
_object->idNameIndex = registerString(idQString);
- _object->locationOfIdProperty.line = idLocation.startLine;
- _object->locationOfIdProperty.column = idLocation.startColumn;
+ _object->locationOfIdProperty.set(idLocation.startLine, idLocation.startColumn);
return true;
}
@@ -1390,13 +1523,13 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
// If it's a namespace, prepend the qualifier and we'll resolve it later to the correct type.
QString currentName = qualifiedIdElement->name.toString();
if (qualifiedIdElement->next) {
- for (const QV4::CompiledData::Import* import : qAsConst(_imports))
+ for (const QV4::CompiledData::Import* import : std::as_const(_imports))
if (import->qualifierIndex != emptyStringIndex
&& stringAt(import->qualifierIndex) == currentName) {
qualifiedIdElement = qualifiedIdElement->next;
currentName += QLatin1Char('.') + qualifiedIdElement->name;
- if (!qualifiedIdElement->name.unicode()->isUpper())
+ if (!qualifiedIdElement->name.data()->isUpper())
COMPILE_EXCEPTION(qualifiedIdElement->firstSourceLocation(), tr("Expected type name"));
break;
@@ -1406,7 +1539,7 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
*object = _object;
while (qualifiedIdElement->next) {
const quint32 propertyNameIndex = registerString(currentName);
- const bool isAttachedProperty = qualifiedIdElement->name.unicode()->isUpper();
+ const bool isAttachedProperty = qualifiedIdElement->name.data()->isUpper();
Binding *binding = (*object)->findBinding(propertyNameIndex);
if (binding) {
@@ -1421,22 +1554,22 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
binding->offset = qualifiedIdElement->identifierToken.offset;
- binding->location.line = qualifiedIdElement->identifierToken.startLine;
- binding->location.column = qualifiedIdElement->identifierToken.startColumn;
- binding->valueLocation.line = qualifiedIdElement->next->identifierToken.startLine;
- binding->valueLocation.column = qualifiedIdElement->next->identifierToken.startColumn;
- binding->flags = 0;
+ binding->location.set(qualifiedIdElement->identifierToken.startLine,
+ qualifiedIdElement->identifierToken.startColumn);
+ binding->valueLocation.set(qualifiedIdElement->next->identifierToken.startLine,
+ qualifiedIdElement->next->identifierToken.startColumn);
+ binding->clearFlags();
if (onAssignment)
- binding->flags |= QV4::CompiledData::Binding::IsOnAssignment;
+ binding->setFlag(QV4::CompiledData::Binding::IsOnAssignment);
if (isAttachedProperty)
- binding->type = QV4::CompiledData::Binding::Type_AttachedProperty;
+ binding->setType(QV4::CompiledData::Binding::Type_AttachedProperty);
else
- binding->type = QV4::CompiledData::Binding::Type_GroupProperty;
+ binding->setType(QV4::CompiledData::Binding::Type_GroupProperty);
int objIndex = 0;
- if (!defineQMLObject(&objIndex, nullptr, QQmlJS::AST::SourceLocation(), nullptr, nullptr))
+ if (!defineQMLObject(&objIndex, nullptr, binding->location, nullptr, nullptr))
return false;
binding->value.objectIndex = objIndex;
@@ -1459,11 +1592,10 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
return true;
}
-void IRBuilder::recordError(const QQmlJS::AST::SourceLocation &location, const QString &description)
+void IRBuilder::recordError(const QQmlJS::SourceLocation &location, const QString &description)
{
QQmlJS::DiagnosticMessage error;
- error.line = location.startLine;
- error.column = location.startColumn;
+ error.loc = location;
error.message = description;
errors << error;
}
@@ -1495,7 +1627,7 @@ bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement)
bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement)
{
- if (property->isBuiltinType || property->isList)
+ if (property->isCommonType() || property->isList())
return false;
QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
if (!exprStmt)
@@ -1506,23 +1638,91 @@ bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *prope
void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
{
+ using namespace QV4::CompiledData;
+
output.jsGenerator.stringTable.registerString(output.jsModule.fileName);
output.jsGenerator.stringTable.registerString(output.jsModule.finalUrl);
- QV4::CompiledData::Unit *jsUnit = nullptr;
+ Unit *jsUnit = nullptr;
+
+ if (!output.javaScriptCompilationUnit)
+ output.javaScriptCompilationUnit.adopt(new QV4::CompiledData::CompilationUnit);
// We may already have unit data if we're loading an ahead-of-time generated cache file.
- if (output.javaScriptCompilationUnit.data) {
- jsUnit = const_cast<QV4::CompiledData::Unit *>(output.javaScriptCompilationUnit.data);
- output.javaScriptCompilationUnit.dynamicStrings = output.jsGenerator.stringTable.allStrings();
+ if (output.javaScriptCompilationUnit->unitData()) {
+ jsUnit = const_cast<Unit *>(output.javaScriptCompilationUnit->unitData());
+ output.javaScriptCompilationUnit->dynamicStrings
+ = output.jsGenerator.stringTable.allStrings();
} else {
- QV4::CompiledData::Unit *createdUnit;
+ Unit *createdUnit;
jsUnit = createdUnit = output.jsGenerator.generateUnit();
// enable flag if we encountered pragma Singleton
- for (Pragma *p : qAsConst(output.pragmas)) {
- if (p->type == Pragma::PragmaSingleton) {
- createdUnit->flags |= QV4::CompiledData::Unit::IsSingleton;
+ for (Pragma *p : std::as_const(output.pragmas)) {
+ switch (p->type) {
+ case Pragma::Singleton:
+ createdUnit->flags |= Unit::IsSingleton;
+ break;
+ case Pragma::Strict:
+ createdUnit->flags |= Unit::IsStrict;
+ break;
+ case Pragma::ComponentBehavior:
+ // ### Qt7: Change the default to Bound by reverting the meaning of the flag.
+ switch (p->componentBehavior) {
+ case Pragma::Bound:
+ createdUnit->flags |= Unit::ComponentsBound;
+ break;
+ case Pragma::Unbound:
+ // this is the default
+ break;
+ }
+ break;
+ case Pragma::ListPropertyAssignBehavior:
+ switch (p->listPropertyAssignBehavior) {
+ case Pragma::Replace:
+ createdUnit->flags |= Unit::ListPropertyAssignReplace;
+ break;
+ case Pragma::ReplaceIfNotDefault:
+ createdUnit->flags |= Unit::ListPropertyAssignReplaceIfNotDefault;
+ break;
+ case Pragma::Append:
+ // this is the default
+ break;
+ }
+ break;
+ case Pragma::FunctionSignatureBehavior:
+ switch (p->functionSignatureBehavior) {
+ case Pragma::Enforced:
+ break;
+ case Pragma::Ignored:
+ createdUnit->flags |= Unit::FunctionSignaturesIgnored;
+ break;
+ }
+ break;
+ case Pragma::NativeMethodBehavior:
+ switch (p->nativeMethodBehavior) {
+ case Pragma::AcceptThisObject:
+ createdUnit->flags |= Unit::NativeMethodsAcceptThisObject;
+ break;
+ case Pragma::RejectThisObject:
+ // this is the default;
+ break;
+ }
+ break;
+ case Pragma::ValueTypeBehavior:
+ if (Pragma::ValueTypeBehaviorValues(p->valueTypeBehavior)
+ .testFlag(Pragma::Copy)) {
+ createdUnit->flags |= Unit::ValueTypesCopied;
+ }
+ if (Pragma::ValueTypeBehaviorValues(p->valueTypeBehavior)
+ .testFlag(Pragma::Addressable)) {
+ createdUnit->flags |= Unit::ValueTypesAddressable;
+ }
+ break;
+ case Pragma::Translator:
+ if (createdUnit->translationTableSize)
+ if (quint32_le *index = createdUnit->translationContextIndex())
+ *index = p->translationContextIndex;
break;
}
}
@@ -1542,16 +1742,16 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
// No more new strings after this point, we're calculating offsets.
output.jsGenerator.stringTable.freeze();
- const uint importSize = sizeof(QV4::CompiledData::Import) * output.imports.count();
- const uint objectOffsetTableSize = output.objects.count() * sizeof(quint32);
+ const uint importSize = uint(sizeof(QV4::CompiledData::Import)) * output.imports.size();
+ const uint objectOffsetTableSize = output.objects.size() * uint(sizeof(quint32));
QHash<const Object*, quint32> objectOffsets;
const unsigned int objectOffset = sizeof(QV4::CompiledData::QmlUnit) + importSize;
uint nextOffset = objectOffset + objectOffsetTableSize;
- for (Object *o : qAsConst(output.objects)) {
+ for (Object *o : std::as_const(output.objects)) {
objectOffsets.insert(o, nextOffset);
- nextOffset += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.size());
+ nextOffset += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.size(), o->inlineComponentCount(), o->requiredPropertyExtraDataCount());
int signalTableSize = 0;
for (const Signal *s = o->firstSignal(); s; s = s->next)
@@ -1571,13 +1771,13 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
memset(data, 0, totalSize);
QV4::CompiledData::QmlUnit *qmlUnit = reinterpret_cast<QV4::CompiledData::QmlUnit *>(data);
qmlUnit->offsetToImports = sizeof(*qmlUnit);
- qmlUnit->nImports = output.imports.count();
+ qmlUnit->nImports = output.imports.size();
qmlUnit->offsetToObjects = objectOffset;
- qmlUnit->nObjects = output.objects.count();
+ qmlUnit->nObjects = output.objects.size();
// write imports
char *importPtr = data + qmlUnit->offsetToImports;
- for (const QV4::CompiledData::Import *imp : qAsConst(output.imports)) {
+ for (const QV4::CompiledData::Import *imp : std::as_const(output.imports)) {
QV4::CompiledData::Import *importToWrite = reinterpret_cast<QV4::CompiledData::Import*>(importPtr);
*importToWrite = *imp;
importPtr += sizeof(QV4::CompiledData::Import);
@@ -1585,7 +1785,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
// write objects
quint32_le *objectTable = reinterpret_cast<quint32_le*>(data + qmlUnit->offsetToObjects);
- for (int i = 0; i < output.objects.count(); ++i) {
+ for (int i = 0; i < output.objects.size(); ++i) {
const Object *o = output.objects.at(i);
char * const objectPtr = data + objectOffsets.value(o);
*objectTable++ = objectOffsets.value(o);
@@ -1593,10 +1793,10 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr);
objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex;
objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias;
- objectToWrite->defaultPropertyIsAlias = o->defaultPropertyIsAlias;
- objectToWrite->flags = o->flags;
+ objectToWrite->setHasAliasAsDefaultProperty(o->defaultPropertyIsAlias);
+ objectToWrite->setFlags(QV4::CompiledData::Object::Flags(o->flags));
objectToWrite->idNameIndex = o->idNameIndex;
- objectToWrite->id = o->id;
+ objectToWrite->setObjectId(o->id);
objectToWrite->location = o->location;
objectToWrite->locationOfIdProperty = o->locationOfIdProperty;
@@ -1630,6 +1830,14 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
objectToWrite->offsetToNamedObjectsInComponent = nextOffset;
nextOffset += objectToWrite->nNamedObjectsInComponent * sizeof(quint32);
+ objectToWrite->nInlineComponents = o->inlineComponentCount();
+ objectToWrite->offsetToInlineComponents = nextOffset;
+ nextOffset += objectToWrite->nInlineComponents * sizeof (QV4::CompiledData::InlineComponent);
+
+ objectToWrite->nRequiredPropertyExtraData = o->requiredPropertyExtraDataCount();
+ objectToWrite->offsetToRequiredPropertyExtraData = nextOffset;
+ nextOffset += objectToWrite->nRequiredPropertyExtraData * sizeof(QV4::CompiledData::RequiredPropertyExtraData);
+
quint32_le *functionsTable = reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToFunctions);
for (const Function *f = o->firstFunction(); f; f = f->next)
*functionsTable++ = o->runtimeFunctionIndices.at(f->index);
@@ -1678,7 +1886,6 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
nextOffset += signalTableSize;
quint32_le *enumOffsetTable = reinterpret_cast<quint32_le*>(objectPtr + objectToWrite->offsetToEnums);
- quint32 enumTableSize = 0;
char *enumPtr = objectPtr + nextOffset;
for (const Enum *e = o->firstEnum(); e; e = e->next) {
*enumOffsetTable++ = enumPtr - objectPtr;
@@ -1693,7 +1900,6 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
*enumValueToWrite = *enumValue;
int size = QV4::CompiledData::Enum::calculateSize(e->enumValues->count);
- enumTableSize += size;
enumPtr += size;
}
@@ -1701,9 +1907,25 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
for (int i = 0; i < o->namedObjectsInComponent.size(); ++i) {
*namedObjectInComponentPtr++ = o->namedObjectsInComponent.at(i);
}
+
+ char *inlineComponentPtr = objectPtr + objectToWrite->offsetToInlineComponents;
+ for (auto it = o->inlineComponentsBegin(); it != o->inlineComponentsEnd(); ++it) {
+ const InlineComponent *ic = it.ptr;
+ QV4::CompiledData::InlineComponent *icToWrite = reinterpret_cast<QV4::CompiledData::InlineComponent*>(inlineComponentPtr);
+ *icToWrite = *ic;
+ inlineComponentPtr += sizeof(QV4::CompiledData::InlineComponent);
+ }
+
+ char *requiredPropertyExtraDataPtr = objectPtr + objectToWrite->offsetToRequiredPropertyExtraData;
+ for (auto it = o->requiredPropertyExtraDataBegin(); it != o->requiredPropertyExtraDataEnd(); ++it) {
+ const RequiredPropertyExtraData *extraData = it.ptr;
+ QV4::CompiledData::RequiredPropertyExtraData *extraDataToWrite = reinterpret_cast<QV4::CompiledData::RequiredPropertyExtraData*>(requiredPropertyExtraDataPtr);
+ *extraDataToWrite = *extraData;
+ requiredPropertyExtraDataPtr += sizeof(QV4::CompiledData::RequiredPropertyExtraData);
+ }
}
- if (!output.javaScriptCompilationUnit.data) {
+ if (!output.javaScriptCompilationUnit->unitData()) {
// Combine the qml data into the general unit data.
jsUnit = static_cast<QV4::CompiledData::Unit *>(realloc(jsUnit, jsUnit->unitSize + totalSize));
jsUnit->offsetToQmlUnit = jsUnit->unitSize;
@@ -1736,8 +1958,8 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
qDebug() << " " << totalStringSize << "bytes total strings";
}
- output.javaScriptCompilationUnit.setUnitData(jsUnit, qmlUnit, output.jsModule.fileName,
- output.jsModule.finalUrl);
+ output.javaScriptCompilationUnit->setUnitData(
+ jsUnit, qmlUnit, output.jsModule.fileName, output.jsModule.finalUrl);
}
char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const
@@ -1747,22 +1969,27 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding
continue;
QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
*bindingToWrite = *b;
- if (b->type == QV4::CompiledData::Binding::Type_Script)
+ if (b->type() == QV4::CompiledData::Binding::Type_Script)
bindingToWrite->value.compiledScriptIndex = o->runtimeFunctionIndices.at(b->value.compiledScriptIndex);
bindingPtr += sizeof(QV4::CompiledData::Binding);
}
return bindingPtr;
}
-JSCodeGen::JSCodeGen(Document *document, const QSet<QString> &globalNames)
- : QV4::Compiler::Codegen(&document->jsGenerator, /*strict mode*/false), document(document)
+JSCodeGen::JSCodeGen(Document *document, const QSet<QString> &globalNames,
+ QV4::Compiler::CodegenWarningInterface *iface,
+ bool storeSourceLocations)
+ : QV4::Compiler::Codegen(&document->jsGenerator, /*strict mode*/ false, iface,
+ storeSourceLocations),
+ document(document)
{
m_globalNames = globalNames;
_module = &document->jsModule;
_fileNameIsUrl = true;
}
-QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions)
+QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(
+ const QList<CompiledFunctionOrExpression> &functions)
{
auto qmlName = [&](const CompiledFunctionOrExpression &c) {
if (c.nameIndex != 0)
@@ -1786,6 +2013,12 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
scan.enterEnvironment(f.parentNode, QV4::Compiler::ContextType::Binding, qmlName(f));
}
+ /* We do not want to visit the whole function, as we already called enterQmlFunction
+ However, there might be a function defined as a default argument of the function.
+ That needs to be considered, too, so we call handleTopLevelFunctionFormals to
+ deal with them.
+ */
+ scan.handleTopLevelFunctionFormals(function);
scan(function ? function->body : f.node);
scan.leaveEnvironment();
}
@@ -1796,7 +2029,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
_context = nullptr;
- for (int i = 0; i < functions.count(); ++i) {
+ for (int i = 0; i < functions.size(); ++i) {
const CompiledFunctionOrExpression &qmlFunction = functions.at(i);
QQmlJS::AST::Node *node = qmlFunction.node;
Q_ASSERT(node != document->program);
@@ -1827,65 +2060,30 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
}
int idx = defineFunction(name, function ? function : qmlFunction.parentNode,
- function ? function->formals : nullptr,
- body);
+ function ? function->formals : nullptr, body);
runtimeFunctionIndices[i] = idx;
}
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)
+bool JSCodeGen::generateRuntimeFunctions(QmlIR::Object *object)
{
- QmlIR::Object *object = document->objects.at(objectIndex);
- if (object->flags & QV4::CompiledData::Object::IsComponent)
+ if (object->functionsAndExpressions->count == 0)
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);
+ QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
+ functionsToCompile.reserve(object->functionsAndExpressions->count);
+ for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe;
+ foe = foe->next) {
+ functionsToCompile << *foe;
}
- 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;
- }
+ const auto runtimeFunctionIndices = generateJSCodeForFunctionsAndBindings(functionsToCompile);
+ if (hasError())
+ return false;
+ object->runtimeFunctionIndices.allocate(document->jsParserEngine.pool(),
+ runtimeFunctionIndices);
return true;
}
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 4279f5b768..546d1fac58 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLIRBUILDER_P_H
#define QQMLIRBUILDER_P_H
@@ -158,6 +122,13 @@ struct PoolList
}
struct Iterator {
+ // turn Iterator into a proper iterator
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = T;
+ using difference_type = ptrdiff_t;
+ using pointer = T *;
+ using reference = T &;
+
T *ptr;
explicit Iterator(T *p) : ptr(p) {}
@@ -178,8 +149,15 @@ struct PoolList
return *ptr;
}
- void operator++() {
+ Iterator& operator++() {
+ ptr = ptr->next;
+ return *this;
+ }
+
+ Iterator operator++(int) {
+ Iterator that {ptr};
ptr = ptr->next;
+ return that;
}
bool operator==(const Iterator &rhs) const {
@@ -189,10 +167,15 @@ struct PoolList
bool operator!=(const Iterator &rhs) const {
return ptr != rhs.ptr;
}
+
+ operator T *() { return ptr; }
+ operator const T *() const { return ptr; }
};
Iterator begin() { return Iterator(first); }
Iterator end() { return Iterator(nullptr); }
+
+ using iterator = Iterator;
};
struct Object;
@@ -220,13 +203,36 @@ struct Parameter : public QV4::CompiledData::Parameter
{
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);
+ template<typename IdGenerator>
+ static bool initType(
+ QV4::CompiledData::ParameterType *type, const IdGenerator &idGenerator,
+ const QQmlJS::AST::Type *annotation)
+ {
+ using Flag = QV4::CompiledData::ParameterType::Flag;
+
+ if (!annotation)
+ return initType(type, QString(), idGenerator(QString()), Flag::NoFlag);
+
+ const QString typeId = annotation->typeId->toString();
+ const QString typeArgument =
+ annotation->typeArgument ? annotation->typeArgument->toString() : QString();
+
+ if (typeArgument.isEmpty())
+ return initType(type, typeId, idGenerator(typeId), Flag::NoFlag);
+
+ if (typeId == QLatin1String("list"))
+ return initType(type, typeArgument, idGenerator(typeArgument), Flag::List);
- static QV4::CompiledData::BuiltinType stringToBuiltinType(const QString &typeName);
+ const QString annotationString = annotation->toString();
+ return initType(type, annotationString, idGenerator(annotationString), Flag::NoFlag);
+ }
+
+ static QV4::CompiledData::CommonType stringToBuiltinType(const QString &typeName);
+
+private:
+ static bool initType(
+ QV4::CompiledData::ParameterType *paramType, const QString &typeName,
+ int typeNameIndex, QV4::CompiledData::ParameterType::Flag listFlag);
};
struct Signal
@@ -259,11 +265,21 @@ struct Binding : public QV4::CompiledData::Binding
Binding *next;
};
+struct InlineComponent : public QV4::CompiledData::InlineComponent
+{
+ InlineComponent *next;
+};
+
struct Alias : public QV4::CompiledData::Alias
{
Alias *next;
};
+struct RequiredPropertyExtraData : public QV4::CompiledData::RequiredPropertyExtraData
+{
+ RequiredPropertyExtraData *next;
+};
+
struct Function
{
QV4::CompiledData::Location location;
@@ -280,7 +296,7 @@ struct Function
Function *next;
};
-struct Q_QMLCOMPILER_PRIVATE_EXPORT CompiledFunctionOrExpression
+struct Q_QML_COMPILER_EXPORT CompiledFunctionOrExpression
{
CompiledFunctionOrExpression()
{}
@@ -291,7 +307,7 @@ struct Q_QMLCOMPILER_PRIVATE_EXPORT CompiledFunctionOrExpression
CompiledFunctionOrExpression *next = nullptr;
};
-struct Q_QMLCOMPILER_PRIVATE_EXPORT Object
+struct Q_QML_COMPILER_EXPORT Object
{
Q_DECLARE_TR_FUNCTIONS(Object)
public:
@@ -317,6 +333,11 @@ public:
int bindingCount() const { return bindings->count; }
const Function *firstFunction() const { return functions->first; }
int functionCount() const { return functions->count; }
+ const InlineComponent *inlineComponent() const { return inlineComponents->first; }
+ int inlineComponentCount() const { return inlineComponents->count; }
+ const RequiredPropertyExtraData *requiredPropertyExtraData() const {return requiredPropertyExtraDatas->first; }
+ int requiredPropertyExtraDataCount() const { return requiredPropertyExtraDatas->count; }
+ void simplifyRequiredProperties();
PoolList<Binding>::Iterator bindingsBegin() const { return bindings->begin(); }
PoolList<Binding>::Iterator bindingsEnd() const { return bindings->end(); }
@@ -330,18 +351,24 @@ public:
PoolList<Signal>::Iterator signalsEnd() const { return qmlSignals->end(); }
PoolList<Function>::Iterator functionsBegin() const { return functions->begin(); }
PoolList<Function>::Iterator functionsEnd() const { return functions->end(); }
+ PoolList<InlineComponent>::Iterator inlineComponentsBegin() const { return inlineComponents->begin(); }
+ PoolList<InlineComponent>::Iterator inlineComponentsEnd() const { return inlineComponents->end(); }
+ PoolList<RequiredPropertyExtraData>::Iterator requiredPropertyExtraDataBegin() const {return requiredPropertyExtraDatas->begin(); }
+ PoolList<RequiredPropertyExtraData>::Iterator requiredPropertyExtraDataEnd() const {return requiredPropertyExtraDatas->end(); }
// If set, then declarations for this object (and init bindings for these) should go into the
// specified object. Used for declarations inside group properties.
Object *declarationsOverride;
- void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &location = QQmlJS::AST::SourceLocation());
+ void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QV4::CompiledData::Location &location);
QString appendEnum(Enum *enumeration);
QString appendSignal(Signal *signal);
- QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
- QString appendAlias(Alias *prop, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
+ QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::SourceLocation &defaultToken, QQmlJS::SourceLocation *errorLocation);
+ QString appendAlias(Alias *prop, const QString &aliasName, bool isDefaultProperty, const QQmlJS::SourceLocation &defaultToken, QQmlJS::SourceLocation *errorLocation);
void appendFunction(QmlIR::Function *f);
+ void appendInlineComponent(InlineComponent *ic);
+ void appendRequiredPropertyExtraData(RequiredPropertyExtraData *extraData);
QString appendBinding(Binding *b, bool isListBinding);
Binding *findBinding(quint32 nameIndex) const;
@@ -356,6 +383,10 @@ public:
int namedObjectsInComponentCount() const { return namedObjectsInComponent.size(); }
const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); }
+ bool hasFlag(QV4::CompiledData::Object::Flag flag) const { return flags & flag; }
+ qint32 objectId() const { return id; }
+ bool hasAliasAsDefaultProperty() const { return defaultPropertyIsAlias; }
+
private:
friend struct ::QQmlIRLoader;
@@ -365,19 +396,71 @@ private:
PoolList<Signal> *qmlSignals;
PoolList<Binding> *bindings;
PoolList<Function> *functions;
+ PoolList<InlineComponent> *inlineComponents;
+ PoolList<RequiredPropertyExtraData> *requiredPropertyExtraDatas;
};
-struct Q_QMLCOMPILER_PRIVATE_EXPORT Pragma
+struct Q_QML_COMPILER_EXPORT Pragma
{
- enum PragmaType {
- PragmaSingleton = 0x1
+ enum PragmaType
+ {
+ Singleton,
+ Strict,
+ ListPropertyAssignBehavior,
+ ComponentBehavior,
+ FunctionSignatureBehavior,
+ NativeMethodBehavior,
+ ValueTypeBehavior,
+ Translator,
+ };
+
+ enum ListPropertyAssignBehaviorValue
+ {
+ Append,
+ Replace,
+ ReplaceIfNotDefault,
+ };
+
+ enum ComponentBehaviorValue
+ {
+ Unbound,
+ Bound
+ };
+
+ enum FunctionSignatureBehaviorValue
+ {
+ Ignored,
+ Enforced
+ };
+
+ enum NativeMethodBehaviorValue
+ {
+ AcceptThisObject,
+ RejectThisObject
+ };
+
+ enum ValueTypeBehaviorValue
+ {
+ Copy = 0x1,
+ Addressable = 0x2,
+ };
+ Q_DECLARE_FLAGS(ValueTypeBehaviorValues, ValueTypeBehaviorValue);
+
+ PragmaType type;
+
+ union {
+ ListPropertyAssignBehaviorValue listPropertyAssignBehavior;
+ ComponentBehaviorValue componentBehavior;
+ FunctionSignatureBehaviorValue functionSignatureBehavior;
+ NativeMethodBehaviorValue nativeMethodBehavior;
+ ValueTypeBehaviorValues::Int valueTypeBehavior;
+ uint translationContextIndex;
};
- quint32 type;
QV4::CompiledData::Location location;
};
-struct Q_QMLCOMPILER_PRIVATE_EXPORT Document
+struct Q_QML_COMPILER_EXPORT Document
{
Document(bool debugMode);
QString code;
@@ -389,13 +472,22 @@ struct Q_QMLCOMPILER_PRIVATE_EXPORT Document
QVector<Object*> objects;
QV4::Compiler::JSUnitGenerator jsGenerator;
- QV4::CompiledData::CompilationUnit javaScriptCompilationUnit;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> javaScriptCompilationUnit;
+
+ bool isSingleton() const {
+ return std::any_of(pragmas.constBegin(), pragmas.constEnd(), [](const Pragma *pragma) {
+ return pragma->type == Pragma::Singleton;
+ });
+ }
int registerString(const QString &str) { return jsGenerator.registerString(str); }
QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }
+
+ int objectCount() const {return objects.size();}
+ Object* objectAt(int i) const {return objects.at(i);}
};
-class Q_QMLCOMPILER_PRIVATE_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives
+class Q_QML_COMPILER_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives
{
QmlIR::Document *document;
QQmlJS::Engine *engine;
@@ -409,15 +501,13 @@ public:
void importModule(const QString &uri, const QString &version, const QString &module, int lineNumber, int column) override;
};
-struct Q_QMLCOMPILER_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor
+struct Q_QML_COMPILER_EXPORT IRBuilder : public QQmlJS::AST::Visitor
{
Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator)
public:
IRBuilder(const QSet<QString> &illegalNames);
bool generateFromQml(const QString &code, const QString &url, Document *output);
- static bool isSignalPropertyName(const QString &name);
-
using QQmlJS::AST::Visitor::visit;
using QQmlJS::AST::Visitor::endVisit;
@@ -433,57 +523,71 @@ public:
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::UiInlineComponent *ast) override;
bool visit(QQmlJS::AST::UiEnumDeclaration *ast) override;
bool visit(QQmlJS::AST::UiPublicMember *ast) override;
bool visit(QQmlJS::AST::UiScriptBinding *ast) override;
bool visit(QQmlJS::AST::UiSourceElement *ast) override;
+ bool visit(QQmlJS::AST::UiRequired *ast) override;
void throwRecursionDepthError() override
{
- recordError(QQmlJS::AST::SourceLocation(),
+ recordError(QQmlJS::SourceLocation(),
QStringLiteral("Maximum statement or expression depth exceeded"));
}
void accept(QQmlJS::AST::Node *node);
// returns index in _objects
- bool defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId, const QQmlJS::AST::SourceLocation &location, QQmlJS::AST::UiObjectInitializer *initializer, Object *declarationsOverride = nullptr);
- bool defineQMLObject(int *objectIndex, QQmlJS::AST::UiObjectDefinition *node, Object *declarationsOverride = nullptr)
- { return defineQMLObject(objectIndex, node->qualifiedTypeNameId, node->qualifiedTypeNameId->firstSourceLocation(), node->initializer, declarationsOverride); }
+ bool defineQMLObject(
+ int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId,
+ const QV4::CompiledData::Location &location,
+ QQmlJS::AST::UiObjectInitializer *initializer, Object *declarationsOverride = nullptr);
+
+ bool defineQMLObject(
+ int *objectIndex, QQmlJS::AST::UiObjectDefinition *node,
+ Object *declarationsOverride = nullptr)
+ {
+ const QQmlJS::SourceLocation location = node->qualifiedTypeNameId->firstSourceLocation();
+ return defineQMLObject(
+ objectIndex, node->qualifiedTypeNameId,
+ { location.startLine, location.startColumn }, node->initializer,
+ declarationsOverride);
+ }
static QString asString(QQmlJS::AST::UiQualifiedId *node);
- QStringRef asStringRef(QQmlJS::AST::Node *node);
- static void extractVersion(const QStringRef &string, int *maj, int *min);
- QStringRef textRefAt(const QQmlJS::AST::SourceLocation &loc) const
- { return QStringRef(&sourceCode, loc.offset, loc.length); }
- QStringRef textRefAt(const QQmlJS::AST::SourceLocation &first,
- const QQmlJS::AST::SourceLocation &last) const;
+ QStringView asStringRef(QQmlJS::AST::Node *node);
+ static QTypeRevision extractVersion(QStringView string);
+ QStringView textRefAt(const QQmlJS::SourceLocation &loc) const
+ { return QStringView(sourceCode).mid(loc.offset, loc.length); }
+ QStringView textRefAt(const QQmlJS::SourceLocation &first,
+ const QQmlJS::SourceLocation &last) const;
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 tryGeneratingTranslationBinding(QStringView base, QQmlJS::AST::ArgumentList *args, QV4::CompiledData::Binding *binding);
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,
+ void appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocation,
+ const QQmlJS::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,
+ void appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocation,
+ const QQmlJS::SourceLocation &nameLocation, quint32 propertyNameIndex,
int objectIndex, bool isListItem = false, bool isOnAssignment = false);
bool appendAlias(QQmlJS::AST::UiPublicMember *node);
Object *bindingsTarget() const;
- bool setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST::Statement *value);
+ bool setId(const QQmlJS::SourceLocation &idLocation, QQmlJS::AST::Statement *value);
// resolves qualified name (font.pixelSize for example) and returns the last name along
// with the object any right-hand-side of a binding should apply to.
bool resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, Object **object, bool onAssignment = false);
- void recordError(const QQmlJS::AST::SourceLocation &location, const QString &description);
+ void recordError(const QQmlJS::SourceLocation &location, const QString &description);
quint32 registerString(const QString &str) const { return jsGenerator->registerString(str); }
template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); }
@@ -493,11 +597,12 @@ public:
static bool isStatementNodeScript(QQmlJS::AST::Statement *statement);
static bool isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement);
- QString sanityCheckFunctionNames(Object *obj, const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation);
+ QString sanityCheckFunctionNames(Object *obj, const QSet<QString> &illegalNames, QQmlJS::SourceLocation *errorLocation);
QList<QQmlJS::DiagnosticMessage> errors;
QSet<QString> illegalNames;
+ QSet<QString> inlineComponentsNames;
QList<const QV4::CompiledData::Import *> _imports;
QList<Pragma*> _pragmas;
@@ -511,9 +616,11 @@ public:
QQmlJS::MemoryPool *pool;
QString sourceCode;
QV4::Compiler::JSUnitGenerator *jsGenerator;
+
+ bool insideInlineComponent = false;
};
-struct Q_QMLCOMPILER_PRIVATE_EXPORT QmlUnitGenerator
+struct Q_QML_COMPILER_EXPORT QmlUnitGenerator
{
void generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher = QV4::CompiledData::DependentTypesHasher());
@@ -522,21 +629,223 @@ private:
char *writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const;
};
-struct Q_QMLCOMPILER_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen
+struct Q_QML_COMPILER_EXPORT JSCodeGen : public QV4::Compiler::Codegen
{
- JSCodeGen(Document *document, const QSet<QString> &globalNames);
+ JSCodeGen(Document *document, const QSet<QString> &globalNames,
+ QV4::Compiler::CodegenWarningInterface *iface =
+ QV4::Compiler::defaultCodegenWarningInterface(),
+ bool storeSourceLocations = false);
// Returns mapping from input functions to index in IR::Module::functions / compiledData->runtimeFunctions
- QVector<int> generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions);
+ QVector<int>
+ generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions);
- bool generateCodeForComponents(const QVector<quint32> &componentRoots);
- bool compileComponent(int contextObject);
- bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
+ bool generateRuntimeFunctions(QmlIR::Object *object);
private:
Document *document;
};
+// RegisterStringN ~= std::function<int(QStringView)>
+// FinalizeTranlationData ~= std::function<void(QV4::CompiledData::Binding::ValueType, QV4::CompiledData::TranslationData)>
+/*
+ \internal
+ \a base: name of the potential translation function
+ \a args: arguments to the function call
+ \a registerMainString: Takes the first argument passed to the translation function, and it's
+ result will be stored in a TranslationData's stringIndex for translation bindings and in numbeIndex
+ for string bindings.
+ \a registerCommentString: Takes the comment argument passed to some of the translation functions.
+ Result will be stored in a TranslationData's commentIndex
+ \a finalizeTranslationData: Takes the type of the binding and the previously set up TranslationData
+ */
+template<
+ typename RegisterMainString,
+ typename RegisterCommentString,
+ typename RegisterContextString,
+ typename FinalizeTranslationData>
+void tryGeneratingTranslationBindingBase(QStringView base, QQmlJS::AST::ArgumentList *args,
+ RegisterMainString registerMainString,
+ RegisterCommentString registerCommentString,
+ RegisterContextString registerContextString,
+ FinalizeTranslationData finalizeTranslationData
+ )
+{
+ if (base == QLatin1String("qsTr")) {
+ QV4::CompiledData::TranslationData translationData;
+ translationData.number = -1;
+
+ // empty string
+ translationData.commentIndex = 0;
+
+ // No context (not empty string)
+ translationData.contextIndex = QV4::CompiledData::TranslationData::NoContextIndex;
+
+ if (!args || !args->expression)
+ return; // no arguments, stop
+
+ QStringView translation;
+ if (QQmlJS::AST::StringLiteral *arg1 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) {
+ translation = arg1->value;
+ } else {
+ return; // first argument is not a string, stop
+ }
+
+ translationData.stringIndex = registerMainString(translation);
+
+ args = args->next;
+
+ if (args) {
+ QQmlJS::AST::StringLiteral *arg2 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression);
+ if (!arg2)
+ return; // second argument is not a string, stop
+ translationData.commentIndex = registerCommentString(arg2->value);
+
+ args = args->next;
+ if (args) {
+ if (QQmlJS::AST::NumericLiteral *arg3 = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(args->expression)) {
+ translationData.number = int(arg3->value);
+ args = args->next;
+ } else {
+ return; // third argument is not a translation number, stop
+ }
+ }
+ }
+
+ if (args)
+ return; // too many arguments, stop
+
+ finalizeTranslationData(QV4::CompiledData::Binding::Type_Translation, translationData);
+ } else if (base == QLatin1String("qsTrId")) {
+ QV4::CompiledData::TranslationData translationData;
+ translationData.number = -1;
+
+ // empty string, but unused
+ translationData.commentIndex = 0;
+
+ // No context (not empty string)
+ translationData.contextIndex = QV4::CompiledData::TranslationData::NoContextIndex;
+
+ if (!args || !args->expression)
+ return; // no arguments, stop
+
+ QStringView id;
+ if (QQmlJS::AST::StringLiteral *arg1 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) {
+ id = arg1->value;
+ } else {
+ return; // first argument is not a string, stop
+ }
+ translationData.stringIndex = registerMainString(id);
+
+ args = args->next;
+
+ if (args) {
+ if (QQmlJS::AST::NumericLiteral *arg3 = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(args->expression)) {
+ translationData.number = int(arg3->value);
+ args = args->next;
+ } else {
+ return; // third argument is not a translation number, stop
+ }
+ }
+
+ if (args)
+ return; // too many arguments, stop
+
+ finalizeTranslationData(QV4::CompiledData::Binding::Type_TranslationById, translationData);
+ } else if (base == QLatin1String("QT_TR_NOOP") || base == QLatin1String("QT_TRID_NOOP")) {
+ if (!args || !args->expression)
+ return; // no arguments, stop
+
+ QStringView str;
+ if (QQmlJS::AST::StringLiteral *arg1 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) {
+ str = arg1->value;
+ } else {
+ return; // first argument is not a string, stop
+ }
+
+ args = args->next;
+ if (args)
+ return; // too many arguments, stop
+
+ QV4::CompiledData::TranslationData translationData;
+ translationData.number = registerMainString(str);
+ finalizeTranslationData(QV4::CompiledData::Binding::Type_String, translationData);
+ } else if (base == QLatin1String("QT_TRANSLATE_NOOP")) {
+ if (!args || !args->expression)
+ return; // no arguments, stop
+
+ args = args->next;
+ if (!args || !args->expression)
+ return; // no second arguments, stop
+
+ QStringView str;
+ if (QQmlJS::AST::StringLiteral *arg2 = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) {
+ str = arg2->value;
+ } else {
+ return; // first argument is not a string, stop
+ }
+
+ args = args->next;
+ if (args)
+ return; // too many arguments, stop
+
+ QV4::CompiledData::TranslationData fakeTranslationData;
+ fakeTranslationData.number = registerMainString(str);
+ finalizeTranslationData(QV4::CompiledData::Binding::Type_String, fakeTranslationData);
+ } else if (base == QLatin1String("qsTranslate")) {
+ QV4::CompiledData::TranslationData translationData;
+ translationData.number = -1;
+ translationData.commentIndex = 0; // empty string
+
+ if (!args || !args->next)
+ return; // less than 2 arguments, stop
+
+ QStringView translation;
+ if (QQmlJS::AST::StringLiteral *arg1
+ = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression)) {
+ translation = arg1->value;
+ } else {
+ return; // first argument is not a string, stop
+ }
+
+ translationData.contextIndex = registerContextString(translation);
+
+ args = args->next;
+ Q_ASSERT(args);
+
+ QQmlJS::AST::StringLiteral *arg2
+ = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression);
+ if (!arg2)
+ return; // second argument is not a string, stop
+ translationData.stringIndex = registerMainString(arg2->value);
+
+ args = args->next;
+ if (args) {
+ QQmlJS::AST::StringLiteral *arg3
+ = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(args->expression);
+ if (!arg3)
+ return; // third argument is not a string, stop
+ translationData.commentIndex = registerCommentString(arg3->value);
+
+ args = args->next;
+ if (args) {
+ if (QQmlJS::AST::NumericLiteral *arg4
+ = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(args->expression)) {
+ translationData.number = int(arg4->value);
+ args = args->next;
+ } else {
+ return; // fourth argument is not a translation number, stop
+ }
+ }
+ }
+
+ if (args)
+ return; // too many arguments, stop
+
+ finalizeTranslationData(QV4::CompiledData::Binding::Type_Translation, translationData);
+ }
+}
+
} // namespace QmlIR
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4bytecodegenerator.cpp b/src/qml/compiler/qv4bytecodegenerator.cpp
index 7df1614ffe..b88c83512f 100644
--- a/src/qml/compiler/qv4bytecodegenerator.cpp
+++ b/src/qml/compiler/qv4bytecodegenerator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qv4bytecodegenerator_p.h>
#include <private/qv4compilercontext_p.h>
@@ -45,9 +9,15 @@ QT_USE_NAMESPACE
using namespace QV4;
using namespace Moth;
-void BytecodeGenerator::setLocation(const QQmlJS::AST::SourceLocation &loc)
+void BytecodeGenerator::setLocation(const QQmlJS::SourceLocation &loc)
{
currentLine = static_cast<int>(loc.startLine);
+ currentSourceLocation = loc;
+}
+
+void BytecodeGenerator::incrementStatement()
+{
+ ++currentStatement;
}
int BytecodeGenerator::newRegister()
@@ -164,26 +134,36 @@ void BytecodeGenerator::finalize(Compiler::Context *context)
// collect content and line numbers
QByteArray code;
- QVector<CompiledData::CodeOffsetToLine> lineNumbers;
+ QVector<CompiledData::CodeOffsetToLineAndStatement> lineAndStatementNumbers;
+
currentLine = -1;
+ currentStatement = -1;
+
Q_UNUSED(startLine);
- for (const auto &i : qAsConst(instructions)) {
- if (i.line != currentLine) {
- currentLine = i.line;
- CompiledData::CodeOffsetToLine entry;
+ for (qsizetype i = 0; i < instructions.size(); i++) {
+ if (instructions[i].line != currentLine || instructions[i].statement != currentStatement) {
+ currentLine = instructions[i].line;
+ currentStatement = instructions[i].statement;
+ CompiledData::CodeOffsetToLineAndStatement entry;
entry.codeOffset = code.size();
entry.line = currentLine;
- lineNumbers.append(entry);
+ entry.statement = currentStatement;
+ lineAndStatementNumbers.append(entry);
}
- code.append(reinterpret_cast<const char *>(i.packed), i.size);
+
+ if (m_sourceLocationTable)
+ m_sourceLocationTable->entries[i].offset = static_cast<quint32>(code.size());
+
+ code.append(reinterpret_cast<const char *>(instructions[i].packed), instructions[i].size);
}
context->code = code;
- context->lineNumberMapping = lineNumbers;
+ context->lineAndStatementNumberMapping = lineAndStatementNumbers;
+ context->sourceLocationTable = std::move(m_sourceLocationTable);
- for (const auto &li : _labelInfos) {
+ context->labelInfo.reserve(context->labelInfo.size() + _labelInfos.size());
+ for (const auto &li : _labelInfos)
context->labelInfo.push_back(instructions.at(labels.at(li.labelIndex)).position);
- }
}
int BytecodeGenerator::addInstructionHelper(Instr::Type type, const Instr &i, int offsetOfOffset) {
@@ -215,6 +195,7 @@ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // broken gcc warns about Instru
currentLine = -currentLine;
addInstruction(Instruction::Debug());
currentLine = -currentLine;
+ currentSourceLocation = QQmlJS::SourceLocation();
}
QT_WARNING_POP
}
@@ -225,7 +206,16 @@ QT_WARNING_POP
int s = argCount*sizeof(int);
if (offsetOfOffset != -1)
offsetOfOffset += Instr::encodedLength(type);
- I instr{type, static_cast<short>(s + Instr::encodedLength(type)), 0, currentLine, offsetOfOffset, -1, "\0\0" };
+ I instr {
+ type,
+ static_cast<short>(s + Instr::encodedLength(type)),
+ 0,
+ currentLine,
+ currentStatement,
+ offsetOfOffset,
+ -1,
+ "\0\0"
+ };
uchar *code = instr.packed;
code = Instr::pack(code, Instr::wideInstructionType(type));
@@ -235,6 +225,8 @@ QT_WARNING_POP
}
instructions.append(instr);
+ if (m_sourceLocationTable)
+ m_sourceLocationTable->entries.append({ 0, currentSourceLocation });
return pos;
}
diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h
index 8c509dd9f1..fa14754f85 100644
--- a/src/qml/compiler/qv4bytecodegenerator_p.h
+++ b/src/qml/compiler/qv4bytecodegenerator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4BYTECODEGENERATOR_P_H
#define QV4BYTECODEGENERATOR_P_H
@@ -52,14 +16,16 @@
//
#include <private/qv4instr_moth_p.h>
#include <private/qv4compileddata_p.h>
+#include <private/qv4compilercontext_p.h>
+#include <private/qqmljssourcelocation_p.h>
+
+#include <memory>
QT_BEGIN_NAMESPACE
namespace QQmlJS {
-namespace AST {
class SourceLocation;
}
-}
namespace QV4 {
@@ -71,8 +37,12 @@ namespace Moth {
class BytecodeGenerator {
public:
- BytecodeGenerator(int line, bool debug)
- : startLine(line), debugMode(debug) {}
+ BytecodeGenerator(int line, bool debug, bool storeSourceLocation = false)
+ : startLine(line), debugMode(debug)
+ {
+ if (storeSourceLocation)
+ m_sourceLocationTable.reset(new QV4::Compiler::Context::SourceLocationTable {});
+ }
struct Label {
enum LinkMode {
@@ -88,7 +58,7 @@ public:
link();
}
- void link() {
+ void link() const {
Q_ASSERT(index >= 0);
Q_ASSERT(generator->labels[index] == -1);
generator->labels[index] = generator->instructions.size();
@@ -188,13 +158,27 @@ QT_WARNING_POP
Q_REQUIRED_RESULT Jump jumpNotUndefined()
{
- Instruction::JumpNotUndefined data;
+ Instruction::JumpNotUndefined data{};
return addJumpInstruction(data);
}
Q_REQUIRED_RESULT Jump jumpNoException()
{
- Instruction::JumpNoException data;
+ Instruction::JumpNoException data{};
+ return addJumpInstruction(data);
+ }
+
+ Q_REQUIRED_RESULT Jump jumpOptionalLookup(int index)
+ {
+ Instruction::GetOptionalLookup data{};
+ data.index = index;
+ return addJumpInstruction(data);
+ }
+
+ Q_REQUIRED_RESULT Jump jumpOptionalProperty(int name)
+ {
+ Instruction::LoadOptionalProperty data{};
+ data.name = name;
return addJumpInstruction(data);
}
@@ -244,7 +228,8 @@ QT_WARNING_POP
- void setLocation(const QQmlJS::AST::SourceLocation &loc);
+ void setLocation(const QQmlJS::SourceLocation &loc);
+ void incrementStatement();
ExceptionHandler *exceptionHandler() const {
return currentExceptionHandler;
@@ -295,6 +280,7 @@ private:
short size;
uint position;
int line;
+ int statement;
int offsetForJump;
int linkedLabel;
unsigned char packed[sizeof(Instr) + 2]; // 2 for instruction type
@@ -313,6 +299,9 @@ public:
private:
int startLine = 0;
int currentLine = 0;
+ int currentStatement = 0;
+ QQmlJS::SourceLocation currentSourceLocation;
+ std::unique_ptr<QV4::Compiler::Context::SourceLocationTable> m_sourceLocationTable;
bool debugMode = false;
int lastInstrType = -1;
diff --git a/src/qml/compiler/qv4bytecodehandler.cpp b/src/qml/compiler/qv4bytecodehandler.cpp
index f9f755b8c0..6ee027a6b7 100644
--- a/src/qml/compiler/qv4bytecodehandler.cpp
+++ b/src/qml/compiler/qv4bytecodehandler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qv4bytecodehandler_p.h>
diff --git a/src/qml/compiler/qv4bytecodehandler_p.h b/src/qml/compiler/qv4bytecodehandler_p.h
index f1e7c99447..0a74fc52ed 100644
--- a/src/qml/compiler/qv4bytecodehandler_p.h
+++ b/src/qml/compiler/qv4bytecodehandler_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4BYTECODEHANDLER_P_H
#define QV4BYTECODEHANDLER_P_H
@@ -50,6 +14,8 @@
//
// We mean it.
//
+
+#include <private/qtqmlcompilerglobal_p.h>
#include <private/qv4instr_moth_p.h>
QT_BEGIN_NAMESPACE
@@ -90,12 +56,15 @@ namespace Moth {
#define BYTECODE_HANDLER_DEFINE_VIRTUAL_BYTECODE_HANDLER(instr) \
INSTR_##instr(BYTECODE_HANDLER_DEFINE_VIRTUAL_BYTECODE_HANDLER)
-class ByteCodeHandler
+class Q_QML_COMPILER_EXPORT ByteCodeHandler
{
+ Q_DISABLE_COPY_MOVE(ByteCodeHandler)
public:
+ ByteCodeHandler() = default;
virtual ~ByteCodeHandler();
void decode(const char *code, uint len);
+ void reset() { _currentOffset = _nextOffset = 0; }
int currentInstructionOffset() const { return _currentOffset; }
int nextInstructionOffset() const { return _nextOffset; }
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index c43ea64e2e..25831eab73 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1,49 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4codegen_p.h"
-#include "qv4util_p.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QStringList>
#include <QtCore/QStack>
#include <QtCore/qurl.h>
+#include <QtCore/qloggingcategory.h>
#include <QScopeGuard>
#include <private/qqmljsast_p.h>
#include <private/qqmljslexer_p.h>
@@ -57,20 +21,33 @@
#include <private/qqmljsdiagnosticmessage_p.h>
#include <cmath>
-#include <iostream>
-
-static const bool disable_lookups = false;
#ifdef CONST
#undef CONST
#endif
-QT_USE_NAMESPACE
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcQmlUsedBeforeDeclared, "qt.qml.usedbeforedeclared");
+Q_LOGGING_CATEGORY(lcQmlInjectedParameter, "qt.qml.injectedparameter");
+
using namespace QV4;
using namespace QV4::Compiler;
using namespace QQmlJS;
using namespace QQmlJS::AST;
+void CodegenWarningInterface::reportVarUsedBeforeDeclaration(
+ const QString &name, const QString &fileName, QQmlJS::SourceLocation declarationLocation,
+ QQmlJS::SourceLocation accessLocation)
+{
+ qCWarning(lcQmlUsedBeforeDeclared).nospace().noquote()
+ << fileName << ":" << accessLocation.startLine << ":" << accessLocation.startColumn
+ << " Variable \"" << name << "\" is used before its declaration at "
+ << declarationLocation.startLine << ":" << declarationLocation.startColumn << ".";
+}
+
static inline void setJumpOutLocation(QV4::Moth::BytecodeGenerator *bytecodeGenerator,
const Statement *body, const SourceLocation &fallback)
{
@@ -90,14 +67,39 @@ static inline void setJumpOutLocation(QV4::Moth::BytecodeGenerator *bytecodeGene
}
}
-Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict)
- : _module(nullptr)
- , _returnAddress(-1)
- , _context(nullptr)
- , _labelledStatement(nullptr)
- , jsUnitGenerator(jsUnitGenerator)
- , _strictMode(strict)
- , _fileNameIsUrl(false)
+void Codegen::generateThrowException(const QString &type, const QString &text)
+{
+ RegisterScope scope(this);
+ Instruction::Construct construct;
+ if (text.isEmpty()) {
+ construct.argc = 0;
+ construct.argv = 0;
+ } else {
+ construct.argc = 1;
+ Instruction::LoadRuntimeString load;
+ load.stringId = registerString(text);
+ bytecodeGenerator->addInstruction(load);
+ construct.argv = Reference::fromAccumulator(this).storeOnStack().stackSlot();
+ }
+ Reference r = referenceForName(type, false);
+ r = r.storeOnStack();
+ construct.func = r.stackSlot();
+ bytecodeGenerator->addInstruction(construct);
+ Instruction::ThrowException throwException;
+ bytecodeGenerator->addInstruction(throwException);
+}
+
+Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict,
+ CodegenWarningInterface *iface, bool storeSourceLocations)
+ : _module(nullptr),
+ _returnAddress(-1),
+ _context(nullptr),
+ _labelledStatement(nullptr),
+ jsUnitGenerator(jsUnitGenerator),
+ _strictMode(strict),
+ storeSourceLocations(storeSourceLocations),
+ _fileNameIsUrl(false),
+ _interface(iface)
{
jsUnitGenerator->codeGeneratorName = QStringLiteral("moth");
pushExpr();
@@ -391,6 +393,7 @@ void Codegen::statement(Statement *ast)
{
RegisterScope scope(this);
+ bytecodeGenerator->incrementStatement();
bytecodeGenerator->setLocation(ast->firstSourceLocation());
VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast);
@@ -406,6 +409,7 @@ void Codegen::statement(ExpressionNode *ast)
} else {
RegisterScope scope(this);
+ bytecodeGenerator->incrementStatement();
pushExpr(Result(nx));
VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast);
qSwap(_volatileMemoryLocations, vLocs);
@@ -708,9 +712,8 @@ void Codegen::destructureElementList(const Codegen::Reference &array, PatternEle
RegisterScope scope(this);
Reference iterator = Reference::fromStackSlot(this);
- Reference iteratorValue = Reference::fromStackSlot(this);
- Reference iteratorDone = Reference::fromStackSlot(this);
- Reference::storeConstOnStack(this, Encode(false), iteratorDone.stackSlot());
+ QVarLengthArray<Reference> iteratorValues;
+ Reference ignored;
array.loadInAccumulator();
Instruction::GetIterator iteratorObjInstr;
@@ -718,45 +721,76 @@ void Codegen::destructureElementList(const Codegen::Reference &array, PatternEle
bytecodeGenerator->addInstruction(iteratorObjInstr);
iterator.storeConsumeAccumulator();
+ BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
+ Reference needsClose = Reference::storeConstOnStack(this, Encode(false));
+
+ for (PatternElementList *p = bindingList; p; p = p->next) {
+ PatternElement *e = p->element;
+ for (Elision *elision = p->elision; elision; elision = elision->next) {
+ iterator.loadInAccumulator();
+ Instruction::IteratorNext next;
+ if (!ignored.isValid())
+ ignored = Reference::fromStackSlot(this);
+ next.value = ignored.stackSlot();
+ bytecodeGenerator->addJumpInstruction(next).link(done);
+ }
+
+ if (!e)
+ continue;
+
+ if (e->type != PatternElement::RestElement) {
+ iterator.loadInAccumulator();
+ Instruction::IteratorNext next;
+ iteratorValues.push_back(Reference::fromStackSlot(this));
+ next.value = iteratorValues.back().stackSlot();
+ bytecodeGenerator->addJumpInstruction(next).link(done);
+ }
+ }
+
+ // If we've iterated through all the patterns without exhausing the iterator, it needs
+ // to be closed. But we don't close it here because:
+ // a, closing might throw an exception and we want to assign the values before we handle that
+ // b, there might be a rest element that could still continue iterating
+ Reference::fromConst(this, Encode(true)).storeOnStack(needsClose.stackSlot());
+
+ done.link();
+ bytecodeGenerator->checkException();
+
{
- auto cleanup = [this, iterator, iteratorDone]() {
+ ControlFlowUnwindCleanup flow(this, [&]() {
+ BytecodeGenerator::Label skipClose = bytecodeGenerator->newLabel();
+ needsClose.loadInAccumulator();
+ bytecodeGenerator->jumpFalse().link(skipClose);
iterator.loadInAccumulator();
Instruction::IteratorClose close;
- close.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(close);
- };
-
- ControlFlowUnwindCleanup flow(this, cleanup);
+ skipClose.link();
+ });
+ auto it = iteratorValues.constBegin();
for (PatternElementList *p = bindingList; p; p = p->next) {
PatternElement *e = p->element;
- for (Elision *elision = p->elision; elision; elision = elision->next) {
- iterator.loadInAccumulator();
- Instruction::IteratorNext next;
- next.value = iteratorValue.stackSlot();
- next.done = iteratorDone.stackSlot();
- bytecodeGenerator->addInstruction(next);
- }
if (!e)
continue;
- RegisterScope scope(this);
- iterator.loadInAccumulator();
-
if (e->type == PatternElement::RestElement) {
- Reference::fromConst(this, Encode(true)).storeOnStack(iteratorDone.stackSlot());
+ Q_ASSERT(it == iteratorValues.constEnd());
+
+ // The rest element is guaranteed to exhaust the iterator
+ Reference::fromConst(this, Encode(false)).storeOnStack(needsClose.stackSlot());
+
+ iterator.loadInAccumulator();
bytecodeGenerator->addInstruction(Instruction::DestructureRestElement());
- initializeAndDestructureBindingElement(e, Reference::fromAccumulator(this), isDefinition);
+ initializeAndDestructureBindingElement(
+ e, Reference::fromAccumulator(this), isDefinition);
} else {
- Instruction::IteratorNext next;
- next.value = iteratorValue.stackSlot();
- next.done = iteratorDone.stackSlot();
- bytecodeGenerator->addInstruction(next);
- initializeAndDestructureBindingElement(e, iteratorValue, isDefinition);
- if (hasError())
- return;
+ Q_ASSERT(it != iteratorValues.constEnd());
+ initializeAndDestructureBindingElement(e, *it++, isDefinition);
}
+
+ if (hasError())
+ return;
}
}
}
@@ -775,86 +809,72 @@ void Codegen::destructurePattern(Pattern *p, const Reference &rhs)
bool Codegen::visit(ArgumentList *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(CaseBlock *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(CaseClause *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(CaseClauses *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(Catch *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(DefaultClause *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(Elision *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(Finally *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(FormalParameterList *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(Program *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(PatternElement *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(PatternElementList *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(PatternProperty *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(PatternPropertyList *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(ExportDeclaration *ast)
@@ -895,68 +915,62 @@ bool Codegen::visit(TypeAnnotation *ast)
bool Codegen::visit(StatementList *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(UiArrayMemberList *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(UiImport *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(UiHeaderItemList *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
+}
+
+bool Codegen::visit(UiPragmaValueList *)
+{
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(UiPragma *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(UiObjectInitializer *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(UiObjectMemberList *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(UiParameterList *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(UiProgram *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(UiQualifiedId *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(VariableDeclarationList *)
{
- Q_UNREACHABLE();
- return false;
+ Q_UNREACHABLE_RETURN(false);
}
bool Codegen::visit(ClassExpression *ast)
@@ -1182,7 +1196,6 @@ bool Codegen::visit(ArrayPattern *ast)
RegisterScope scope(this);
Reference iterator = Reference::fromStackSlot(this);
- Reference iteratorDone = Reference::fromConst(this, Encode(false)).storeOnStack();
Reference lhsValue = Reference::fromStackSlot(this);
// There should be a temporal block, so that variables declared in lhs shadow outside vars.
@@ -1202,24 +1215,23 @@ bool Codegen::visit(ArrayPattern *ast)
BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
+ BytecodeGenerator::Label done = bytecodeGenerator->newLabel();
{
- auto cleanup = [this, iterator, iteratorDone]() {
+ auto cleanup = [this, iterator, done]() {
iterator.loadInAccumulator();
Instruction::IteratorClose close;
- close.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(close);
+ done.link();
};
- ControlFlowLoop flow(this, &end, &in, cleanup);
+ ControlFlowLoop flow(this, &end, &in, std::move(cleanup));
in.link();
bytecodeGenerator->addLoopStart(in);
iterator.loadInAccumulator();
Instruction::IteratorNext next;
next.value = lhsValue.stackSlot();
- next.done = iteratorDone.stackSlot();
- bytecodeGenerator->addInstruction(next);
- bytecodeGenerator->addJumpInstruction(Instruction::JumpTrue()).link(end);
+ bytecodeGenerator->addJumpInstruction(next).link(done);
lhsValue.loadInAccumulator();
pushAccumulator();
@@ -1252,13 +1264,23 @@ bool Codegen::visit(ArrayMemberExpression *ast)
if (hasError())
return false;
+ const bool isTailOfChain = traverseOptionalChain(ast);
+
TailCallBlocker blockTailCalls(this);
Reference base = expression(ast->base);
+
+ auto writeSkip = [&]() {
+ base.loadInAccumulator();
+ bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
+ auto jumpToUndefined = bytecodeGenerator->jumpTrue();
+ m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
+ };
+
if (hasError())
return false;
if (base.isSuper()) {
Reference index = expression(ast->expression).storeOnStack();
- setExprResult(Reference::fromSuperProperty(index));
+ optionalChainFinalizer(Reference::fromSuperProperty(index), isTailOfChain);
return false;
}
base = base.storeOnStack();
@@ -1268,17 +1290,32 @@ bool Codegen::visit(ArrayMemberExpression *ast)
QString s = str->value.toString();
uint arrayIndex = stringToArrayIndex(s);
if (arrayIndex == UINT_MAX) {
- setExprResult(Reference::fromMember(base, str->value.toString()));
+ auto ref = Reference::fromMember(base, s, ast->expression->firstSourceLocation(),
+ ast->isOptional,
+ &m_optionalChainsStates.top().jumpsToPatch);
+ setExprResult(ref);
+ optionalChainFinalizer(ref, isTailOfChain);
return false;
}
+
+ if (ast->isOptional)
+ writeSkip();
+
Reference index = Reference::fromConst(this, QV4::Encode(arrayIndex));
- setExprResult(Reference::fromSubscript(base, index));
+ optionalChainFinalizer(Reference::fromSubscript(base, index), isTailOfChain);
return false;
}
+
+
+ if (ast->isOptional)
+ writeSkip();
+
Reference index = expression(ast->expression);
+
if (hasError())
return false;
- setExprResult(Reference::fromSubscript(base, index));
+
+ optionalChainFinalizer(Reference::fromSubscript(base, index), isTailOfChain);
return false;
}
@@ -1371,6 +1408,34 @@ bool Codegen::visit(BinaryExpression *ast)
setExprResult(Reference::fromAccumulator(this));
}
return false;
+ } else if (ast->op == QSOperator::Coalesce) {
+
+ Reference left = expression(ast->left);
+ if (hasError())
+ return false;
+
+ BytecodeGenerator::Label iftrue = bytecodeGenerator->newLabel();
+
+ Instruction::CmpEqNull cmp;
+
+ left = left.storeOnStack();
+ left.loadInAccumulator();
+ bytecodeGenerator->addInstruction(cmp);
+
+ bytecodeGenerator->jumpTrue().link(iftrue);
+
+ blockTailCalls.unblock();
+
+ left.loadInAccumulator();
+ BytecodeGenerator::Jump jump_endif = bytecodeGenerator->jump();
+ iftrue.link();
+
+ Reference right = expression(ast->right);
+ right.loadInAccumulator();
+ jump_endif.link();
+ setExprResult(Reference::fromAccumulator(this));
+
+ return false;
} else if (ast->op == QSOperator::Assign) {
if (AST::Pattern *p = ast->left->patternCast()) {
RegisterScope scope(this);
@@ -1446,7 +1511,7 @@ bool Codegen::visit(BinaryExpression *ast)
if (hasError())
return false;
- binopHelper(baseOp(ast->op), tempLeft, right).loadInAccumulator();
+ binopHelper(ast, baseOp(ast->op), tempLeft, right).loadInAccumulator();
setExprResult(left.storeRetainAccumulator());
break;
@@ -1459,12 +1524,13 @@ bool Codegen::visit(BinaryExpression *ast)
Reference right = expression(ast->right);
if (hasError())
return false;
- setExprResult(binopHelper(static_cast<QSOperator::Op>(ast->op), right, left));
+ setExprResult(binopHelper(ast, static_cast<QSOperator::Op>(ast->op), right, left));
break;
}
- // intentional fall-through!
+ Q_FALLTHROUGH();
case QSOperator::In:
case QSOperator::InstanceOf:
+ case QSOperator::As:
case QSOperator::Equal:
case QSOperator::NotEqual:
case QSOperator::Ge:
@@ -1493,18 +1559,20 @@ bool Codegen::visit(BinaryExpression *ast)
if (hasError())
return false;
- setExprResult(binopHelper(static_cast<QSOperator::Op>(ast->op), left, right));
+ setExprResult(binopHelper(ast, static_cast<QSOperator::Op>(ast->op), left, right));
break;
}
-
} // switch
return false;
}
-Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Reference &right)
+Codegen::Reference Codegen::binopHelper(BinaryExpression *ast, QSOperator::Op oper, Reference &left,
+ Reference &right)
{
+ auto loc = combine(ast->left->firstSourceLocation(), ast->right->lastSourceLocation());
+ bytecodeGenerator->setLocation(loc);
switch (oper) {
case QSOperator::Add: {
left = left.storeOnStack();
@@ -1661,6 +1729,14 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
bytecodeGenerator->addInstruction(binop);
break;
}
+ case QSOperator::As: {
+ Instruction::As as;
+ left = left.storeOnStack();
+ right.loadInAccumulator();
+ as.lhs = left.stackSlot();
+ bytecodeGenerator->addInstruction(as);
+ break;
+ }
case QSOperator::In: {
Instruction::CmpIn binop;
left = left.storeOnStack();
@@ -1872,23 +1948,40 @@ Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Refe
return Reference();
}
+Codegen::Reference Codegen::loadSubscriptForCall(const Codegen::Reference &base)
+{
+ // Retrieve the function to be called before generating the arguments.
+ // Generating the arguments might change the array.
+ base.elementSubscript.loadInAccumulator();
+ Codegen::Instruction::LoadElement load;
+ load.base = base.elementBase;
+ bytecodeGenerator->addInstruction(load);
+ return Reference::fromAccumulator(this);
+}
+
bool Codegen::visit(CallExpression *ast)
{
if (hasError())
return false;
+ const bool isTailOfChain = traverseOptionalChain(ast);
+
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
- Reference base = expression(ast->base);
+ Reference expr = expression(ast->base);
+ Reference base = expr;
if (hasError())
return false;
switch (base.type) {
case Reference::Member:
- case Reference::Subscript:
base = base.asLValue();
break;
+ case Reference::Subscript:
+ base.element = loadSubscriptForCall(base).storeOnStack().stackSlot();
+ base.subscriptLoadedForCall = true;
+ break;
case Reference::Name:
break;
case Reference::Super:
@@ -1901,9 +1994,23 @@ bool Codegen::visit(CallExpression *ast)
break;
}
+ if (expr.hasSavedCallBaseSlot) {
+ // Hack to preserve `this` context in optional chain calls. See optionalChainFinalizer().
+ base.hasSavedCallBaseSlot = true;
+ base.savedCallBaseSlot = expr.savedCallBaseSlot;
+ base.savedCallPropertyNameIndex = expr.savedCallPropertyNameIndex;
+ }
+
int thisObject = bytecodeGenerator->newRegister();
int functionObject = bytecodeGenerator->newRegister();
+ if (ast->isOptional || m_optionalChainsStates.top().actuallyHasOptionals) {
+ base.loadInAccumulator();
+ bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
+ auto jumpToUndefined = bytecodeGenerator->jumpTrue();
+ m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
+ }
+
auto calldata = pushArgs(ast->arguments);
if (hasError())
return false;
@@ -1915,78 +2022,108 @@ bool Codegen::visit(CallExpression *ast)
baseObject.storeOnStack(thisObject);
baseObject = Reference::fromStackSlot(this, thisObject);
}
- if (!base.isStackSlot()) {
- base.storeOnStack(functionObject);
- base = Reference::fromStackSlot(this, functionObject);
- }
+
+ const int func = [&]() {
+ if (base.type == Reference::Subscript)
+ return base.element;
+
+ if (!base.isStackSlot()) {
+ base.storeOnStack(functionObject);
+ base = Reference::fromStackSlot(this, functionObject);
+ }
+
+ return base.stackSlot();
+ }();
if (calldata.hasSpread) {
Instruction::CallWithSpread call;
- call.func = base.stackSlot();
+ call.func = func;
call.thisObject = baseObject.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
bytecodeGenerator->addInstruction(call);
} else {
Instruction::TailCall call;
- call.func = base.stackSlot();
+ call.func = func;
call.thisObject = baseObject.stackSlot();
call.argc = calldata.argc;
call.argv = calldata.argv;
bytecodeGenerator->addInstruction(call);
}
- setExprResult(Reference::fromAccumulator(this));
+ optionalChainFinalizer(Reference::fromAccumulator(this), isTailOfChain);
return false;
-
}
- handleCall(base, calldata, functionObject, thisObject);
+ handleCall(base, calldata, functionObject, thisObject, ast->isOptional);
+ optionalChainFinalizer(Reference::fromAccumulator(this), isTailOfChain);
return false;
}
-void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject)
+void Codegen::endVisit(CallExpression *ast)
{
+ m_seenOptionalChainNodes.remove(ast);
+}
+
+void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject, bool optional)
+{
+ if (base.sourceLocation.isValid())
+ bytecodeGenerator->setLocation(base.sourceLocation);
+
//### Do we really need all these call instructions? can's we load the callee in a temp?
- if (base.type == Reference::Member) {
- if (!disable_lookups && useFastLookups) {
+ if (base.type == Reference::Member || base.hasSavedCallBaseSlot) {
+ if (useFastLookups) {
Instruction::CallPropertyLookup call;
- call.base = base.propertyBase.stackSlot();
- call.lookupIndex = registerGetterLookup(base.propertyNameIndex);
+ if (base.hasSavedCallBaseSlot) {
+ call.base = base.savedCallBaseSlot;
+ call.lookupIndex = registerGetterLookup(
+ base.savedCallPropertyNameIndex, JSUnitGenerator::LookupForCall);
+ } else {
+ call.base = base.propertyBase.stackSlot();
+ call.lookupIndex = registerGetterLookup(
+ base.propertyNameIndex, JSUnitGenerator::LookupForCall);
+ }
call.argc = calldata.argc;
call.argv = calldata.argv;
bytecodeGenerator->addInstruction(call);
} else {
Instruction::CallProperty call;
- call.base = base.propertyBase.stackSlot();
- call.name = base.propertyNameIndex;
+ if (base.hasSavedCallBaseSlot) {
+ call.base = base.savedCallBaseSlot;
+ call.name = base.savedCallPropertyNameIndex;
+ } else {
+ call.base = base.propertyBase.stackSlot();
+ call.name = base.propertyNameIndex;
+ }
call.argc = calldata.argc;
call.argv = calldata.argv;
bytecodeGenerator->addInstruction(call);
}
} else if (base.type == Reference::Subscript) {
- Instruction::CallElement call;
- call.base = base.elementBase;
- call.index = base.elementSubscript.stackSlot();
+ Instruction::CallWithReceiver call;
+ call.thisObject = base.elementBase.stackSlot();
+ call.name = base.element;
call.argc = calldata.argc;
call.argv = calldata.argv;
bytecodeGenerator->addInstruction(call);
} else if (base.type == Reference::Name) {
- if (base.name == QStringLiteral("eval")) {
+ if (base.name == QStringLiteral("eval") && !optional) {
Instruction::CallPossiblyDirectEval call;
call.argc = calldata.argc;
call.argv = calldata.argv;
bytecodeGenerator->addInstruction(call);
- } else if (!disable_lookups && useFastLookups && base.global) {
+ } else if (useFastLookups && base.global) {
if (base.qmlGlobal) {
Instruction::CallQmlContextPropertyLookup call;
- call.index = registerQmlContextPropertyGetterLookup(base.nameAsIndex());
+ call.index = registerQmlContextPropertyGetterLookup(
+ base.nameAsIndex(), JSUnitGenerator::LookupForCall);
call.argc = calldata.argc;
call.argv = calldata.argv;
bytecodeGenerator->addInstruction(call);
} else {
Instruction::CallGlobalLookup call;
- call.index = registerGlobalGetterLookup(base.nameAsIndex());
+ call.index = registerGlobalGetterLookup(
+ base.nameAsIndex(), JSUnitGenerator::LookupForCall);
call.argc = calldata.argc;
call.argv = calldata.argv;
bytecodeGenerator->addInstruction(call);
@@ -2022,8 +2159,6 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.argv = calldata.argv;
bytecodeGenerator->addInstruction(call);
}
-
- setExprResult(Reference::fromAccumulator(this));
}
Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
@@ -2057,8 +2192,10 @@ Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
break;
if (!argc && !it->next && !hasSpread) {
// avoid copy for functions taking a single argument
- if (e.isStackSlot())
+ if (e.isStackSlot()) {
+ e.tdzCheck();
return { 1, e.stackSlot(), hasSpread };
+ }
}
(void) e.storeOnStack(calldata + argc);
++argc;
@@ -2131,12 +2268,18 @@ bool Codegen::visit(DeleteExpression *ast)
if (hasError())
return false;
+ const bool isTailOfChain = traverseOptionalChain(ast);
+
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = expression(ast->expression);
if (hasError())
return false;
+ const bool chainActuallyHasOptionals = m_optionalChainsStates.top().actuallyHasOptionals;
+ if (chainActuallyHasOptionals)
+ Q_ASSERT(expr.type == Reference::Member || expr.type == Reference::Subscript);
+
switch (expr.type) {
case Reference::SuperProperty:
// ### this should throw a reference error at runtime.
@@ -2144,7 +2287,7 @@ bool Codegen::visit(DeleteExpression *ast)
case Reference::StackSlot:
if (!expr.stackSlotIsLocalOrArgument)
break;
- // fall through
+ Q_FALLTHROUGH();
case Reference::ScopedLocal:
// Trying to delete a function argument might throw.
if (_context->isStrict) {
@@ -2167,6 +2310,14 @@ bool Codegen::visit(DeleteExpression *ast)
case Reference::Member: {
//### maybe add a variant where the base can be in the accumulator?
expr = expr.asLValue();
+
+ if (chainActuallyHasOptionals) {
+ expr.loadInAccumulator();
+ bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
+ auto jumpToUndefined = bytecodeGenerator->jumpTrue();
+ m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
+ }
+
Instruction::LoadRuntimeString instr;
instr.stringId = expr.propertyNameIndex;
bytecodeGenerator->addInstruction(instr);
@@ -2176,17 +2327,29 @@ bool Codegen::visit(DeleteExpression *ast)
del.base = expr.propertyBase.stackSlot();
del.index = index.stackSlot();
bytecodeGenerator->addInstruction(del);
- setExprResult(Reference::fromAccumulator(this));
+ auto ref = Reference::fromAccumulator(this);
+
+ optionalChainFinalizer(ref, isTailOfChain, true);
return false;
}
case Reference::Subscript: {
//### maybe add a variant where the index can be in the accumulator?
expr = expr.asLValue();
+
+ if (chainActuallyHasOptionals) {
+ expr.loadInAccumulator();
+ bytecodeGenerator->addInstruction(Instruction::CmpEqNull());
+ auto jumpToUndefined = bytecodeGenerator->jumpTrue();
+ m_optionalChainsStates.top().jumpsToPatch.emplace_back(std::move(jumpToUndefined));
+ }
+
Instruction::DeleteProperty del;
del.base = expr.elementBase;
del.index = expr.elementSubscript.stackSlot();
bytecodeGenerator->addInstruction(del);
- setExprResult(Reference::fromAccumulator(this));
+ auto ref = Reference::fromAccumulator(this);
+
+ optionalChainFinalizer(ref, isTailOfChain, true);
return false;
}
default:
@@ -2197,6 +2360,10 @@ bool Codegen::visit(DeleteExpression *ast)
return false;
}
+void Codegen::endVisit(DeleteExpression *ast) {
+ m_seenOptionalChainNodes.remove(ast);
+}
+
bool Codegen::visit(FalseLiteral *)
{
if (hasError())
@@ -2215,12 +2382,115 @@ bool Codegen::visit(SuperLiteral *)
return false;
}
+bool Codegen::traverseOptionalChain(Node *node)
+{
+ if (m_seenOptionalChainNodes.contains(node))
+ return false;
+
+ const auto isOptionalChainableNode = [](const Node *node) {
+ return node->kind == Node::Kind_FieldMemberExpression ||
+ node->kind == Node::Kind_CallExpression ||
+ node->kind == Node::Kind_ArrayMemberExpression ||
+ node->kind == Node::Kind_DeleteExpression;
+ };
+ m_optionalChainsStates.emplace();
+ while (isOptionalChainableNode(node)) {
+ m_seenOptionalChainNodes.insert(node);
+
+ switch (node->kind) {
+ case Node::Kind_FieldMemberExpression: {
+ auto *fme = AST::cast<FieldMemberExpression *>(node);
+ m_optionalChainsStates.top().actuallyHasOptionals |= fme->isOptional;
+ node = fme->base;
+ break;
+ }
+ case Node::Kind_CallExpression: {
+ auto *ce = AST::cast<CallExpression *>(node);
+ m_optionalChainsStates.top().actuallyHasOptionals |= ce->isOptional;
+ node = ce->base;
+ break;
+ }
+ case Node::Kind_ArrayMemberExpression: {
+ auto *ame = AST::cast<ArrayMemberExpression *>(node);
+ m_optionalChainsStates.top().actuallyHasOptionals |= ame->isOptional;
+ node = ame->base;
+ break;
+ }
+ case Node::Kind_DeleteExpression:
+ node = AST::cast<DeleteExpression *>(node)->expression;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ }
+
+ return true;
+}
+
+void Codegen::optionalChainFinalizer(const Reference &expressionResult, bool tailOfChain,
+ bool isDeleteExpression)
+{
+ auto &chainState = m_optionalChainsStates.top();
+ if (!tailOfChain) {
+ setExprResult(expressionResult);
+ return;
+ } else if (!chainState.actuallyHasOptionals) {
+ setExprResult(expressionResult);
+ m_optionalChainsStates.pop();
+ return;
+ }
+
+ auto savedBaseSlot = -1;
+ if (expressionResult.type == Reference::Member)
+ savedBaseSlot = expressionResult.propertyBase.storeOnStack().stackSlot();
+ expressionResult.loadInAccumulator();
+
+ std::optional<Moth::BytecodeGenerator::Jump> jumpToDone;
+ if (!isDeleteExpression) // Delete expressions always return true, avoid the extra jump
+ jumpToDone.emplace(bytecodeGenerator->jump());
+
+ for (auto &jump : chainState.jumpsToPatch)
+ jump.link();
+
+ if (isDeleteExpression)
+ bytecodeGenerator->addInstruction(Instruction::LoadTrue());
+ else
+ bytecodeGenerator->addInstruction(Instruction::LoadUndefined());
+
+ if (jumpToDone.has_value())
+ jumpToDone.value().link();
+
+ auto ref = Reference::fromAccumulator(this);
+ if (expressionResult.type == Reference::Member) {
+ /* Because the whole optional chain is handled at once with a chain finalizer instead of
+ * instruction by instruction, the result of the chain (either undefined or the result of
+ * the optional operation) is stored in the accumulator. This works fine except for one
+ * edge case where the `this` context is required in a call
+ * (see tst_ecmascripttests: language/expressions/optional-chaining/optional-call-preserves-this.js).
+ *
+ * In order to preserve the `this` context in the call, the call base and the property name
+ * index need to be available as with a Member reference. However, since the result must be
+ * in the accumulator the resulting reference is of type Accumulator. Therefore, the call
+ * base and the property name index are `glued` to an accumulator reference to make it work
+ * when deciding which call instruction to use later on.
+ */
+ ref.hasSavedCallBaseSlot = true;
+ ref.savedCallBaseSlot = savedBaseSlot;
+ ref.savedCallPropertyNameIndex = expressionResult.propertyNameIndex;
+ }
+ setExprResult(ref);
+ m_optionalChainsStates.pop();
+}
+
bool Codegen::visit(FieldMemberExpression *ast)
{
if (hasError())
return false;
+ const bool isTailOfChain = traverseOptionalChain(ast);
+
TailCallBlocker blockTailCalls(this);
+
if (AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(ast->base)) {
if (id->name == QLatin1String("new")) {
// new.target
@@ -2230,16 +2500,18 @@ bool Codegen::visit(FieldMemberExpression *ast)
Reference r = referenceForName(QStringLiteral("new.target"), false);
r.isReadonly = true;
setExprResult(r);
+
return false;
}
- Reference r = Reference::fromStackSlot(this, CallData::NewTarget);
- setExprResult(r);
+ auto ref = Reference::fromStackSlot(this, CallData::NewTarget);
+ optionalChainFinalizer(ref, isTailOfChain);
return false;
}
}
Reference base = expression(ast->base);
+
if (hasError())
return false;
if (base.isSuper()) {
@@ -2247,13 +2519,23 @@ bool Codegen::visit(FieldMemberExpression *ast)
load.stringId = registerString(ast->name.toString());
bytecodeGenerator->addInstruction(load);
Reference property = Reference::fromAccumulator(this).storeOnStack();
- setExprResult(Reference::fromSuperProperty(property));
+
+ optionalChainFinalizer(Reference::fromSuperProperty(property), isTailOfChain);
return false;
}
- setExprResult(Reference::fromMember(base, ast->name.toString()));
+
+ auto ref = Reference::fromMember(base, ast->name.toString(), ast->lastSourceLocation(),
+ ast->isOptional, &m_optionalChainsStates.top().jumpsToPatch);
+
+ optionalChainFinalizer(ref, isTailOfChain);
return false;
}
+void Codegen::endVisit(FieldMemberExpression *ast)
+{
+ m_seenOptionalChainNodes.remove(ast);
+}
+
bool Codegen::visit(TaggedTemplate *ast)
{
if (hasError())
@@ -2271,9 +2553,12 @@ bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
int functionObject = -1, thisObject = -1;
switch (base.type) {
case Reference::Member:
- case Reference::Subscript:
base = base.asLValue();
break;
+ case Reference::Subscript:
+ base.element = loadSubscriptForCall(base).storeOnStack().stackSlot();
+ base.subscriptLoadedForCall = true;
+ break;
case Reference::Name:
break;
case Reference::SuperProperty:
@@ -2296,6 +2581,7 @@ bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
--calldata.argv;
handleCall(base, calldata, functionObject, thisObject);
+ setExprResult(Reference::fromAccumulator(this));
return false;
}
@@ -2336,12 +2622,32 @@ bool Codegen::visit(FunctionExpression *ast)
Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, const SourceLocation &accessLocation)
{
Context::ResolvedName resolved = _context->resolveName(name, accessLocation);
+ bool throwsReferenceError = false;
if (resolved.type == Context::ResolvedName::Local || resolved.type == Context::ResolvedName::Stack
|| resolved.type == Context::ResolvedName::Import) {
if (resolved.isArgOrEval && isLhs)
// ### add correct source location
throwSyntaxError(SourceLocation(), QStringLiteral("Variable name may not be eval or arguments in strict mode"));
+
+ if (resolved.declarationLocation.isValid() && accessLocation.isValid()
+ && resolved.declarationLocation.begin() > accessLocation.end()) {
+ Q_ASSERT(_interface);
+ _interface->reportVarUsedBeforeDeclaration(
+ name, url().toLocalFile(), resolved.declarationLocation, accessLocation);
+ if (resolved.type == Context::ResolvedName::Stack && resolved.requiresTDZCheck)
+ throwsReferenceError = true;
+ }
+
+ if (resolved.isInjected && accessLocation.isValid()) {
+ qCWarning(lcQmlInjectedParameter).nospace().noquote()
+ << url().toString() << ":" << accessLocation.startLine
+ << ":" << accessLocation.startColumn << " Parameter \"" << name
+ << "\" is not declared."
+ << " Injection of parameters into signal handlers is deprecated."
+ << " Use JavaScript functions with formal parameters instead.";
+ }
+
Reference r;
switch (resolved.type) {
case Context::ResolvedName::Local:
@@ -2358,12 +2664,15 @@ Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, co
r.isReferenceToConst = resolved.isConst;
r.requiresTDZCheck = resolved.requiresTDZCheck;
r.name = name; // used to show correct name at run-time when TDZ check fails.
+ r.sourceLocation = accessLocation;
+ r.throwsReferenceError = throwsReferenceError;
return r;
}
Reference r = Reference::fromName(this, name);
r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global || resolved.type == Context::ResolvedName::QmlGlobal);
r.qmlGlobal = resolved.type == Context::ResolvedName::QmlGlobal;
+ r.sourceLocation = accessLocation;
if (!r.global && !r.qmlGlobal && m_globalNames.contains(name))
r.global = true;
return r;
@@ -2781,12 +3090,17 @@ bool Codegen::visit(ThisExpression *)
if (hasError())
return false;
- if (_context->isArrowFunction) {
- Reference r = referenceForName(QStringLiteral("this"), false);
- r.isReadonly = true;
- setExprResult(r);
- return false;
+ for (Context *parentContext = _context; parentContext; parentContext = parentContext->parent) {
+ if (parentContext->isArrowFunction) {
+ Reference r = referenceForName(QStringLiteral("this"), false);
+ r.isReadonly = true;
+ setExprResult(r);
+ return false;
+ }
+ if (parentContext->contextType != ContextType::Block)
+ break;
}
+
setExprResult(Reference::fromThis(this));
return false;
}
@@ -2891,6 +3205,17 @@ bool Codegen::visit(YieldExpression *ast)
return false;
}
+ auto innerMostCurentFunctionContext = _context;
+ while (innerMostCurentFunctionContext && innerMostCurentFunctionContext->contextType != ContextType::Function)
+ innerMostCurentFunctionContext = innerMostCurentFunctionContext->parent;
+
+ Q_ASSERT(innerMostCurentFunctionContext); // yield outside function would have been rejected by parser
+
+ if (!innerMostCurentFunctionContext->isGenerator) {
+ throwSyntaxError(ast->firstSourceLocation(), u"Yield is only valid in generator functions"_s);
+ return false;
+ }
+
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(this, Encode::undefined());
@@ -2925,15 +3250,15 @@ bool Codegen::visit(YieldExpression *ast)
Instruction::IteratorNextForYieldStar next;
next.object = lhsValue.stackSlot();
next.iterator = iterator.stackSlot();
- bytecodeGenerator->addInstruction(next);
-
- BytecodeGenerator::Jump done = bytecodeGenerator->jumpTrue();
+ BytecodeGenerator::Jump done = bytecodeGenerator->addJumpInstruction(next);
bytecodeGenerator->jumpNotUndefined().link(loop);
+
lhsValue.loadInAccumulator();
emitReturn(acc);
done.link();
+ bytecodeGenerator->checkException();
lhsValue.loadInAccumulator();
setExprResult(acc);
@@ -2979,8 +3304,7 @@ static bool endsWithReturn(Module *module, Node *node)
return false;
}
-int Codegen::defineFunction(const QString &name, AST::Node *ast,
- AST::FormalParameterList *formals,
+int Codegen::defineFunction(const QString &name, AST::Node *ast, AST::FormalParameterList *formals,
AST::StatementList *body)
{
enterContext(ast);
@@ -2991,7 +3315,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
_context->name = name.isEmpty() ? currentExpr().result().name : name;
_module->functions.append(_context);
- _context->functionIndex = _module->functions.count() - 1;
+ _context->functionIndex = _module->functions.size() - 1;
Context *savedFunctionContext = _functionContext;
_functionContext = _context;
@@ -3000,7 +3324,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
if (_context->contextType == ContextType::Global || _context->contextType == ContextType::ScriptImportedByQML) {
_module->blocks.append(_context);
- _context->blockIndex = _module->blocks.count() - 1;
+ _context->blockIndex = _module->blocks.size() - 1;
}
if (_module->debugMode) // allow the debugger to see overwritten arguments
_context->argumentsCanEscape = true;
@@ -3011,9 +3335,10 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
// at all, because if the onSignal is a signal handler, the user is actually making it explicit
// that the binding is a function, so we should execute that. However, we don't know that during
// AOT compilation, so mark the surrounding function as only-returning-a-closure.
- _context->returnsClosure = body && body->statement && cast<ExpressionStatement *>(body->statement) && cast<FunctionExpression *>(cast<ExpressionStatement *>(body->statement)->expression);
+ _context->returnsClosure = body && cast<ExpressionStatement *>(body->statement)
+ && cast<FunctionExpression *>(cast<ExpressionStatement *>(body->statement)->expression);
- BytecodeGenerator bytecode(_context->line, _module->debugMode);
+ BytecodeGenerator bytecode(_context->line, _module->debugMode, storeSourceLocations);
BytecodeGenerator *savedBytecodeGenerator;
savedBytecodeGenerator = bytecodeGenerator;
bytecodeGenerator = &bytecode;
@@ -3040,7 +3365,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
// register the lexical scope for global code
if (!_context->parent && _context->requiresExecutionContext) {
_module->blocks.append(_context);
- _context->blockIndex = _module->blocks.count() - 1;
+ _context->blockIndex = _module->blocks.size() - 1;
}
TailCallBlocker maybeBlockTailCalls(this, _context->canHaveTailCalls());
@@ -3114,8 +3439,9 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
if (showCode) {
qDebug() << "=== Bytecode for" << _context->name << "strict mode" << _context->isStrict
<< "register count" << _context->registerCountInFunction << "implicit return" << requiresReturnValue;
- QV4::Moth::dumpBytecode(_context->code, _context->locals.size(), _context->arguments.size(),
- _context->line, _context->lineNumberMapping);
+ qDebug().noquote() << QV4::Moth::dumpBytecode(
+ _context->code, _context->locals.size(), _context->arguments.size(),
+ _context->line, _context->lineAndStatementNumberMapping);
qDebug();
}
}
@@ -3276,7 +3602,6 @@ bool Codegen::visit(ForEachStatement *ast)
TailCallBlocker blockTailCalls(this);
Reference iterator = Reference::fromStackSlot(this);
- Reference iteratorDone = Reference::fromConst(this, Encode(false)).storeOnStack();
Reference lhsValue = Reference::fromStackSlot(this);
// There should be a temporal block, so that variables declared in lhs shadow outside vars.
@@ -3297,25 +3622,28 @@ bool Codegen::visit(ForEachStatement *ast)
BytecodeGenerator::Label in = bytecodeGenerator->newLabel();
BytecodeGenerator::Label end = bytecodeGenerator->newLabel();
+ BytecodeGenerator::Label done;
{
- auto cleanup = [ast, iterator, iteratorDone, this]() {
- if (ast->type == ForEachType::Of) {
+ std::function<void()> cleanup;
+ if (ast->type == ForEachType::Of) {
+ done = bytecodeGenerator->newLabel();
+ cleanup = [iterator, this, done]() {
iterator.loadInAccumulator();
Instruction::IteratorClose close;
- close.done = iteratorDone.stackSlot();
bytecodeGenerator->addInstruction(close);
- }
- };
- ControlFlowLoop flow(this, &end, &in, cleanup);
+ done.link();
+ };
+ } else {
+ done = end;
+ }
+ ControlFlowLoop flow(this, &end, &in, std::move(cleanup));
bytecodeGenerator->addLoopStart(in);
in.link();
iterator.loadInAccumulator();
Instruction::IteratorNext next;
next.value = lhsValue.stackSlot();
- next.done = iteratorDone.stackSlot();
- bytecodeGenerator->addInstruction(next);
- bytecodeGenerator->addJumpInstruction(Instruction::JumpTrue()).link(end);
+ bytecodeGenerator->addJumpInstruction(next).link(done);
// each iteration gets it's own context, as per spec
{
@@ -3631,7 +3959,8 @@ void Codegen::handleTryCatch(TryStatement *ast)
void Codegen::handleTryFinally(TryStatement *ast)
{
RegisterScope scope(this);
- ControlFlowFinally finally(this, ast->finallyExpression);
+ const bool hasCatchBlock = ast->catchExpression;
+ ControlFlowFinally finally(this, ast->finallyExpression, hasCatchBlock);
TailCallBlocker blockTailCalls(this); // IMPORTANT: destruction will unblock tail calls before finally is generated
if (ast->catchExpression) {
@@ -3785,8 +4114,7 @@ void Codegen::throwError(ErrorType errorType, const SourceLocation &loc, const Q
_errorType = errorType;
_error.message = detail;
- _error.line = loc.startLine;
- _error.column = loc.startColumn;
+ _error.loc = loc;
}
void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
@@ -3804,14 +4132,16 @@ QQmlJS::DiagnosticMessage Codegen::error() const
return _error;
}
-QV4::CompiledData::CompilationUnit Codegen::generateCompilationUnit(
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> Codegen::generateCompilationUnit(
bool generateUnitData)
{
- return QV4::CompiledData::CompilationUnit(
- generateUnitData ? jsUnitGenerator->generateUnit() : nullptr);
+ return QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
+ new QV4::CompiledData::CompilationUnit(
+ generateUnitData ? jsUnitGenerator->generateUnit() : nullptr),
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit>::Adopt);
}
-CompiledData::CompilationUnit Codegen::compileModule(
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> Codegen::compileModule(
bool debugMode, const QString &url, const QString &sourceCode,
const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics)
{
@@ -3826,7 +4156,7 @@ CompiledData::CompilationUnit Codegen::compileModule(
*diagnostics = parser.diagnosticMessages();
if (!parsed)
- return CompiledData::CompilationUnit();
+ return QQmlRefPointer<CompiledData::CompilationUnit>();
QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast<QQmlJS::AST::ESModule*>(parser.rootNode());
if (!moduleNode) {
@@ -3847,7 +4177,7 @@ CompiledData::CompilationUnit Codegen::compileModule(
if (cg.hasError()) {
if (diagnostics)
*diagnostics << cg.error();
- return CompiledData::CompilationUnit();
+ return QQmlRefPointer<CompiledData::CompilationUnit>();
}
return cg.generateCompilationUnit();
@@ -3934,14 +4264,14 @@ public:
}
private:
- void collectIdentifiers(QVector<QStringView> &ids, AST::Node *node) {
+ void collectIdentifiers(QList<QStringView> &ids, AST::Node *node) {
class Collector: public QQmlJS::AST::Visitor {
private:
- QVector<QStringView> &ids;
+ QList<QStringView> &ids;
VolatileMemoryLocationScanner *parent;
public:
- Collector(QVector<QStringView> &ids, VolatileMemoryLocationScanner *parent) :
+ Collector(QList<QStringView> &ids, VolatileMemoryLocationScanner *parent) :
QQmlJS::AST::Visitor(parent->recursionDepth()), ids(ids), parent(parent)
{}
@@ -4036,7 +4366,9 @@ bool Codegen::Reference::operator==(const Codegen::Reference &other) const
case Member:
return propertyBase == other.propertyBase && propertyNameIndex == other.propertyNameIndex;
case Subscript:
- return elementBase == other.elementBase && elementSubscript == other.elementSubscript;
+ return elementBase == other.elementBase && other.subscriptLoadedForCall
+ ? (subscriptLoadedForCall && element == other.element)
+ : (!subscriptLoadedForCall && elementSubscript == other.elementSubscript);
case Import:
return index == other.index;
case Const:
@@ -4069,7 +4401,7 @@ Codegen::Reference Codegen::Reference::asLValue() const
case Accumulator:
Q_UNREACHABLE();
case Super:
- codegen->throwSyntaxError(AST::SourceLocation(), QStringLiteral("Super lvalues not implemented."));
+ codegen->throwSyntaxError(SourceLocation(), QStringLiteral("Super lvalues not implemented."));
return *this;
case Member:
if (!propertyBase.isStackSlot()) {
@@ -4153,6 +4485,28 @@ Codegen::Reference Codegen::Reference::doStoreOnStack(int slotIndex) const
return slot;
}
+void Codegen::Reference::tdzCheck(bool requiresCheck, bool throwsReferenceError) const {
+ if (throwsReferenceError) {
+ codegen->generateThrowException(QStringLiteral("ReferenceError"),
+ name + QStringLiteral(" is not defined"));
+ return;
+ }
+ if (!requiresCheck)
+ return;
+ Instruction::DeadTemporalZoneCheck check;
+ check.name = codegen->registerString(name);
+ codegen->bytecodeGenerator->addInstruction(check);
+}
+
+void Codegen::Reference::tdzCheckStackSlot(Moth::StackSlot slot, bool requiresCheck, bool throwsReferenceError) const {
+ if (!requiresCheck)
+ return;
+ Instruction::LoadReg load;
+ load.reg = slot;
+ codegen->bytecodeGenerator->addInstruction(load);
+ tdzCheck(true, throwsReferenceError);
+}
+
Codegen::Reference Codegen::Reference::storeRetainAccumulator() const
{
if (storeWipesAccumulator()) {
@@ -4189,24 +4543,21 @@ bool Codegen::Reference::storeWipesAccumulator() const
void Codegen::Reference::storeAccumulator() const
{
+ if (throwsReferenceError) {
+ codegen->generateThrowException(QStringLiteral("ReferenceError"),
+ name + QStringLiteral(" is not defined"));
+ return;
+ }
+
if (isReferenceToConst) {
// throw a type error
- RegisterScope scope(codegen);
- Reference r = codegen->referenceForName(QStringLiteral("TypeError"), false);
- r = r.storeOnStack();
- Instruction::Construct construct;
- construct.func = r.stackSlot();
- construct.argc = 0;
- construct.argv = 0;
- codegen->bytecodeGenerator->addInstruction(construct);
- Instruction::ThrowException throwException;
- codegen->bytecodeGenerator->addInstruction(throwException);
+ codegen->generateThrowException(QStringLiteral("TypeError"));
return;
}
+
switch (type) {
case Super:
- Q_UNREACHABLE();
- return;
+ Q_UNREACHABLE_RETURN();
case SuperProperty:
Instruction::StoreSuperProperty store;
store.property = property.stackSlot();
@@ -4244,7 +4595,7 @@ void Codegen::Reference::storeAccumulator() const
}
} return;
case Member:
- if (!disable_lookups && codegen->useFastLookups) {
+ if (codegen->useFastLookups) {
Instruction::SetLookup store;
store.base = propertyBase.stackSlot();
store.index = codegen->registerSetterLookup(propertyNameIndex);
@@ -4274,30 +4625,13 @@ void Codegen::Reference::storeAccumulator() const
void Codegen::Reference::loadInAccumulator() const
{
- auto tdzCheck = [this](bool requiresCheck){
- if (!requiresCheck)
- return;
- Instruction::DeadTemporalZoneCheck check;
- check.name = codegen->registerString(name);
- codegen->bytecodeGenerator->addInstruction(check);
- };
- auto tdzCheckStackSlot = [this, tdzCheck](Moth::StackSlot slot, bool requiresCheck){
- if (!requiresCheck)
- return;
- Instruction::LoadReg load;
- load.reg = slot;
- codegen->bytecodeGenerator->addInstruction(load);
- tdzCheck(true);
- };
-
switch (type) {
case Accumulator:
return;
case Super:
- Q_UNREACHABLE();
- return;
+ Q_UNREACHABLE_RETURN();
case SuperProperty:
- tdzCheckStackSlot(property, subscriptRequiresTDZCheck);
+ tdzCheckStackSlot(property, subscriptRequiresTDZCheck, false);
Instruction::LoadSuperProperty load;
load.property = property.stackSlot();
codegen->bytecodeGenerator->addInstruction(load);
@@ -4321,7 +4655,7 @@ QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // the loads below are empty str
StaticValue p = StaticValue::fromReturnedValue(constant);
if (p.isNumber()) {
double d = p.asDouble();
- int i = static_cast<int>(d);
+ int i = QJSNumberCoercion::toInteger(d);
if (d == i && (d != 0 || !std::signbit(d))) {
if (!i) {
Instruction::LoadZero load;
@@ -4344,7 +4678,7 @@ QT_WARNING_POP
Instruction::LoadReg load;
load.reg = stackSlot();
codegen->bytecodeGenerator->addInstruction(load);
- tdzCheck(requiresTDZCheck);
+ tdzCheck(requiresTDZCheck, throwsReferenceError);
} return;
case ScopedLocal: {
if (!scope) {
@@ -4357,7 +4691,7 @@ QT_WARNING_POP
load.scope = scope;
codegen->bytecodeGenerator->addInstruction(load);
}
- tdzCheck(requiresTDZCheck);
+ tdzCheck(requiresTDZCheck, throwsReferenceError);
return;
}
case Name:
@@ -4375,14 +4709,20 @@ QT_WARNING_POP
return;
}
}
- if (!disable_lookups && global) {
+
+ if (sourceLocation.isValid())
+ codegen->bytecodeGenerator->setLocation(sourceLocation);
+
+ if (global) {
if (qmlGlobal) {
Instruction::LoadQmlContextPropertyLookup load;
- load.index = codegen->registerQmlContextPropertyGetterLookup(nameAsIndex());
+ load.index = codegen->registerQmlContextPropertyGetterLookup(
+ nameAsIndex(), JSUnitGenerator::LookupForStorage);
codegen->bytecodeGenerator->addInstruction(load);
} else {
Instruction::LoadGlobalLookup load;
- load.index = codegen->registerGlobalGetterLookup(nameAsIndex());
+ load.index = codegen->registerGlobalGetterLookup(
+ nameAsIndex(), JSUnitGenerator::LookupForStorage);
codegen->bytecodeGenerator->addInstruction(load);
}
} else {
@@ -4393,27 +4733,44 @@ QT_WARNING_POP
return;
case Member:
propertyBase.loadInAccumulator();
- tdzCheck(requiresTDZCheck);
- if (!disable_lookups && codegen->useFastLookups) {
- Instruction::GetLookup load;
- load.index = codegen->registerGetterLookup(propertyNameIndex);
- codegen->bytecodeGenerator->addInstruction(load);
+ tdzCheck(requiresTDZCheck, throwsReferenceError);
+
+ if (sourceLocation.isValid())
+ codegen->bytecodeGenerator->setLocation(sourceLocation);
+
+ if (codegen->useFastLookups) {
+ if (optionalChainJumpsToPatch && isOptional) {
+ auto jump = codegen->bytecodeGenerator->jumpOptionalLookup(
+ codegen->registerGetterLookup(
+ propertyNameIndex, JSUnitGenerator::LookupForStorage));
+ optionalChainJumpsToPatch->emplace_back(std::move(jump));
+ } else {
+ Instruction::GetLookup load;
+ load.index = codegen->registerGetterLookup(
+ propertyNameIndex, JSUnitGenerator::LookupForStorage);
+ codegen->bytecodeGenerator->addInstruction(load);
+ }
} else {
- Instruction::LoadProperty load;
- load.name = propertyNameIndex;
- codegen->bytecodeGenerator->addInstruction(load);
+ if (optionalChainJumpsToPatch && isOptional) {
+ auto jump = codegen->bytecodeGenerator->jumpOptionalProperty(propertyNameIndex);
+ optionalChainJumpsToPatch->emplace_back(std::move(jump));
+ } else {
+ Instruction::LoadProperty load;
+ load.name = propertyNameIndex;
+ codegen->bytecodeGenerator->addInstruction(load);
+ }
}
return;
case Import: {
Instruction::LoadImport load;
load.index = index;
codegen->bytecodeGenerator->addInstruction(load);
- tdzCheck(requiresTDZCheck);
+ tdzCheck(requiresTDZCheck, throwsReferenceError);
} return;
case Subscript: {
- tdzCheckStackSlot(elementBase, requiresTDZCheck);
+ tdzCheckStackSlot(elementBase, requiresTDZCheck, throwsReferenceError);
elementSubscript.loadInAccumulator();
- tdzCheck(subscriptRequiresTDZCheck);
+ tdzCheck(subscriptRequiresTDZCheck, false);
Instruction::LoadElement load;
load.base = elementBase;
codegen->bytecodeGenerator->addInstruction(load);
@@ -4423,3 +4780,5 @@ QT_WARNING_POP
}
Q_UNREACHABLE();
}
+
+QT_END_NAMESPACE
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 82a4fc3289..3a27cb1487 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4CODEGEN_P_H
#define QV4CODEGEN_P_H
@@ -60,6 +24,9 @@
#include <private/qv4bytecodegenerator_p.h>
#include <private/qv4calldata_p.h>
+#include <QtCore/qsharedpointer.h>
+#include <stack>
+
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -78,14 +45,30 @@ struct ControlFlow;
struct ControlFlowCatch;
struct ControlFlowFinally;
-class Q_QMLCOMPILER_PRIVATE_EXPORT Codegen: protected QQmlJS::AST::Visitor
+class Q_QML_COMPILER_EXPORT CodegenWarningInterface
+{
+public:
+ virtual void reportVarUsedBeforeDeclaration(const QString &name, const QString &fileName,
+ QQmlJS::SourceLocation declarationLocation,
+ QQmlJS::SourceLocation accessLocation);
+ virtual ~CodegenWarningInterface() = default;
+};
+
+inline CodegenWarningInterface *defaultCodegenWarningInterface()
+{
+ static CodegenWarningInterface iface;
+ return &iface;
+}
+
+class Q_QML_COMPILER_EXPORT Codegen: protected QQmlJS::AST::Visitor
{
protected:
using BytecodeGenerator = QV4::Moth::BytecodeGenerator;
using Instruction = QV4::Moth::Instruction;
public:
- Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict);
-
+ Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict,
+ CodegenWarningInterface *iface = defaultCodegenWarningInterface(),
+ bool storeSourceLocations = false);
void generateFromProgram(const QString &fileName,
const QString &finalUrl,
@@ -105,15 +88,15 @@ public:
class VolatileMemoryLocations {
friend VolatileMemoryLocationScanner;
bool allVolatile = false;
- QVector<QStringView> specificLocations;
+ QList<QStringView> specificLocations;
public:
- bool isVolatile(const QStringView &name) {
+ bool isVolatile(QStringView name) {
if (allVolatile)
return true;
return specificLocations.contains(name);
}
- void add(const QStringRef &name) { if (!allVolatile) specificLocations.append(name); }
+ void add(QStringView name) { if (!allVolatile) specificLocations.append(name); }
void setAllVolatile() { allVolatile = true; }
};
class RValue {
@@ -206,7 +189,11 @@ public:
stackSlotIsLocalOrArgument(false),
isVolatile(false),
global(false),
- qmlGlobal(false)
+ qmlGlobal(false),
+ throwsReferenceError(false),
+ subscriptLoadedForCall(false),
+ isOptional(false),
+ hasSavedCallBaseSlot(false)
{}
Reference(const Reference &) = default;
@@ -253,14 +240,6 @@ public:
r.stackSlotIsLocalOrArgument = isLocal;
return r;
}
- static Reference fromArgument(Codegen *cg, int index, bool isVolatile) {
- Reference r(cg, StackSlot);
- r.theStackSlot = Moth::StackSlot::createRegister(
- index + sizeof(CallData) / sizeof(StaticValue) - 1);
- r.stackSlotIsLocalOrArgument = true;
- r.isVolatile = isVolatile;
- return r;
- }
static Reference fromScopedLocal(Codegen *cg, int index, int scope) {
Reference r(cg, ScopedLocal);
r.index = index;
@@ -277,11 +256,20 @@ public:
r.name = name;
return r;
}
- static Reference fromMember(const Reference &baseRef, const QString &name) {
+ static Reference
+ fromMember(const Reference &baseRef, const QString &name,
+ QQmlJS::SourceLocation sourceLocation = QQmlJS::SourceLocation(),
+ bool isOptional = false,
+ std::vector<Moth::BytecodeGenerator::Jump> *optionalChainJumpsToPatch = nullptr)
+ {
+ Q_ASSERT(baseRef.isValid());
Reference r(baseRef.codegen, Member);
r.propertyBase = baseRef.asRValue();
r.propertyNameIndex = r.codegen->registerString(name);
r.requiresTDZCheck = baseRef.requiresTDZCheck;
+ r.sourceLocation = sourceLocation;
+ r.optionalChainJumpsToPatch = optionalChainJumpsToPatch;
+ r.isOptional = isOptional;
return r;
}
static Reference fromSuperProperty(const Reference &property) {
@@ -345,6 +333,14 @@ public:
return theStackSlot;
}
+ void tdzCheck() const
+ {
+ if (isAccumulator())
+ tdzCheck(requiresTDZCheck, throwsReferenceError);
+ else if (isStackSlot())
+ tdzCheckStackSlot(stackSlot(), requiresTDZCheck, throwsReferenceError);
+ }
+
union {
Moth::StackSlot theStackSlot;
QV4::ReturnedValue constant;
@@ -358,7 +354,10 @@ public:
};
struct {
Moth::StackSlot elementBase;
- RValue elementSubscript;
+ union {
+ RValue elementSubscript;
+ Moth::StackSlot element;
+ };
};
Moth::StackSlot property; // super property
};
@@ -374,10 +373,21 @@ public:
quint32 isVolatile:1;
quint32 global:1;
quint32 qmlGlobal:1;
+ quint32 throwsReferenceError:1;
+ quint32 subscriptLoadedForCall:1;
+ quint32 isOptional: 1;
+ quint32 hasSavedCallBaseSlot: 1;
+ QQmlJS::SourceLocation sourceLocation = QQmlJS::SourceLocation();
+ std::vector<Moth::BytecodeGenerator::Jump> *optionalChainJumpsToPatch = nullptr;
+ int savedCallBaseSlot = -1;
+ int savedCallPropertyNameIndex = -1;
private:
void storeAccumulator() const;
Reference doStoreOnStack(int tempIndex) const;
+ void tdzCheck(bool requiresCheck, bool throwsReferenceError) const;
+ void tdzCheckStackSlot(
+ Moth::StackSlot slot, bool requiresCheck, bool throwsReferenceError) const;
};
struct RegisterScope {
@@ -511,11 +521,26 @@ public:
int registerString(const QString &name) {
return jsUnitGenerator->registerString(name);
}
- int registerConstant(QV4::ReturnedValue v) { return jsUnitGenerator->registerConstant(v); }
- int registerGetterLookup(int nameIndex) { return jsUnitGenerator->registerGetterLookup(nameIndex); }
- int registerSetterLookup(int nameIndex) { return jsUnitGenerator->registerSetterLookup(nameIndex); }
- int registerGlobalGetterLookup(int nameIndex) { return jsUnitGenerator->registerGlobalGetterLookup(nameIndex); }
- int registerQmlContextPropertyGetterLookup(int nameIndex) { return jsUnitGenerator->registerQmlContextPropertyGetterLookup(nameIndex); }
+ int registerConstant(QV4::ReturnedValue v)
+ {
+ return jsUnitGenerator->registerConstant(v);
+ }
+ int registerGetterLookup(int nameIndex, JSUnitGenerator::LookupMode mode)
+ {
+ return jsUnitGenerator->registerGetterLookup(nameIndex, mode);
+ }
+ int registerSetterLookup(int nameIndex)
+ {
+ return jsUnitGenerator->registerSetterLookup(nameIndex);
+ }
+ int registerGlobalGetterLookup(int nameIndex, JSUnitGenerator::LookupMode mode)
+ {
+ return jsUnitGenerator->registerGlobalGetterLookup(nameIndex, mode);
+ }
+ int registerQmlContextPropertyGetterLookup(int nameIndex, JSUnitGenerator::LookupMode mode)
+ {
+ return jsUnitGenerator->registerQmlContextPropertyGetterLookup(nameIndex, mode);
+ }
// Returns index in _module->functions
virtual int defineFunction(const QString &name, QQmlJS::AST::Node *ast,
@@ -575,6 +600,7 @@ protected:
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::UiPragmaValueList *ast) override;
bool visit(QQmlJS::AST::UiPragma *ast) override;
bool visit(QQmlJS::AST::UiObjectInitializer *ast) override;
bool visit(QQmlJS::AST::UiObjectMemberList *ast) override;
@@ -598,11 +624,14 @@ protected:
bool visit(QQmlJS::AST::ArrayMemberExpression *ast) override;
bool visit(QQmlJS::AST::BinaryExpression *ast) override;
bool visit(QQmlJS::AST::CallExpression *ast) override;
+ void endVisit(QQmlJS::AST::CallExpression *ast) override;
bool visit(QQmlJS::AST::ConditionalExpression *ast) override;
bool visit(QQmlJS::AST::DeleteExpression *ast) override;
+ void endVisit(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;
+ void endVisit(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;
@@ -661,12 +690,12 @@ protected:
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);
+ const QQmlJS::SourceLocation &loc);
+ virtual void throwSyntaxError(const QQmlJS::SourceLocation &loc, const QString &detail);
+ virtual void throwReferenceError(const QQmlJS::SourceLocation &loc, const QString &detail);
void throwRecursionDepthError() override
{
- throwSyntaxError(QQmlJS::AST::SourceLocation(),
+ throwSyntaxError(QQmlJS::SourceLocation(),
QStringLiteral("Maximum statement or expression depth exceeded"));
}
@@ -682,11 +711,12 @@ public:
QQmlJS::DiagnosticMessage error() const;
QUrl url() const;
- Reference binopHelper(QSOperator::Op oper, Reference &left, Reference &right);
+ Reference binopHelper(QQmlJS::AST::BinaryExpression *ast, 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(QQmlJS::AST::ArgumentList *args);
- void handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject);
+ void handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject, bool optional = false);
Arguments pushTemplateArgs(QQmlJS::AST::TemplateLiteral *args);
bool handleTaggedTemplate(Reference base, QQmlJS::AST::TaggedTemplate *ast);
@@ -700,10 +730,11 @@ public:
Reference referenceForName(
const QString &name, bool lhs,
- const QQmlJS::AST::SourceLocation &accessLocation = QQmlJS::AST::SourceLocation());
+ const QQmlJS::SourceLocation &accessLocation = QQmlJS::SourceLocation());
- QV4::CompiledData::CompilationUnit generateCompilationUnit(bool generateUnitData = true);
- static QV4::CompiledData::CompilationUnit compileModule(
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> generateCompilationUnit(
+ bool generateUnitData = true);
+ static QQmlRefPointer<QV4::CompiledData::CompilationUnit> compileModule(
bool debugMode, const QString &url, const QString &sourceCode,
const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics);
@@ -775,13 +806,24 @@ protected:
bool inFormalParameterList = false;
bool functionEndsWithReturn = false;
bool _tailCallsAreAllowed = true;
+ bool storeSourceLocations = false;
QSet<QString> m_globalNames;
+ struct OptionalChainState
+ {
+ QQmlJS::AST::Node *tailNodeOfChain = nullptr;
+ std::vector<Moth::BytecodeGenerator::Jump> jumpsToPatch;
+ bool actuallyHasOptionals = false;
+ };
+ QSet<QQmlJS::AST::Node*> m_seenOptionalChainNodes;
+ std::stack<OptionalChainState> m_optionalChainsStates;
+
ControlFlow *controlFlow = nullptr;
bool _fileNameIsUrl;
ErrorType _errorType = NoError;
QQmlJS::DiagnosticMessage _error;
+ CodegenWarningInterface *_interface;
class TailCallBlocker
{
@@ -808,10 +850,16 @@ protected:
};
private:
+ Q_DISABLE_COPY(Codegen)
VolatileMemoryLocations scanVolatileMemoryLocations(QQmlJS::AST::Node *ast);
void handleConstruct(const Reference &base, QQmlJS::AST::ArgumentList *args);
- void throwError(ErrorType errorType, const QQmlJS::AST::SourceLocation &loc,
+ void throwError(ErrorType errorType, const QQmlJS::SourceLocation &loc,
const QString &detail);
+ bool traverseOptionalChain(QQmlJS::AST::Node *node);
+ void optionalChainFinalizer(const Reference &expressionResult, bool tailOfChain,
+ bool isDeleteExpression = false);
+ Reference loadSubscriptForCall(const Reference &base);
+ void generateThrowException(const QString &type, const QString &text = QString());
};
}
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index acc4b02e96..7a7c8f621b 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -1,41 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qv4compiler_p.h>
#include <qv4codegen_p.h>
@@ -47,14 +12,20 @@
#include <private/qml_compile_hash_p.h>
#include <private/qqmlirbuilder_p.h>
#include <QCryptographicHash>
+#include <QtEndian>
// Efficient implementation that takes advantage of powers of two.
+
+QT_BEGIN_NAMESPACE
+namespace QtPrivate { // Disambiguate from WTF::roundUpToMultipleOf
static inline size_t roundUpToMultipleOf(size_t divisor, size_t x)
{
Q_ASSERT(divisor && !(divisor & (divisor - 1)));
const size_t remainderMask = divisor - 1;
return (x + remainderMask) & ~remainderMask;
}
+}
+QT_END_NAMESPACE
QV4::Compiler::StringTableGenerator::StringTableGenerator()
{
@@ -100,7 +71,8 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
{
char *dataStart = reinterpret_cast<char *>(unit);
quint32_le *stringTable = reinterpret_cast<quint32_le *>(dataStart + unit->offsetToStringTable);
- char *stringData = reinterpret_cast<char *>(stringTable) + roundUpToMultipleOf(8, unit->stringTableSize * sizeof(uint));
+ char *stringData = reinterpret_cast<char *>(stringTable)
+ + QtPrivate::roundUpToMultipleOf(8, unit->stringTableSize * sizeof(uint));
for (int i = backingUnitTableSize ; i < strings.size(); ++i) {
const int index = i - backingUnitTableSize;
stringTable[index] = stringData - dataStart;
@@ -108,19 +80,11 @@ void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
QV4::CompiledData::String *s = reinterpret_cast<QV4::CompiledData::String *>(stringData);
Q_ASSERT(reinterpret_cast<uintptr_t>(s) % alignof(QV4::CompiledData::String) == 0);
- s->refcount = -1;
- s->size = qstr.length();
- s->allocAndCapacityReservedFlag = 0;
- s->offsetOn32Bit = sizeof(QV4::CompiledData::String);
- s->offsetOn64Bit = sizeof(QV4::CompiledData::String);
+ Q_ASSERT(qstr.size() >= 0);
+ s->size = qstr.size();
ushort *uc = reinterpret_cast<ushort *>(reinterpret_cast<char *>(s) + sizeof(*s));
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- memcpy(uc, qstr.constData(), s->size * sizeof(ushort));
-#else
- for (int i = 0; i < s->size; ++i)
- uc[i] = qToLittleEndian<ushort>(qstr.at(i).unicode());
-#endif
+ qToLittleEndian<ushort>(qstr.constData(), s->size, uc);
uc[s->size] = 0;
stringData += QV4::CompiledData::String::calculateSize(qstr);
@@ -136,7 +100,7 @@ void QV4::Compiler::JSUnitGenerator::generateUnitChecksum(QV4::CompiledData::Uni
= offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(unit->md5Checksum);
const char *dataPtr = reinterpret_cast<const char *>(unit) + checksummableDataOffset;
- hash.addData(dataPtr, unit->unitSize - checksummableDataOffset);
+ hash.addData({dataPtr, qsizetype(unit->unitSize - checksummableDataOffset)});
QByteArray checksum = hash.result();
Q_ASSERT(checksum.size() == sizeof(unit->md5Checksum));
@@ -153,17 +117,22 @@ QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::Compiler::Module *module)
registerString(QString());
}
-int QV4::Compiler::JSUnitGenerator::registerGetterLookup(const QString &name)
+int QV4::Compiler::JSUnitGenerator::registerGetterLookup(const QString &name, LookupMode mode)
+{
+ return registerGetterLookup(registerString(name), mode);
+}
+
+static QV4::CompiledData::Lookup::Mode lookupMode(QV4::Compiler::JSUnitGenerator::LookupMode mode)
{
- return registerGetterLookup(registerString(name));
+ return mode == QV4::Compiler::JSUnitGenerator::LookupForCall
+ ? QV4::CompiledData::Lookup::Mode_ForCall
+ : QV4::CompiledData::Lookup::Mode_ForStorage;
}
-int QV4::Compiler::JSUnitGenerator::registerGetterLookup(int nameIndex)
+int QV4::Compiler::JSUnitGenerator::registerGetterLookup(int nameIndex, LookupMode mode)
{
- CompiledData::Lookup l;
- l.type_and_flags = CompiledData::Lookup::Type_Getter;
- l.nameIndex = nameIndex;
- lookups << l;
+ lookups << CompiledData::Lookup(
+ CompiledData::Lookup::Type_Getter, lookupMode(mode), nameIndex);
return lookups.size() - 1;
}
@@ -174,49 +143,43 @@ int QV4::Compiler::JSUnitGenerator::registerSetterLookup(const QString &name)
int QV4::Compiler::JSUnitGenerator::registerSetterLookup(int nameIndex)
{
- CompiledData::Lookup l;
- l.type_and_flags = CompiledData::Lookup::Type_Setter;
- l.nameIndex = nameIndex;
- lookups << l;
+ lookups << CompiledData::Lookup(
+ CompiledData::Lookup::Type_Setter,
+ CompiledData::Lookup::Mode_ForStorage, nameIndex);
return lookups.size() - 1;
}
-int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(int nameIndex)
+int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(int nameIndex, LookupMode mode)
{
- CompiledData::Lookup l;
- l.type_and_flags = CompiledData::Lookup::Type_GlobalGetter;
- l.nameIndex = nameIndex;
- lookups << l;
+ lookups << CompiledData::Lookup(
+ CompiledData::Lookup::Type_GlobalGetter, lookupMode(mode), nameIndex);
return lookups.size() - 1;
}
-int QV4::Compiler::JSUnitGenerator::registerQmlContextPropertyGetterLookup(int nameIndex)
+int QV4::Compiler::JSUnitGenerator::registerQmlContextPropertyGetterLookup(
+ int nameIndex, LookupMode mode)
{
- CompiledData::Lookup l;
- l.type_and_flags = CompiledData::Lookup::Type_QmlContextPropertyGetter;
- l.nameIndex = nameIndex;
- lookups << l;
+ lookups << CompiledData::Lookup(
+ CompiledData::Lookup::Type_QmlContextPropertyGetter, lookupMode(mode),
+ nameIndex);
return lookups.size() - 1;
}
int QV4::Compiler::JSUnitGenerator::registerRegExp(QQmlJS::AST::RegExpLiteral *regexp)
{
- CompiledData::RegExp re;
- re.stringIndex = registerString(regexp->pattern.toString());
-
- re.flags = 0;
+ quint32 flags = 0;
if (regexp->flags & QQmlJS::Lexer::RegExp_Global)
- re.flags |= CompiledData::RegExp::RegExp_Global;
+ flags |= CompiledData::RegExp::RegExp_Global;
if (regexp->flags & QQmlJS::Lexer::RegExp_IgnoreCase)
- re.flags |= CompiledData::RegExp::RegExp_IgnoreCase;
+ flags |= CompiledData::RegExp::RegExp_IgnoreCase;
if (regexp->flags & QQmlJS::Lexer::RegExp_Multiline)
- re.flags |= CompiledData::RegExp::RegExp_Multiline;
+ flags |= CompiledData::RegExp::RegExp_Multiline;
if (regexp->flags & QQmlJS::Lexer::RegExp_Unicode)
- re.flags |= CompiledData::RegExp::RegExp_Unicode;
+ flags |= CompiledData::RegExp::RegExp_Unicode;
if (regexp->flags & QQmlJS::Lexer::RegExp_Sticky)
- re.flags |= CompiledData::RegExp::RegExp_Sticky;
+ flags |= CompiledData::RegExp::RegExp_Sticky;
- regexps.append(re);
+ regexps.append(CompiledData::RegExp(flags, registerString(regexp->pattern.toString())));
return regexps.size() - 1;
}
@@ -229,11 +192,15 @@ int QV4::Compiler::JSUnitGenerator::registerConstant(QV4::ReturnedValue v)
return constants.size() - 1;
}
-QV4::ReturnedValue QV4::Compiler::JSUnitGenerator::constant(int idx)
+QV4::ReturnedValue QV4::Compiler::JSUnitGenerator::constant(int idx) const
{
return constants.at(idx);
}
+// The JSClass object and its members are stored contiguously in the jsClassData.
+// In order to get to the members you have to skip over the JSClass, therefore +1.
+static constexpr qsizetype jsClassMembersOffset = 1;
+
int QV4::Compiler::JSUnitGenerator::registerJSClass(const QStringList &members)
{
// ### re-use existing class definitions.
@@ -246,17 +213,36 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(const QStringList &members)
CompiledData::JSClass *jsClass = reinterpret_cast<CompiledData::JSClass*>(jsClassData.data() + oldSize);
jsClass->nMembers = members.size();
- CompiledData::JSClassMember *member = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + 1);
+ CompiledData::JSClassMember *member
+ = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + jsClassMembersOffset);
for (const auto &name : members) {
- member->nameOffset = registerString(name);
- member->isAccessor = false;
+ member->set(registerString(name), false);
++member;
}
return jsClassOffsets.size() - 1;
}
+int QV4::Compiler::JSUnitGenerator::jsClassSize(int jsClassId) const
+{
+ const CompiledData::JSClass *jsClass
+ = reinterpret_cast<const CompiledData::JSClass*>(
+ jsClassData.data() + jsClassOffsets[jsClassId]);
+ return jsClass->nMembers;
+}
+
+QString QV4::Compiler::JSUnitGenerator::jsClassMember(int jsClassId, int member) const
+{
+ const CompiledData::JSClass *jsClass = reinterpret_cast<const CompiledData::JSClass*>(
+ jsClassData.data() + jsClassOffsets[jsClassId]);
+ Q_ASSERT(member >= 0);
+ Q_ASSERT(uint(member) < jsClass->nMembers);
+ const CompiledData::JSClassMember *members
+ = reinterpret_cast<const CompiledData::JSClassMember*>(jsClass + jsClassMembersOffset);
+ return stringForIndex(members[member].nameOffset());
+}
+
int QV4::Compiler::JSUnitGenerator::registerTranslation(const QV4::CompiledData::TranslationData &translation)
{
translations.append(translation);
@@ -265,19 +251,33 @@ int QV4::Compiler::JSUnitGenerator::registerTranslation(const QV4::CompiledData:
QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option)
{
+ const auto registerTypeStrings = [this](QQmlJS::AST::Type *type) {
+ if (!type)
+ return;
+
+ if (type->typeArgument) {
+ registerString(type->typeArgument->toString());
+ registerString(type->typeId->toString());
+ }
+ registerString(type->toString());
+ };
+
registerString(module->fileName);
registerString(module->finalUrl);
- for (Context *f : qAsConst(module->functions)) {
+ for (Context *f : std::as_const(module->functions)) {
registerString(f->name);
- registerString(f->returnType);
+ registerTypeStrings(f->returnType);
for (int i = 0; i < f->arguments.size(); ++i) {
registerString(f->arguments.at(i).id);
- registerString(f->arguments.at(i).typeName());
+ if (const QQmlJS::AST::TypeAnnotation *annotation
+ = f->arguments.at(i).typeAnnotation.data()) {
+ registerTypeStrings(annotation->type);
+ }
}
for (int i = 0; i < f->locals.size(); ++i)
registerString(f->locals.at(i));
}
- for (Context *c : qAsConst(module->blocks)) {
+ for (Context *c : std::as_const(module->blocks)) {
for (int i = 0; i < c->locals.size(); ++i)
registerString(c->locals.at(i));
}
@@ -348,15 +348,17 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
}
CompiledData::Lookup *lookupsToWrite = reinterpret_cast<CompiledData::Lookup*>(dataPtr + unit->offsetToLookupTable);
- for (const CompiledData::Lookup &l : qAsConst(lookups))
+ for (const CompiledData::Lookup &l : std::as_const(lookups))
*lookupsToWrite++ = l;
CompiledData::RegExp *regexpTable = reinterpret_cast<CompiledData::RegExp *>(dataPtr + unit->offsetToRegexpTable);
- memcpy(regexpTable, regexps.constData(), regexps.size() * sizeof(*regexpTable));
+ if (regexps.size())
+ memcpy(regexpTable, regexps.constData(), regexps.size() * sizeof(*regexpTable));
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
ReturnedValue *constantTable = reinterpret_cast<ReturnedValue *>(dataPtr + unit->offsetToConstantTable);
- memcpy(constantTable, constants.constData(), constants.size() * sizeof(ReturnedValue));
+ if (constants.size())
+ memcpy(constantTable, constants.constData(), constants.size() * sizeof(ReturnedValue));
#else
quint64_le *constantTable = reinterpret_cast<quint64_le *>(dataPtr + unit->offsetToConstantTable);
for (int i = 0; i < constants.count(); ++i)
@@ -364,16 +366,18 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
#endif
{
- memcpy(dataPtr + jsClassDataOffset, jsClassData.constData(), jsClassData.size());
+ if (jsClassData.size())
+ memcpy(dataPtr + jsClassDataOffset, jsClassData.constData(), jsClassData.size());
// write js classes and js class lookup table
quint32_le *jsClassOffsetTable = reinterpret_cast<quint32_le *>(dataPtr + unit->offsetToJSClassTable);
- for (int i = 0; i < jsClassOffsets.count(); ++i)
+ for (int i = 0; i < jsClassOffsets.size(); ++i)
jsClassOffsetTable[i] = jsClassDataOffset + jsClassOffsets.at(i);
}
-
- memcpy(dataPtr + unit->offsetToTranslationTable, translations.constData(), translations.count() * sizeof(CompiledData::TranslationData));
+ if (translations.size()) {
+ memcpy(dataPtr + unit->offsetToTranslationTable, translations.constData(), translations.size() * sizeof(CompiledData::TranslationData));
+ }
{
const auto populateExportEntryTable = [this, dataPtr](const QVector<Compiler::ExportEntry> &table, quint32_le offset) {
@@ -424,7 +428,7 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
{
QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
- quint32 currentOffset = static_cast<quint32>(roundUpToMultipleOf(8, sizeof(*function)));
+ quint32 currentOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, sizeof(*function)));
function->nameIndex = getStringId(irFunction->name);
function->flags = 0;
@@ -434,15 +438,29 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->flags |= CompiledData::Function::IsArrowFunction;
if (irFunction->isGenerator)
function->flags |= CompiledData::Function::IsGenerator;
- function->nestedFunctionIndex =
- irFunction->returnsClosure ? quint32(module->functions.indexOf(irFunction->nestedContexts.first()))
- : std::numeric_limits<uint32_t>::max();
+ if (irFunction->returnsClosure)
+ function->flags |= CompiledData::Function::IsClosureWrapper;
+
+ if (!irFunction->returnsClosure
+ || irFunction->innerFunctionAccessesThis
+ || irFunction->innerFunctionAccessesNewTarget) {
+ // If the inner function does things with this and new.target we need to do some work in
+ // the outer function. Then we shouldn't directly access the nested function.
+ function->nestedFunctionIndex = std::numeric_limits<uint32_t>::max();
+ } else {
+ // Otherwise we can directly use the nested function.
+ function->nestedFunctionIndex
+ = quint32(module->functions.indexOf(irFunction->nestedContexts.first()));
+ }
+
function->length = irFunction->formals ? irFunction->formals->length() : 0;
function->nFormals = irFunction->arguments.size();
function->formalsOffset = currentOffset;
currentOffset += function->nFormals * sizeof(CompiledData::Parameter);
- QmlIR::Parameter::initType(&function->returnType, this, getStringId(irFunction->returnType));
+ const auto idGenerator = [this](const QString &str) { return getStringId(str); };
+
+ QmlIR::Parameter::initType(&function->returnType, idGenerator, irFunction->returnType);
function->sizeOfLocalTemporalDeadZone = irFunction->sizeOfLocalTemporalDeadZone;
function->sizeOfRegisterTemporalDeadZone = irFunction->sizeOfRegisterTemporalDeadZone;
@@ -452,9 +470,11 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->localsOffset = currentOffset;
currentOffset += function->nLocals * sizeof(quint32);
- function->nLineNumbers = irFunction->lineNumberMapping.size();
- Q_ASSERT(function->lineNumberOffset() == currentOffset);
- currentOffset += function->nLineNumbers * sizeof(CompiledData::CodeOffsetToLine);
+ function->nLineAndStatementNumbers
+ = irFunction->lineAndStatementNumberMapping.size();
+ Q_ASSERT(function->lineAndStatementNumberOffset() == currentOffset);
+ currentOffset += function->nLineAndStatementNumbers
+ * sizeof(CompiledData::CodeOffsetToLineAndStatement);
function->nRegisters = irFunction->registerCountInFunction;
@@ -464,8 +484,7 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
currentOffset += function->nLabelInfos * sizeof(quint32);
}
- function->location.line = irFunction->line;
- function->location.column = irFunction->column;
+ function->location.set(irFunction->line, irFunction->column);
function->codeOffset = currentOffset;
function->codeSize = irFunction->code.size();
@@ -473,8 +492,10 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
// write formals
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()));
+ auto *formal = &formals[i];
+ formal->nameIndex = getStringId(irFunction->arguments.at(i).id);
+ if (QQmlJS::AST::TypeAnnotation *annotation = irFunction->arguments.at(i).typeAnnotation.data())
+ QmlIR::Parameter::initType(&formal->type, idGenerator, annotation->type);
}
// write locals
@@ -482,8 +503,11 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
for (int i = 0; i < irFunction->locals.size(); ++i)
locals[i] = getStringId(irFunction->locals.at(i));
- // write line numbers
- memcpy(f + function->lineNumberOffset(), irFunction->lineNumberMapping.constData(), irFunction->lineNumberMapping.size()*sizeof(CompiledData::CodeOffsetToLine));
+ // write line and statement numbers
+ memcpy(f + function->lineAndStatementNumberOffset(),
+ irFunction->lineAndStatementNumberMapping.constData(),
+ irFunction->lineAndStatementNumberMapping.size()
+ * sizeof(CompiledData::CodeOffsetToLineAndStatement));
quint32_le *labels = (quint32_le *)(f + function->labelInfosOffset());
for (unsigned u : irFunction->labelInfo) {
@@ -524,25 +548,26 @@ void QV4::Compiler::JSUnitGenerator::writeClass(char *b, const QV4::Compiler::Cl
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
if (showCode) {
- qDebug() << "=== Class " << stringForIndex(cls->nameIndex) << "static methods" << cls->nStaticMethods << "methods" << cls->nMethods;
+ qDebug() << "=== Class" << stringForIndex(cls->nameIndex) << "static methods"
+ << cls->nStaticMethods << "methods" << cls->nMethods;
qDebug() << " constructor:" << cls->constructorFunction;
- const char *staticString = ": static ";
for (uint i = 0; i < cls->nStaticMethods + cls->nMethods; ++i) {
- if (i == cls->nStaticMethods)
- staticString = ": ";
- const char *type;
+ QDebug output = qDebug().nospace();
+ output << " " << i << ": ";
+ if (i < cls->nStaticMethods)
+ output << "static ";
switch (cls->methodTable()[i].type) {
case CompiledData::Method::Getter:
- type = "get "; break;
+ output << "get "; break;
case CompiledData::Method::Setter:
- type = "set "; break;
+ output << "set "; break;
default:
- type = "";
-
+ break;
}
- qDebug() << " " << i << staticString << type << stringForIndex(cls->methodTable()[i].name) << cls->methodTable()[i].function;
+ output << stringForIndex(cls->methodTable()[i].name) << " "
+ << cls->methodTable()[i].function;
}
- qDebug();
+ qDebug().space();
}
}
@@ -578,7 +603,7 @@ void QV4::Compiler::JSUnitGenerator::writeBlock(char *b, QV4::Compiler::Context
{
QV4::CompiledData::Block *block = reinterpret_cast<QV4::CompiledData::Block *>(b);
- quint32 currentOffset = static_cast<quint32>(roundUpToMultipleOf(8, sizeof(*block)));
+ quint32 currentOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, sizeof(*block)));
block->sizeOfLocalTemporalDeadZone = irBlock->sizeOfLocalTemporalDeadZone;
block->nLocals = irBlock->locals.size();
@@ -630,7 +655,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.offsetToBlockTable = nextOffset;
nextOffset += unit.blockTableSize * sizeof(uint);
- unit.lookupTableSize = lookups.count();
+ unit.lookupTableSize = lookups.size();
unit.offsetToLookupTable = nextOffset;
nextOffset += unit.lookupTableSize * sizeof(CompiledData::Lookup);
@@ -641,53 +666,58 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.constantTableSize = constants.size();
// Ensure we load constants from well-aligned addresses into for example SSE registers.
- nextOffset = static_cast<quint32>(roundUpToMultipleOf(16, nextOffset));
+ nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(16, nextOffset));
unit.offsetToConstantTable = nextOffset;
nextOffset += unit.constantTableSize * sizeof(ReturnedValue);
- unit.jsClassTableSize = jsClassOffsets.count();
+ unit.jsClassTableSize = jsClassOffsets.size();
unit.offsetToJSClassTable = nextOffset;
nextOffset += unit.jsClassTableSize * sizeof(uint);
*jsClassDataOffset = nextOffset;
nextOffset += jsClassData.size();
- nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
- unit.translationTableSize = translations.count();
+ unit.translationTableSize = translations.size();
unit.offsetToTranslationTable = nextOffset;
nextOffset += unit.translationTableSize * sizeof(CompiledData::TranslationData);
+ if (unit.translationTableSize != 0) {
+ constexpr auto spaceForTranslationContextId = sizeof(quint32_le);
+ nextOffset += spaceForTranslationContextId;
+ }
- nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
const auto reserveExportTable = [&nextOffset](int count, quint32_le *tableSizePtr, quint32_le *offsetPtr) {
*tableSizePtr = count;
*offsetPtr = nextOffset;
nextOffset += count * sizeof(CompiledData::ExportEntry);
- nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
};
- reserveExportTable(module->localExportEntries.count(), &unit.localExportEntryTableSize, &unit.offsetToLocalExportEntryTable);
- reserveExportTable(module->indirectExportEntries.count(), &unit.indirectExportEntryTableSize, &unit.offsetToIndirectExportEntryTable);
- reserveExportTable(module->starExportEntries.count(), &unit.starExportEntryTableSize, &unit.offsetToStarExportEntryTable);
+ reserveExportTable(module->localExportEntries.size(), &unit.localExportEntryTableSize, &unit.offsetToLocalExportEntryTable);
+ reserveExportTable(module->indirectExportEntries.size(), &unit.indirectExportEntryTableSize, &unit.offsetToIndirectExportEntryTable);
+ reserveExportTable(module->starExportEntries.size(), &unit.starExportEntryTableSize, &unit.offsetToStarExportEntryTable);
- unit.importEntryTableSize = module->importEntries.count();
+ unit.importEntryTableSize = module->importEntries.size();
unit.offsetToImportEntryTable = nextOffset;
nextOffset += unit.importEntryTableSize * sizeof(CompiledData::ImportEntry);
- nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
- unit.moduleRequestTableSize = module->moduleRequests.count();
+ unit.moduleRequestTableSize = module->moduleRequests.size();
unit.offsetToModuleRequestTable = nextOffset;
nextOffset += unit.moduleRequestTableSize * sizeof(uint);
- nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
quint32 functionSize = 0;
for (int i = 0; i < module->functions.size(); ++i) {
Context *f = module->functions.at(i);
blockAndFunctionOffsets[i] = nextOffset;
- quint32 size = QV4::CompiledData::Function::calculateSize(f->arguments.size(), f->locals.size(), f->lineNumberMapping.size(), f->nestedContexts.size(),
- int(f->labelInfo.size()), f->code.size());
+ quint32 size = QV4::CompiledData::Function::calculateSize(
+ f->arguments.size(), f->locals.size(), f->lineAndStatementNumberMapping.size(),
+ f->nestedContexts.size(), int(f->labelInfo.size()), f->code.size());
functionSize += size - f->code.size();
nextOffset += size;
}
@@ -719,7 +749,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
if (option == GenerateWithStringTable) {
unit.stringTableSize = stringTable.stringCount();
- nextOffset = static_cast<quint32>(roundUpToMultipleOf(8, nextOffset));
+ nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
unit.offsetToStringTable = nextOffset;
nextOffset += stringTable.sizeOfTableAndData();
} else {
@@ -738,7 +768,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
if (showStats) {
qDebug() << "Generated JS unit that is" << unit.unitSize << "bytes contains:";
qDebug() << " " << functionSize << "bytes for non-code function data for" << unit.functionTableSize << "functions";
- qDebug() << " " << translations.count() * sizeof(CompiledData::TranslationData) << "bytes for" << translations.count() << "translations";
+ qDebug() << " " << translations.size() * sizeof(CompiledData::TranslationData) << "bytes for" << translations.size() << "translations";
}
return unit;
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 4f3c718175..bf2f5c8167 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4COMPILER_P_H
#define QV4COMPILER_P_H
@@ -78,7 +42,7 @@ struct Module;
struct Class;
struct TemplateObject;
-struct Q_QMLCOMPILER_PRIVATE_EXPORT StringTableGenerator {
+struct Q_QML_COMPILER_EXPORT StringTableGenerator {
StringTableGenerator();
int registerString(const QString &str);
@@ -105,7 +69,9 @@ private:
bool frozen = false;
};
-struct Q_QMLCOMPILER_PRIVATE_EXPORT JSUnitGenerator {
+struct Q_QML_COMPILER_EXPORT JSUnitGenerator {
+ enum LookupMode { LookupForStorage, LookupForCall };
+
static void generateUnitChecksum(CompiledData::Unit *unit);
struct MemberInfo {
@@ -119,19 +85,23 @@ struct Q_QMLCOMPILER_PRIVATE_EXPORT JSUnitGenerator {
int getStringId(const QString &string) const { return stringTable.getStringId(string); }
QString stringForIndex(int index) const { return stringTable.stringForIndex(index); }
- int registerGetterLookup(const QString &name);
- int registerGetterLookup(int nameIndex);
+ int registerGetterLookup(const QString &name, LookupMode mode);
+ int registerGetterLookup(int nameIndex, LookupMode mode);
int registerSetterLookup(const QString &name);
int registerSetterLookup(int nameIndex);
- int registerGlobalGetterLookup(int nameIndex);
- int registerQmlContextPropertyGetterLookup(int nameIndex);
+ int registerGlobalGetterLookup(int nameIndex, LookupMode mode);
+ int registerQmlContextPropertyGetterLookup(int nameIndex, LookupMode mode);
+ int lookupNameIndex(int index) const { return lookups[index].nameIndex(); }
+ QString lookupName(int index) const { return stringForIndex(lookupNameIndex(index)); }
int registerRegExp(QQmlJS::AST::RegExpLiteral *regexp);
int registerConstant(ReturnedValue v);
- ReturnedValue constant(int idx);
+ ReturnedValue constant(int idx) const;
int registerJSClass(const QStringList &members);
+ int jsClassSize(int jsClassId) const;
+ QString jsClassMember(int jsClassId, int member) const;
int registerTranslation(const CompiledData::TranslationData &translation);
@@ -148,6 +118,7 @@ struct Q_QMLCOMPILER_PRIVATE_EXPORT JSUnitGenerator {
StringTableGenerator stringTable;
QString codeGeneratorName;
+
private:
CompiledData::Unit generateHeader(GeneratorOption option, quint32_le *functionOffsets, uint *jsClassDataOffset);
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index 88837b0feb..499c804b79 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -1,50 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qv4codegen_p.h"
#include "qv4compilercontext_p.h"
-#include "qv4compilercontrolflow_p.h"
#include "qv4bytecodegenerator_p.h"
+#include <QtQml/private/qv4calldata_p.h>
QT_USE_NAMESPACE
using namespace QV4;
using namespace QV4::Compiler;
using namespace QQmlJS::AST;
+using namespace QQmlJS;
QT_BEGIN_NAMESPACE
@@ -79,14 +45,16 @@ bool Context::Member::requiresTDZCheck(const SourceLocation &accessLocation, boo
if (accessAcrossContextBoundaries)
return true;
- if (!accessLocation.isValid() || !endOfInitializerLocation.isValid())
+ if (!accessLocation.isValid() || !declarationLocation.isValid())
return true;
- return accessLocation.begin() < endOfInitializerLocation.end();
+ return accessLocation.begin() < declarationLocation.end();
}
-bool Context::addLocalVar(const QString &name, Context::MemberType type, VariableScope scope, FunctionExpression *function,
- const QQmlJS::AST::SourceLocation &endOfInitializer)
+bool Context::addLocalVar(
+ const QString &name, Context::MemberType type, VariableScope scope,
+ FunctionExpression *function, const QQmlJS::SourceLocation &declarationLocation,
+ bool isInjected)
{
// ### can this happen?
if (name.isEmpty())
@@ -111,18 +79,19 @@ bool Context::addLocalVar(const QString &name, Context::MemberType type, Variabl
// hoist var declarations to the function level
if (contextType == ContextType::Block && (scope == VariableScope::Var && type != MemberType::FunctionDefinition))
- return parent->addLocalVar(name, type, scope, function, endOfInitializer);
+ return parent->addLocalVar(name, type, scope, function, declarationLocation);
Member m;
m.type = type;
m.function = function;
m.scope = scope;
- m.endOfInitializerLocation = endOfInitializer;
+ m.declarationLocation = declarationLocation;
+ m.isInjected = isInjected;
members.insert(name, m);
return true;
}
-Context::ResolvedName Context::resolveName(const QString &name, const QQmlJS::AST::SourceLocation &accessLocation)
+Context::ResolvedName Context::resolveName(const QString &name, const QQmlJS::SourceLocation &accessLocation)
{
int scope = 0;
Context *c = this;
@@ -142,12 +111,14 @@ Context::ResolvedName Context::resolveName(const QString &name, const QQmlJS::AS
result.scope = scope;
result.index = m.index;
result.isConst = (m.scope == VariableScope::Const);
- result.requiresTDZCheck = m.requiresTDZCheck(accessLocation, c != this);
+ result.requiresTDZCheck = m.requiresTDZCheck(accessLocation, c != this) || c->isCaseBlock();
if (c->isStrict && (name == QLatin1String("arguments") || name == QLatin1String("eval")))
result.isArgOrEval = true;
+ result.declarationLocation = m.declarationLocation;
+ result.isInjected = m.isInjected;
return result;
}
- const int argIdx = c->findArgument(name);
+ const int argIdx = c->findArgument(name, &result.isInjected);
if (argIdx != -1) {
if (c->argumentsCanEscape) {
result.index = argIdx + c->locals.size();
@@ -173,8 +144,11 @@ Context::ResolvedName Context::resolveName(const QString &name, const QQmlJS::AS
c = c->parent;
}
- if (c && c->contextType == ContextType::ESModule) {
- for (int i = 0; i < c->importEntries.count(); ++i) {
+ if (!c)
+ return result;
+
+ if (c->contextType == ContextType::ESModule) {
+ for (int i = 0; i < c->importEntries.size(); ++i) {
if (c->importEntries.at(i).localName == name) {
result.index = i;
result.type = ResolvedName::Import;
@@ -207,7 +181,7 @@ void Context::emitBlockHeader(Codegen *codegen)
if (requiresExecutionContext) {
if (blockIndex < 0) {
codegen->module()->blocks.append(this);
- blockIndex = codegen->module()->blocks.count() - 1;
+ blockIndex = codegen->module()->blocks.size() - 1;
}
if (contextType == ContextType::Global) {
@@ -299,7 +273,7 @@ void Context::emitBlockHeader(Codegen *codegen)
codegen->referenceForName(QStringLiteral("arguments"), false).storeConsumeAccumulator();
}
- for (const Context::Member &member : qAsConst(members)) {
+ for (const Context::Member &member : std::as_const(members)) {
if (member.function) {
const int function = codegen->defineFunction(member.function->name.toString(), member.function, member.function->formals, member.function->body);
codegen->loadClosure(function);
@@ -387,8 +361,8 @@ void Context::setupFunctionIndices(Moth::BytecodeGenerator *bytecodeGenerator)
break;
}
- sizeOfLocalTemporalDeadZone = localsInTDZ.count();
- for (auto &member: qAsConst(localsInTDZ)) {
+ sizeOfLocalTemporalDeadZone = localsInTDZ.size();
+ for (auto &member: std::as_const(localsInTDZ)) {
member->index = locals.size();
locals.append(member.key());
}
@@ -402,9 +376,9 @@ void Context::setupFunctionIndices(Moth::BytecodeGenerator *bytecodeGenerator)
}
}
- sizeOfRegisterTemporalDeadZone = registersInTDZ.count();
+ sizeOfRegisterTemporalDeadZone = registersInTDZ.size();
firstTemporalDeadZoneRegister = bytecodeGenerator->currentRegister();
- for (auto &member: qAsConst(registersInTDZ))
+ for (auto &member: std::as_const(registersInTDZ))
member->index = bytecodeGenerator->newRegister();
nRegisters = bytecodeGenerator->currentRegister() - registerOffset;
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index 8c124ac409..ceb5d00a0b 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4COMPILERCONTEXT_P_H
#define QV4COMPILERCONTEXT_P_H
@@ -56,6 +20,11 @@
#include <QtCore/QDateTime>
#include <QtCore/QStack>
#include <QtCore/QHash>
+#include <QtCore/QMap>
+#include <QtCore/QSet>
+#include <QtCore/QVarLengthArray>
+
+#include <memory>
QT_BEGIN_NAMESPACE
@@ -177,16 +146,27 @@ struct Context {
FunctionDefinition
};
+ struct SourceLocationTable
+ {
+ struct Entry
+ {
+ quint32 offset;
+ QQmlJS::SourceLocation location;
+ };
+ QVector<Entry> entries;
+ };
+
struct Member {
MemberType type = UndefinedMember;
int index = -1;
QQmlJS::AST::VariableScope scope = QQmlJS::AST::VariableScope::Var;
mutable bool canEscape = false;
+ bool isInjected = false;
QQmlJS::AST::FunctionExpression *function = nullptr;
- QQmlJS::AST::SourceLocation endOfInitializerLocation;
+ QQmlJS::SourceLocation declarationLocation;
bool isLexicallyScoped() const { return this->scope != QQmlJS::AST::VariableScope::Var; }
- bool requiresTDZCheck(const QQmlJS::AST::SourceLocation &accessLocation, bool accessAcrossContextBoundaries) const;
+ bool requiresTDZCheck(const QQmlJS::SourceLocation &accessLocation, bool accessAcrossContextBoundaries) const;
};
typedef QMap<QString, Member> MemberMap;
@@ -194,7 +174,7 @@ struct Context {
QSet<QString> usedVariables;
QQmlJS::AST::FormalParameterList *formals = nullptr;
QQmlJS::AST::BoundNames arguments;
- QString returnType;
+ QQmlJS::AST::Type *returnType = nullptr;
QStringList locals;
QStringList moduleRequests;
QVector<ImportEntry> importEntries;
@@ -204,7 +184,8 @@ struct Context {
ControlFlow *controlFlow = nullptr;
QByteArray code;
- QVector<CompiledData::CodeOffsetToLine> lineNumberMapping;
+ QVector<CompiledData::CodeOffsetToLineAndStatement> lineAndStatementNumberMapping;
+ std::unique_ptr<SourceLocationTable> sourceLocationTable;
std::vector<unsigned> labelInfo;
int nRegisters = 0;
@@ -227,7 +208,7 @@ struct Context {
bool isWithBlock = false;
bool isCatchBlock = false;
QString caughtVariable;
- QQmlJS::AST::SourceLocation lastBlockInitializerLocation;
+ QQmlJS::SourceLocation lastBlockInitializerLocation;
enum UsesArgumentsObject {
ArgumentsObjectUnknown,
@@ -289,12 +270,20 @@ struct Context {
isStrict = true;
}
- int findArgument(const QString &name) const
+ bool hasArgument(const QString &name) const
+ {
+ return arguments.contains(name);
+ }
+
+ int findArgument(const QString &name, bool *isInjected) const
{
// search backwards to handle duplicate argument names correctly
for (int i = arguments.size() - 1; i >= 0; --i) {
- if (arguments.at(i).id == name)
+ const auto &arg = arguments.at(i);
+ if (arg.id == name) {
+ *isInjected = arg.isInjected();
return i;
+ }
}
return -1;
}
@@ -330,8 +319,11 @@ struct Context {
usedVariables.insert(name);
}
- bool addLocalVar(const QString &name, MemberType contextType, QQmlJS::AST::VariableScope scope, QQmlJS::AST::FunctionExpression *function = nullptr,
- const QQmlJS::AST::SourceLocation &endOfInitializer = QQmlJS::AST::SourceLocation());
+ bool addLocalVar(
+ const QString &name, MemberType contextType, QQmlJS::AST::VariableScope scope,
+ QQmlJS::AST::FunctionExpression *function = nullptr,
+ const QQmlJS::SourceLocation &declarationLocation = QQmlJS::SourceLocation(),
+ bool isInjected = false);
struct ResolvedName {
enum Type {
@@ -346,12 +338,13 @@ struct Context {
bool isArgOrEval = false;
bool isConst = false;
bool requiresTDZCheck = false;
+ bool isInjected = false;
int scope = -1;
int index = -1;
- QQmlJS::AST::SourceLocation endOfDeclarationLocation;
+ QQmlJS::SourceLocation declarationLocation;
bool isValid() const { return type != Unresolved; }
};
- ResolvedName resolveName(const QString &name, const QQmlJS::AST::SourceLocation &accessLocation);
+ ResolvedName resolveName(const QString &name, const QQmlJS::SourceLocation &accessLocation);
void emitBlockHeader(Compiler::Codegen *codegen);
void emitBlockFooter(Compiler::Codegen *codegen);
@@ -367,6 +360,11 @@ struct Context {
return parent->canHaveTailCalls();
return false;
}
+
+ bool isCaseBlock() const
+ {
+ return contextType == ContextType::Block && name == u"%CaseBlock";
+ }
};
diff --git a/src/qml/compiler/qv4compilercontrolflow_p.h b/src/qml/compiler/qv4compilercontrolflow_p.h
index 5623473726..b190b77410 100644
--- a/src/qml/compiler/qv4compilercontrolflow_p.h
+++ b/src/qml/compiler/qv4compilercontrolflow_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4COMPILERCONTROLFLOW_P_H
#define QV4COMPILERCONTROLFLOW_P_H
@@ -203,8 +167,8 @@ struct ControlFlowUnwindCleanup : public ControlFlowUnwind
~ControlFlowUnwindCleanup() {
if (cleanup) {
unwindLabel.link();
- generator()->setUnwindHandler(parentUnwindHandler());
cleanup();
+ generator()->setUnwindHandler(parentUnwindHandler());
emitUnwindHandler();
}
}
@@ -374,12 +338,17 @@ struct ControlFlowFinally : public ControlFlowUnwind
QQmlJS::AST::Finally *finally;
bool insideFinally = false;
- ControlFlowFinally(Codegen *cg, QQmlJS::AST::Finally *finally)
+ ControlFlowFinally(Codegen *cg, QQmlJS::AST::Finally *finally, bool hasCatchBlock)
: ControlFlowUnwind(cg, Finally), finally(finally)
{
Q_ASSERT(finally != nullptr);
setupUnwindHandler();
- generator()->setUnwindHandler(&unwindLabel);
+
+ // No need to set the handler for the finally now if there is a catch block.
+ // In that case, a handler for the latter will be set immediately after this.
+ if (!hasCatchBlock) {
+ generator()->setUnwindHandler(&unwindLabel);
+ }
}
virtual bool requiresUnwind() override {
diff --git a/src/qml/compiler/qv4compilerglobal_p.h b/src/qml/compiler/qv4compilerglobal_p.h
index 3478074827..c997e33093 100644
--- a/src/qml/compiler/qv4compilerglobal_p.h
+++ b/src/qml/compiler/qv4compilerglobal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4COMPILERGLOBAL_H
#define QV4COMPILERGLOBAL_H
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp
index ab0ebf3d4b..f667548878 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4compilerscanfunctions_p.h"
@@ -55,12 +19,9 @@ using namespace QV4::Compiler;
using namespace QQmlJS;
using namespace QQmlJS::AST;
-static CompiledData::Location location(const QQmlJS::AST::SourceLocation &astLocation)
+static CompiledData::Location location(const QQmlJS::SourceLocation &astLocation)
{
- CompiledData::Location target;
- target.line = astLocation.startLine;
- target.column = astLocation.startColumn;
- return target;
+ return CompiledData::Location(astLocation.startLine, astLocation.startColumn);
}
@@ -107,6 +68,7 @@ void ScanFunctions::leaveEnvironment()
void ScanFunctions::checkDirectivePrologue(StatementList *ast)
{
+ Q_ASSERT(_context);
for (StatementList *it = ast; it; it = it->next) {
if (ExpressionStatement *expr = cast<ExpressionStatement *>(it->statement)) {
if (StringLiteral *strLit = cast<StringLiteral *>(expr->expression)) {
@@ -115,7 +77,7 @@ void ScanFunctions::checkDirectivePrologue(StatementList *ast)
// allowed.
if (strLit->literalToken.length < 2)
continue;
- QStringRef str = _sourceCode.midRef(strLit->literalToken.offset + 1, strLit->literalToken.length - 2);
+ QStringView str = QStringView{_sourceCode}.mid(strLit->literalToken.offset + 1, strLit->literalToken.length - 2);
if (str == QLatin1String("use strict")) {
_context->isStrict = true;
} else {
@@ -129,8 +91,9 @@ void ScanFunctions::checkDirectivePrologue(StatementList *ast)
}
}
-void ScanFunctions::checkName(const QStringRef &name, const SourceLocation &loc)
+void ScanFunctions::checkName(QStringView name, const QQmlJS::SourceLocation &loc)
{
+ Q_ASSERT(_context);
if (_context->isStrict) {
if (name == QLatin1String("implements")
|| name == QLatin1String("interface")
@@ -161,6 +124,7 @@ void ScanFunctions::endVisit(Program *)
bool ScanFunctions::visit(ESModule *ast)
{
enterEnvironment(ast, defaultProgramType, QStringLiteral("%ModuleCode"));
+ Q_ASSERT(_context);
_context->isStrict = true;
return true;
}
@@ -172,6 +136,7 @@ void ScanFunctions::endVisit(ESModule *)
bool ScanFunctions::visit(ExportDeclaration *declaration)
{
+ Q_ASSERT(_context);
QString module;
if (declaration->fromClause) {
module = declaration->fromClause->moduleSpecifier.toString();
@@ -181,7 +146,9 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
QString localNameForDefaultExport = QStringLiteral("*default*");
- if (declaration->exportAll) {
+ if (declaration->exportsAll()) {
+ Q_ASSERT_X(declaration->fromClause, "ScanFunctions",
+ "ExportDeclaration with exportAll always have a fromClause");
Compiler::ExportEntry entry;
entry.moduleRequest = declaration->fromClause->moduleSpecifier.toString();
entry.importName = QStringLiteral("*");
@@ -262,6 +229,7 @@ bool ScanFunctions::visit(ExportDeclaration *declaration)
bool ScanFunctions::visit(ImportDeclaration *declaration)
{
+ Q_ASSERT(_context);
QString module;
if (declaration->fromClause) {
module = declaration->fromClause->moduleSpecifier.toString();
@@ -310,6 +278,7 @@ bool ScanFunctions::visit(ImportDeclaration *declaration)
bool ScanFunctions::visit(CallExpression *ast)
{
+ Q_ASSERT(_context);
if (!_context->hasDirectEval) {
if (IdentifierExpression *id = cast<IdentifierExpression *>(ast->base)) {
if (id->name == QLatin1String("eval")) {
@@ -324,20 +293,25 @@ bool ScanFunctions::visit(CallExpression *ast)
bool ScanFunctions::visit(PatternElement *ast)
{
+ Q_ASSERT(_context);
if (!ast->isVariableDeclaration())
return true;
BoundNames names;
ast->boundNames(&names);
- QQmlJS::AST::SourceLocation lastInitializerLocation = ast->lastSourceLocation();
- if (_context->lastBlockInitializerLocation.isValid())
- lastInitializerLocation = _context->lastBlockInitializerLocation;
+ QQmlJS::SourceLocation declarationLocation = ast->firstSourceLocation();
+ if (_context->lastBlockInitializerLocation.isValid()) {
+ declarationLocation.length = _context->lastBlockInitializerLocation.end()
+ - declarationLocation.offset;
+ } else {
+ declarationLocation.length = ast->lastSourceLocation().end() - declarationLocation.offset;
+ }
- for (const auto &name : qAsConst(names)) {
+ for (const auto &name : std::as_const(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.id), ast->identifierToken);
+ checkName(QStringView(name.id), ast->identifierToken);
if (name.id == QLatin1String("arguments"))
_context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
if (ast->scope == VariableScope::Const && !ast->initializer && !ast->isForDeclaration && !ast->destructuringPattern()) {
@@ -345,7 +319,7 @@ bool ScanFunctions::visit(PatternElement *ast)
return false;
}
if (!_context->addLocalVar(name.id, ast->initializer ? Context::VariableDefinition : Context::VariableDeclaration, ast->scope,
- /*function*/nullptr, lastInitializerLocation)) {
+ /*function*/nullptr, declarationLocation)) {
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name.id));
return false;
}
@@ -355,6 +329,7 @@ bool ScanFunctions::visit(PatternElement *ast)
bool ScanFunctions::visit(IdentifierExpression *ast)
{
+ Q_ASSERT(_context);
checkName(ast->name, ast->identifierToken);
if (_context->usesArgumentsObject == Context::ArgumentsObjectUnknown && ast->name == QLatin1String("arguments"))
_context->usesArgumentsObject = Context::ArgumentsObjectUsed;
@@ -368,15 +343,18 @@ bool ScanFunctions::visit(ExpressionStatement *ast)
if (!_allowFuncDecls)
_cg->throwSyntaxError(expr->functionToken, QStringLiteral("conditional function or closure declaration"));
- if (!enterFunction(expr, /*enterName*/ true))
+ if (!enterFunction(expr, expr->identifierToken.length > 0
+ ? FunctionNameContext::Inner
+ : FunctionNameContext::None)) {
return false;
+ }
Node::accept(expr->formals, this);
Node::accept(expr->body, this);
leaveEnvironment();
return false;
} else {
SourceLocation firstToken = ast->firstSourceLocation();
- if (_sourceCode.midRef(firstToken.offset, firstToken.length) == QLatin1String("function")) {
+ if (QStringView{_sourceCode}.mid(firstToken.offset, firstToken.length) == QLatin1String("function")) {
_cg->throwSyntaxError(firstToken, QStringLiteral("unexpected token"));
}
}
@@ -385,12 +363,15 @@ bool ScanFunctions::visit(ExpressionStatement *ast)
bool ScanFunctions::visit(FunctionExpression *ast)
{
- return enterFunction(ast, /*enterName*/ false);
+ return enterFunction(ast, ast->identifierToken.length > 0
+ ? FunctionNameContext::Inner
+ : FunctionNameContext::None);
}
bool ScanFunctions::visit(ClassExpression *ast)
{
enterEnvironment(ast, ContextType::Block, QStringLiteral("%Class"));
+ Q_ASSERT(_context);
_context->isStrict = true;
_context->hasNestedFunctions = true;
if (!ast->name.isEmpty())
@@ -405,6 +386,7 @@ void ScanFunctions::endVisit(ClassExpression *)
bool ScanFunctions::visit(ClassDeclaration *ast)
{
+ Q_ASSERT(_context);
if (!ast->name.isEmpty())
_context->addLocalVar(ast->name.toString(), Context::VariableDeclaration, AST::VariableScope::Let);
@@ -434,9 +416,10 @@ bool ScanFunctions::visit(TemplateLiteral *ast)
bool ScanFunctions::visit(SuperLiteral *)
{
+ Q_ASSERT(_context);
Context *c = _context;
bool needContext = false;
- while (c && (c->contextType == ContextType::Block || c->isArrowFunction)) {
+ while (c->contextType == ContextType::Block || c->isArrowFunction) {
needContext |= c->isArrowFunction;
c = c->parent;
}
@@ -455,6 +438,7 @@ bool ScanFunctions::visit(FieldMemberExpression *ast)
_cg->throwSyntaxError(ast->identifierToken, QLatin1String("Expected 'target' after 'new.'."));
return false;
}
+ Q_ASSERT(_context);
Context *c = _context;
bool needContext = false;
while (c->contextType == ContextType::Block || c->isArrowFunction) {
@@ -479,11 +463,12 @@ bool ScanFunctions::visit(ArrayPattern *ast)
return false;
}
-bool ScanFunctions::enterFunction(FunctionExpression *ast, bool enterName)
+bool ScanFunctions::enterFunction(FunctionExpression *ast, FunctionNameContext nameContext)
{
+ Q_ASSERT(_context);
if (_context->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Function name may not be eval or arguments in strict mode"));
- return enterFunction(ast, ast->name.toString(), ast->formals, ast->body, enterName);
+ return enterFunction(ast, ast->name.toString(), ast->formals, ast->body, nameContext);
}
void ScanFunctions::endVisit(FunctionExpression *)
@@ -518,7 +503,7 @@ void ScanFunctions::endVisit(PatternProperty *)
bool ScanFunctions::visit(FunctionDeclaration *ast)
{
- return enterFunction(ast, /*enterName*/ true);
+ return enterFunction(ast, FunctionNameContext::Outer);
}
void ScanFunctions::endVisit(FunctionDeclaration *)
@@ -553,10 +538,13 @@ void ScanFunctions::endVisit(ForStatement *)
leaveEnvironment();
}
-bool ScanFunctions::visit(ForEachStatement *ast) {
+bool ScanFunctions::visit(ForEachStatement *ast)
+{
enterEnvironment(ast, ContextType::Block, QStringLiteral("%Foreach"));
- if (ast->expression)
+ if (ast->expression) {
+ Q_ASSERT(_context);
_context->lastBlockInitializerLocation = ast->expression->lastSourceLocation();
+ }
Node::accept(ast->lhs, this);
Node::accept(ast->expression, this);
@@ -573,6 +561,7 @@ void ScanFunctions::endVisit(ForEachStatement *)
bool ScanFunctions::visit(ThisExpression *)
{
+ Q_ASSERT(_context);
_context->usesThis = true;
return false;
}
@@ -603,6 +592,7 @@ void ScanFunctions::endVisit(CaseBlock *)
bool ScanFunctions::visit(Catch *ast)
{
+ Q_ASSERT(_context);
TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _context->isStrict ? false : _allowFuncDecls);
enterEnvironment(ast, ContextType::Block, QStringLiteral("%CatchBlock"));
_context->isCatchBlock = true;
@@ -630,6 +620,7 @@ void ScanFunctions::endVisit(Catch *)
bool ScanFunctions::visit(WithStatement *ast)
{
+ Q_ASSERT(_context);
Node::accept(ast->expression, this);
TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _context->isStrict ? false : _allowFuncDecls);
@@ -650,7 +641,9 @@ void ScanFunctions::endVisit(WithStatement *)
leaveEnvironment();
}
-bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, StatementList *body, bool enterName)
+bool ScanFunctions::enterFunction(
+ Node *ast, const QString &name, FormalParameterList *formals, StatementList *body,
+ FunctionNameContext nameContext)
{
Context *outerContext = _context;
enterEnvironment(ast, ContextType::Function, name);
@@ -661,7 +654,7 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
if (outerContext) {
outerContext->hasNestedFunctions = true;
// The identifier of a function expression cannot be referenced from the enclosing environment.
- if (enterName) {
+ if (nameContext == FunctionNameContext::Outer) {
if (!outerContext->addLocalVar(name, Context::FunctionDefinition, VariableScope::Var, expr)) {
_cg->throwSyntaxError(ast->firstSourceLocation(), QStringLiteral("Identifier %1 has already been declared").arg(name));
return false;
@@ -672,6 +665,7 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
outerContext->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
}
+ Q_ASSERT(_context);
_context->name = name;
if (formals && formals->containsName(QStringLiteral("arguments")))
_context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
@@ -682,12 +676,14 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
_context->isGenerator = true;
if (expr->typeAnnotation)
- _context->returnType = expr->typeAnnotation->type->toString();
+ _context->returnType = expr->typeAnnotation->type;
}
- if (!enterName && (!name.isEmpty() && (!formals || !formals->containsName(name))))
+ if (nameContext == FunctionNameContext::Inner
+ && (!name.isEmpty() && (!formals || !formals->containsName(name)))) {
_context->addLocalVar(name, Context::ThisFunctionName, VariableScope::Var);
+ }
_context->formals = formals;
if (body && !_context->isStrict)
@@ -699,22 +695,24 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
const BoundNames boundNames = formals ? formals->boundNames() : BoundNames();
for (int i = 0; i < boundNames.size(); ++i) {
- const QString &arg = boundNames.at(i).id;
+ const auto &arg = boundNames.at(i);
if (_context->isStrict || !isSimpleParameterList) {
- bool duplicate = (boundNames.indexOf(arg, i + 1) != -1);
+ bool duplicate = (boundNames.indexOf(arg.id, i + 1) != -1);
if (duplicate) {
- _cg->throwSyntaxError(formals->firstSourceLocation(), QStringLiteral("Duplicate parameter name '%1' is not allowed.").arg(arg));
+ _cg->throwSyntaxError(formals->firstSourceLocation(), QStringLiteral("Duplicate parameter name '%1' is not allowed.").arg(arg.id));
return false;
}
}
if (_context->isStrict) {
- if (arg == QLatin1String("eval") || arg == QLatin1String("arguments")) {
- _cg->throwSyntaxError(formals->firstSourceLocation(), QStringLiteral("'%1' cannot be used as parameter name in strict mode").arg(arg));
+ if (arg.id == QLatin1String("eval") || arg.id == QLatin1String("arguments")) {
+ _cg->throwSyntaxError(formals->firstSourceLocation(), QStringLiteral("'%1' cannot be used as parameter name in strict mode").arg(arg.id));
return false;
}
}
- if (!_context->arguments.contains(arg))
- _context->addLocalVar(arg, Context::VariableDefinition, VariableScope::Var);
+ if (!_context->arguments.contains(arg.id)) {
+ _context->addLocalVar(arg.id, Context::VariableDefinition, VariableScope::Var, nullptr,
+ QQmlJS::SourceLocation(), arg.isInjected());
+ }
}
return true;
@@ -724,7 +722,7 @@ void ScanFunctions::calcEscapingVariables()
{
Module *m = _cg->_module;
- for (Context *inner : qAsConst(m->contextMap)) {
+ for (Context *inner : std::as_const(m->contextMap)) {
if (inner->usesArgumentsObject != Context::ArgumentsObjectUsed)
continue;
if (inner->contextType != ContextType::Block && !inner->isArrowFunction)
@@ -736,7 +734,7 @@ void ScanFunctions::calcEscapingVariables()
c->usesArgumentsObject = Context::ArgumentsObjectUsed;
inner->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
}
- for (Context *inner : qAsConst(m->contextMap)) {
+ for (Context *inner : std::as_const(m->contextMap)) {
if (!inner->parent || inner->usesArgumentsObject == Context::ArgumentsObjectUnknown)
inner->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
if (inner->usesArgumentsObject == Context::ArgumentsObjectUsed) {
@@ -749,7 +747,7 @@ void ScanFunctions::calcEscapingVariables()
}
}
- for (Context *c : qAsConst(m->contextMap)) {
+ for (Context *c : std::as_const(m->contextMap)) {
if (c->contextType != ContextType::ESModule)
continue;
for (const auto &entry: c->exportEntries) {
@@ -760,8 +758,8 @@ void ScanFunctions::calcEscapingVariables()
break;
}
- for (Context *inner : qAsConst(m->contextMap)) {
- for (const QString &var : qAsConst(inner->usedVariables)) {
+ for (Context *inner : std::as_const(m->contextMap)) {
+ for (const QString &var : std::as_const(inner->usedVariables)) {
Context *c = inner;
while (c) {
Context *current = c;
@@ -783,7 +781,7 @@ void ScanFunctions::calcEscapingVariables()
}
break;
}
- if (c->findArgument(var) != -1) {
+ if (c->hasArgument(var)) {
c->argumentsCanEscape = true;
c->requiresExecutionContext = true;
break;
@@ -823,7 +821,7 @@ void ScanFunctions::calcEscapingVariables()
c->innerFunctionAccessesThis |= innerFunctionAccessesThis;
}
}
- for (Context *c : qAsConst(m->contextMap)) {
+ for (Context *c : std::as_const(m->contextMap)) {
if (c->innerFunctionAccessesThis) {
// add an escaping 'this' variable
c->addLocalVar(QStringLiteral("this"), Context::VariableDefinition, VariableScope::Let);
@@ -849,7 +847,7 @@ void ScanFunctions::calcEscapingVariables()
c->requiresExecutionContext = true;
c->argumentsCanEscape = true;
} else {
- for (const auto &m : qAsConst(c->members)) {
+ for (const auto &m : std::as_const(c->members)) {
if (m.isLexicallyScoped()) {
c->requiresExecutionContext = true;
break;
@@ -864,13 +862,13 @@ void ScanFunctions::calcEscapingVariables()
mIt->canEscape = true;
}
const QLatin1String exprForOn("expression for on");
- if (c->contextType == ContextType::Binding && c->name.length() > exprForOn.size() &&
+ if (c->contextType == ContextType::Binding && c->name.size() > exprForOn.size() &&
c->name.startsWith(exprForOn) && c->name.at(exprForOn.size()).isUpper())
// we don't really need this for bindings, but we do for signal handlers, and in this case,
// we don't know if the code is a signal handler or not.
c->requiresExecutionContext = true;
if (c->allVarsEscape) {
- for (const auto &m : qAsConst(c->members))
+ for (const auto &m : std::as_const(c->members))
m.canEscape = true;
}
}
@@ -878,7 +876,7 @@ void ScanFunctions::calcEscapingVariables()
static const bool showEscapingVars = qEnvironmentVariableIsSet("QV4_SHOW_ESCAPING_VARS");
if (showEscapingVars) {
qDebug() << "==== escaping variables ====";
- for (Context *c : qAsConst(m->contextMap)) {
+ for (Context *c : std::as_const(m->contextMap)) {
qDebug() << "Context" << c << c->name << "requiresExecutionContext" << c->requiresExecutionContext << "isStrict" << c->isStrict;
qDebug() << " isArrowFunction" << c->isArrowFunction << "innerFunctionAccessesThis" << c->innerFunctionAccessesThis;
qDebug() << " parent:" << c->parent;
diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h
index 2de80eac44..db160db09d 100644
--- a/src/qml/compiler/qv4compilerscanfunctions_p.h
+++ b/src/qml/compiler/qv4compilerscanfunctions_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4COMPILERSCANFUNCTIONS_P_H
#define QV4COMPILERSCANFUNCTIONS_P_H
@@ -83,21 +47,38 @@ public:
ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType);
void operator()(QQmlJS::AST::Node *node);
+ // see comment at its call site in generateJSCodeForFunctionsAndBindings
+ // for why this function is necessary
+ void handleTopLevelFunctionFormals(QQmlJS::AST::FunctionExpression *node) {
+ if (node && node->formals)
+ node->formals->accept(this);
+ }
+
void enterGlobalEnvironment(ContextType compilationMode);
void enterEnvironment(QQmlJS::AST::Node *node, ContextType compilationMode,
const QString &name);
void leaveEnvironment();
void enterQmlFunction(QQmlJS::AST::FunctionExpression *ast)
- { enterFunction(ast, false); }
+ { enterFunction(ast, FunctionNameContext::None); }
protected:
+ // Function declarations add their name to the outer scope, but not the
+ // inner scope. Function expressions add their name to the inner scope,
+ // unless the name is actually picked from the outer scope rather than
+ // given after the function token. QML functions don't add their name
+ // anywhere because the name is already recorded in the QML element.
+ // This enum is used to control the behavior of enterFunction().
+ enum class FunctionNameContext {
+ None, Inner, Outer
+ };
+
using Visitor::visit;
using Visitor::endVisit;
void checkDirectivePrologue(QQmlJS::AST::StatementList *ast);
- void checkName(const QStringRef &name, const QQmlJS::AST::SourceLocation &loc);
+ void checkName(QStringView name, const QQmlJS::SourceLocation &loc);
bool visit(QQmlJS::AST::Program *ast) override;
void endVisit(QQmlJS::AST::Program *) override;
@@ -118,7 +99,8 @@ protected:
bool visit(QQmlJS::AST::FieldMemberExpression *) override;
bool visit(QQmlJS::AST::ArrayPattern *) override;
- bool enterFunction(QQmlJS::AST::FunctionExpression *ast, bool enterName);
+ bool enterFunction(QQmlJS::AST::FunctionExpression *ast,
+ FunctionNameContext nameContext);
void endVisit(QQmlJS::AST::FunctionExpression *) override;
@@ -161,7 +143,7 @@ protected:
protected:
bool enterFunction(QQmlJS::AST::Node *ast, const QString &name,
QQmlJS::AST::FormalParameterList *formals,
- QQmlJS::AST::StatementList *body, bool enterName);
+ QQmlJS::AST::StatementList *body, FunctionNameContext nameContext);
void calcEscapingVariables();
// fields:
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 640a908dd3..edba9d40b0 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4instr_moth_p.h"
#include <private/qv4compileddata_p.h>
@@ -84,20 +48,18 @@ static QByteArray rawBytes(const char *data, int n)
}
#define ABSOLUTE_OFFSET() \
- (code - start + offset)
+ (code + beginOffset - start + offset)
#define MOTH_BEGIN_INSTR(instr) \
{ \
INSTR_##instr(MOTH_DECODE_WITH_BASE) \
- QDebug d = qDebug(); \
- d.noquote(); \
- d.nospace(); \
if (static_cast<int>(Instr::Type::instr) >= 0x100) \
--base_ptr; \
- d << alignedLineNumber(line) << alignedNumber(codeOffset).constData() << ": " \
+ s << alignedLineNumber(line) << alignedNumber(beginOffset + codeOffset).constData() << ": " \
<< rawBytes(base_ptr, int(code - base_ptr)) << #instr << " ";
#define MOTH_END_INSTR(instr) \
+ s << "\n"; \
continue; \
}
@@ -142,19 +104,37 @@ QString dumpArguments(int argc, int argv, int nFormals)
return QStringLiteral("(") + dumpRegister(argv, nFormals) + QStringLiteral(", ") + QString::number(argc) + QStringLiteral(")");
}
-void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*startLine*/, const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping)
+QString dumpBytecode(
+ const char *code, int len, int nLocals, int nFormals, int /*startLine*/,
+ const QVector<CompiledData::CodeOffsetToLineAndStatement> &lineAndStatementNumberMapping)
{
+ return dumpBytecode(code, len, nLocals, nFormals, 0, len - 1, lineAndStatementNumberMapping);
+}
+
+QString dumpBytecode(
+ const char *code, int len, int nLocals, int nFormals, int beginOffset, int endOffset,
+ const QVector<CompiledData::CodeOffsetToLineAndStatement> &lineAndStatementNumberMapping)
+{
+ Q_ASSERT(beginOffset <= endOffset && 0 <= beginOffset && endOffset <= len);
+
MOTH_JUMP_TABLE;
- auto findLine = [](const CompiledData::CodeOffsetToLine &entry, uint offset) {
+ auto findLine = [](const CompiledData::CodeOffsetToLineAndStatement &entry, uint offset) {
return entry.codeOffset < offset;
};
+ QString output;
+ QTextStream s{ &output };
+
int lastLine = -1;
+ code += beginOffset;
const char *start = code;
- const char *end = code + len;
+ const char *end = code + (endOffset - beginOffset) + 1;
while (code < end) {
- const CompiledData::CodeOffsetToLine *codeToLine = std::lower_bound(lineNumberMapping.constBegin(), lineNumberMapping.constEnd(), static_cast<uint>(code - start) + 1, findLine) - 1;
+ const auto codeToLine = std::lower_bound(
+ lineAndStatementNumberMapping.constBegin(),
+ lineAndStatementNumberMapping.constEnd(),
+ static_cast<uint>(code - start + beginOffset) + 1, findLine) - 1;
int line = int(codeToLine->line);
if (line != lastLine)
lastLine = line;
@@ -166,23 +146,23 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_DISPATCH()
MOTH_BEGIN_INSTR(LoadReg)
- d << dumpRegister(reg, nFormals);
+ s << dumpRegister(reg, nFormals);
MOTH_END_INSTR(LoadReg)
MOTH_BEGIN_INSTR(StoreReg)
- d << dumpRegister(reg, nFormals);
+ s << dumpRegister(reg, nFormals);
MOTH_END_INSTR(StoreReg)
MOTH_BEGIN_INSTR(MoveReg)
- d << dumpRegister(destReg, nFormals) << ", " << dumpRegister(srcReg, nFormals);
+ s << dumpRegister(srcReg, nFormals) << ", " << dumpRegister(destReg, nFormals);
MOTH_END_INSTR(MoveReg)
MOTH_BEGIN_INSTR(LoadImport)
- d << "i" << index;
+ s << "i" << index;
MOTH_END_INSTR(LoadImport)
MOTH_BEGIN_INSTR(LoadConst)
- d << "C" << index;
+ s << "C" << index;
MOTH_END_INSTR(LoadConst)
MOTH_BEGIN_INSTR(LoadNull)
@@ -201,103 +181,111 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(LoadUndefined)
MOTH_BEGIN_INSTR(LoadInt)
- d << value;
+ s << value;
MOTH_END_INSTR(LoadInt)
MOTH_BEGIN_INSTR(MoveConst)
- d << dumpRegister(destTemp, nFormals) << ", C" << constIndex;
+ s << "C" << constIndex << ", " << dumpRegister(destTemp, nFormals);
MOTH_END_INSTR(MoveConst)
MOTH_BEGIN_INSTR(LoadLocal)
if (index < nLocals)
- d << "l" << index;
+ s << "l" << index;
else
- d << "a" << (index - nLocals);
+ s << "a" << (index - nLocals);
MOTH_END_INSTR(LoadLocal)
MOTH_BEGIN_INSTR(StoreLocal)
if (index < nLocals)
- d << "l" << index;
+ s << "l" << index;
else
- d << "a" << (index - nLocals);
+ s << "a" << (index - nLocals);
MOTH_END_INSTR(StoreLocal)
MOTH_BEGIN_INSTR(LoadScopedLocal)
if (index < nLocals)
- d << "l" << index << "@" << scope;
+ s << "l" << index << "@" << scope;
else
- d << "a" << (index - nLocals) << "@" << scope;
+ s << "a" << (index - nLocals) << "@" << scope;
MOTH_END_INSTR(LoadScopedLocal)
MOTH_BEGIN_INSTR(StoreScopedLocal)
if (index < nLocals)
- d << ", " << "l" << index << "@" << scope;
+ s << ", " << "l" << index << "@" << scope;
else
- d << ", " << "a" << (index - nLocals) << "@" << scope;
+ s << ", " << "a" << (index - nLocals) << "@" << scope;
MOTH_END_INSTR(StoreScopedLocal)
MOTH_BEGIN_INSTR(LoadRuntimeString)
- d << stringId;
+ s << stringId;
MOTH_END_INSTR(LoadRuntimeString)
MOTH_BEGIN_INSTR(MoveRegExp)
- d << dumpRegister(destReg, nFormals) << ", " <<regExpId;
+ s << regExpId << ", " << dumpRegister(destReg, nFormals);
MOTH_END_INSTR(MoveRegExp)
MOTH_BEGIN_INSTR(LoadClosure)
- d << value;
+ s << value;
MOTH_END_INSTR(LoadClosure)
MOTH_BEGIN_INSTR(LoadName)
- d << name;
+ s << name;
MOTH_END_INSTR(LoadName)
MOTH_BEGIN_INSTR(LoadGlobalLookup)
- d << index;
+ s << index;
MOTH_END_INSTR(LoadGlobalLookup)
MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
- d << index;
+ s << index;
MOTH_END_INSTR(LoadQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(StoreNameSloppy)
- d << name;
+ s << name;
MOTH_END_INSTR(StoreNameSloppy)
MOTH_BEGIN_INSTR(StoreNameStrict)
- d << name;
+ s << name;
MOTH_END_INSTR(StoreNameStrict)
MOTH_BEGIN_INSTR(LoadElement)
- d << dumpRegister(base, nFormals) << "[acc]";
+ s << dumpRegister(base, nFormals) << "[acc]";
MOTH_END_INSTR(LoadElement)
MOTH_BEGIN_INSTR(StoreElement)
- d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]";
+ s << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]";
MOTH_END_INSTR(StoreElement)
MOTH_BEGIN_INSTR(LoadProperty)
- d << "acc[" << name << "]";
+ s << "acc[" << name << "]";
MOTH_END_INSTR(LoadProperty)
+ MOTH_BEGIN_INSTR(LoadOptionalProperty)
+ s << "acc[" << name << "], jump(" << ABSOLUTE_OFFSET() << ")";
+ MOTH_END_INSTR(LoadOptionalProperty)
+
MOTH_BEGIN_INSTR(GetLookup)
- d << "acc(" << index << ")";
+ s << "acc(" << index << ")";
MOTH_END_INSTR(GetLookup)
+ MOTH_BEGIN_INSTR(GetOptionalLookup)
+ s << "acc(" << index << "), jump(" << ABSOLUTE_OFFSET() << ")";
+ MOTH_END_INSTR(GetOptionalLookup)
+
MOTH_BEGIN_INSTR(StoreProperty)
- d << dumpRegister(base, nFormals) << "[" << name<< "]";
+ s << dumpRegister(base, nFormals) << "[" << name<< "]";
MOTH_END_INSTR(StoreProperty)
MOTH_BEGIN_INSTR(SetLookup)
- d << dumpRegister(base, nFormals) << "(" << index << ")";
+ s << dumpRegister(base, nFormals) << "(" << index << ")";
MOTH_END_INSTR(SetLookup)
MOTH_BEGIN_INSTR(LoadSuperProperty)
- d << dumpRegister(property, nFormals);
+ s << dumpRegister(property, nFormals);
MOTH_END_INSTR(LoadSuperProperty)
MOTH_BEGIN_INSTR(StoreSuperProperty)
- d << dumpRegister(property, nFormals);
+ s << dumpRegister(property, nFormals);
MOTH_END_INSTR(StoreSuperProperty)
MOTH_BEGIN_INSTR(Yield)
@@ -307,78 +295,73 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(YieldStar)
MOTH_BEGIN_INSTR(Resume)
- d << ABSOLUTE_OFFSET();
+ s << ABSOLUTE_OFFSET();
MOTH_END_INSTR(Resume)
MOTH_BEGIN_INSTR(CallValue)
- d << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals);
+ s << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallValue)
MOTH_BEGIN_INSTR(CallWithReceiver)
- d << dumpRegister(name, nFormals) << dumpRegister(thisObject, nFormals)
+ s << dumpRegister(name, nFormals) << dumpRegister(thisObject, nFormals)
<< dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallWithReceiver)
MOTH_BEGIN_INSTR(CallProperty)
- d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals)
+ s << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals)
;
MOTH_END_INSTR(CallProperty)
MOTH_BEGIN_INSTR(CallPropertyLookup)
- d << dumpRegister(base, nFormals) << "." << lookupIndex
+ s << dumpRegister(base, nFormals) << "." << lookupIndex
<< dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallPropertyLookup)
- MOTH_BEGIN_INSTR(CallElement)
- d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]"
- << dumpArguments(argc, argv, nFormals);
- MOTH_END_INSTR(CallElement)
-
MOTH_BEGIN_INSTR(CallName)
- d << name << dumpArguments(argc, argv, nFormals);
+ s << name << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallName)
MOTH_BEGIN_INSTR(CallPossiblyDirectEval)
- d << dumpArguments(argc, argv, nFormals);
+ s << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallPossiblyDirectEval)
MOTH_BEGIN_INSTR(CallGlobalLookup)
- d << index << dumpArguments(argc, argv, nFormals);
+ s << index << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallGlobalLookup)
MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
- d << index << dumpArguments(argc, argv, nFormals);
+ s << index << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(CallWithSpread)
- d << "new " << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals)
+ s << "new " << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals)
<< dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallWithSpread)
MOTH_BEGIN_INSTR(Construct)
- d << "new " << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
+ s << "new " << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(Construct)
MOTH_BEGIN_INSTR(ConstructWithSpread)
- d << "new " << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
+ s << "new " << dumpRegister(func, nFormals) << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(ConstructWithSpread)
MOTH_BEGIN_INSTR(SetUnwindHandler)
if (offset)
- d << ABSOLUTE_OFFSET();
+ s << ABSOLUTE_OFFSET();
else
- d << "<null>";
+ s << "<null>";
MOTH_END_INSTR(SetUnwindHandler)
MOTH_BEGIN_INSTR(UnwindDispatch)
MOTH_END_INSTR(UnwindDispatch)
MOTH_BEGIN_INSTR(UnwindToLabel)
- d << "(" << level << ") " << ABSOLUTE_OFFSET();
+ s << "(" << level << ") " << ABSOLUTE_OFFSET();
MOTH_END_INSTR(UnwindToLabel)
MOTH_BEGIN_INSTR(DeadTemporalZoneCheck)
- d << name;
+ s << name;
MOTH_END_INSTR(DeadTemporalZoneCheck)
MOTH_BEGIN_INSTR(ThrowException)
@@ -394,21 +377,21 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(CreateCallContext)
MOTH_BEGIN_INSTR(PushCatchContext)
- d << index << ", " << name;
+ s << index << ", " << name;
MOTH_END_INSTR(PushCatchContext)
MOTH_BEGIN_INSTR(PushWithContext)
MOTH_END_INSTR(PushWithContext)
MOTH_BEGIN_INSTR(PushBlockContext)
- d << index;
+ s << index;
MOTH_END_INSTR(PushBlockContext)
MOTH_BEGIN_INSTR(CloneBlockContext)
MOTH_END_INSTR(CloneBlockContext)
MOTH_BEGIN_INSTR(PushScriptContext)
- d << index;
+ s << index;
MOTH_END_INSTR(PushScriptContext)
MOTH_BEGIN_INSTR(PopScriptContext)
@@ -418,55 +401,55 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(PopContext)
MOTH_BEGIN_INSTR(GetIterator)
- d << iterator;
+ s << iterator;
MOTH_END_INSTR(GetIterator)
MOTH_BEGIN_INSTR(IteratorNext)
- d << dumpRegister(value, nFormals) << ", " << dumpRegister(done, nFormals);
+ s << dumpRegister(value, nFormals) << ", " << ABSOLUTE_OFFSET();
MOTH_END_INSTR(IteratorNext)
MOTH_BEGIN_INSTR(IteratorNextForYieldStar)
- d << dumpRegister(iterator, nFormals) << ", " << dumpRegister(object, nFormals);
+ s << dumpRegister(iterator, nFormals) << ", " << dumpRegister(object, nFormals)
+ << ABSOLUTE_OFFSET();
MOTH_END_INSTR(IteratorNextForYieldStar)
MOTH_BEGIN_INSTR(IteratorClose)
- d << dumpRegister(done, nFormals);
MOTH_END_INSTR(IteratorClose)
MOTH_BEGIN_INSTR(DestructureRestElement)
MOTH_END_INSTR(DestructureRestElement)
MOTH_BEGIN_INSTR(DeleteProperty)
- d << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]";
+ s << dumpRegister(base, nFormals) << "[" << dumpRegister(index, nFormals) << "]";
MOTH_END_INSTR(DeleteProperty)
MOTH_BEGIN_INSTR(DeleteName)
- d << name;
+ s << name;
MOTH_END_INSTR(DeleteName)
MOTH_BEGIN_INSTR(TypeofName)
- d << name;
+ s << name;
MOTH_END_INSTR(TypeofName)
MOTH_BEGIN_INSTR(TypeofValue)
MOTH_END_INSTR(TypeofValue)
MOTH_BEGIN_INSTR(DeclareVar)
- d << isDeletable << ", " << varName;
+ s << isDeletable << ", " << varName;
MOTH_END_INSTR(DeclareVar)
MOTH_BEGIN_INSTR(DefineArray)
- d << dumpRegister(args, nFormals) << ", " << argc;
+ s << dumpRegister(args, nFormals) << ", " << argc;
MOTH_END_INSTR(DefineArray)
MOTH_BEGIN_INSTR(DefineObjectLiteral)
- d << internalClassId
+ s << internalClassId
<< ", " << argc
<< ", " << dumpRegister(args, nFormals);
MOTH_END_INSTR(DefineObjectLiteral)
MOTH_BEGIN_INSTR(CreateClass)
- d << classIndex
+ s << classIndex
<< ", " << dumpRegister(heritage, nFormals)
<< ", " << dumpRegister(computedNames, nFormals);
MOTH_END_INSTR(CreateClass)
@@ -478,7 +461,7 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(CreateUnmappedArgumentsObject)
MOTH_BEGIN_INSTR(CreateRestParameter)
- d << argIndex;
+ s << argIndex;
MOTH_END_INSTR(CreateRestParameter)
MOTH_BEGIN_INSTR(ConvertThisToObject)
@@ -491,23 +474,23 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(ToObject)
MOTH_BEGIN_INSTR(Jump)
- d << ABSOLUTE_OFFSET();
+ s << ABSOLUTE_OFFSET();
MOTH_END_INSTR(Jump)
MOTH_BEGIN_INSTR(JumpTrue)
- d << ABSOLUTE_OFFSET();
+ s << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpTrue)
MOTH_BEGIN_INSTR(JumpFalse)
- d << ABSOLUTE_OFFSET();
+ s << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpFalse)
MOTH_BEGIN_INSTR(JumpNotUndefined)
- d << ABSOLUTE_OFFSET();
+ s << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpNotUndefined)
MOTH_BEGIN_INSTR(JumpNoException)
- d << ABSOLUTE_OFFSET();
+ s << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpNoException)
MOTH_BEGIN_INSTR(CheckException)
@@ -520,43 +503,43 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(CmpNeNull)
MOTH_BEGIN_INSTR(CmpEqInt)
- d << lhs;
+ s << lhs;
MOTH_END_INSTR(CmpEq)
MOTH_BEGIN_INSTR(CmpNeInt)
- d << lhs;
+ s << lhs;
MOTH_END_INSTR(CmpNeInt)
MOTH_BEGIN_INSTR(CmpEq)
- d << dumpRegister(lhs, nFormals);
+ s << dumpRegister(lhs, nFormals);
MOTH_END_INSTR(CmpEq)
MOTH_BEGIN_INSTR(CmpNe)
- d << dumpRegister(lhs, nFormals);
+ s << dumpRegister(lhs, nFormals);
MOTH_END_INSTR(CmpNe)
MOTH_BEGIN_INSTR(CmpGt)
- d << dumpRegister(lhs, nFormals);
+ s << dumpRegister(lhs, nFormals);
MOTH_END_INSTR(CmpGt)
MOTH_BEGIN_INSTR(CmpGe)
- d << dumpRegister(lhs, nFormals);
+ s << dumpRegister(lhs, nFormals);
MOTH_END_INSTR(CmpGe)
MOTH_BEGIN_INSTR(CmpLt)
- d << dumpRegister(lhs, nFormals);
+ s << dumpRegister(lhs, nFormals);
MOTH_END_INSTR(CmpLt)
MOTH_BEGIN_INSTR(CmpLe)
- d << dumpRegister(lhs, nFormals);
+ s << dumpRegister(lhs, nFormals);
MOTH_END_INSTR(CmpLe)
MOTH_BEGIN_INSTR(CmpStrictEqual)
- d << dumpRegister(lhs, nFormals);
+ s << dumpRegister(lhs, nFormals);
MOTH_END_INSTR(CmpStrictEqual)
MOTH_BEGIN_INSTR(CmpStrictNotEqual)
- d << dumpRegister(lhs, nFormals);
+ s << dumpRegister(lhs, nFormals);
MOTH_END_INSTR(CmpStrictNotEqual)
MOTH_BEGIN_INSTR(UNot)
@@ -578,83 +561,87 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Decrement)
MOTH_BEGIN_INSTR(Add)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Add)
MOTH_BEGIN_INSTR(BitAnd)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(BitAnd)
MOTH_BEGIN_INSTR(BitOr)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(BitOr)
MOTH_BEGIN_INSTR(BitXor)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(BitXor)
MOTH_BEGIN_INSTR(UShr)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(UShr)
MOTH_BEGIN_INSTR(Shr)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Shr)
MOTH_BEGIN_INSTR(Shl)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Shl)
MOTH_BEGIN_INSTR(BitAndConst)
- d << "acc, " << rhs;
+ s << "acc, " << rhs;
MOTH_END_INSTR(BitAndConst)
MOTH_BEGIN_INSTR(BitOrConst)
- d << "acc, " << rhs;
+ s << "acc, " << rhs;
MOTH_END_INSTR(BitOr)
MOTH_BEGIN_INSTR(BitXorConst)
- d << "acc, " << rhs;
+ s << "acc, " << rhs;
MOTH_END_INSTR(BitXor)
MOTH_BEGIN_INSTR(UShrConst)
- d << "acc, " << rhs;
+ s << "acc, " << rhs;
MOTH_END_INSTR(UShrConst)
MOTH_BEGIN_INSTR(ShrConst)
- d << "acc, " << rhs;
+ s << "acc, " << rhs;
MOTH_END_INSTR(ShrConst)
MOTH_BEGIN_INSTR(ShlConst)
- d << "acc, " << rhs;
+ s << "acc, " << rhs;
MOTH_END_INSTR(ShlConst)
MOTH_BEGIN_INSTR(Exp)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Exp)
MOTH_BEGIN_INSTR(Mul)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Mul)
MOTH_BEGIN_INSTR(Div)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Div)
MOTH_BEGIN_INSTR(Mod)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Mod)
MOTH_BEGIN_INSTR(Sub)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
+ MOTH_END_INSTR(Sub)
+
+ MOTH_BEGIN_INSTR(As)
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(Sub)
MOTH_BEGIN_INSTR(CmpIn)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(CmpIn)
MOTH_BEGIN_INSTR(CmpInstanceOf)
- d << dumpRegister(lhs, nFormals) << ", acc";
+ s << dumpRegister(lhs, nFormals) << ", acc";
MOTH_END_INSTR(CmpInstanceOf)
MOTH_BEGIN_INSTR(Ret)
@@ -664,20 +651,21 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
MOTH_END_INSTR(Debug)
MOTH_BEGIN_INSTR(InitializeBlockDeadTemporalZone)
- d << dumpRegister(firstReg, nFormals) << ", " << count;
+ s << dumpRegister(firstReg, nFormals) << ", " << count;
MOTH_END_INSTR(InitializeBlockDeadTemporalZone)
MOTH_BEGIN_INSTR(ThrowOnNullOrUndefined)
MOTH_END_INSTR(ThrowOnNullOrUndefined)
MOTH_BEGIN_INSTR(GetTemplateObject)
- d << index;
+ s << index;
MOTH_END_INSTR(GetTemplateObject)
MOTH_BEGIN_INSTR(TailCall)
- d << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals) << dumpArguments(argc, argv, nFormals);
+ s << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals) << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(TailCall)
}
+ return output;
}
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index c0dd696b8a..4dde924379 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4INSTR_MOTH_P_H
#define QV4INSTR_MOTH_P_H
@@ -89,12 +53,14 @@ QT_BEGIN_NAMESPACE
#define INSTR_StoreNameSloppy(op) INSTRUCTION(op, StoreNameSloppy, 1, name)
#define INSTR_StoreNameStrict(op) INSTRUCTION(op, StoreNameStrict, 1, name)
#define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 1, name)
+#define INSTR_LoadOptionalProperty(op) INSTRUCTION(op, LoadOptionalProperty, 2, name, offset)
#define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 1, index)
+#define INSTR_GetOptionalLookup(op) INSTRUCTION(op, GetOptionalLookup, 2, index, offset)
#define INSTR_LoadIdObject(op) INSTRUCTION(op, LoadIdObject, 2, index, base)
#define INSTR_Yield(op) INSTRUCTION(op, Yield, 0)
#define INSTR_YieldStar(op) INSTRUCTION(op, YieldStar, 0)
#define INSTR_Resume(op) INSTRUCTION(op, Resume, 1, offset)
-#define INSTR_IteratorNextForYieldStar(op) INSTRUCTION(op, IteratorNextForYieldStar, 2, iterator, object)
+#define INSTR_IteratorNextForYieldStar(op) INSTRUCTION(op, IteratorNextForYieldStar, 3, iterator, object, offset)
#define INSTR_StoreProperty(op) INSTRUCTION(op, StoreProperty, 2, name, base)
#define INSTR_SetLookup(op) INSTRUCTION(op, SetLookup, 2, index, base)
#define INSTR_LoadSuperProperty(op) INSTRUCTION(op, LoadSuperProperty, 1, property)
@@ -105,7 +71,6 @@ QT_BEGIN_NAMESPACE
#define INSTR_CallWithReceiver(op) INSTRUCTION(op, CallWithReceiver, 4, name, thisObject, argc, argv)
#define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 4, name, base, argc, argv)
#define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 4, lookupIndex, base, argc, argv)
-#define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 4, base, index, argc, argv)
#define INSTR_CallName(op) INSTRUCTION(op, CallName, 3, name, argc, argv)
#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 2, argc, argv)
#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 3, index, argc, argv)
@@ -129,8 +94,8 @@ QT_BEGIN_NAMESPACE
#define INSTR_PopScriptContext(op) INSTRUCTION(op, PopScriptContext, 0)
#define INSTR_PopContext(op) INSTRUCTION(op, PopContext, 0)
#define INSTR_GetIterator(op) INSTRUCTION(op, GetIterator, 1, iterator)
-#define INSTR_IteratorNext(op) INSTRUCTION(op, IteratorNext, 2, value, done)
-#define INSTR_IteratorClose(op) INSTRUCTION(op, IteratorClose, 1, done)
+#define INSTR_IteratorNext(op) INSTRUCTION(op, IteratorNext, 2, value, offset)
+#define INSTR_IteratorClose(op) INSTRUCTION(op, IteratorClose, 0)
#define INSTR_DestructureRestElement(op) INSTRUCTION(op, DestructureRestElement, 0)
#define INSTR_DeleteProperty(op) INSTRUCTION(op, DeleteProperty, 2, base, index)
#define INSTR_DeleteName(op) INSTRUCTION(op, DeleteName, 1, name)
@@ -190,6 +155,7 @@ QT_BEGIN_NAMESPACE
#define INSTR_Div(op) INSTRUCTION(op, Div, 1, lhs)
#define INSTR_Mod(op) INSTRUCTION(op, Mod, 1, lhs)
#define INSTR_Sub(op) INSTRUCTION(op, Sub, 1, lhs)
+#define INSTR_As(op) INSTRUCTION(op, As, 1, lhs)
#define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result)
#define INSTR_InitializeBlockDeadTemporalZone(op) INSTRUCTION(op, InitializeBlockDeadTemporalZone, 2, firstReg, count)
#define INSTR_ThrowOnNullOrUndefined(op) INSTRUCTION(op, ThrowOnNullOrUndefined, 0)
@@ -229,7 +195,9 @@ QT_BEGIN_NAMESPACE
F(LoadElement) \
F(StoreElement) \
F(LoadProperty) \
+ F(LoadOptionalProperty) \
F(GetLookup) \
+ F(GetOptionalLookup) \
F(StoreProperty) \
F(SetLookup) \
F(LoadSuperProperty) \
@@ -280,11 +248,11 @@ QT_BEGIN_NAMESPACE
F(Div) \
F(Mod) \
F(Sub) \
+ F(As) \
F(CallValue) \
F(CallWithReceiver) \
F(CallProperty) \
F(CallPropertyLookup) \
- F(CallElement) \
F(CallName) \
F(CallPossiblyDirectEval) \
F(CallGlobalLookup) \
@@ -336,11 +304,7 @@ QT_BEGIN_NAMESPACE
#define MOTH_NUM_INSTRUCTIONS() (static_cast<int>(Moth::Instr::Type::Debug_Wide) + 1)
#if defined(Q_CC_GNU)
-#if defined(Q_CC_INTEL)
-// icc before version 1200 doesn't support computed goto, and at least up to version 18.0.0 the
-// current use results in an internal compiler error. We could enable this if/when it gets fixed
-// in a later version.
-# elif defined(Q_OS_WASM) && !defined(__asmjs)
+#if defined(Q_OS_WASM) && !defined(__asmjs)
// Upstream llvm does not support computed goto for the wasm target, unlike the 'fastcomp' llvm fork
// shipped with the emscripten SDK. Disable computed goto usage for non-fastcomp llvm on Wasm.
#else
@@ -348,7 +312,7 @@ QT_BEGIN_NAMESPACE
#endif
#endif
-#define MOTH_INSTR_ALIGN_MASK (Q_ALIGNOF(QV4::Moth::Instr) - 1)
+#define MOTH_INSTR_ALIGN_MASK (alignof(QV4::Moth::Instr) - 1)
#define MOTH_INSTR_ENUM(I) I, I##_Wide,
#define MOTH_INSTR_SIZE(I) (sizeof(QV4::Moth::Instr::instr_##I))
@@ -508,7 +472,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace CompiledData {
-struct CodeOffsetToLine;
+struct CodeOffsetToLineAndStatement;
}
namespace Moth {
@@ -533,11 +497,22 @@ inline bool operator!=(const StackSlot &l, const StackSlot &r) { return l.stackS
// When making changes to the instructions, make sure to bump QV4_DATA_STRUCTURE_VERSION in qv4compileddata_p.h
-void dumpBytecode(const char *bytecode, int len, int nLocals, int nFormals, int startLine = 1,
- const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping = QVector<CompiledData::CodeOffsetToLine>());
-inline void dumpBytecode(const QByteArray &bytecode, int nLocals, int nFormals, int startLine = 1,
- const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping = QVector<CompiledData::CodeOffsetToLine>()) {
- dumpBytecode(bytecode.constData(), bytecode.length(), nLocals, nFormals, startLine, lineNumberMapping);
+Q_QML_EXPORT
+QString dumpBytecode(
+ const char *bytecode, int len, int nLocals, int nFormals, int beginOffset, int endOffset,
+ const QVector<CompiledData::CodeOffsetToLineAndStatement> &lineAndStatementNumberMapping =
+ QVector<CompiledData::CodeOffsetToLineAndStatement>());
+QString dumpBytecode(
+ const char *bytecode, int len, int nLocals, int nFormals, int startLine = 1,
+ const QVector<CompiledData::CodeOffsetToLineAndStatement> &lineAndStatementNumberMapping =
+ QVector<CompiledData::CodeOffsetToLineAndStatement>());
+inline QString dumpBytecode(
+ const QByteArray &bytecode, int nLocals, int nFormals, int startLine = 1,
+ const QVector<CompiledData::CodeOffsetToLineAndStatement> &lineAndStatementNumberMapping =
+ QVector<CompiledData::CodeOffsetToLineAndStatement>())
+{
+ return dumpBytecode(bytecode.constData(), bytecode.size(), nLocals, nFormals, startLine,
+ lineAndStatementNumberMapping);
}
union Instr
diff --git a/src/qml/compiler/qv4util_p.h b/src/qml/compiler/qv4util_p.h
index bd9758c1fb..4215003e7c 100644
--- a/src/qml/compiler/qv4util_p.h
+++ b/src/qml/compiler/qv4util_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4UTIL_H
#define QV4UTIL_H
@@ -51,6 +15,7 @@
//
#include <QtCore/QBitArray>
+#include <QtCore/private/qglobal_p.h>
#include <algorithm>
#include <vector>
diff --git a/src/qml/configure.cmake b/src/qml/configure.cmake
new file mode 100644
index 0000000000..1bc647ff29
--- /dev/null
+++ b/src/qml/configure.cmake
@@ -0,0 +1,195 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+
+
+#### Inputs
+
+
+
+#### Libraries
+
+
+qt_find_package(LTTngUST PROVIDED_TARGETS LTTng::UST MODULE_NAME qml QMAKE_LIB lttng-ust)
+qt_find_package(Python REQUIRED)
+if(Python_Interpreter_FOUND)
+ # Need to make it globally available to the project
+ set(QT_INTERNAL_DECLARATIVE_PYTHON "${Python_EXECUTABLE}" CACHE STRING "" FORCE)
+endif()
+
+#### Tests
+
+# arm_thumb
+qt_config_compile_test(arm_thumb
+ LABEL "THUMB mode on ARM"
+ CODE
+"
+
+
+int main(int argc, char **argv)
+{
+ (void)argc; (void)argv;
+ /* BEGIN TEST: */
+#if defined(thumb2) || defined(__thumb2__)
+# define THUMB_OK
+#elif (defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4
+# define THUMB_OK
+#elif defined(__ARM_ARCH_ISA_THUMB) && __ARM_ARCH_ISA_THUMB == 2
+// clang 3.5 and later will set this if the core supports the Thumb-2 ISA.
+# define THUMB_OK
+#else
+# error \"fail\"
+#endif
+ /* END TEST: */
+ return 0;
+}
+")
+
+# arm_fp
+qt_config_compile_test(arm_fp
+ LABEL "Sufficiently recent FPU on ARM"
+ CODE
+"
+
+
+int main(int argc, char **argv)
+{
+ (void)argc; (void)argv;
+ /* BEGIN TEST: */
+// if !defined(__ARM_FP) we might be on MSVC or we might have a device
+// without an FPU.
+// TODO: The latter case is not supported, but the test still succeeds.
+#if defined(__ARM_FP) && (__ARM_FP <= 0x04)
+# error \"fail\"
+#endif
+ /* END TEST: */
+ return 0;
+}
+")
+
+
+
+#### Features
+
+qt_feature("qml-network" PUBLIC
+ SECTION "QML"
+ LABEL "QML network support"
+ PURPOSE "Provides network transparency."
+ CONDITION QT_FEATURE_network
+)
+
+qt_feature("qml-ssl" PUBLIC
+ SECTION "QML"
+ LABEL "QML SSL support"
+ PURPOSE "Provides ssl support in QML."
+ CONDITION QT_FEATURE_qml_network AND QT_FEATURE_ssl
+)
+
+# On arm and arm64 we need a specialization of cacheFlush() for each OS to be
+# enabled. Therefore the config white list. Finally, ios and tvos can
+# technically use the JIT but Apple does not allow it. Therefore, it's disabled
+# by default.
+qt_feature("qml-jit" PRIVATE
+ SECTION "QML"
+ LABEL "QML just-in-time compiler"
+ PURPOSE "Provides a JIT for QML and JavaScript"
+ AUTODETECT NOT IOS AND NOT TVOS
+ CONDITION ( ( TEST_architecture_arch STREQUAL i386 AND QT_FEATURE_sse2 ) OR
+ ( TEST_architecture_arch STREQUAL x86_64 AND QT_FEATURE_sse2 ) OR
+ ( TEST_architecture_arch STREQUAL arm AND TEST_arm_fp AND TEST_arm_thumb AND ( ANDROID OR LINUX OR IOS OR TVOS OR QNX ) ) OR
+ ( TEST_architecture_arch STREQUAL arm64 AND TEST_arm_fp AND ( ANDROID OR LINUX OR IOS OR TVOS OR QNX OR INTEGRITY ) ) )
+)
+# special case begin
+# When doing macOS universal builds, JIT needs to be disabled for the ARM slice.
+# Because both arm and x86_64 slices are built in one clang frontend invocation
+# we need this hack to ensure each backend invocation sees the correct value
+# of the feature definition.
+qt_extra_definition("QT_QML_JIT_SUPPORTED_IMPL" "0
+// Unset dummy value
+#undef QT_QML_JIT_SUPPORTED_IMPL
+// Compute per-arch value and save in extra define
+#if QT_CONFIG(qml_jit) && !(defined(Q_OS_MACOS) && defined(Q_PROCESSOR_ARM))
+#define QT_QML_JIT_SUPPORTED_IMPL 1
+#else
+#define QT_QML_JIT_SUPPORTED_IMPL 0
+#endif
+// Unset original feature value
+#undef QT_FEATURE_qml_jit
+// Set new value based on previous computation
+#if QT_QML_JIT_SUPPORTED_IMPL
+#define QT_FEATURE_qml_jit 1
+#else
+#define QT_FEATURE_qml_jit -1
+#endif
+" PRIVATE)
+# special case end
+qt_feature("qml-debug" PUBLIC
+ SECTION "QML"
+ LABEL "QML debugging and profiling support"
+ PURPOSE "Provides infrastructure and plugins for debugging and profiling."
+)
+qt_feature("qml-profiler" PRIVATE
+ SECTION "QML"
+ LABEL "Command line QML Profiler"
+ PURPOSE "Supports retrieving QML tracing data from an application."
+ CONDITION ( QT_FEATURE_commandlineparser ) AND ( QT_FEATURE_qml_debug ) AND ( QT_FEATURE_qml_network AND QT_FEATURE_localserver ) AND ( QT_FEATURE_xmlstreamwriter ) AND QT_FEATURE_process
+)
+qt_feature("qml-preview" PRIVATE
+ SECTION "QML"
+ LABEL "Command line QML Preview tool"
+ PURPOSE "Updates QML documents in your application live as you change them on disk"
+ CONDITION ( QT_FEATURE_commandlineparser ) AND ( QT_FEATURE_filesystemwatcher ) AND ( QT_FEATURE_qml_network AND QT_FEATURE_localserver ) AND ( QT_FEATURE_process ) AND ( QT_FEATURE_qml_debug )
+)
+qt_feature("qml-xml-http-request" PRIVATE
+ SECTION "QML"
+ LABEL "QML XML http request"
+ PURPOSE "Provides support for sending XML http requests."
+ CONDITION ( QT_FEATURE_xmlstreamreader ) AND ( QT_FEATURE_qml_network )
+)
+qt_feature("qml-locale" PRIVATE
+ SECTION "QML"
+ LABEL "QML Locale"
+ PURPOSE "Provides support for locales in QML."
+)
+qt_feature("qml-animation" PRIVATE
+ SECTION "QML"
+ LABEL "QML Animations"
+ PURPOSE "Provides support for animations and timers in QML."
+ CONDITION QT_FEATURE_animation
+)
+qt_feature("qml-worker-script" PRIVATE
+ SECTION "QML"
+ LABEL "QML WorkerScript"
+ 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
+)
+qt_feature("qml-xmllistmodel" PRIVATE
+ SECTION "QML"
+ LABEL "QML XmlListModel"
+ PURPOSE "Enable XmlListModel in QML"
+ CONDITION QT_FEATURE_qml_itemmodel AND QT_FEATURE_future
+)
+
+qt_feature("qml-python" PRIVATE
+ LABEL "python"
+ CONDITION Python_Interpreter_FOUND
+)
+qt_configure_add_summary_section(NAME "Qt QML")
+qt_configure_add_summary_entry(ARGS "qml-network")
+qt_configure_add_summary_entry(ARGS "qml-debug")
+qt_configure_add_summary_entry(ARGS "qml-jit")
+qt_configure_add_summary_entry(ARGS "qml-xml-http-request")
+qt_configure_add_summary_entry(ARGS "qml-locale")
+qt_configure_add_summary_entry(ARGS "qml-ssl")
+qt_configure_end_summary_section() # end of "Qt QML" section
+qt_configure_add_report_entry(
+ TYPE ERROR
+ MESSAGE "Python is required to build QtQml."
+ CONDITION NOT QT_FEATURE_qml_python
+)
diff --git a/src/qml/configure.json b/src/qml/configure.json
deleted file mode 100644
index 3fc1fd528b..0000000000
--- a/src/qml/configure.json
+++ /dev/null
@@ -1,204 +0,0 @@
-{
- "module": "qml",
- "depends": [
- "core-private",
- "network-private"
- ],
-
- "commandline": {
- "options": {
- "qml-network": "boolean",
- "qml-debug": "boolean"
- }
- },
-
- "tests": {
- "cxx14_make_unique": {
- "label": "C++14 make_unique()",
- "type": "compile",
- "test": {
- "include": "memory",
- "main": [
- "std::unique_ptr<int> ptr = std::make_unique<int>();"
- ],
- "qmake": "CONFIG += c++11"
- }
- },
- "pointer_32bit": {
- "label": "32bit pointers",
- "type": "compile",
- "test": {
- "main": "static_assert(sizeof(void *) == 4, \"fail\");"
- }
- },
- "pointer_64bit": {
- "label": "64bit pointers",
- "type": "compile",
- "test": {
- "main": "static_assert(sizeof(void *) == 8, \"fail\");"
- }
- },
- "arm_thumb": {
- "label": "THUMB mode on ARM",
- "type": "compile",
- "test": {
- "main": [
- "#if defined(thumb2) || defined(__thumb2__)",
- "# define THUMB_OK",
- "#elif (defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4",
- "# define THUMB_OK",
- "#elif defined(__ARM_ARCH_ISA_THUMB) && __ARM_ARCH_ISA_THUMB == 2",
- "// clang 3.5 and later will set this if the core supports the Thumb-2 ISA.",
- "# define THUMB_OK",
- "#else",
- "# error \"fail\"",
- "#endif"
- ]
- }
- },
- "arm_fp": {
- "label": "Sufficiently recent FPU on ARM",
- "type": "compile",
- "test": {
- "main": [
- "// if !defined(__ARM_FP) we might be on MSVC or we might have a device",
- "// without an FPU.",
- "// TODO: The latter case is not supported, but the test still succeeds.",
- "#if defined(__ARM_FP) && (__ARM_FP <= 0x04)",
- "# error \"fail\"",
- "#endif"
- ]
- }
- }
- },
-
- "features": {
- "cxx14_make_unique": {
- "label": "C++14 make_unique",
- "condition": "features.c++14 || tests.cxx14_make_unique",
- "output": [ "privateFeature" ]
- },
- "qml-network": {
- "label": "QML network support",
- "purpose": "Provides network transparency.",
- "section": "QML",
- "condition": "features.network",
- "output": [ "publicFeature" ]
- },
- "qml-jit": {
- "label": "QML just-in-time compiler",
- "purpose": "Provides a JIT for QML and JavaScript",
- "section": "QML",
- "condition": [
- " (arch.i386 && tests.pointer_32bit && features.sse2)
- || (arch.x86_64 && tests.pointer_64bit && features.sse2)
- || (arch.arm && tests.pointer_32bit && tests.arm_fp && tests.arm_thumb
- && (config.linux || config.ios || config.tvos || config.qnx))
- || (arch.arm64 && tests.pointer_64bit && tests.arm_fp
- && (config.linux || config.ios || config.tvos || config.qnx || config.integrity))"
- ],
- "output": [ "privateFeature" ],
- "autoDetect": "!config.ios && !config.tvos",
- "comment": "On arm and arm64 we need a specialization of cacheFlush() for each OS to be
- enabeled. Therefore the config white list.
- Also Mind that e.g. x86_32 has arch.x86_64 but 32bit pointers. Therefore
- the checks for architecture and pointer size.
- Finally, ios and tvos can technically use the JIT but Apple does not allow
- it. Therefore, it's disabled by default."
- },
- "qml-debug": {
- "label": "QML debugging and profiling support",
- "purpose": "Provides infrastructure and plugins for debugging and profiling.",
- "section": "QML",
- "output": [ "publicFeature" ]
- },
- "qml-profiler": {
- "label": "Command line QML Profiler",
- "purpose": "Supports retrieving QML tracing data from an application.",
- "section": "QML",
- "condition": [
- "features.commandlineparser",
- "features.qml-debug",
- "features.qml-network && features.localserver",
- "features.xmlstreamwriter"
- ],
- "output": [ "privateFeature" ]
- },
- "qml-preview": {
- "label": "Command line QML Preview tool",
- "purpose": "Updates QML documents in your application live as you change them on disk",
- "section": "QML",
- "condition": [
- "features.commandlineparser",
- "features.filesystemwatcher",
- "features.qml-network && features.localserver",
- "features.process",
- "features.qml-debug"
- ],
- "output": [ "privateFeature" ]
- },
- "qml-devtools": {
- "label": "QML Development Tools",
- "purpose": "Provides the QmlDevtools library and various utilities.",
- "section": "QML",
- "output": [ "privateFeature" ]
- },
- "qml-sequence-object": {
- "label": "QML sequence object",
- "purpose": "Supports mapping sequence types into QML.",
- "section": "QML",
- "output": [ "privateFeature" ]
- },
- "qml-xml-http-request": {
- "label": "QML XML http request",
- "purpose": "Provides support for sending XML http requests.",
- "section": "QML",
- "condition": [
- "features.xmlstreamreader",
- "features.qml-network"
- ],
- "output": [ "privateFeature" ]
- },
- "qml-locale": {
- "label": "QML Locale",
- "purpose": "Provides support for locales in QML.",
- "section": "QML",
- "output": [ "privateFeature" ]
- },
- "qml-animation": {
- "label": "QML Animations",
- "purpose": "Provides support for animations and timers in QML.",
- "section": "QML",
- "condition": "features.animation",
- "output": [ "privateFeature" ]
- },
- "qml-worker-script": {
- "label": "QML WorkerScript",
- "purpose": "Enables the use of threads in QML.",
- "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" ]
- }
- },
-
- "summary": [
- {
- "section": "Qt QML",
- "entries": [
- "qml-network",
- "qml-debug",
- "qml-jit",
- "qml-sequence-object",
- "qml-xml-http-request",
- "qml-locale"
- ]
- }
- ]
-}
diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri
deleted file mode 100644
index 1281886816..0000000000
--- a/src/qml/debugger/debugger.pri
+++ /dev/null
@@ -1,28 +0,0 @@
-qtConfig(qml-debug) {
- HEADERS += \
- $$PWD/qqmlabstractprofileradapter_p.h \
- $$PWD/qqmlconfigurabledebugservice_p.h \
- $$PWD/qqmldebugpluginmanager_p.h \
- $$PWD/qqmldebugservice_p.h \
- $$PWD/qqmldebugservicefactory_p.h \
- $$PWD/qqmldebugserver_p.h \
- $$PWD/qqmldebugserverconnection_p.h \
- $$PWD/qqmlprofilerdefinitions_p.h
-
- SOURCES += \
- $$PWD/qqmldebug.cpp \
- $$PWD/qqmldebugconnector.cpp \
- $$PWD/qqmldebugservice.cpp \
- $$PWD/qqmlabstractprofileradapter.cpp \
- $$PWD/qqmlprofiler.cpp \
- $$PWD/qqmldebugserviceinterfaces.cpp
-}
-
-HEADERS += \
- $$PWD/qqmldebugconnector_p.h \
- $$PWD/qqmldebugserviceinterfaces_p.h \
- $$PWD/qqmldebugstatesdelegate_p.h \
- $$PWD/qqmldebug.h \
- $$PWD/qqmlprofiler_p.h
-
-INCLUDEPATH += $$PWD
diff --git a/src/qml/debugger/qqmlabstractprofileradapter.cpp b/src/qml/debugger/qqmlabstractprofileradapter.cpp
index 68b45ec6bf..94c71a94ad 100644
--- a/src/qml/debugger/qqmlabstractprofileradapter.cpp
+++ b/src/qml/debugger/qqmlabstractprofileradapter.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlabstractprofileradapter_p.h"
diff --git a/src/qml/debugger/qqmlabstractprofileradapter_p.h b/src/qml/debugger/qqmlabstractprofileradapter_p.h
index f39f8fccd2..c95eee949f 100644
--- a/src/qml/debugger/qqmlabstractprofileradapter_p.h
+++ b/src/qml/debugger/qqmlabstractprofileradapter_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLABSTRACTPROFILERADAPTER_P_H
#define QQMLABSTRACTPROFILERADAPTER_P_H
@@ -62,7 +26,7 @@ QT_BEGIN_NAMESPACE
QT_REQUIRE_CONFIG(qml_debug);
class QQmlProfilerService;
-class Q_QML_PRIVATE_EXPORT QQmlAbstractProfilerAdapter : public QObject, public QQmlProfilerDefinitions {
+class Q_QML_EXPORT QQmlAbstractProfilerAdapter : public QObject, public QQmlProfilerDefinitions {
Q_OBJECT
public:
@@ -79,7 +43,7 @@ public:
void stopProfiling();
- void reportData() { emit dataRequested(); }
+ void reportData() { Q_EMIT dataRequested(); }
void stopWaiting() { waiting = false; }
void startWaiting() { waiting = true; }
@@ -87,9 +51,9 @@ public:
bool isRunning() const { return featuresEnabled != 0; }
quint64 features() const { return featuresEnabled; }
- void synchronize(const QElapsedTimer &t) { emit referenceTimeKnown(t); }
+ void synchronize(const QElapsedTimer &t) { Q_EMIT referenceTimeKnown(t); }
-signals:
+Q_SIGNALS:
void profilingEnabled(quint64 features);
void profilingEnabledWhileWaiting(quint64 features);
@@ -107,7 +71,7 @@ private:
quint64 featuresEnabled;
};
-class Q_QML_PRIVATE_EXPORT QQmlAbstractProfilerAdapterFactory : public QObject
+class Q_QML_EXPORT QQmlAbstractProfilerAdapterFactory : public QObject
{
Q_OBJECT
public:
diff --git a/src/qml/debugger/qqmlconfigurabledebugservice_p.h b/src/qml/debugger/qqmlconfigurabledebugservice_p.h
index 38f41047c0..ce911c5baf 100644
--- a/src/qml/debugger/qqmlconfigurabledebugservice_p.h
+++ b/src/qml/debugger/qqmlconfigurabledebugservice_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCONFIGURABLEDEBUGSEVICE_P_H
@@ -73,8 +37,8 @@ protected:
{
QMutexLocker lock(&m_configMutex);
m_waitingForConfiguration = false;
- for (QJSEngine *engine : qAsConst(m_waitingEngines))
- emit Base::attachedToEngine(engine);
+ for (QJSEngine *engine : std::as_const(m_waitingEngines))
+ Q_EMIT Base::attachedToEngine(engine);
m_waitingEngines.clear();
}
@@ -100,7 +64,7 @@ protected:
if (m_waitingForConfiguration)
m_waitingEngines.append(engine);
else
- emit Base::attachedToEngine(engine);
+ Q_EMIT Base::attachedToEngine(engine);
}
QRecursiveMutex m_configMutex;
diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp
index 6532576e03..b9d984db1d 100644
--- a/src/qml/debugger/qqmldebug.cpp
+++ b/src/qml/debugger/qqmldebug.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmldebug.h"
#include "qqmldebugconnector_p.h"
@@ -44,19 +8,35 @@
#include <private/qqmlengine_p.h>
#include <private/qv4compileddata_p.h>
+#include <atomic>
#include <cstdio>
QT_REQUIRE_CONFIG(qml_debug);
QT_BEGIN_NAMESPACE
-QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
+#if __cplusplus >= 202002L
+# define Q_ATOMIC_FLAG_INIT {}
+#else
+# define Q_ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT // deprecated in C++20
+#endif
+
+Q_CONSTINIT static std::atomic_flag s_printedWarning = Q_ATOMIC_FLAG_INIT;
+
+void QQmlDebuggingEnabler::enableDebugging(bool printWarning)
{
- if (!QQmlEnginePrivate::qml_debugging_enabled && printWarning)
+ if (printWarning && !s_printedWarning.test_and_set(std::memory_order_relaxed))
fprintf(stderr, "QML debugging is enabled. Only use this in a safe environment.\n");
- QQmlEnginePrivate::qml_debugging_enabled = true;
+ QQmlEnginePrivate::qml_debugging_enabled.store(true, std::memory_order_relaxed);
}
+#if QT_DEPRECATED_SINCE(6, 4)
+QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
+{
+ enableDebugging(printWarning);
+};
+#endif // QT_DEPRECATED_SINCE(6, 4)
+
/*!
* Retrieves the plugin keys of the debugger services provided by default. The debugger services
* enable a debug client to use a Qml/JavaScript debugger, in order to set breakpoints, pause
@@ -65,8 +45,7 @@ QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
*/
QStringList QQmlDebuggingEnabler::debuggerServices()
{
- return QStringList() << QV4DebugService::s_key << QQmlEngineDebugService::s_key
- << QDebugMessageService::s_key;
+ return {QV4DebugService::s_key, QQmlEngineDebugService::s_key, QDebugMessageService::s_key};
}
/*!
@@ -76,7 +55,7 @@ QStringList QQmlDebuggingEnabler::debuggerServices()
*/
QStringList QQmlDebuggingEnabler::inspectorServices()
{
- return QStringList() << QQmlInspectorService::s_key;
+ return {QQmlInspectorService::s_key};
}
/*!
@@ -87,8 +66,7 @@ QStringList QQmlDebuggingEnabler::inspectorServices()
*/
QStringList QQmlDebuggingEnabler::profilerServices()
{
- return QStringList() << QQmlProfilerService::s_key << QQmlEngineControlService::s_key
- << QDebugMessageService::s_key;
+ return {QQmlProfilerService::s_key, QQmlEngineControlService::s_key, QDebugMessageService::s_key};
}
/*!
@@ -99,7 +77,7 @@ QStringList QQmlDebuggingEnabler::profilerServices()
*/
QStringList QQmlDebuggingEnabler::nativeDebuggerServices()
{
- return QStringList() << QQmlNativeDebugService::s_key;
+ return {QQmlNativeDebugService::s_key};
}
/*!
@@ -197,7 +175,7 @@ quintptr Q_QML_EXPORT qtDeclarativeHookData[] = {
// TypeInformationVersion, an integral value, bumped whenever private
// object sizes or member offsets that are used in Qt Creator's
// data structure "pretty printing" change.
- 3,
+ 4,
// Version of the cache data.
QV4_DATA_STRUCTURE_VERSION
diff --git a/src/qml/debugger/qqmldebug.h b/src/qml/debugger/qqmldebug.h
index d0ceb28cdc..6cc658a3e6 100644
--- a/src/qml/debugger/qqmldebug.h
+++ b/src/qml/debugger/qqmldebug.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDEBUG_H
#define QQMLDEBUG_H
@@ -43,6 +7,7 @@
#include <QtQml/qtqmlglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
+#include <QtCore/qhash.h> // QVariantHash
QT_BEGIN_NAMESPACE
@@ -55,7 +20,13 @@ struct Q_QML_EXPORT QQmlDebuggingEnabler
WaitForClient
};
+ static void enableDebugging(bool printWarning);
+
+#if QT_DEPRECATED_SINCE(6, 4)
+ QT_DEPRECATED_VERSION_X_6_4("Use QQmlTriviallyDestructibleDebuggingEnabler instead "
+ "or just call QQmlDebuggingEnabler::enableDebugging().")
QQmlDebuggingEnabler(bool printWarning = true);
+#endif
static QStringList debuggerServices();
static QStringList inspectorServices();
@@ -72,12 +43,23 @@ struct Q_QML_EXPORT QQmlDebuggingEnabler
const QVariantHash &configuration = QVariantHash());
};
+// Unnamed namespace to signal the compiler that we
+// indeed want each TU to have its own QQmlDebuggingEnabler.
+namespace {
+struct QQmlTriviallyDestructibleDebuggingEnabler {
+ QQmlTriviallyDestructibleDebuggingEnabler(bool printWarning = true)
+ {
+ static_assert(std::is_trivially_destructible_v<QQmlTriviallyDestructibleDebuggingEnabler>);
+ QQmlDebuggingEnabler::enableDebugging(printWarning);
+ }
+};
// Execute code in constructor before first QQmlEngine is instantiated
#if defined(QT_QML_DEBUG_NO_WARNING)
-static QQmlDebuggingEnabler qQmlEnableDebuggingHelper(false);
+static QQmlTriviallyDestructibleDebuggingEnabler qQmlEnableDebuggingHelper(false);
#elif defined(QT_QML_DEBUG)
-static QQmlDebuggingEnabler qQmlEnableDebuggingHelper(true);
+static QQmlTriviallyDestructibleDebuggingEnabler qQmlEnableDebuggingHelper(true);
#endif
+} // unnamed namespace
#endif
diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp
index 0ef40d6911..0b66a29e18 100644
--- a/src/qml/debugger/qqmldebugconnector.cpp
+++ b/src/qml/debugger/qqmldebugconnector.cpp
@@ -1,50 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmldebugpluginmanager_p.h"
#include "qqmldebugconnector_p.h"
#include "qqmldebugservicefactory_p.h"
#include <QtCore/QPluginLoader>
+#include <QtCore/QCborArray>
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QDebug>
-#include <QtCore/QJsonArray>
#include <QtCore/QDataStream>
#include <private/qcoreapplication_p.h>
@@ -111,7 +75,7 @@ QQmlDebugConnector *QQmlDebugConnector::instance()
if (!params)
return nullptr;
- if (!QQmlEnginePrivate::qml_debugging_enabled) {
+ if (!QQmlEnginePrivate::qml_debugging_enabled.load(std::memory_order_relaxed)) {
if (!params->arguments.isEmpty()) {
qWarning().noquote() << QString::fromLatin1(
"QML Debugger: Ignoring \"-qmljsdebugger=%1\". Debugging "
@@ -131,7 +95,7 @@ QQmlDebugConnector *QQmlDebugConnector::instance()
int connectorEnd = params->arguments.indexOf(QLatin1Char(','), connectorBegin);
if (connectorEnd == -1)
- connectorEnd = params->arguments.length();
+ connectorEnd = params->arguments.size();
params->instance = loadQQmlDebugConnector(params->arguments.mid(
connectorBegin,
@@ -145,10 +109,10 @@ QQmlDebugConnector *QQmlDebugConnector::instance()
if (params->instance) {
const auto metaData = metaDataForQQmlDebugService();
- for (const QJsonObject &object : metaData) {
- const auto keys = object.value(QLatin1String("MetaData")).toObject()
+ for (const QPluginParsedMetaData &md : metaData) {
+ const auto keys = md.value(QtPluginMetaDataKeys::MetaData).toMap()
.value(QLatin1String("Keys")).toArray();
- for (const QJsonValue &key : keys) {
+ for (const QCborValue key : keys) {
QString keyString = key.toString();
if (params->services.isEmpty() || params->services.contains(keyString))
loadQQmlDebugService(keyString);
diff --git a/src/qml/debugger/qqmldebugconnector_p.h b/src/qml/debugger/qqmldebugconnector_p.h
index d1ad90adfd..d021020bf4 100644
--- a/src/qml/debugger/qqmldebugconnector_p.h
+++ b/src/qml/debugger/qqmldebugconnector_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDEBUGCONNECTOR_H
#define QQMLDEBUGCONNECTOR_H
@@ -63,8 +27,9 @@ QT_BEGIN_NAMESPACE
#if !QT_CONFIG(qml_debug)
-class Q_QML_PRIVATE_EXPORT QQmlDebugConnector
+class Q_QML_EXPORT QQmlDebugConnector
{
+ virtual ~QQmlDebugConnector() = default; // don't break 'override' on ~QQmlDebugServer
public:
static QQmlDebugConnector *instance() { return nullptr; }
@@ -85,7 +50,7 @@ public:
#else
class QQmlDebugService;
-class Q_QML_PRIVATE_EXPORT QQmlDebugConnector : public QObject
+class Q_QML_EXPORT QQmlDebugConnector : public QObject
{
Q_OBJECT
public:
@@ -122,7 +87,7 @@ protected:
static int s_dataStreamVersion;
};
-class Q_QML_PRIVATE_EXPORT QQmlDebugConnectorFactory : public QObject {
+class Q_QML_EXPORT QQmlDebugConnectorFactory : public QObject {
Q_OBJECT
public:
virtual QQmlDebugConnector *create(const QString &key) = 0;
diff --git a/src/qml/debugger/qqmldebugpluginmanager_p.h b/src/qml/debugger/qqmldebugpluginmanager_p.h
index 2575cbb96a..ffeeea17a8 100644
--- a/src/qml/debugger/qqmldebugpluginmanager_p.h
+++ b/src/qml/debugger/qqmldebugpluginmanager_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDEBUGPLUGINMANAGER_P_H
#define QQMLDEBUGPLUGINMANAGER_P_H
@@ -60,28 +24,27 @@ QT_BEGIN_NAMESPACE
#if !QT_CONFIG(qml_debug)
#define Q_QML_DEBUG_PLUGIN_LOADER(interfaceName)\
- interfaceName *load##interfaceName(const QString &key)\
+ static interfaceName *load##interfaceName(const QString &key)\
{\
qWarning() << "Qml Debugger: QtQml is not configured for debugging. Ignoring request for"\
<< "debug plugin" << key;\
return 0;\
}\
- QList<QJsonObject> metaDataFor##interfaceName()\
+ Q_DECL_UNUSED static QList<QPluginParsedMetaData> metaDataFor##interfaceName()\
{\
- return QList<QJsonObject>();\
+ return {};\
}
-#define Q_QML_IMPORT_DEBUG_PLUGIN(className)
#else // QT_CONFIG(qml_debug)
#define Q_QML_DEBUG_PLUGIN_LOADER(interfaceName)\
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, interfaceName##Loader,\
(interfaceName##Factory_iid, QLatin1String("/qmltooling")))\
- interfaceName *load##interfaceName(const QString &key)\
+ static interfaceName *load##interfaceName(const QString &key)\
{\
return qLoadPlugin<interfaceName, interfaceName##Factory>(interfaceName##Loader(), key);\
}\
- QList<QJsonObject> metaDataFor##interfaceName()\
+ Q_DECL_UNUSED static QList<QPluginParsedMetaData> metaDataFor##interfaceName()\
{\
return interfaceName##Loader()->metaData();\
}
diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp
new file mode 100644
index 0000000000..55a29ff1c5
--- /dev/null
+++ b/src/qml/debugger/qqmldebugserver.cpp
@@ -0,0 +1,13 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmldebugserver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlDebugServer::~QQmlDebugServer()
+ = default;
+
+QT_END_NAMESPACE
+
+#include "moc_qqmldebugserver_p.cpp"
diff --git a/src/qml/debugger/qqmldebugserver_p.h b/src/qml/debugger/qqmldebugserver_p.h
index e848b00bda..04e8b95f67 100644
--- a/src/qml/debugger/qqmldebugserver_p.h
+++ b/src/qml/debugger/qqmldebugserver_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDEBUGSERVER_P_H
#define QQMLDEBUGSERVER_P_H
@@ -58,10 +22,11 @@
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlDebugServer : public QQmlDebugConnector
+class Q_QML_EXPORT QQmlDebugServer : public QQmlDebugConnector
{
Q_OBJECT
public:
+ ~QQmlDebugServer() override;
virtual void setDevice(QIODevice *socket) = 0;
};
diff --git a/src/qml/debugger/qqmldebugserverconnection.cpp b/src/qml/debugger/qqmldebugserverconnection.cpp
new file mode 100644
index 0000000000..8e23ee9be0
--- /dev/null
+++ b/src/qml/debugger/qqmldebugserverconnection.cpp
@@ -0,0 +1,16 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmldebugserverconnection_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlDebugServerConnection::~QQmlDebugServerConnection()
+ = default;
+
+QQmlDebugServerConnectionFactory::~QQmlDebugServerConnectionFactory()
+ = default;
+
+QT_END_NAMESPACE
+
+#include "moc_qqmldebugserverconnection_p.cpp"
diff --git a/src/qml/debugger/qqmldebugserverconnection_p.h b/src/qml/debugger/qqmldebugserverconnection_p.h
index 9c4af4d225..c7ec68727c 100644
--- a/src/qml/debugger/qqmldebugserverconnection_p.h
+++ b/src/qml/debugger/qqmldebugserverconnection_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDEBUGSERVERCONNECTION_P_H
#define QQMLDEBUGSERVERCONNECTION_P_H
@@ -57,11 +21,12 @@
QT_BEGIN_NAMESPACE
class QQmlDebugServer;
-class Q_QML_PRIVATE_EXPORT QQmlDebugServerConnection : public QObject
+class Q_QML_EXPORT QQmlDebugServerConnection : public QObject
{
Q_OBJECT
public:
QQmlDebugServerConnection(QObject *parent = nullptr) : QObject(parent) {}
+ ~QQmlDebugServerConnection() override;
virtual void setServer(QQmlDebugServer *server) = 0;
virtual bool setPortRange(int portFrom, int portTo, bool block, const QString &hostaddress) = 0;
@@ -72,10 +37,11 @@ public:
virtual void flush() = 0;
};
-class Q_QML_PRIVATE_EXPORT QQmlDebugServerConnectionFactory : public QObject
+class Q_QML_EXPORT QQmlDebugServerConnectionFactory : public QObject
{
Q_OBJECT
public:
+ ~QQmlDebugServerConnectionFactory() override;
virtual QQmlDebugServerConnection *create(const QString &key) = 0;
};
diff --git a/src/qml/debugger/qqmldebugservice.cpp b/src/qml/debugger/qqmldebugservice.cpp
index 4b77bee2c9..56cffc169c 100644
--- a/src/qml/debugger/qqmldebugservice.cpp
+++ b/src/qml/debugger/qqmldebugservice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmldebugservice_p.h"
#include "qqmldebugconnector_p.h"
@@ -139,8 +103,8 @@ Q_GLOBAL_STATIC(ObjectReferenceHash, objectReferenceHash)
void ObjectReferenceHash::remove(QObject *obj)
{
- QHash<QObject *, int>::Iterator iter = objects.find(obj);
- if (iter != objects.end()) {
+ const auto iter = objects.constFind(obj);
+ if (iter != objects.cend()) {
ids.remove(iter.value());
objects.erase(iter);
}
@@ -156,9 +120,9 @@ int QQmlDebugService::idForObject(QObject *object)
return -1;
ObjectReferenceHash *hash = objectReferenceHash();
- QHash<QObject *, int>::Iterator iter = hash->objects.find(object);
+ auto iter = hash->objects.constFind(object);
- if (iter == hash->objects.end()) {
+ if (iter == hash->objects.cend()) {
int id = hash->nextId++;
hash->ids.insert(id, object);
iter = hash->objects.insert(object, id);
diff --git a/src/qml/debugger/qqmldebugservice_p.h b/src/qml/debugger/qqmldebugservice_p.h
index c52ba90a79..5970e89038 100644
--- a/src/qml/debugger/qqmldebugservice_p.h
+++ b/src/qml/debugger/qqmldebugservice_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDEBUGSERVICE_H
#define QQMLDEBUGSERVICE_H
@@ -63,7 +27,7 @@ QT_BEGIN_NAMESPACE
class QJSEngine;
class QQmlDebugServicePrivate;
-class Q_QML_PRIVATE_EXPORT QQmlDebugService : public QObject
+class Q_QML_EXPORT QQmlDebugService : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlDebugService)
@@ -82,8 +46,8 @@ public:
virtual void stateChanged(State) {}
virtual void messageReceived(const QByteArray &) {}
- virtual void engineAboutToBeAdded(QJSEngine *engine) { emit attachedToEngine(engine); }
- virtual void engineAboutToBeRemoved(QJSEngine *engine) { emit detachedFromEngine(engine); }
+ virtual void engineAboutToBeAdded(QJSEngine *engine) { Q_EMIT attachedToEngine(engine); }
+ virtual void engineAboutToBeRemoved(QJSEngine *engine) { Q_EMIT detachedFromEngine(engine); }
virtual void engineAdded(QJSEngine *) {}
virtual void engineRemoved(QJSEngine *) {}
@@ -95,7 +59,7 @@ public:
protected:
explicit QQmlDebugService(const QString &, float version, QObject *parent = nullptr);
-signals:
+Q_SIGNALS:
void attachedToEngine(QJSEngine *);
void detachedFromEngine(QJSEngine *);
diff --git a/src/qml/debugger/qqmldebugservicefactory.cpp b/src/qml/debugger/qqmldebugservicefactory.cpp
new file mode 100644
index 0000000000..799052673d
--- /dev/null
+++ b/src/qml/debugger/qqmldebugservicefactory.cpp
@@ -0,0 +1,13 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmldebugservicefactory_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlDebugServiceFactory::~QQmlDebugServiceFactory()
+ = default;
+
+QT_END_NAMESPACE
+
+#include "moc_qqmldebugservicefactory_p.cpp"
diff --git a/src/qml/debugger/qqmldebugservicefactory_p.h b/src/qml/debugger/qqmldebugservicefactory_p.h
index 575a909f35..e9e4069efb 100644
--- a/src/qml/debugger/qqmldebugservicefactory_p.h
+++ b/src/qml/debugger/qqmldebugservicefactory_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDEBUGSERVICEFACTORY_P_H
#define QQMLDEBUGSERVICEFACTORY_P_H
@@ -55,10 +19,11 @@
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlDebugServiceFactory : public QObject
+class Q_QML_EXPORT QQmlDebugServiceFactory : public QObject
{
Q_OBJECT
public:
+ ~QQmlDebugServiceFactory() override;
virtual QQmlDebugService *create(const QString &key) = 0;
};
diff --git a/src/qml/debugger/qqmldebugserviceinterfaces.cpp b/src/qml/debugger/qqmldebugserviceinterfaces.cpp
index 76205c7760..db1ec2db5e 100644
--- a/src/qml/debugger/qqmldebugserviceinterfaces.cpp
+++ b/src/qml/debugger/qqmldebugserviceinterfaces.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmldebugserviceinterfaces_p.h"
@@ -48,6 +12,84 @@ const QString QQmlProfilerService::s_key = QStringLiteral("CanvasFrameRate");
const QString QDebugMessageService::s_key = QStringLiteral("DebugMessages");
const QString QQmlEngineControlService::s_key = QStringLiteral("EngineControl");
const QString QQmlNativeDebugService::s_key = QStringLiteral("NativeQmlDebugger");
+#if QT_CONFIG(translation)
+const QString QQmlDebugTranslationService::s_key = QStringLiteral("DebugTranslation");
+#endif
+
+QV4DebugService::~QV4DebugService()
+ = default;
+QQmlEngineDebugService::~QQmlEngineDebugService()
+ = default;
+QQmlInspectorService::~QQmlInspectorService()
+ = default;
+QQmlProfilerService::~QQmlProfilerService()
+ = default;
+QDebugMessageService::~QDebugMessageService()
+ = default;
+QQmlEngineControlService::~QQmlEngineControlService()
+ = default;
+QQmlNativeDebugService::~QQmlNativeDebugService()
+ = default;
+
+static QQmlDebugStatesDelegate *(*statesDelegateFactory)() = nullptr;
+void QQmlEngineDebugService::setStatesDelegateFactory(QQmlDebugStatesDelegate *(*factory)())
+{
+ statesDelegateFactory = factory;
+}
+
+QQmlDebugStatesDelegate *QQmlEngineDebugService::createStatesDelegate()
+{
+ return statesDelegateFactory ? statesDelegateFactory() : nullptr;
+}
+
+#if QT_CONFIG(translation)
+QQmlDebugTranslationService::~QQmlDebugTranslationService()
+ = default;
+
+const TranslationBindingInformation TranslationBindingInformation::create(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QV4::CompiledData::Binding *binding, QObject *scopeObject,
+ QQmlRefPointer<QQmlContextData> ctxt)
+{
+ QQmlTranslation translation;
+ if (binding->type() == QV4::CompiledData::Binding::Type_TranslationById) {
+ const QV4::CompiledData::TranslationData data =
+ compilationUnit->unitData()->translations()[binding->value.translationDataIndex];
+ const QString id = compilationUnit->stringAt(data.stringIndex);
+ const int n = data.number;
+
+ translation = QQmlTranslation(QQmlTranslation::QsTrIdData(id, n));
+ } else {
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Translation);
+
+ const QV4::CompiledData::TranslationData data =
+ compilationUnit->unitData()->translations()[binding->value.translationDataIndex];
+ const QString text = compilationUnit->stringAt(data.stringIndex);
+ const QString comment = compilationUnit->stringAt(data.commentIndex);
+ const bool hasContext
+ = data.contextIndex != QV4::CompiledData::TranslationData::NoContextIndex;
+ const int n = data.number;
+
+ translation = QQmlTranslation(
+ QQmlTranslation::QsTrData(
+ hasContext
+ ? compilationUnit->stringAt(data.contextIndex)
+ : QQmlTranslation::contextFromQmlFilename(
+ compilationUnit->fileName()),
+ text, comment, n));
+ }
+
+ return { compilationUnit,
+ scopeObject,
+ ctxt,
+
+ compilationUnit->stringAt(binding->propertyNameIndex),
+ translation,
+
+ binding->location.line(),
+ binding->location.column() };
+}
+#endif
QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmldebugserviceinterfaces_p.h b/src/qml/debugger/qqmldebugserviceinterfaces_p.h
index 01693aee24..cd9022b497 100644
--- a/src/qml/debugger/qqmldebugserviceinterfaces_p.h
+++ b/src/qml/debugger/qqmldebugserviceinterfaces_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDEBUGSERVICEINTERFACES_P_H
#define QQMLDEBUGSERVICEINTERFACES_P_H
@@ -58,6 +22,7 @@
#endif
#include <private/qqmldebugstatesdelegate_p.h>
#include <private/qqmlboundsignal_p.h>
+#include <private/qqmltranslation_p.h>
#include <limits>
@@ -66,8 +31,11 @@ QT_BEGIN_NAMESPACE
class QWindow;
class QQuickWindow;
+
#if !QT_CONFIG(qml_debug)
+class TranslationBindingInformation;
+
class QV4DebugService
{
public:
@@ -90,7 +58,7 @@ class QQmlEngineDebugService
{
public:
void objectCreated(QJSEngine *, QObject *) {}
- virtual void setStatesDelegate(QQmlDebugStatesDelegate *) {}
+ static void setStatesDelegateFactory(QQmlDebugStatesDelegate *(*)()) {}
};
class QQmlInspectorService {
@@ -103,13 +71,19 @@ public:
class QDebugMessageService {};
class QQmlEngineControlService {};
class QQmlNativeDebugService {};
+class QQmlDebugTranslationService {
+public:
+ virtual void foundTranslationBinding(const TranslationBindingInformation &) {}
+};
#else
-class Q_QML_PRIVATE_EXPORT QV4DebugService : public QQmlDebugService
+class Q_QML_EXPORT QV4DebugService : public QQmlDebugService
{
Q_OBJECT
public:
+ ~QV4DebugService() override;
+
static const QString s_key;
virtual void signalEmitted(const QString &signal) = 0;
@@ -117,15 +91,17 @@ public:
protected:
friend class QQmlDebugConnector;
- QV4DebugService(float version, QObject *parent = nullptr) :
+ explicit QV4DebugService(float version, QObject *parent = nullptr) :
QQmlDebugService(s_key, version, parent) {}
};
class QQmlAbstractProfilerAdapter;
-class Q_QML_PRIVATE_EXPORT QQmlProfilerService : public QQmlDebugService
+class Q_QML_EXPORT QQmlProfilerService : public QQmlDebugService
{
Q_OBJECT
public:
+ ~QQmlProfilerService() override;
+
static const QString s_key;
virtual void addGlobalProfiler(QQmlAbstractProfilerAdapter *profiler) = 0;
@@ -140,32 +116,74 @@ public:
protected:
friend class QQmlDebugConnector;
- QQmlProfilerService(float version, QObject *parent = nullptr) :
+ explicit QQmlProfilerService(float version, QObject *parent = nullptr) :
QQmlDebugService(s_key, version, parent) {}
};
-class Q_QML_PRIVATE_EXPORT QQmlEngineDebugService : public QQmlDebugService
+class Q_QML_EXPORT QQmlEngineDebugService : public QQmlDebugService
{
Q_OBJECT
public:
+ ~QQmlEngineDebugService() override;
+
static const QString s_key;
virtual void objectCreated(QJSEngine *engine, QObject *object) = 0;
- virtual void setStatesDelegate(QQmlDebugStatesDelegate *) = 0;
+ static void setStatesDelegateFactory(QQmlDebugStatesDelegate *(*factory)());
+ static QQmlDebugStatesDelegate *createStatesDelegate();
protected:
friend class QQmlDebugConnector;
- QQmlEngineDebugService(float version, QObject *parent = nullptr) :
+ explicit QQmlEngineDebugService(float version, QObject *parent = nullptr) :
QQmlDebugService(s_key, version, parent) {}
QQmlBoundSignal *nextSignal(QQmlBoundSignal *prev) { return prev->m_nextSignal; }
};
-class Q_QML_PRIVATE_EXPORT QQmlInspectorService : public QQmlDebugService
+#if QT_CONFIG(translation)
+struct TranslationBindingInformation
+{
+ static const TranslationBindingInformation
+ create(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QV4::CompiledData::Binding *binding, QObject *scopeObject,
+ QQmlRefPointer<QQmlContextData> ctxt);
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
+ QObject *scopeObject;
+ QQmlRefPointer<QQmlContextData> ctxt;
+
+ QString propertyName;
+ QQmlTranslation translation;
+
+ quint32 line;
+ quint32 column;
+};
+
+class Q_QML_EXPORT QQmlDebugTranslationService : public QQmlDebugService
+{
+ Q_OBJECT
+public:
+ ~QQmlDebugTranslationService() override;
+
+ static const QString s_key;
+
+ virtual void foundTranslationBinding(const TranslationBindingInformation &translationBindingInformation) = 0;
+protected:
+ friend class QQmlDebugConnector;
+
+ explicit QQmlDebugTranslationService(float version, QObject *parent = nullptr) :
+ QQmlDebugService(s_key, version, parent) {}
+
+};
+#endif //QT_CONFIG(translation)
+
+class Q_QML_EXPORT QQmlInspectorService : public QQmlDebugService
{
Q_OBJECT
public:
+ ~QQmlInspectorService() override;
+
static const QString s_key;
virtual void addWindow(QQuickWindow *) = 0;
@@ -175,14 +193,16 @@ public:
protected:
friend class QQmlDebugConnector;
- QQmlInspectorService(float version, QObject *parent = nullptr) :
+ explicit QQmlInspectorService(float version, QObject *parent = nullptr) :
QQmlDebugService(s_key, version, parent) {}
};
-class Q_QML_PRIVATE_EXPORT QDebugMessageService : public QQmlDebugService
+class Q_QML_EXPORT QDebugMessageService : public QQmlDebugService
{
Q_OBJECT
public:
+ ~QDebugMessageService() override;
+
static const QString s_key;
virtual void synchronizeTime(const QElapsedTimer &otherTimer) = 0;
@@ -190,14 +210,16 @@ public:
protected:
friend class QQmlDebugConnector;
- QDebugMessageService(float version, QObject *parent = nullptr) :
+ explicit QDebugMessageService(float version, QObject *parent = nullptr) :
QQmlDebugService(s_key, version, parent) {}
};
-class Q_QML_PRIVATE_EXPORT QQmlEngineControlService : public QQmlDebugService
+class Q_QML_EXPORT QQmlEngineControlService : public QQmlDebugService
{
Q_OBJECT
public:
+ ~QQmlEngineControlService() override;
+
static const QString s_key;
protected:
@@ -208,16 +230,18 @@ protected:
};
-class Q_QML_PRIVATE_EXPORT QQmlNativeDebugService : public QQmlDebugService
+class Q_QML_EXPORT QQmlNativeDebugService : public QQmlDebugService
{
Q_OBJECT
public:
+ ~QQmlNativeDebugService() override;
+
static const QString s_key;
protected:
friend class QQmlDebugConnector;
- QQmlNativeDebugService(float version, QObject *parent = nullptr)
+ explicit QQmlNativeDebugService(float version, QObject *parent = nullptr)
: QQmlDebugService(s_key, version, parent) {}
};
diff --git a/src/qml/debugger/qqmldebugstatesdelegate_p.h b/src/qml/debugger/qqmldebugstatesdelegate_p.h
index b2e14873dc..b2b17070e7 100644
--- a/src/qml/debugger/qqmldebugstatesdelegate_p.h
+++ b/src/qml/debugger/qqmldebugstatesdelegate_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDEBUGSTATESDELEGATE_P_H
#define QQMLDEBUGSTATESDELEGATE_P_H
@@ -54,6 +18,7 @@
#include <QtQml/qtqmlglobal.h>
#include <QtCore/QList>
#include <QtCore/QPointer>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/debugger/qqmldebugtranslationprotocol_p.h b/src/qml/debugger/qqmldebugtranslationprotocol_p.h
new file mode 100644
index 0000000000..d4f5b8e1f4
--- /dev/null
+++ b/src/qml/debugger/qqmldebugtranslationprotocol_p.h
@@ -0,0 +1,265 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QQMLDEBUGTRANSLATIONPROTOCOL_P_H
+#define QQMLDEBUGTRANSLATIONPROTOCOL_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/qdatastream.h>
+#include <QtCore/qbuffer.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qobjectdefs.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/private/qglobal_p.h>
+#include <tuple>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlDebugTranslation {
+
+enum class Request {
+ ChangeLanguage = 1,
+ StateList,
+ ChangeState,
+ TranslationIssues,
+ TranslatableTextOccurrences,
+ WatchTextElides,
+ DisableWatchTextElides,
+ // following are obsolete, just provided for compilation compatibility
+ MissingTranslations
+};
+
+enum class Reply {
+ LanguageChanged = 101,
+ StateList,
+ StateChanged,
+ TranslationIssues,
+ TranslatableTextOccurrences,
+ // following are obsolete, just provided for compilation compatibility
+ MissingTranslations,
+ TextElided
+};
+
+inline QDataStream &operator<<(QDataStream &ds, Request r)
+{
+ return ds << int(r);
+}
+
+inline QDataStream &operator>>(QDataStream &ds, Request &r)
+{
+ int i;
+ ds >> i;
+ r = Request(i);
+ return ds;
+}
+
+inline QDataStream &operator<<(QDataStream &ds, Reply r)
+{
+ return ds << int(r);
+}
+
+inline QDataStream &operator>>(QDataStream &ds, Reply &r)
+{
+ int i;
+ ds >> i;
+ r = Reply(i);
+ return ds;
+}
+
+inline QByteArray createChangeLanguageRequest(QDataStream &packet, const QUrl &url,
+ const QString &locale)
+{
+ packet << Request::ChangeLanguage << url << locale;
+ return qobject_cast<QBuffer *>(packet.device())->data();
+}
+
+inline QByteArray createChangeStateRequest(QDataStream &packet, const QString &state)
+{
+ packet << Request::ChangeState << state;
+ return qobject_cast<QBuffer *>(packet.device())->data();
+}
+
+inline QByteArray createMissingTranslationsRequest(QDataStream &packet)
+{
+ packet << Request::MissingTranslations;
+ return qobject_cast<QBuffer *>(packet.device())->data();
+}
+
+inline QByteArray createTranslationIssuesRequest(QDataStream &packet)
+{
+ packet << Request::TranslationIssues;
+ return qobject_cast<QBuffer *>(packet.device())->data();
+}
+
+inline QByteArray createTranslatableTextOccurrencesRequest(QDataStream &packet)
+{
+ packet << Request::TranslatableTextOccurrences;
+ return qobject_cast<QBuffer *>(packet.device())->data();
+}
+
+inline QByteArray createStateListRequest(QDataStream &packet)
+{
+ packet << Request::StateList;
+ return qobject_cast<QBuffer *>(packet.device())->data();
+}
+
+inline QByteArray createWatchTextElidesRequest(QDataStream &packet)
+{
+ packet << Request::WatchTextElides;
+ return qobject_cast<QBuffer *>(packet.device())->data();
+}
+
+inline QByteArray createDisableWatchTextElidesRequest(QDataStream &packet)
+{
+ packet << Request::DisableWatchTextElides;
+ return qobject_cast<QBuffer *>(packet.device())->data();
+}
+
+class CodeMarker
+{
+public:
+ friend QDataStream &operator>>(QDataStream &stream, CodeMarker &codeMarker)
+ {
+ return stream >> codeMarker.url
+ >> codeMarker.line
+ >> codeMarker.column;
+ }
+
+ friend QDataStream &operator<<(QDataStream &stream, const CodeMarker &codeMarker)
+ {
+ return stream << codeMarker.url
+ << codeMarker.line
+ << codeMarker.column;
+ }
+
+ friend bool operator<(const CodeMarker &first, const CodeMarker &second)
+ {
+ return std::tie(first.url, first.line, first.column)
+ < std::tie(second.url, second.line, second.column);
+ }
+
+ friend bool operator==(const CodeMarker &first, const CodeMarker &second)
+ {
+ return first.line == second.line
+ && first.column == second.column
+ && first.url == second.url;
+ }
+
+ QUrl url;
+ int line = -1;
+ int column = -1;
+};
+class TranslationIssue
+{
+public:
+ enum class Type{
+ Missing,
+ Elided
+ };
+
+ friend QDataStream &operator>>(QDataStream &stream, TranslationIssue &issue)
+ {
+ int t;
+ stream >> issue.codeMarker
+ >> issue.language
+ >> t;
+ issue.type = Type(t);
+ return stream;
+ }
+
+ friend QDataStream &operator<<(QDataStream &stream, const TranslationIssue &issue)
+ {
+ return stream << issue.codeMarker
+ << issue.language
+ << int(issue.type);
+ }
+
+ friend bool operator==(const TranslationIssue &first, const TranslationIssue &second)
+ {
+ return first.type == second.type
+ && first.language == second.language
+ && first.codeMarker == second.codeMarker;
+ }
+
+ QString toDebugString() const
+ {
+ QString debugString(QLatin1String(
+ "TranslationIssue(type=%1, line=%2, column=%3, url=%4, language=%5)"));
+ return debugString.arg(type == TranslationIssue::Type::Missing ? QLatin1String("Missing")
+ : QLatin1String("Elided"),
+ QString::number(codeMarker.line), QString::number(codeMarker.column),
+ codeMarker.url.toString(), language);
+ }
+
+ QString language;
+ Type type = Type::Missing;
+ CodeMarker codeMarker;
+};
+class QmlElement
+{
+public:
+ QmlElement() = default;
+
+ friend QDataStream &operator>>(QDataStream &stream, QmlElement &qmlElement)
+ {
+ return stream >> qmlElement.codeMarker >> qmlElement.elementId >> qmlElement.elementType
+ >> qmlElement.propertyName >> qmlElement.translationId >> qmlElement.translatedText
+ >> qmlElement.fontFamily >> qmlElement.fontPointSize >> qmlElement.fontPixelSize
+ >> qmlElement.fontStyleName >> qmlElement.horizontalAlignment
+ >> qmlElement.verticalAlignment >> qmlElement.stateName;
+ }
+
+ friend QDataStream &operator<<(QDataStream &stream, const QmlElement &qmlElement)
+ {
+ return stream << qmlElement.codeMarker << qmlElement.elementId << qmlElement.elementType
+ << qmlElement.propertyName << qmlElement.translationId
+ << qmlElement.translatedText << qmlElement.fontFamily
+ << qmlElement.fontPointSize << qmlElement.fontPixelSize
+ << qmlElement.fontStyleName << qmlElement.horizontalAlignment
+ << qmlElement.verticalAlignment << qmlElement.stateName;
+ }
+
+ CodeMarker codeMarker;
+ QString propertyName;
+ QString translationId;
+ QString translatedText;
+ QString fontFamily;
+ QString fontStyleName;
+ QString elementId;
+ QString elementType;
+ qreal fontPointSize = 0.0;
+ QString stateName;
+ int fontPixelSize = 0;
+ int horizontalAlignment = 0;
+ int verticalAlignment = 0;
+};
+
+class QmlState
+{
+public:
+ QmlState() = default;
+
+ friend QDataStream &operator>>(QDataStream &stream, QmlState &qmlState)
+ {
+ return stream >> qmlState.name;
+ }
+
+ friend QDataStream &operator<<(QDataStream &stream, const QmlState &qmlState)
+ {
+ return stream << qmlState.name;
+ }
+
+ QString name;
+};
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLDEBUGTRANSLATIONPROTOCOL_P_H
diff --git a/src/qml/debugger/qqmlprofiler.cpp b/src/qml/debugger/qqmlprofiler.cpp
index da0b14dd85..281fdcda3c 100644
--- a/src/qml/debugger/qqmlprofiler.cpp
+++ b/src/qml/debugger/qqmlprofiler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlprofiler_p.h"
#include "qqmldebugservice_p.h"
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index d3eedab1c6..2cf0e85760 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROFILER_P_H
#define QQMLPROFILER_P_H
@@ -51,17 +15,18 @@
// We mean it.
//
-#include <private/qv4function_p.h>
-#include <private/qqmlboundsignal_p.h>
#include <private/qfinitestack_p.h>
#include <private/qqmlbinding_p.h>
+#include <private/qqmlboundsignal_p.h>
+#include <private/qqmlglobal_p.h>
+#include <private/qv4function_p.h>
+
#if QT_CONFIG(qml_debug)
#include "qqmlprofilerdefinitions_p.h"
-#include "qqmlabstractprofileradapter_p.h"
#endif
-#include <QUrl>
-#include <QString>
+#include <QtCore/qurl.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -145,9 +110,9 @@ struct Q_AUTOTEST_EXPORT QQmlProfilerData : public QQmlProfilerDefinitions
RangeType detailType;
};
-Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_RELOCATABLE_TYPE);
-class Q_QML_PRIVATE_EXPORT QQmlProfiler : public QObject, public QQmlProfilerDefinitions {
+class Q_QML_EXPORT QQmlProfiler : public QObject, public QQmlProfilerDefinitions {
Q_OBJECT
public:
@@ -176,7 +141,7 @@ public:
RefLocation(QV4::ExecutableCompilationUnit *ref, const QUrl &url,
const QV4::CompiledData::Object *obj, const QString &type)
- : Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url),
+ : Location(QQmlSourceLocation(type, obj->location.line(), obj->location.column()), url),
locationType(Creating), sent(false)
{
unit = ref;
@@ -387,7 +352,7 @@ public:
void reportData();
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
-signals:
+Q_SIGNALS:
void dataReady(const QVector<QQmlProfilerData> &, const QQmlProfiler::LocationHash &);
protected:
diff --git a/src/qml/debugger/qqmlprofilerdefinitions_p.h b/src/qml/debugger/qqmlprofilerdefinitions_p.h
index 7b972c5d0d..7e87e8ac13 100644
--- a/src/qml/debugger/qqmlprofilerdefinitions_p.h
+++ b/src/qml/debugger/qqmlprofilerdefinitions_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROFILERDEFINITIONS_P_H
#define QQMLPROFILERDEFINITIONS_P_H
@@ -70,6 +34,7 @@ struct QQmlProfilerDefinitions {
SceneGraphFrame,
MemoryAllocation,
DebugMessage,
+ Quick3DFrame,
MaximumMessage
};
@@ -124,6 +89,22 @@ struct QQmlProfilerDefinitions {
NumGUIThreadFrameTypes = MaximumSceneGraphFrameType - NumRenderThreadFrameTypes
};
+ enum Quick3DFrameType {
+ Quick3DRenderFrame, // Render Thread
+ Quick3DSynchronizeFrame,
+ Quick3DPrepareFrame,
+ Quick3DMeshLoad,
+ Quick3DCustomMeshLoad,
+ Quick3DTextureLoad,
+ Quick3DGenerateShader,
+ Quick3DLoadShader,
+ Quick3DParticleUpdate, // GUI Thread
+ Quick3DRenderCall, // Render Thread
+ Quick3DRenderPass, // Render Thread
+ Quick3DEventData, // N/A
+ MaximumQuick3DFrameType,
+ };
+
enum ProfileFeature {
ProfileJavaScript,
ProfileMemory,
@@ -137,6 +118,7 @@ struct QQmlProfilerDefinitions {
ProfileHandlingSignal,
ProfileInputEvents,
ProfileDebugMessages,
+ ProfileQuick3D,
MaximumProfileFeature
};
diff --git a/src/qml/doc/images/cpp-qml-integration-flowchart.odg b/src/qml/doc/images/cpp-qml-integration-flowchart.odg
index f24021635e..c0d8b7a8d7 100644
--- a/src/qml/doc/images/cpp-qml-integration-flowchart.odg
+++ b/src/qml/doc/images/cpp-qml-integration-flowchart.odg
Binary files differ
diff --git a/src/qml/doc/images/cpp-qml-integration-flowchart.png b/src/qml/doc/images/cpp-qml-integration-flowchart.png
index 3649ff9e41..1e76e823c4 100644
--- a/src/qml/doc/images/cpp-qml-integration-flowchart.png
+++ b/src/qml/doc/images/cpp-qml-integration-flowchart.png
Binary files differ
diff --git a/src/qml/doc/images/cppintegration-ex.png b/src/qml/doc/images/cppintegration-ex.png
deleted file mode 100644
index 0b476ccb93..0000000000
--- a/src/qml/doc/images/cppintegration-ex.png
+++ /dev/null
Binary files differ
diff --git a/src/qml/doc/images/extending-qml-advanced-word-cloud.png b/src/qml/doc/images/extending-qml-advanced-word-cloud.png
new file mode 100644
index 0000000000..b479b4f793
--- /dev/null
+++ b/src/qml/doc/images/extending-qml-advanced-word-cloud.png
Binary files differ
diff --git a/src/qml/doc/images/listmodel-nested.png b/src/qml/doc/images/listmodel-nested.png
deleted file mode 100644
index ee7ffba67a..0000000000
--- a/src/qml/doc/images/listmodel-nested.png
+++ /dev/null
Binary files differ
diff --git a/src/qml/doc/images/listmodel.png b/src/qml/doc/images/listmodel.png
deleted file mode 100644
index 7ab1771f15..0000000000
--- a/src/qml/doc/images/listmodel.png
+++ /dev/null
Binary files differ
diff --git a/src/qml/doc/images/objectmodel.png b/src/qml/doc/images/objectmodel.png
deleted file mode 100644
index 5e6d1325b2..0000000000
--- a/src/qml/doc/images/objectmodel.png
+++ /dev/null
Binary files differ
diff --git a/src/qml/doc/images/qmlsc-compilation-scheme.png b/src/qml/doc/images/qmlsc-compilation-scheme.png
new file mode 100644
index 0000000000..8a7785ea4b
--- /dev/null
+++ b/src/qml/doc/images/qmlsc-compilation-scheme.png
Binary files differ
diff --git a/src/qml/doc/images/qmltc-compilation-scheme.png b/src/qml/doc/images/qmltc-compilation-scheme.png
new file mode 100644
index 0000000000..7bcf0c2b5e
--- /dev/null
+++ b/src/qml/doc/images/qmltc-compilation-scheme.png
Binary files differ
diff --git a/src/qml/doc/images/statemachine-button-history.png b/src/qml/doc/images/statemachine-button-history.png
deleted file mode 100644
index 0462b3b99b..0000000000
--- a/src/qml/doc/images/statemachine-button-history.png
+++ /dev/null
Binary files differ
diff --git a/src/qml/doc/images/statemachine-button-nested.png b/src/qml/doc/images/statemachine-button-nested.png
deleted file mode 100644
index 762ac14df1..0000000000
--- a/src/qml/doc/images/statemachine-button-nested.png
+++ /dev/null
Binary files differ
diff --git a/src/qml/doc/images/statemachine-button.png b/src/qml/doc/images/statemachine-button.png
deleted file mode 100644
index 10102bdf2c..0000000000
--- a/src/qml/doc/images/statemachine-button.png
+++ /dev/null
Binary files differ
diff --git a/src/qml/doc/images/statemachine-finished.png b/src/qml/doc/images/statemachine-finished.png
deleted file mode 100644
index 0ac081d6ba..0000000000
--- a/src/qml/doc/images/statemachine-finished.png
+++ /dev/null
Binary files differ
diff --git a/src/qml/doc/images/statemachine-nonparallel.png b/src/qml/doc/images/statemachine-nonparallel.png
deleted file mode 100644
index f9850a74a6..0000000000
--- a/src/qml/doc/images/statemachine-nonparallel.png
+++ /dev/null
Binary files differ
diff --git a/src/qml/doc/images/statemachine-parallel.png b/src/qml/doc/images/statemachine-parallel.png
deleted file mode 100644
index a65c297f5b..0000000000
--- a/src/qml/doc/images/statemachine-parallel.png
+++ /dev/null
Binary files differ
diff --git a/src/qml/doc/qtqml.qdocconf b/src/qml/doc/qtqml.qdocconf
index 74d0a3b27c..9c1632e537 100644
--- a/src/qml/doc/qtqml.qdocconf
+++ b/src/qml/doc/qtqml.qdocconf
@@ -15,9 +15,6 @@ qhp.QtQml.virtualFolder = qtqml
qhp.QtQml.indexTitle = Qt QML
qhp.QtQml.indexRoot =
-qhp.QtQml.filterAttributes = qtqml $QT_VERSION qtrefdoc
-qhp.QtQml.customFilters.Qt.name = QtQml $QT_VERSION
-qhp.QtQml.customFilters.Qt.filterAttributes = qtqml $QT_VERSION
qhp.QtQml.subprojects = qmltypes classes examples
qhp.QtQml.subprojects.classes.title = C++ Classes
qhp.QtQml.subprojects.classes.indexTitle = Qt QML C++ Classes
@@ -34,20 +31,23 @@ qhp.QtQml.subprojects.qmltypes.sortPages = true
tagfile = ../../../doc/qtqml/qtqml.tags
-depends += qtcore qtgui qtquick qtdoc qtlinguist qmake qtscript qtwidgets qtxmlpatterns qtquickcontrols
+depends += \
+ qtcore \
+ qtnetwork \
+ qtqmlmodels \
+ qtqmlworkerscript \
+ qtgui \
+ qtquick \
+ qtdoc \
+ qtlinguist \
+ qtwidgets \
+ qtquickcontrols \
+ qmake \
+ qtcmake
-headerdirs += .. \
- ../../imports/models \
- ../../qmlmodels \
- ../../qml \
- ../../qmlworkerscript
+headerdirs += ..
-sourcedirs += .. \
- ../../imports/models \
- ../../imports/statemachine \
- ../../qmlmodels \
- ../../qml \
- ../../qmlworkerscript
+sourcedirs += ..
exampledirs += ../../../examples/qml \
../ \
@@ -60,8 +60,15 @@ manifestmeta.thumbnail.names += "QtQml/Chapter 4*" \
"QtQml/Chapter 6*" \
"QtQml/C++ Extensions: *"
-manifestmeta.highlighted.names = "QtQml/Writing QML Extensions with C++"
-
navigation.landingpage = "Qt QML"
navigation.cppclassespage = "Qt QML C++ Classes"
navigation.qmltypespage = "Qt QML QML Types"
+# Auto-generate navigation linking based on the \list structures on the following:
+navigation.toctitles = "Qt Quick Compiler"
+
+navigation.toctitles.inclusive = true
+# suppress qdoc warnings for \instantiates entries
+spurious += "C\\+\\+ class .*\\\\instantiates .*"
+
+# Enforce zero documentation warnings
+warninglimit = 0
diff --git a/src/qml/doc/snippets/cmake/qt_target_qml_sources/CMakeLists.txt b/src/qml/doc/snippets/cmake/qt_target_qml_sources/CMakeLists.txt
new file mode 100644
index 0000000000..7ec50e425f
--- /dev/null
+++ b/src/qml/doc/snippets/cmake/qt_target_qml_sources/CMakeLists.txt
@@ -0,0 +1,46 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.19)
+project(qt_target_qml_sources_snippet)
+
+set(CMAKE_AUTOMOC TRUE)
+set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+# ![0]
+set_source_files_properties(nested/way/down/File.qml PROPERTIES
+ QT_RESOURCE_ALIAS File.qml
+)
+set_source_files_properties(TemplateFile.qml PROPERTIES
+ QT_RESOURCE_ALIAS templates/File.qml
+ QT_QML_SKIP_QMLDIR_ENTRY TRUE
+ QT_QML_SKIP_QMLLINT TRUE
+ QT_QML_SKIP_CACHEGEN TRUE
+)
+set_source_files_properties(FunnySingleton.qml PROPERTIES
+ QT_QML_SINGLETON_TYPE TRUE
+)
+qt_add_qml_module(qt_target_qml_sources_example
+ URI Example
+ VERSION 2.3
+ RESOURCE_PREFIX /my.company.com/imports
+ QML_FILES
+ nested/way/down/File.qml
+ TemplateFile.qml
+ FunnySingleton.qml
+)
+
+set_source_files_properties(some_old_thing.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "1.1;2.0"
+ QT_QML_SOURCE_TYPENAME OldThing
+)
+set_source_files_properties(../../../images/button-types.png PROPERTIES
+ QT_RESOURCE_ALIAS button-types.png
+)
+qt_target_qml_sources(qt_target_qml_sources_example
+ QML_FILES some_old_thing.qml
+ RESOURCES
+ ../../../images/button-types.png
+ doc/README.txt
+)
+# ![0]
diff --git a/src/qml/doc/snippets/cmake/qt_target_qml_sources/FunnySingleton.qml b/src/qml/doc/snippets/cmake/qt_target_qml_sources/FunnySingleton.qml
new file mode 100644
index 0000000000..6d7a748f2a
--- /dev/null
+++ b/src/qml/doc/snippets/cmake/qt_target_qml_sources/FunnySingleton.qml
@@ -0,0 +1,9 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [0]
+pragma Singleton
+import QtQml
+
+QtObject {}
+//! [0]
diff --git a/src/qml/doc/snippets/cmake/qt_target_qml_sources/TemplateFile.qml b/src/qml/doc/snippets/cmake/qt_target_qml_sources/TemplateFile.qml
new file mode 100644
index 0000000000..8fc36a40da
--- /dev/null
+++ b/src/qml/doc/snippets/cmake/qt_target_qml_sources/TemplateFile.qml
@@ -0,0 +1,3 @@
+import QtQml
+
+QtObject {}
diff --git a/src/qml/doc/snippets/cmake/qt_target_qml_sources/doc/README.txt b/src/qml/doc/snippets/cmake/qt_target_qml_sources/doc/README.txt
new file mode 100644
index 0000000000..52d51e034d
--- /dev/null
+++ b/src/qml/doc/snippets/cmake/qt_target_qml_sources/doc/README.txt
@@ -0,0 +1 @@
+Dummy file, contents not important.
diff --git a/src/qml/doc/snippets/cmake/qt_target_qml_sources/nested/way/down/File.qml b/src/qml/doc/snippets/cmake/qt_target_qml_sources/nested/way/down/File.qml
new file mode 100644
index 0000000000..8fc36a40da
--- /dev/null
+++ b/src/qml/doc/snippets/cmake/qt_target_qml_sources/nested/way/down/File.qml
@@ -0,0 +1,3 @@
+import QtQml
+
+QtObject {}
diff --git a/src/qml/doc/snippets/cmake/qt_target_qml_sources/some_old_thing.qml b/src/qml/doc/snippets/cmake/qt_target_qml_sources/some_old_thing.qml
new file mode 100644
index 0000000000..8fc36a40da
--- /dev/null
+++ b/src/qml/doc/snippets/cmake/qt_target_qml_sources/some_old_thing.qml
@@ -0,0 +1,3 @@
+import QtQml
+
+QtObject {}
diff --git a/src/qml/doc/snippets/code/backend/backend.cpp b/src/qml/doc/snippets/code/backend/backend.cpp
deleted file mode 100644
index 58f5a15e2a..0000000000
--- a/src/qml/doc/snippets/code/backend/backend.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-//! [backend_cpp]
-#include "backend.h"
-
-BackEnd::BackEnd(QObject *parent) :
- QObject(parent)
-{
-}
-
-QString BackEnd::userName()
-{
- return m_userName;
-}
-
-void BackEnd::setUserName(const QString &userName)
-{
- if (userName == m_userName)
- return;
-
- m_userName = userName;
- emit userNameChanged();
-}
-//! [backend_cpp]
diff --git a/src/qml/doc/snippets/code/backend/backend.h b/src/qml/doc/snippets/code/backend/backend.h
deleted file mode 100644
index fa7ce9eb86..0000000000
--- a/src/qml/doc/snippets/code/backend/backend.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-//! [backend_header]
-#ifndef BACKEND_H
-#define BACKEND_H
-
-#include <QObject>
-#include <QString>
-
-class BackEnd : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged)
-
-public:
- explicit BackEnd(QObject *parent = nullptr);
-
- QString userName();
- void setUserName(const QString &userName);
-
-signals:
- void userNameChanged();
-
-private:
- QString m_userName;
-};
-
-#endif // BACKEND_H
-//! [backend_header]
diff --git a/src/qml/doc/snippets/code/backend/main.cpp b/src/qml/doc/snippets/code/backend/main.cpp
index 91a012dfda..7559e472c7 100644
--- a/src/qml/doc/snippets/code/backend/main.cpp
+++ b/src/qml/doc/snippets/code/backend/main.cpp
@@ -1,64 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [main_cpp]
#include <QGuiApplication>
#include <QQmlApplicationEngine>
-#include "backend.h"
-
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
- qmlRegisterType<BackEnd>("io.qt.examples.backend", 1, 0, "BackEnd");
-
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
diff --git a/src/qml/doc/snippets/code/backend/main.qml b/src/qml/doc/snippets/code/backend/main.qml
index fadc9cd768..7bad89374f 100644
--- a/src/qml/doc/snippets/code/backend/main.qml
+++ b/src/qml/doc/snippets/code/backend/main.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [main_qml]
-import QtQuick 2.6
-import QtQuick.Controls 2.0
+import QtQuick
+import QtQuick.Controls
//![import]
import io.qt.examples.backend 1.0
//![import]
@@ -72,7 +25,7 @@ ApplicationWindow {
placeholderText: qsTr("User name")
anchors.centerIn: parent
- onTextChanged: backend.userName = text
+ onEditingFinished: backend.userName = text
}
//![username_input]
}
diff --git a/src/qml/doc/snippets/code/doc_src_qtqml.cmake b/src/qml/doc/snippets/code/doc_src_qtqml.cmake
new file mode 100644
index 0000000000..1d9dccc49a
--- /dev/null
+++ b/src/qml/doc/snippets/code/doc_src_qtqml.cmake
@@ -0,0 +1,13 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#! [0]
+find_package(Qt6 REQUIRED COMPONENTS Qml)
+target_link_libraries(mytarget PRIVATE Qt6::Qml)
+#! [0]
+
+#! [1]
+find_package(Qt6 REQUIRED COMPONENTS QmlIntegration)
+target_link_libraries(mytarget PRIVATE Qt6::QmlIntegration)
+#! [1]
+
diff --git a/src/qml/doc/snippets/code/doc_src_qtqml.cpp b/src/qml/doc/snippets/code/doc_src_qtqml.cpp
deleted file mode 100644
index 745e2f8f94..0000000000
--- a/src/qml/doc/snippets/code/doc_src_qtqml.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [0]
-#include <QtQml>
-//! [0]
diff --git a/src/qml/doc/snippets/code/doc_src_qtqml.pro b/src/qml/doc/snippets/code/doc_src_qtqml.pro
deleted file mode 100644
index 48dc3ebf6c..0000000000
--- a/src/qml/doc/snippets/code/doc_src_qtqml.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-#! [0]
-QT += qml
-#! [0]
diff --git a/src/qml/doc/snippets/code/src_network_access_qnetworkaccessmanager.cpp b/src/qml/doc/snippets/code/src_network_access_qnetworkaccessmanager.cpp
new file mode 100644
index 0000000000..b200261035
--- /dev/null
+++ b/src/qml/doc/snippets/code/src_network_access_qnetworkaccessmanager.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [0]
+class CachingNetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory
+{
+public:
+
+ inline QNetworkAccessManager *create(QObject *parent) override
+ {
+ QNetworkAccessManager *networkAccessManager = new QNetworkAccessManager(parent);
+ QNetworkDiskCache *diskCache = new QNetworkDiskCache(parent);
+ diskCache->setCacheDirectory("requestCache");
+ networkAccessManager->setCache(diskCache);
+
+ return networkAccessManager;
+ }
+};
+//! [0]
+
+//! [1]
+CachingNetworkAccessManagerFactory networkManagerFactory;
+engine->setNetworkAccessManagerFactory(&networkManagerFactory);
+//! [1]
diff --git a/src/qml/doc/snippets/code/src_qml_qqmlengine.cpp b/src/qml/doc/snippets/code/src_qml_qqmlengine.cpp
new file mode 100644
index 0000000000..ff4cf634a0
--- /dev/null
+++ b/src/qml/doc/snippets/code/src_qml_qqmlengine.cpp
@@ -0,0 +1,51 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [0]
+class MySingleton : public QObject {
+ Q_OBJECT
+
+ // Register as default constructed singleton.
+ QML_ELEMENT
+ QML_SINGLETON
+
+ static int typeId;
+ // ...
+};
+//! [0]
+
+/*
+//! [1]
+ MySingleton::typeId = qmlTypeId(...);
+//! [1]
+*/
+
+void wrapper2() {
+//! [2]
+ // Retrieve as QObject*
+ QQmlEngine engine;
+ MySingleton* instance = engine.singletonInstance<MySingleton*>(MySingleton::typeId);
+//! [2]
+}
+
+/*
+//! [3]
+ // Register with QJSValue callback
+ int typeId = qmlRegisterSingletonType(...);
+//! [3]
+*/
+
+void wrapper4(int typeId) {
+//! [4]
+ // Retrieve as QJSValue
+ QQmlEngine engine;
+ QJSValue instance = engine.singletonInstance<QJSValue>(typeId);
+//! [4]
+}
+
+void wrapper5() {
+///! [5]
+ QQmlEngine engine;
+ MySingleton *singleton = engine.singletonInstance<MySingleton *>("mymodule", "MySingleton");
+///! [5]
+}
diff --git a/src/qml/doc/snippets/code/src_qml_qqmllist.cpp b/src/qml/doc/snippets/code/src_qml_qqmllist.cpp
new file mode 100644
index 0000000000..69c7fd9f22
--- /dev/null
+++ b/src/qml/doc/snippets/code/src_qml_qqmllist.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+namespace DocWrapper0 {
+//! [0]
+class FruitBasket : QObject {
+ Q_OBJECT
+ QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
+ Q_PROPERTY(QQmlListProperty<Fruit> fruit READ fruit)
+
+ public:
+ // ...
+ QQmlListProperty<Fruit> fruit();
+ // ...
+};
+//! [0]
+}
+
+namespace DocWrapper1 {
+//! [1]
+class FruitBasket : QObject {
+ Q_OBJECT
+ QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
+ Q_PROPERTY(QQmlListProperty<Fruit> fruit READ fruit)
+
+ public:
+ // ...
+ QQmlListProperty<Fruit> fruit();
+ // ...
+};
+//! [1]
+}
+
+namespace DocWrapper2 {
+//! [2]
+class FruitBasket : QObject {
+ Q_OBJECT
+ QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
+ Q_PROPERTY(QQmlListProperty<Fruit> fruit READ fruit)
+
+ public:
+ // ...
+ QQmlListProperty<Fruit> fruit();
+ // ...
+};
+//! [2]
+}
diff --git a/src/qml/doc/snippets/code/src_qml_qqmlparserstatus.cpp b/src/qml/doc/snippets/code/src_qml_qqmlparserstatus.cpp
new file mode 100644
index 0000000000..980b81a056
--- /dev/null
+++ b/src/qml/doc/snippets/code/src_qml_qqmlparserstatus.cpp
@@ -0,0 +1,19 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtCore/qobject.h>
+#include <QtQml/qqmlparserstatus.h>
+
+//! [0]
+class MyObject : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+
+public:
+ MyObject(QObject *parent = nullptr);
+ // ...
+ void classBegin() override;
+ void componentComplete() override;
+};
+//! [0]
diff --git a/src/qml/doc/snippets/code/src_script_qjsengine.cpp b/src/qml/doc/snippets/code/src_script_qjsengine.cpp
index 6c58fd8a18..c92db44ce7 100644
--- a/src/qml/doc/snippets/code/src_script_qjsengine.cpp
+++ b/src/qml/doc/snippets/code/src_script_qjsengine.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QJSEngine myEngine;
diff --git a/src/qml/doc/snippets/code/src_script_qjsvalue.cpp b/src/qml/doc/snippets/code/src_script_qjsvalue.cpp
index 1386ffb760..7922b40e40 100644
--- a/src/qml/doc/snippets/code/src_script_qjsvalue.cpp
+++ b/src/qml/doc/snippets/code/src_script_qjsvalue.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QJSEngine myEngine;
diff --git a/src/qml/doc/snippets/code/src_script_qjsvalueiterator.cpp b/src/qml/doc/snippets/code/src_script_qjsvalueiterator.cpp
index 3cb43bc327..9316317c40 100644
--- a/src/qml/doc/snippets/code/src_script_qjsvalueiterator.cpp
+++ b/src/qml/doc/snippets/code/src_script_qjsvalueiterator.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QJSValue object;
diff --git a/src/qml/doc/snippets/qml/Button.qml b/src/qml/doc/snippets/qml/Button.qml
index 964bebb575..aacce0c37a 100644
--- a/src/qml/doc/snippets/qml/Button.qml
+++ b/src/qml/doc/snippets/qml/Button.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [document]
-import QtQuick 2.0
+import QtQuick
//! [parent begin]
Rectangle {
diff --git a/src/qml/doc/snippets/qml/CMakeLists.txt b/src/qml/doc/snippets/qml/CMakeLists.txt
new file mode 100644
index 0000000000..717f153e7d
--- /dev/null
+++ b/src/qml/doc/snippets/qml/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+qt_add_library(extra_module STATIC)
+qt_add_qml_module(extra_module
+ URI "ExtraModule"
+ VERSION 1.0
+ QML_FILES
+ Extra.qml
+ SOURCES
+ extrathing.cpp extrathing.h
+ RESOURCE_PREFIX /
+)
+
+add_subdirectory(ExtraModule)
diff --git a/src/qml/doc/snippets/qml/DynamicText.qml b/src/qml/doc/snippets/qml/DynamicText.qml
index e8068a7a16..93b614a628 100644
--- a/src/qml/doc/snippets/qml/DynamicText.qml
+++ b/src/qml/doc/snippets/qml/DynamicText.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
+import QtQuick
Text {
id: textElement
diff --git a/src/qml/doc/snippets/qml/MajorProject-CMakeLists.txt b/src/qml/doc/snippets/qml/MajorProject-CMakeLists.txt
new file mode 100644
index 0000000000..3e5cbd4565
--- /dev/null
+++ b/src/qml/doc/snippets/qml/MajorProject-CMakeLists.txt
@@ -0,0 +1,23 @@
+
+set_source_files_properties(Thing.qml
+ PROPERTIES
+ QT_QML_SOURCE_VERSIONS "1.4;2.0;3.0"
+)
+
+set_source_files_properties(OtherThing.qml
+ PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.2;3.0"
+)
+
+qt_add_qml_module(my_module
+ URI MyModule
+ VERSION 3.2
+ PAST_MAJOR_VERSIONS
+ 1 2
+ QML_FILES
+ Thing.qml
+ OtherThing.qml
+ OneMoreThing.qml
+ SOURCES
+ everything.cpp everything.h
+)
diff --git a/src/qml/doc/snippets/qml/SelfDestroyingRect.qml b/src/qml/doc/snippets/qml/SelfDestroyingRect.qml
index ebbca20a96..b31c0857ba 100644
--- a/src/qml/doc/snippets/qml/SelfDestroyingRect.qml
+++ b/src/qml/doc/snippets/qml/SelfDestroyingRect.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
+import QtQuick
Rectangle {
id: rect
diff --git a/src/qml/doc/snippets/qml/Sprite.qml b/src/qml/doc/snippets/qml/Sprite.qml
index 60d046c77d..fc0032c4f7 100644
--- a/src/qml/doc/snippets/qml/Sprite.qml
+++ b/src/qml/doc/snippets/qml/Sprite.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
+import QtQuick
Rectangle { width: 80; height: 50; color: "red" }
//![0]
diff --git a/src/qml/doc/snippets/qml/XHRForm.qml b/src/qml/doc/snippets/qml/XHRForm.qml
new file mode 100644
index 0000000000..90c918ddbb
--- /dev/null
+++ b/src/qml/doc/snippets/qml/XHRForm.qml
@@ -0,0 +1,83 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//![0]
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import "request.js" as XHR
+
+ApplicationWindow {
+ width: 640
+ height: 640
+ visible: true
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ RowLayout {
+ Layout.fillWidth: true
+
+ TextField {
+ id: urlTextField
+ text: "https://www.example.com/index.html"
+ Layout.fillWidth: true
+ }
+ Button {
+ text: qsTr("Send!")
+ onClicked: XHR.sendRequest(urlTextField.text, function(response) {
+ statusTextField.text = response.status;
+ let isPlainText = response.contentType.length === 0
+
+ contentTypeTextField.text = isPlainText ? "text" : response.contentType;
+
+ if (isPlainText)
+ contentTextArea.text = response.content;
+ });
+ }
+ }
+
+ GridLayout {
+ columns: 2
+
+ Layout.fillWidth: true
+
+ Label {
+ text: qsTr("Status code")
+
+ Layout.fillWidth: true
+ }
+ Label {
+ text: qsTr("Response type")
+
+ Layout.fillWidth: true
+ }
+ TextField {
+ id: statusTextField
+
+ Layout.fillWidth: true
+ }
+ TextField {
+ id: contentTypeTextField
+
+ Layout.fillWidth: true
+ }
+ }
+ Flickable {
+ clip: true
+ contentWidth: contentTextArea.width
+ contentHeight: contentTextArea.height
+ Text {
+ id: contentTextArea
+ }
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ ScrollBar.vertical: ScrollBar {}
+ ScrollBar.horizontal: ScrollBar {}
+ }
+ }
+}
+
+//![0]
+
diff --git a/src/qml/doc/snippets/qml/application.qml b/src/qml/doc/snippets/qml/application.qml
index 3deccf4a00..a7eb91c37c 100644
--- a/src/qml/doc/snippets/qml/application.qml
+++ b/src/qml/doc/snippets/qml/application.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [document]
-import QtQuick 2.0
+import QtQuick
Rectangle {
width: 300; height: 55
diff --git a/src/qml/doc/snippets/qml/comments.qml b/src/qml/doc/snippets/qml/comments.qml
index a6a5280d56..aa01bf110b 100644
--- a/src/qml/doc/snippets/qml/comments.qml
+++ b/src/qml/doc/snippets/qml/comments.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
Text {
diff --git a/src/qml/doc/snippets/qml/component.qml b/src/qml/doc/snippets/qml/component.qml
index ea2ae75fc5..c166d87fa5 100644
--- a/src/qml/doc/snippets/qml/component.qml
+++ b/src/qml/doc/snippets/qml/component.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
+import QtQuick
Item {
width: 100; height: 100
diff --git a/src/qml/doc/snippets/qml/component/MyItem.qml b/src/qml/doc/snippets/qml/component/MyItem.qml
index 482a2ad833..7a3290ffa6 100644
--- a/src/qml/doc/snippets/qml/component/MyItem.qml
+++ b/src/qml/doc/snippets/qml/component/MyItem.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
Item {
diff --git a/src/qml/doc/snippets/qml/component/main.qml b/src/qml/doc/snippets/qml/component/main.qml
index a58e66b2d4..a76471dce2 100644
--- a/src/qml/doc/snippets/qml/component/main.qml
+++ b/src/qml/doc/snippets/qml/component/main.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
ListView {
diff --git a/src/qml/doc/snippets/qml/createComponent-simple.qml b/src/qml/doc/snippets/qml/createComponent-simple.qml
index 887890fcfa..2adc1c49f2 100644
--- a/src/qml/doc/snippets/qml/createComponent-simple.qml
+++ b/src/qml/doc/snippets/qml/createComponent-simple.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
+import QtQuick
Item {
id: container
diff --git a/src/qml/doc/snippets/qml/createComponent.qml b/src/qml/doc/snippets/qml/createComponent.qml
index e79835af77..f71526fc70 100644
--- a/src/qml/doc/snippets/qml/createComponent.qml
+++ b/src/qml/doc/snippets/qml/createComponent.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
+import QtQuick
import "componentCreation.js" as MyScript
Rectangle {
diff --git a/src/qml/doc/snippets/qml/createQmlObject.qml b/src/qml/doc/snippets/qml/createQmlObject.qml
index 8a082a71de..32d9e8cff2 100644
--- a/src/qml/doc/snippets/qml/createQmlObject.qml
+++ b/src/qml/doc/snippets/qml/createQmlObject.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
Rectangle {
id: parentItem
@@ -58,9 +11,18 @@ Rectangle {
function createIt() {
//![0]
-var newObject = Qt.createQmlObject('import QtQuick 2.0; Rectangle {color: "red"; width: 20; height: 20}',
- parentItem,
- "dynamicSnippet1");
+const newObject = Qt.createQmlObject(`
+ import QtQuick
+
+ Rectangle {
+ color: "red"
+ width: 20
+ height: 20
+ }
+ `,
+ parentItem,
+ "myDynamicSnippet"
+);
//![0]
//![destroy]
diff --git a/src/qml/doc/snippets/qml/dynamicObjects-destroy.qml b/src/qml/doc/snippets/qml/dynamicObjects-destroy.qml
index fbf5d856f4..91db58f7bb 100644
--- a/src/qml/doc/snippets/qml/dynamicObjects-destroy.qml
+++ b/src/qml/doc/snippets/qml/dynamicObjects-destroy.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
+import QtQuick
Item {
id: container
diff --git a/src/qml/doc/snippets/qml/events.qml b/src/qml/doc/snippets/qml/events.qml
index f437e32890..3e5171102a 100644
--- a/src/qml/doc/snippets/qml/events.qml
+++ b/src/qml/doc/snippets/qml/events.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![document]
-import QtQuick 2.0
+import QtQuick
//![parent begin]
Rectangle {
@@ -66,7 +19,7 @@ Rectangle {
//! [signal handler declaration]
onTrigger: console.log("trigger signal emitted")
-onSend: {
+onSend: (notice)=> {
console.log("send signal emitted with notice: " + notice)
}
@@ -90,7 +43,7 @@ Rectangle {
signal send(person: string, notice: string)
- onSend: {
+ onSend: (person, notice)=> {
console.log("For " + person + ", the notice is: " + notice)
}
@@ -103,7 +56,7 @@ Rectangle {
id: relay
signal send(person: string, notice: string)
- onSend: console.log("Send signal to: " + person + ", " + notice)
+ onSend: (person, notice)=> console.log("Send signal to: " + person + ", " + notice)
Component.onCompleted: {
relay.send.connect(sendToPost)
diff --git a/src/qml/doc/snippets/qml/exposing-state/RequiredProperties.qml b/src/qml/doc/snippets/qml/exposing-state/RequiredProperties.qml
new file mode 100644
index 0000000000..18425930de
--- /dev/null
+++ b/src/qml/doc/snippets/qml/exposing-state/RequiredProperties.qml
@@ -0,0 +1,23 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+//![0]
+pragma ComponentBehavior: Bound
+
+import QtQuick
+
+Window {
+ id: root
+ visible: true
+
+ required property int thing
+
+ Text {
+ anchors.fill: parent
+ text: "The thing is " + root.thing
+ }
+
+ component Inner: QtObject {
+ objectName: "I can see " + root.thing + " because I'm bound."
+ }
+}
+//![0]
diff --git a/src/qml/doc/snippets/qml/exposing-state/createWithInitialProperties.cpp b/src/qml/doc/snippets/qml/exposing-state/createWithInitialProperties.cpp
new file mode 100644
index 0000000000..1e5f1859f9
--- /dev/null
+++ b/src/qml/doc/snippets/qml/exposing-state/createWithInitialProperties.cpp
@@ -0,0 +1,23 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtGui/qguiapplication.h>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+//![0]
+ QQmlEngine engine;
+
+ QQmlComponent component(&engine, "MyModule", "RequiredProperties");
+ QScopedPointer<QObject> o(component.createWithInitialProperties({
+ {"thing", 11}
+ }));
+//![0]
+
+ return app.exec();
+}
diff --git a/src/qml/doc/snippets/qml/exposing-state/singleton.h b/src/qml/doc/snippets/qml/exposing-state/singleton.h
new file mode 100644
index 0000000000..e600531883
--- /dev/null
+++ b/src/qml/doc/snippets/qml/exposing-state/singleton.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SINGLETON_H
+#define SINGLETON_H
+
+#include <QtQml/qobject.h>
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlengine.h>
+
+//![0]
+// Singleton.h
+class Singleton : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int thing READ thing WRITE setThing NOTIFY thingChanged FINAL)
+ QML_ELEMENT
+ QML_SINGLETON
+
+public:
+ Singleton(QObject *parent = nullptr) : QObject(parent) {}
+
+ int thing() const { return m_value; }
+ void setThing(int v)
+ {
+ if (v != m_value) {
+ m_value = v;
+ emit thingChanged();
+ }
+ }
+
+signals:
+ void thingChanged();
+
+private:
+ int m_value = 12;
+};
+//![0]
+
+inline void setTheThing(QQmlEngine *engine)
+{
+//![1]
+ Singleton *singleton
+ = engine->singletonInstance<Singleton *>("MyModule", "Singleton");
+ singleton->setThing(77);
+//![1]
+}
+
+#endif
diff --git a/src/qml/doc/snippets/qml/exposing-state/useSingleton.qml b/src/qml/doc/snippets/qml/exposing-state/useSingleton.qml
new file mode 100644
index 0000000000..a9021a9241
--- /dev/null
+++ b/src/qml/doc/snippets/qml/exposing-state/useSingleton.qml
@@ -0,0 +1,9 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+//![0]
+import QtQml
+
+QtObject {
+ objectName: "The thing is " + Singleton.thing
+}
+//![0]
diff --git a/src/qml/doc/snippets/qml/imports/chart.qml b/src/qml/doc/snippets/qml/imports/chart.qml
index 6f205b952b..67c6fbcee5 100644
--- a/src/qml/doc/snippets/qml/imports/chart.qml
+++ b/src/qml/doc/snippets/qml/imports/chart.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [import]
import Charts 1.0
diff --git a/src/qml/doc/snippets/qml/imports/installed-module.qml b/src/qml/doc/snippets/qml/imports/installed-module.qml
index b0d0e0bb5d..fa8534b4f8 100644
--- a/src/qml/doc/snippets/qml/imports/installed-module.qml
+++ b/src/qml/doc/snippets/qml/imports/installed-module.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [imports]
-import QtQuick 2.0
+import QtQuick
import com.nokia.qml.mymodule 1.0
//! [imports]
diff --git a/src/qml/doc/snippets/qml/imports/merged-named-imports.qml b/src/qml/doc/snippets/qml/imports/merged-named-imports.qml
index 8fab0436bd..9a89468fcd 100644
--- a/src/qml/doc/snippets/qml/imports/merged-named-imports.qml
+++ b/src/qml/doc/snippets/qml/imports/merged-named-imports.qml
@@ -1,56 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [imports]
-import QtQuick 2.0 as Project
-import QtMultimedia 5.0 as Project
+import QtQuick as Project
+import QtMultimedia as Project
Project.Rectangle {
width: 100; height: 50
diff --git a/src/qml/doc/snippets/qml/imports/named-imports.qml b/src/qml/doc/snippets/qml/imports/named-imports.qml
deleted file mode 100644
index b4141ba829..0000000000
--- a/src/qml/doc/snippets/qml/imports/named-imports.qml
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [imports]
-import QtQuick 2.0 as QtLibrary
-import "../MyComponents" as MyComponents
-import com.nokia.qml.mymodule 1.0 as MyModule
-//! [imports]
-
-Item {
- //! [imported items]
- QtLibrary.Rectangle {
- // ...
- }
-
- MyComponents.Slider {
- // ...
- }
-
- MyModule.SomeComponent {
- // ...
- }
- //! [imported items]
-}
diff --git a/src/qml/doc/snippets/qml/imports/network-imports.qml b/src/qml/doc/snippets/qml/imports/network-imports.qml
index 08cd784eb8..f707cfb360 100644
--- a/src/qml/doc/snippets/qml/imports/network-imports.qml
+++ b/src/qml/doc/snippets/qml/imports/network-imports.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [imports]
import "http://www.my-server.com/MyQMLProject/MyComponents"
diff --git a/src/qml/doc/snippets/qml/imports/qtquick-1.0.qml b/src/qml/doc/snippets/qml/imports/qtquick-1.0.qml
index 26df4de76b..7a1d3d85a7 100644
--- a/src/qml/doc/snippets/qml/imports/qtquick-1.0.qml
+++ b/src/qml/doc/snippets/qml/imports/qtquick-1.0.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [import]
-import QtQuick 2.0
+import QtQuick
//! [import]
Item {
diff --git a/src/qml/doc/snippets/qml/imports/timeexample.qml b/src/qml/doc/snippets/qml/imports/timeexample.qml
index bff92e1310..18a432a0e0 100644
--- a/src/qml/doc/snippets/qml/imports/timeexample.qml
+++ b/src/qml/doc/snippets/qml/imports/timeexample.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [import]
import TimeExample 1.0
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/connectjs.qml b/src/qml/doc/snippets/qml/integrating-javascript/connectjs.qml
index 3f50c67aba..a83f9466d8 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/connectjs.qml
+++ b/src/qml/doc/snippets/qml/integrating-javascript/connectjs.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.12
+import QtQuick
import "script.js" as MyScript
Item {
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/includejs/app.qml b/src/qml/doc/snippets/qml/integrating-javascript/includejs/app.qml
index e2104f8740..84c35c4900 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/includejs/app.qml
+++ b/src/qml/doc/snippets/qml/integrating-javascript/includejs/app.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
+import QtQuick
import "script.mjs" as MyScript
Item {
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/includejs/factorial.mjs b/src/qml/doc/snippets/qml/integrating-javascript/includejs/factorial.mjs
index d0a09b68ad..a15695e97b 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/includejs/factorial.mjs
+++ b/src/qml/doc/snippets/qml/integrating-javascript/includejs/factorial.mjs
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// factorial.mjs
export function factorial(a) {
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs b/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs
index ef7688693d..7a5e362be7 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs
+++ b/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs
@@ -1,57 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-// script.js
+// script.mjs
import { factorial } from "factorial.mjs"
+export { factorial }
-function showCalculations(value) {
+export function showCalculations(value) {
console.log(
"Call factorial() from script.js:",
factorial(value));
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.cpp b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.cpp
index d74cc13d04..48f2beeef0 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.cpp
+++ b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.cpp
@@ -1,134 +1,105 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "avatarExample.h"
#include <QQmlEngine>
#include <QQmlComponent>
+#include <QGuiApplication>
-void registerTypes()
+struct Expectations
{
-//![0]
- qmlRegisterType<AvatarExample>("Qt.example", 1, 0, "AvatarExample");
-//![0]
-}
+ QQmlEngine engine;
-void expectOne()
-{
+ void expectOne()
+ {
//![1]
-QQmlComponent component(&engine, "exampleOne.qml");
-QObject *object = component.create();
-// The scarce resource will have been released automatically
-// by this point, after the binding expression was evaluated.
-delete object;
+ QQmlComponent component(&engine, "qrc:/exampleOne.qml");
+ QObject *object = component.create();
+ // The scarce resource will have been released automatically
+ // by this point, after the binding expression was evaluated.
+ bool expectedResult = (object->property("avatarWidth").toInt() == 100);
+ delete object;
//![1]
-}
+ Q_ASSERT(expectedResult);
+ }
-void expectTwo()
-{
+ void expectTwo()
+ {
//![2]
-QQmlComponent component(&engine, "exampleTwo.qml");
-QObject *object = component.create();
-// The scarce resource will not have been released automatically
-// after the binding expression was evaluated.
-// Since the scarce resource was not released explicitly prior
-// to the binding expression being evaluated, we get:
-bool expectedResult = (object->property("avatar").isValid() == true);
-delete object;
+ QQmlComponent component(&engine, "qrc:/exampleTwo.qml");
+ QObject *object = component.create();
+ // The scarce resource will not have been released automatically
+ // after the binding expression was evaluated.
+ // Since the scarce resource was not released explicitly prior
+ // to the binding expression being evaluated, we get:
+ bool expectedResult = (object->property("avatar").isValid() == true);
+ delete object;
//![2]
-}
+ Q_ASSERT(expectedResult);
+ }
-void expectThree()
-{
+ void expectThree()
+ {
//![3]
-QQmlComponent component(&engine, "exampleThree.qml");
-QObject *object = component.create();
-// The resource was preserved explicitly during evaluation of the
-// JavaScript expression. Thus, during property assignment, the
-// scarce resource was still valid, and so we get:
-bool expectedResult = (object->property("avatar").isValid() == true);
-// The scarce resource will not be released until all references to
-// the resource are released, and the JavaScript garbage collector runs.
-delete object;
+ QQmlComponent component(&engine, "qrc:/exampleThree.qml");
+ QObject *object = component.create();
+ // The resource was preserved explicitly during evaluation of the
+ // JavaScript expression. Thus, during property assignment, the
+ // scarce resource was still valid, and so we get:
+ bool expectedResult = (object->property("avatar").isValid() == true);
+ // The scarce resource will not be released until all references to
+ // the resource are released, and the JavaScript garbage collector runs.
+ delete object;
//![3]
-}
+ Q_ASSERT(expectedResult);
+ }
-void expectFour()
-{
+ void expectFour()
+ {
//![4]
-QQmlComponent component(&engine, "exampleFour.qml");
-QObject *object = component.create();
-// The scarce resource was explicitly preserved by the client during
-// the importAvatar() function, and so the scarce resource
-// remains valid until the explicit call to releaseAvatar(). As such,
-// we get the expected results:
-bool expectedResultOne = (object->property("avatarOne").isValid() == true);
-bool expectedResultTwo = (object->property("avatarTwo").isValid() == false);
-// Because the scarce resource referenced by avatarTwo was released explicitly,
-// it will no longer be consuming any system resources (beyond what a normal
-// JS Object would; that small overhead will exist until the JS GC runs, as per
-// any other JavaScript object).
-delete object;
+ QQmlComponent component(&engine, "qrc:/exampleFour.qml");
+ QObject *object = component.create();
+ // The scarce resource was explicitly preserved by the client during
+ // the importAvatar() function, and so the scarce resource
+ // remains valid until the explicit call to releaseAvatar(). As such,
+ // we get the expected results:
+ bool expectedResultOne = (object->property("avatarOne").isValid() == true);
+ bool expectedResultTwo = (object->property("avatarTwo").isValid() == false);
+ // Because the scarce resource referenced by avatarTwo was released explicitly,
+ // it will no longer be consuming any system resources (beyond what a normal
+ // JS Object would; that small overhead will exist until the JS GC runs, as per
+ // any other JavaScript object).
+ delete object;
//![4]
-}
+ Q_ASSERT(expectedResultOne);
+ Q_ASSERT(expectedResultTwo);
+ }
-void expectFive()
-{
+ void expectFive()
+ {
//![5]
-QQmlComponent component(&engine, "exampleFive.qml");
-QObject *object = component.create();
-// We have the expected results:
-bool expectedResultOne = (object->property("avatarOne").isValid() == false);
-bool expectedResultTwo = (object->property("avatarTwo").isValid() == false);
-// Because although only avatarTwo was explicitly released,
-// avatarOne and avatarTwo were referencing the same
-// scarce resource.
-delete object;
+ QQmlComponent component(&engine, "qrc:/exampleFive.qml");
+ QObject *object = component.create();
+ // We have the expected results:
+ bool expectedResultOne = (object->property("avatarOne").isValid() == false);
+ bool expectedResultTwo = (object->property("avatarTwo").isValid() == false);
+ // Because although only avatarTwo was explicitly released,
+ // avatarOne and avatarTwo were referencing the same
+ // scarce resource.
+ delete object;
//![5]
+ Q_ASSERT(expectedResultOne);
+ Q_ASSERT(expectedResultTwo);
+ }
+};
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+ Expectations expectations;
+ expectations.expectOne();
+ expectations.expectTwo();
+ expectations.expectThree();
+ expectations.expectFour();
+ expectations.expectFive();
}
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.h b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.h
index fb9e238512..3b3f4f7537 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.h
+++ b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/avatarExample.h
@@ -1,58 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef AVATAREXAMPLE_P_H
#define AVATAREXAMPLE_P_H
#include <QObject>
#include <QPixmap>
+#include <qqml.h>
//![0]
// avatarExample.h
@@ -60,8 +14,10 @@ class AvatarExample : public QObject
{
Q_OBJECT
Q_PROPERTY(QPixmap avatar READ avatar WRITE setAvatar NOTIFY avatarChanged)
+ QML_ELEMENT
+
public:
- AvatarExample(QObject *parent = 0)
+ AvatarExample(QObject *parent = nullptr)
: QObject(parent), m_value(100, 100)
{
m_value.fill(Qt::blue);
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFive.qml b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFive.qml
index 5b90336775..d72de68a23 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFive.qml
+++ b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFive.qml
@@ -1,56 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// exampleFive.qml
-import QtQuick 2.0
-import Qt.example 1.0
+import QtQuick
+import Qt.example
import "exampleFour.js" as ExampleFourJs // use factory from example four
QtObject {
@@ -61,4 +14,4 @@ QtObject {
ExampleFourJs.releaseAvatar(avatarTwo);
}
}
-//![0] \ No newline at end of file
+//![0]
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFour.js b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFour.js
index 7b1e37b03f..569f29f751 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFour.js
+++ b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFour.js
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// exampleFour.js
.import Qt.example 1.0 as QtExample
@@ -63,4 +16,4 @@ function importAvatar() {
function releaseAvatar(avatar) {
avatar.destroy();
}
-//![0] \ No newline at end of file
+//![0]
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFour.qml b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFour.qml
index 92e0805114..2002ed394b 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFour.qml
+++ b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleFour.qml
@@ -1,56 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// exampleFour.qml
-import QtQuick 2.0
-import Qt.example 1.0
+import QtQuick
+import Qt.example
import "exampleFour.js" as ExampleFourJs
QtObject {
@@ -63,4 +16,4 @@ QtObject {
ExampleFourJs.releaseAvatar(avatarTwo);
}
}
-//![0] \ No newline at end of file
+//![0]
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleOne.qml b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleOne.qml
index 47963bf0b0..76b161fe26 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleOne.qml
+++ b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleOne.qml
@@ -1,56 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// exampleOne.qml
-import QtQuick 2.0
-import Qt.example 1.0
+import QtQuick
+import Qt.example
QtObject {
property AvatarExample a;
@@ -61,4 +14,4 @@ QtObject {
// E.g., you could imagine some js function which takes
// an avatar, and returns the width of the avatar.
}
-//![0] \ No newline at end of file
+//![0]
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleThree.js b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleThree.js
index 3700a072ea..70b24f8698 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleThree.js
+++ b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleThree.js
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// exampleThree.js
.import Qt.example 1.0 as QtExample
@@ -65,4 +18,4 @@ retn.preserve();
function importAvatar() {
return retn;
}
-//![0] \ No newline at end of file
+//![0]
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleThree.qml b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleThree.qml
index 579e17fa20..286ff8aaef 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleThree.qml
+++ b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleThree.qml
@@ -1,59 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// exampleThree.qml
-import QtQuick 2.0
-import Qt.example 1.0
+import QtQuick
+import Qt.example
import "exampleThree.js" as ExampleThreeJs
QtObject {
property var avatar: ExampleThreeJs.importAvatar()
}
-//![0] \ No newline at end of file
+//![0]
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleTwo.qml b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleTwo.qml
index e222d03c2d..dcfe6e4cd0 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleTwo.qml
+++ b/src/qml/doc/snippets/qml/integrating-javascript/scarceresources/exampleTwo.qml
@@ -1,56 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// exampleTwo.qml
-import QtQuick 2.0
-import Qt.example 1.0
+import QtQuick
+import Qt.example
QtObject {
property AvatarExample a;
@@ -58,4 +11,4 @@ QtObject {
property var avatar: example.avatar
// Now `avatar' contains a reference to the scarce resource.
}
-//![0] \ No newline at end of file
+//![0]
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/script.js b/src/qml/doc/snippets/qml/integrating-javascript/script.js
index f5843a8bad..91bfe8aded 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/script.js
+++ b/src/qml/doc/snippets/qml/integrating-javascript/script.js
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// script.js
diff --git a/src/qml/doc/snippets/qml/myProject-CMakeLists.txt b/src/qml/doc/snippets/qml/myProject-CMakeLists.txt
new file mode 100644
index 0000000000..49c63a1513
--- /dev/null
+++ b/src/qml/doc/snippets/qml/myProject-CMakeLists.txt
@@ -0,0 +1,13 @@
+qt_add_executable(main_program main.cpp)
+
+qt_add_qml_module(main_program
+ VERSION 1.0
+ URI myProject
+ QML_FILES
+ main.qml
+ SOURCES
+ onething.cpp onething.h
+
+)
+
+target_link_libraries(main_program PRIVATE extra_moduleplugin)
diff --git a/src/qml/doc/snippets/qml/myimageprovider.txt b/src/qml/doc/snippets/qml/myimageprovider.txt
new file mode 100644
index 0000000000..4605734398
--- /dev/null
+++ b/src/qml/doc/snippets/qml/myimageprovider.txt
@@ -0,0 +1,15 @@
+qt_add_qml_module(imageproviderplugin
+ VERSION 1.0
+ URI "ImageProvider"
+ PLUGIN_TARGET imageproviderplugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ CLASS_NAME ImageProviderExtensionPlugin
+ QML_FILES
+ AAA.qml
+ BBB.qml
+ SOURCES
+ moretypes.cpp moretypes.h
+ myimageprovider.cpp myimageprovider.h
+ plugin.cpp
+)
diff --git a/src/qml/doc/snippets/qml/plugin.cpp.txt b/src/qml/doc/snippets/qml/plugin.cpp.txt
new file mode 100644
index 0000000000..02d1112a4a
--- /dev/null
+++ b/src/qml/doc/snippets/qml/plugin.cpp.txt
@@ -0,0 +1,14 @@
+#include <myimageprovider.h>
+#include <QtQml/qqmlextensionplugin.h>
+
+class ImageProviderExtensionPlugin : public QQmlEngineExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid)
+public:
+ void initializeEngine(QQmlEngine *engine, const char *uri) final
+ {
+ Q_UNUSED(uri);
+ engine->addImageProvider("myimg", new MyImageProvider);
+ }
+};
diff --git a/src/qml/doc/snippets/qml/properties.qml b/src/qml/doc/snippets/qml/properties.qml
index e924ba5439..39f508e424 100644
--- a/src/qml/doc/snippets/qml/properties.qml
+++ b/src/qml/doc/snippets/qml/properties.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [document]
-import QtQuick 2.0
+import QtQuick
//! [parent begin]
Rectangle {
@@ -132,8 +85,7 @@ Rectangle {
states: State {
name: "WARNING"
PropertyChanges {
- target: rectangle
- color: warning.color
+ rectangle.color: warning.color
}
}
}
@@ -277,20 +229,9 @@ Button {
//! [image alias]
Item {
-id: widget
-
-//! [alias complete]
-property alias widgetLabel: label
-
-//will generate an error
-//widgetLabel.text: "Initial text"
-
-//will generate an error
-//property alias widgetLabelText: widgetLabel.text
-
-Component.onCompleted: widgetLabel.text = "Alias completed Initialization"
-//! [alias complete]
+ id: widget
+ property alias widgetLabel: label
Text {id: label}
}
diff --git a/src/qml/doc/snippets/qml/qml-documents/A.qml b/src/qml/doc/snippets/qml/qml-documents/A.qml
new file mode 100644
index 0000000000..de9894788b
--- /dev/null
+++ b/src/qml/doc/snippets/qml/qml-documents/A.qml
@@ -0,0 +1,14 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+//! [document]
+// A.qml
+import QtQuick
+
+Item {
+ id: root
+ property string message: "From A"
+ component MyInlineComponent : Item {
+ Component.onCompleted: console.log(root.message)
+ }
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/qml-documents/B.qml b/src/qml/doc/snippets/qml/qml-documents/B.qml
new file mode 100644
index 0000000000..27fce37d9f
--- /dev/null
+++ b/src/qml/doc/snippets/qml/qml-documents/B.qml
@@ -0,0 +1,11 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+// B.qml
+import QtQuick
+
+Item {
+ A.MyInlineComponent {}
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/qml-documents/Images.qml b/src/qml/doc/snippets/qml/qml-documents/Images.qml
new file mode 100644
index 0000000000..613e223b34
--- /dev/null
+++ b/src/qml/doc/snippets/qml/qml-documents/Images.qml
@@ -0,0 +1,37 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+//! [document]
+// Images.qml
+import QtQuick
+
+Item {
+ component LabeledImage: Column {
+ property alias source: image.source
+ property alias caption: text.text
+
+ Image {
+ id: image
+ width: 50
+ height: 50
+ }
+ Text {
+ id: text
+ font.bold: true
+ }
+ }
+
+ Row {
+ LabeledImage {
+ id: before
+ source: "before.png"
+ caption: "Before"
+ }
+ LabeledImage {
+ id: after
+ source: "after.png"
+ caption: "After"
+ }
+ }
+ property LabeledImage selectedImage: before
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/qml-documents/LabeledImageBox.qml b/src/qml/doc/snippets/qml/qml-documents/LabeledImageBox.qml
new file mode 100644
index 0000000000..bfc5a7b45e
--- /dev/null
+++ b/src/qml/doc/snippets/qml/qml-documents/LabeledImageBox.qml
@@ -0,0 +1,17 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+// LabeledImageBox.qml
+import QtQuick
+
+Rectangle {
+ property alias caption: image.caption
+ property alias source: image.source
+ border.width: 2
+ border.color: "black"
+ Images.LabeledImage {
+ id: image
+ }
+}
+//! [document]
diff --git a/src/qml/doc/snippets/qml/qml-documents/inline-component.qml b/src/qml/doc/snippets/qml/qml-documents/inline-component.qml
index 0b0429511f..32286790a5 100644
--- a/src/qml/doc/snippets/qml/qml-documents/inline-component.qml
+++ b/src/qml/doc/snippets/qml/qml-documents/inline-component.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [document]
-import QtQuick 2.0
+import QtQuick
Rectangle {
width: 240; height: 320;
diff --git a/src/qml/doc/snippets/qml/qml-documents/inline-text-component.qml b/src/qml/doc/snippets/qml/qml-documents/inline-text-component.qml
index 9885705308..096d060583 100644
--- a/src/qml/doc/snippets/qml/qml-documents/inline-text-component.qml
+++ b/src/qml/doc/snippets/qml/qml-documents/inline-text-component.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [document]
-import QtQuick 2.0
+import QtQuick
Rectangle {
width: 240; height: 320;
diff --git a/src/qml/doc/snippets/qml/qml-documents/non-trivial.qml b/src/qml/doc/snippets/qml/qml-documents/non-trivial.qml
index fd942bf655..9fccc3d286 100644
--- a/src/qml/doc/snippets/qml/qml-documents/non-trivial.qml
+++ b/src/qml/doc/snippets/qml/qml-documents/non-trivial.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [document]
-import QtQuick 2.0
+import QtQuick
Rectangle {
width: 240; height: 320;
diff --git a/src/qml/doc/snippets/qml/qml-documents/qmldocuments.qml b/src/qml/doc/snippets/qml/qml-documents/qmldocuments.qml
index de1106feac..b71ff6cad8 100644
--- a/src/qml/doc/snippets/qml/qml-documents/qmldocuments.qml
+++ b/src/qml/doc/snippets/qml/qml-documents/qmldocuments.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [document]
-import QtQuick 2.0
+import QtQuick
Rectangle {
property alias text: textItem.text
diff --git a/src/qml/doc/snippets/qml/qsTr.qml b/src/qml/doc/snippets/qml/qsTr.qml
index da0e35199f..c1a48c9d32 100644
--- a/src/qml/doc/snippets/qml/qsTr.qml
+++ b/src/qml/doc/snippets/qml/qsTr.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
Text { text: qsTr("hello") }
diff --git a/src/qml/doc/snippets/qml/qsTrId.1.qml b/src/qml/doc/snippets/qml/qsTrId.1.qml
index 44298cb6c6..4989adad25 100644
--- a/src/qml/doc/snippets/qml/qsTrId.1.qml
+++ b/src/qml/doc/snippets/qml/qsTrId.1.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
Text {
diff --git a/src/qml/doc/snippets/qml/qsTrId.qml b/src/qml/doc/snippets/qml/qsTrId.qml
index 1f62c9176a..b407896943 100644
--- a/src/qml/doc/snippets/qml/qsTrId.qml
+++ b/src/qml/doc/snippets/qml/qsTrId.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
Text { text: qsTrId("hello_id") }
diff --git a/src/qml/doc/snippets/qml/qsTranslate.qml b/src/qml/doc/snippets/qml/qsTranslate.qml
index bfcf496d82..fe0936b1b7 100644
--- a/src/qml/doc/snippets/qml/qsTranslate.qml
+++ b/src/qml/doc/snippets/qml/qsTranslate.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
Text { text: qsTranslate("CustomContext", "hello") }
diff --git a/src/qml/doc/snippets/qml/qtBinding.1.qml b/src/qml/doc/snippets/qml/qtBinding.1.qml
index b6327ec700..5ea94d36ab 100644
--- a/src/qml/doc/snippets/qml/qtBinding.1.qml
+++ b/src/qml/doc/snippets/qml/qtBinding.1.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
Item {
diff --git a/src/qml/doc/snippets/qml/qtBinding.2.qml b/src/qml/doc/snippets/qml/qtBinding.2.qml
index 3d5e8b57d5..57151f341f 100644
--- a/src/qml/doc/snippets/qml/qtBinding.2.qml
+++ b/src/qml/doc/snippets/qml/qtBinding.2.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
Item {
diff --git a/src/qml/doc/snippets/qml/qtBinding.3.qml b/src/qml/doc/snippets/qml/qtBinding.3.qml
index 23e04ef21d..8ec24a7c7f 100644
--- a/src/qml/doc/snippets/qml/qtBinding.3.qml
+++ b/src/qml/doc/snippets/qml/qtBinding.3.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
Item {
diff --git a/src/qml/doc/snippets/qml/qtBinding.4.qml b/src/qml/doc/snippets/qml/qtBinding.4.qml
index 1c81631f05..08f0953314 100644
--- a/src/qml/doc/snippets/qml/qtBinding.4.qml
+++ b/src/qml/doc/snippets/qml/qtBinding.4.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
Item {
diff --git a/src/qml/doc/snippets/qml/qtLater.qml b/src/qml/doc/snippets/qml/qtLater.qml
index 035929f874..cb999b09c1 100644
--- a/src/qml/doc/snippets/qml/qtLater.qml
+++ b/src/qml/doc/snippets/qml/qtLater.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
+import QtQuick
Rectangle {
width: 480
diff --git a/src/qml/doc/snippets/qml/qtTrIdNoOp.qml b/src/qml/doc/snippets/qml/qtTrIdNoOp.qml
index 9411385ecd..14d802c776 100644
--- a/src/qml/doc/snippets/qml/qtTrIdNoOp.qml
+++ b/src/qml/doc/snippets/qml/qtTrIdNoOp.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
Item {
diff --git a/src/qml/doc/snippets/qml/qtTrNoOp.qml b/src/qml/doc/snippets/qml/qtTrNoOp.qml
index fba1a50ecb..550619afd7 100644
--- a/src/qml/doc/snippets/qml/qtTrNoOp.qml
+++ b/src/qml/doc/snippets/qml/qtTrNoOp.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
Item {
diff --git a/src/qml/doc/snippets/qml/qtTranslateNoOp.qml b/src/qml/doc/snippets/qml/qtTranslateNoOp.qml
index fd840eb462..46d5dc05da 100644
--- a/src/qml/doc/snippets/qml/qtTranslateNoOp.qml
+++ b/src/qml/doc/snippets/qml/qtTranslateNoOp.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//![0]
Item {
diff --git a/src/qml/doc/snippets/qml/qtbinding/context-advanced/MyItem.qml b/src/qml/doc/snippets/qml/qtbinding/context-advanced/MyItem.qml
index 38e5eeb1bc..486b3bba42 100644
--- a/src/qml/doc/snippets/qml/qtbinding/context-advanced/MyItem.qml
+++ b/src/qml/doc/snippets/qml/qtbinding/context-advanced/MyItem.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// MyItem.qml
-import QtQuick 2.0
+import QtQuick
Text { text: applicationData.getCurrentDateTime() }
//![0]
diff --git a/src/qml/doc/snippets/qml/qtbinding/context-advanced/applicationdata.h b/src/qml/doc/snippets/qml/qtbinding/context-advanced/applicationdata.h
index c5973afafc..c35799abe2 100644
--- a/src/qml/doc/snippets/qml/qtbinding/context-advanced/applicationdata.h
+++ b/src/qml/doc/snippets/qml/qtbinding/context-advanced/applicationdata.h
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QObject>
#include <QDateTime>
diff --git a/src/qml/doc/snippets/qml/qtbinding/context-advanced/connections.qml b/src/qml/doc/snippets/qml/qtbinding/context-advanced/connections.qml
index 60adf6bc14..f769e3246c 100644
--- a/src/qml/doc/snippets/qml/qtbinding/context-advanced/connections.qml
+++ b/src/qml/doc/snippets/qml/qtbinding/context-advanced/connections.qml
@@ -1,53 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-import QtQuick 2.0
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+import QtQuick
//![0]
Text {
diff --git a/src/qml/doc/snippets/qml/qtbinding/context-advanced/main.cpp b/src/qml/doc/snippets/qml/qtbinding/context-advanced/main.cpp
index e44bcb37ac..78bc168f1c 100644
--- a/src/qml/doc/snippets/qml/qtbinding/context-advanced/main.cpp
+++ b/src/qml/doc/snippets/qml/qtbinding/context-advanced/main.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
#include <QtQuick>
diff --git a/src/qml/doc/snippets/qml/qtbinding/context/MyItem.qml b/src/qml/doc/snippets/qml/qtbinding/context/MyItem.qml
index b78ef6ee60..c03a5d26b7 100644
--- a/src/qml/doc/snippets/qml/qtbinding/context/MyItem.qml
+++ b/src/qml/doc/snippets/qml/qtbinding/context/MyItem.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// MyItem.qml
-import QtQuick 2.0
+import QtQuick
Text { text: currentDateTime }
//![0]
diff --git a/src/qml/doc/snippets/qml/qtbinding/context/main.cpp b/src/qml/doc/snippets/qml/qtbinding/context/main.cpp
index d8f7515bb3..4bfc274002 100644
--- a/src/qml/doc/snippets/qml/qtbinding/context/main.cpp
+++ b/src/qml/doc/snippets/qml/qtbinding/context/main.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
#include <QtQuick>
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 59907c38e7..b26522f3f0 100644
--- a/src/qml/doc/snippets/qml/qtbinding/functions-qml/MyItem.qml
+++ b/src/qml/doc/snippets/qml/qtbinding/functions-qml/MyItem.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// MyItem.qml
-import QtQuick 2.0
+import QtQuick
Item {
function myQmlFunction(msg: string) : string {
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 a562eae2b4..672ff3aaf2 100644
--- a/src/qml/doc/snippets/qml/qtbinding/functions-qml/main.cpp
+++ b/src/qml/doc/snippets/qml/qtbinding/functions-qml/main.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtCore>
#include <QtQuick>
diff --git a/src/qml/doc/snippets/qml/qtbinding/loading/MyItem.qml b/src/qml/doc/snippets/qml/qtbinding/loading/MyItem.qml
index c9f7b60144..a2403ce9d2 100644
--- a/src/qml/doc/snippets/qml/qtbinding/loading/MyItem.qml
+++ b/src/qml/doc/snippets/qml/qtbinding/loading/MyItem.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![start]
-import QtQuick 2.0
+import QtQuick
Item {
width: 100; height: 100
diff --git a/src/qml/doc/snippets/qml/qtbinding/loading/main.cpp b/src/qml/doc/snippets/qml/qtbinding/loading/main.cpp
index 1df6905278..f8c19a6b84 100644
--- a/src/qml/doc/snippets/qml/qtbinding/loading/main.cpp
+++ b/src/qml/doc/snippets/qml/qtbinding/loading/main.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
#include <QtQml>
#include <QtQuick>
diff --git a/src/qml/doc/snippets/qml/qtbinding/properties-qml/MyItem.qml b/src/qml/doc/snippets/qml/qtbinding/properties-qml/MyItem.qml
index 0bf0c9dddf..ff626d3837 100644
--- a/src/qml/doc/snippets/qml/qtbinding/properties-qml/MyItem.qml
+++ b/src/qml/doc/snippets/qml/qtbinding/properties-qml/MyItem.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// MyItem.qml
-import QtQuick 2.0
+import QtQuick
Item {
property int someNumber: 100
diff --git a/src/qml/doc/snippets/qml/qtbinding/properties-qml/main.cpp b/src/qml/doc/snippets/qml/qtbinding/properties-qml/main.cpp
index d55eb7e436..c2ddb75ebf 100644
--- a/src/qml/doc/snippets/qml/qtbinding/properties-qml/main.cpp
+++ b/src/qml/doc/snippets/qml/qtbinding/properties-qml/main.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtCore>
#include <QtQml>
diff --git a/src/qml/doc/snippets/qml/qtbinding/resources/example.qdoc b/src/qml/doc/snippets/qml/qtbinding/resources/example.qdoc
index b26ad10b94..88a06f54bf 100644
--- a/src/qml/doc/snippets/qml/qtbinding/resources/example.qdoc
+++ b/src/qml/doc/snippets/qml/qtbinding/resources/example.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
//![0]
<!DOCTYPE RCC>
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 aadc89b72c..9d141be179 100644
--- a/src/qml/doc/snippets/qml/qtbinding/signals-qml/MyItem.qml
+++ b/src/qml/doc/snippets/qml/qtbinding/signals-qml/MyItem.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
// MyItem.qml
-import QtQuick 2.0
+import QtQuick
Item {
id: item
diff --git a/src/qml/doc/snippets/qml/qtbinding/signals-qml/main.cpp b/src/qml/doc/snippets/qml/qtbinding/signals-qml/main.cpp
index cd4e538963..c10e2f4f5a 100644
--- a/src/qml/doc/snippets/qml/qtbinding/signals-qml/main.cpp
+++ b/src/qml/doc/snippets/qml/qtbinding/signals-qml/main.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
#include <QtQuick>
diff --git a/src/qml/doc/snippets/qml/qtbinding/signals-qml/myclass.h b/src/qml/doc/snippets/qml/qtbinding/signals-qml/myclass.h
index f584b5b792..ce1a4bc7c5 100644
--- a/src/qml/doc/snippets/qml/qtbinding/signals-qml/myclass.h
+++ b/src/qml/doc/snippets/qml/qtbinding/signals-qml/myclass.h
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QObject>
#include <QDebug>
//![0]
diff --git a/src/qml/doc/snippets/qml/qtbinding/variantlistmap/MyItem.qml b/src/qml/doc/snippets/qml/qtbinding/variantlistmap/MyItem.qml
index b0f910af17..e50ae519b0 100644
--- a/src/qml/doc/snippets/qml/qtbinding/variantlistmap/MyItem.qml
+++ b/src/qml/doc/snippets/qml/qtbinding/variantlistmap/MyItem.qml
@@ -1,53 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-import QtQuick 2.0
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+import QtQuick
//![0]
// MyItem.qml
diff --git a/src/qml/doc/snippets/qml/qtbinding/variantlistmap/main.cpp b/src/qml/doc/snippets/qml/qtbinding/variantlistmap/main.cpp
index ddd2c71a96..e435ccb389 100644
--- a/src/qml/doc/snippets/qml/qtbinding/variantlistmap/main.cpp
+++ b/src/qml/doc/snippets/qml/qtbinding/variantlistmap/main.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
#include <QtQuick>
diff --git a/src/qml/doc/snippets/qml/qtobject.qml b/src/qml/doc/snippets/qml/qtobject.qml
index 9f342e41cd..7707123511 100644
--- a/src/qml/doc/snippets/qml/qtobject.qml
+++ b/src/qml/doc/snippets/qml/qtobject.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
+import QtQuick
Item {
QtObject {
diff --git a/src/qml/doc/snippets/qml/reusablecomponents/Button.qml b/src/qml/doc/snippets/qml/reusablecomponents/Button.qml
index 1142b8abf3..5554befa3e 100644
--- a/src/qml/doc/snippets/qml/reusablecomponents/Button.qml
+++ b/src/qml/doc/snippets/qml/reusablecomponents/Button.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [document]
//contents of Button.qml
-import QtQuick 2.0
+import QtQuick
//! [parent begin]
Rectangle {
diff --git a/src/qml/doc/snippets/qml/reusablecomponents/application.qml b/src/qml/doc/snippets/qml/reusablecomponents/application.qml
index 507080d056..7c40bda2b6 100644
--- a/src/qml/doc/snippets/qml/reusablecomponents/application.qml
+++ b/src/qml/doc/snippets/qml/reusablecomponents/application.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [document]
-import QtQuick 2.0
+import QtQuick
Rectangle {
width: 175; height: 350
diff --git a/src/qml/doc/snippets/qml/reusablecomponents/component.qml b/src/qml/doc/snippets/qml/reusablecomponents/component.qml
index a2bd0cf01b..ba70f0b9e2 100644
--- a/src/qml/doc/snippets/qml/reusablecomponents/component.qml
+++ b/src/qml/doc/snippets/qml/reusablecomponents/component.qml
@@ -1,54 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [document]
-import QtQuick 2.0
+import QtQuick
//! [parent begin]
Rectangle {
diff --git a/src/qml/doc/snippets/qml/reusablecomponents/focusbutton.qml b/src/qml/doc/snippets/qml/reusablecomponents/focusbutton.qml
index f6903a6c09..be1feabe67 100644
--- a/src/qml/doc/snippets/qml/reusablecomponents/focusbutton.qml
+++ b/src/qml/doc/snippets/qml/reusablecomponents/focusbutton.qml
@@ -1,55 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [document]
//contents of focusbutton.qml
-import QtQuick 2.0
+import QtQuick
//! [parent begin]
FocusScope {
diff --git a/src/qml/doc/snippets/qml/statemachine/Button.qml b/src/qml/doc/snippets/qml/statemachine/Button.qml
deleted file mode 100644
index 38d13475a9..0000000000
--- a/src/qml/doc/snippets/qml/statemachine/Button.qml
+++ /dev/null
@@ -1,98 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-import QtQuick 2.1
-import QtQuick.Window 2.1
-
-Item {
- id: container
-
- property alias text: buttonLabel.text
- property alias label: buttonLabel
- signal clicked
- property alias containsMouse: mouseArea.containsMouse
- property alias pressed: mouseArea.pressed
- implicitHeight: Math.max(Screen.pixelDensity * 7, buttonLabel.implicitHeight * 1.2)
- implicitWidth: Math.max(Screen.pixelDensity * 11, buttonLabel.implicitWidth * 1.3)
- height: implicitHeight
- width: implicitWidth
- property bool checkable: false
- property bool checked: false
-
- SystemPalette { id: palette }
-
- Rectangle {
- id: frame
- anchors.fill: parent
- color: palette.button
- gradient: Gradient {
- GradientStop { position: 0.0; color: mouseArea.pressed ? Qt.darker(palette.button, 1.3) : palette.button }
- GradientStop { position: 1.0; color: Qt.darker(palette.button, 1.3) }
- }
- antialiasing: true
- radius: height / 6
- border.color: Qt.darker(palette.button, 1.5)
- border.width: 1
- }
-
- MouseArea {
- id: mouseArea
- anchors.fill: parent
- onClicked: container.clicked()
- hoverEnabled: true
- }
-
- Text {
- id: buttonLabel
- text: container.text
- color: palette.buttonText
- anchors.centerIn: parent
- }
-}
diff --git a/src/qml/doc/snippets/qml/statemachine/basicstate.qml b/src/qml/doc/snippets/qml/statemachine/basicstate.qml
deleted file mode 100644
index d8da3f939d..0000000000
--- a/src/qml/doc/snippets/qml/statemachine/basicstate.qml
+++ /dev/null
@@ -1,65 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ford Motor Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [document]
-import QtQuick 2.0
-import QtQml.StateMachine 1.0 as DSM
-
-Rectangle {
- DSM.StateMachine {
- id: stateMachine
- initialState: state
- running: true
- DSM.State {
- id: state
- }
- }
-}
-//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/finalstate.qml b/src/qml/doc/snippets/qml/statemachine/finalstate.qml
deleted file mode 100644
index 984daadf36..0000000000
--- a/src/qml/doc/snippets/qml/statemachine/finalstate.qml
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ford Motor Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [document]
-import QtQuick 2.0
-import QtQml.StateMachine 1.0 as DSM
-
-Rectangle {
- DSM.StateMachine {
- id: stateMachine
- initialState: state
- running: true
- DSM.State {
- id: state
- DSM.TimeoutTransition {
- targetState: finalState
- timeout: 200
- }
- }
- DSM.FinalState {
- id: finalState
- }
- onFinished: console.log("state finished")
- }
-}
-//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/guardcondition.qml b/src/qml/doc/snippets/qml/statemachine/guardcondition.qml
deleted file mode 100644
index f1ec89b6ba..0000000000
--- a/src/qml/doc/snippets/qml/statemachine/guardcondition.qml
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ford Motor Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [document]
-import QtQuick 2.0
-import QtQml.StateMachine 1.0 as DSM
-
-Rectangle {
- Button {
- anchors.fill: parent
- id: button
- DSM.StateMachine {
- DSM.State {
- DSM.SignalTransition {
- targetState: finalState
- signal: button.mysignal
- // the guard condition uses the mystr string argument from mysignal
- guard: mystr == "test"
- }
- }
- DSM.FinalState {
- id: finalState
- }
- }
- // define the signal the SignalTransition is connected with
- signal mysignal(mystr: string)
- // on clicking the button emit the signal with a single string argument
- onClicked: button.mysignal("test")
- }
-}
-//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/historystate.qml b/src/qml/doc/snippets/qml/statemachine/historystate.qml
deleted file mode 100644
index 28e4e06756..0000000000
--- a/src/qml/doc/snippets/qml/statemachine/historystate.qml
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ford Motor Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [document]
-import QtQuick 2.0
-import QtQml.StateMachine 1.0 as DSM
-
-Rectangle {
- Button {
- anchors.fill: parent
- id: button
- text: "Press me"
- DSM.StateMachine {
- id: stateMachine
- initialState: parentState
- running: true
- DSM.State {
- id: parentState
- initialState: child2
- onEntered: console.log("parentState entered")
- onExited: console.log("parentState exited")
- DSM.State {
- id: child1
- onEntered: console.log("child1 entered")
- onExited: console.log("child1 exited")
- }
- DSM.State {
- id: child2
- onEntered: console.log("child2 entered")
- onExited: console.log("child2 exited")
- }
- DSM.HistoryState {
- id: historyState
- defaultState: child1
- }
- DSM.SignalTransition {
- targetState: historyState
-
- // Clicking the button will cause the state machine to enter the child state
- // that parentState was in the last time parentState was exited, or the history state's default
- // state if parentState has never been entered.
- signal: button.clicked
- }
- }
- }
- }
-}
-//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/signaltransition.qml b/src/qml/doc/snippets/qml/statemachine/signaltransition.qml
deleted file mode 100644
index 925d728ed7..0000000000
--- a/src/qml/doc/snippets/qml/statemachine/signaltransition.qml
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ford Motor Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [document]
-import QtQuick 2.0
-import QtQml.StateMachine 1.0 as DSM
-
-Rectangle {
- DSM.StateMachine {
- id: stateMachine
- initialState: state
- running: true
- DSM.State {
- id: state
- DSM.SignalTransition {
- targetState: finalState
- signal: button.clicked
- guard: guardButton.checked
- }
- }
- DSM.FinalState {
- id: finalState
- }
- onFinished: Qt.quit()
- }
- Row {
- spacing: 2
- Button {
- id: button
- text: "Finish state"
- }
-
- Button {
- id: guardButton
- checkable: true
- text: checked ? "Press to block the SignalTransition" : "Press to unblock the SignalTransition"
- }
- }
-}
-//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/signaltransitionsignal.qml b/src/qml/doc/snippets/qml/statemachine/signaltransitionsignal.qml
deleted file mode 100644
index d5510cb44d..0000000000
--- a/src/qml/doc/snippets/qml/statemachine/signaltransitionsignal.qml
+++ /dev/null
@@ -1,72 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ford Motor Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [document]
-import QtQuick 2.0
-import QtQml.StateMachine 1.0 as DSM
-
-Rectangle {
- Button {
- anchors.fill: parent
- id: button
- DSM.StateMachine {
- DSM.State {
- DSM.SignalTransition {
- targetState: finalState
- signal: button.clicked
- }
- }
- DSM.FinalState {
- id: finalState
- }
- }
- }
-}
-//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/simplestatemachine.qml b/src/qml/doc/snippets/qml/statemachine/simplestatemachine.qml
deleted file mode 100644
index fc1768f4a0..0000000000
--- a/src/qml/doc/snippets/qml/statemachine/simplestatemachine.qml
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ford Motor Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [document]
-import QtQuick 2.0
-import QtQml.StateMachine 1.0 as DSM
-
-Rectangle {
- Button {
- anchors.fill: parent
- id: button
- text: "Finish state"
- DSM.StateMachine {
- id: stateMachine
- initialState: state
- running: true
- DSM.State {
- id: state
- DSM.SignalTransition {
- targetState: finalState
- signal: button.clicked
- }
- }
- DSM.FinalState {
- id: finalState
- }
- onFinished: Qt.quit()
- }
- }
-}
-//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/statemachine-button-history.qml b/src/qml/doc/snippets/qml/statemachine/statemachine-button-history.qml
deleted file mode 100644
index b6cd325c03..0000000000
--- a/src/qml/doc/snippets/qml/statemachine/statemachine-button-history.qml
+++ /dev/null
@@ -1,159 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ford Motor Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [document]
-import QtQuick 2.0
-import QtQml.StateMachine 1.0
-
-Rectangle {
-//![0]
- Row {
- anchors.fill: parent
- spacing: 2
- Button {
- id: button
- // change the button label to the active state id
- text: s11.active ? "s11" : s12.active ? "s12" : s13.active ? "s13" : "s3"
- }
- Button {
- id: interruptButton
- text: s1.active ? "Interrupt" : "Resume"
- }
- Button {
- id: quitButton
- text: "quit"
- }
- }
-
- StateMachine {
- id: stateMachine
- // set the initial state
- initialState: s1
-
- // start the state machine
- running: true
-
- State {
- id: s1
- // set the initial state
- initialState: s11
-
- // create a transition from s1 to s2 when the button is clicked
- SignalTransition {
- targetState: s2
- signal: quitButton.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s1 entered")
- onExited: console.log("s1 exited")
- State {
- id: s11
- // create a transition from s1 to s2 when the button is clicked
- SignalTransition {
- targetState: s12
- signal: button.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s11 entered")
- onExited: console.log("s11 exited")
- }
-
- State {
- id: s12
- // create a transition from s2 to s3 when the button is clicked
- SignalTransition {
- targetState: s13
- signal: button.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s12 entered")
- onExited: console.log("s12 exited")
- }
- State {
- id: s13
- // create a transition from s3 to s1 when the button is clicked
- SignalTransition {
- targetState: s1
- signal: button.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s13 entered")
- onExited: console.log("s13 exited")
- }
-
- // create a transition from s1 to s3 when the button is clicked
- SignalTransition {
- targetState: s3
- signal: interruptButton.clicked
- }
- HistoryState {
- id: s1h
- }
- }
- FinalState {
- id: s2
- onEntered: console.log("s2 entered")
- onExited: console.log("s2 exited")
- }
- State {
- id: s3
- SignalTransition {
- targetState: s1h
- signal: interruptButton.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s3 entered")
- onExited: console.log("s3 exited")
- }
- onFinished: Qt.quit()
- }
-//![0]
-}
-//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml b/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml
deleted file mode 100644
index 77cf253b73..0000000000
--- a/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml
+++ /dev/null
@@ -1,144 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ford Motor Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [document]
-import QtQuick 2.0
-import QtQml.StateMachine 1.0
-
-Rectangle {
- Row {
- anchors.fill: parent
- spacing: 2
- Button {
- id: button
- // change the button label to the active state id
- text: s11.active ? "s11" : s12.active ? "s12" : "s13"
- }
- Button {
- id: quitButton
- text: "quit"
- }
- }
-
- StateMachine {
- id: stateMachine
- // set the initial state
- initialState: s1
-
- // start the state machine
- running: true
-
- State {
- id: s1
- // set the initial state
- initialState: s11
-
- // create a transition from s1 to s2 when the button is clicked
- SignalTransition {
- targetState: s2
- signal: quitButton.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s1 entered")
- onExited: console.log("s1 exited")
- State {
- id: s11
- // create a transition from s11 to s12 when the button is clicked
- SignalTransition {
- targetState: s12
- signal: button.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s11 entered")
- onExited: console.log("s11 exited")
- }
-
-//![0]
- State {
- id: s12
- // create a transition from s12 to s13 when the button is clicked
- SignalTransition {
- targetState: s13
- signal: button.clicked
- }
-
- // ignore Quit button when we are in state 12
- SignalTransition {
- targetState: s12
- signal: quitButton.clicked
- }
-
- // do something when the state enters/exits
- onEntered: console.log("s12 entered")
- onExited: console.log("s12 exited")
- }
-//![0]
-
- State {
- id: s13
- // create a transition from s13 to s11 when the button is clicked
- SignalTransition {
- targetState: s11
- signal: button.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s13 entered")
- onExited: console.log("s13 exited")
- }
- }
- FinalState {
- id: s2
- onEntered: console.log("s2 entered")
- onExited: console.log("s2 exited")
- }
- onFinished: Qt.quit()
- }
-}
-//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested.qml b/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested.qml
deleted file mode 100644
index 19ab69315b..0000000000
--- a/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested.qml
+++ /dev/null
@@ -1,136 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ford Motor Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [document]
-import QtQuick 2.0
-import QtQml.StateMachine 1.0
-
-Rectangle {
-//![0]
- Row {
- anchors.fill: parent
- spacing: 2
- Button {
- id: button
- // change the button label to the active state id
- text: s11.active ? "s11" : s12.active ? "s12" : "s13"
- }
- Button {
- id: quitButton
- text: "quit"
- }
- }
-
- StateMachine {
- id: stateMachine
- // set the initial state
- initialState: s1
-
- // start the state machine
- running: true
-
- State {
- id: s1
- // set the initial state
- initialState: s11
-
- // create a transition from s1 to s2 when the button is clicked
- SignalTransition {
- targetState: s2
- signal: quitButton.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s1 entered")
- onExited: console.log("s1 exited")
- State {
- id: s11
- // create a transition from s11 to s12 when the button is clicked
- SignalTransition {
- targetState: s12
- signal: button.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s11 entered")
- onExited: console.log("s11 exited")
- }
-
- State {
- id: s12
- // create a transition from s12 to s13 when the button is clicked
- SignalTransition {
- targetState: s13
- signal: button.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s12 entered")
- onExited: console.log("s12 exited")
- }
- State {
- id: s13
- // create a transition from s13 to s11 when the button is clicked
- SignalTransition {
- targetState: s11
- signal: button.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s13 entered")
- onExited: console.log("s13 exited")
- }
- }
- FinalState {
- id: s2
- onEntered: console.log("s2 entered")
- onExited: console.log("s2 exited")
- }
- onFinished: Qt.quit()
- }
-//![0]
-}
-//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/statemachine-button.qml b/src/qml/doc/snippets/qml/statemachine/statemachine-button.qml
deleted file mode 100644
index 8fcbe6195f..0000000000
--- a/src/qml/doc/snippets/qml/statemachine/statemachine-button.qml
+++ /dev/null
@@ -1,110 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ford Motor Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [document]
-import QtQuick 2.0
-import QtQml.StateMachine 1.0
-
-Rectangle {
-//![0]
- Button {
- anchors.fill: parent
- id: button
-
- // change the button label to the active state id
- text: s1.active ? "s1" : s2.active ? "s2" : "s3"
- }
-
- StateMachine {
- id: stateMachine
- // set the initial state
- initialState: s1
-
- // start the state machine
- running: true
-
- State {
- id: s1
- // create a transition from s1 to s2 when the button is clicked
- SignalTransition {
- targetState: s2
- signal: button.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s1 entered")
- onExited: console.log("s1 exited")
- }
-
- State {
- id: s2
- // create a transition from s2 to s3 when the button is clicked
- SignalTransition {
- targetState: s3
- signal: button.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s2 entered")
- onExited: console.log("s2 exited")
- }
- State {
- id: s3
- // create a transition from s3 to s1 when the button is clicked
- SignalTransition {
- targetState: s1
- signal: button.clicked
- }
- // do something when the state enters/exits
- onEntered: console.log("s3 entered")
- onExited: console.log("s3 exited")
- }
- }
-//![0]
-}
-//! [document]
diff --git a/src/qml/doc/snippets/qml/statemachine/timeouttransition.qml b/src/qml/doc/snippets/qml/statemachine/timeouttransition.qml
deleted file mode 100644
index b629e84941..0000000000
--- a/src/qml/doc/snippets/qml/statemachine/timeouttransition.qml
+++ /dev/null
@@ -1,79 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Ford Motor Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [document]
-import QtQuick 2.0
-import QtQml.StateMachine 1.0 as DSM
-
-Rectangle {
- Button {
- anchors.fill: parent
- id: button
- text: "Finish state"
- enabled: !stateMachine.running
- onClicked: stateMachine.running = true
- DSM.StateMachine {
- id: stateMachine
- initialState: state
- running: true
- DSM.State {
- id: state
- DSM.TimeoutTransition {
- targetState: finalState
- timeout: 1000
- }
- }
- DSM.FinalState {
- id: finalState
- }
- }
- }
-}
-//! [document]
diff --git a/src/qml/doc/snippets/qml/workerscript/script.mjs b/src/qml/doc/snippets/qml/workerscript/script.mjs
deleted file mode 100644
index f55dee3507..0000000000
--- a/src/qml/doc/snippets/qml/workerscript/script.mjs
+++ /dev/null
@@ -1,4 +0,0 @@
-WorkerScript.onMessage = function(message) {
- // ... long-running operations and calculations are done here
- WorkerScript.sendMessage({ 'reply': 'Mouse is at ' + message.x + ',' + message.y })
-}
diff --git a/src/qml/doc/snippets/qml/workerscript/workerscript.qml b/src/qml/doc/snippets/qml/workerscript/workerscript.qml
deleted file mode 100644
index cc637d34cf..0000000000
--- a/src/qml/doc/snippets/qml/workerscript/workerscript.qml
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//![0]
-import QtQuick 2.0
-
-Rectangle {
- width: 300; height: 300
-
- Text {
- id: myText
- text: 'Click anywhere'
- }
-
- WorkerScript {
- id: myWorker
- source: "script.mjs"
-
- onMessage: myText.text = messageObject.reply
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: myWorker.sendMessage({ 'x': mouse.x, 'y': mouse.y })
- }
-}
-//![0]
diff --git a/src/qml/doc/snippets/qml/xmlhttprequest.js b/src/qml/doc/snippets/qml/xmlhttprequest.js
new file mode 100644
index 0000000000..f395a15d8d
--- /dev/null
+++ b/src/qml/doc/snippets/qml/xmlhttprequest.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//![0]
+function sendRequest(url, callback)
+{
+ let request = new XMLHttpRequest();
+
+ request.onreadystatechange = function() {
+ if (request.readyState === XMLHttpRequest.DONE) {
+ let response = {
+ status : request.status,
+ headers : request.getAllResponseHeaders(),
+ contentType : request.responseType,
+ content : request.response
+ };
+
+ callback(response);
+ }
+ }
+
+ request.open("GET", url);
+ request.send();
+}
+//![0]
diff --git a/src/qml/doc/snippets/qmllint/config.ini b/src/qml/doc/snippets/qmllint/config.ini
new file mode 100644
index 0000000000..29fa21438a
--- /dev/null
+++ b/src/qml/doc/snippets/qmllint/config.ini
@@ -0,0 +1,19 @@
+[General]
+AdditionalQmlImportPaths=
+DisableDefaultImports=false
+OverwriteImportTypes=
+ResourcePath=
+
+[Warnings]
+BadSignalHandler=warning
+Deprecated=warning
+ImportFailure=warning
+InheritanceCycle=warning
+MultilineStrings=info
+PropertyAlias=warning
+RequiredProperty=warning
+TypeError=warning
+UnknownProperty=warning
+UnqualifiedAccess=warning
+UnusedImports=info
+WithStatement=warning
diff --git a/src/qml/doc/snippets/qmltc/CMakeLists.txt b/src/qml/doc/snippets/qmltc/CMakeLists.txt
new file mode 100644
index 0000000000..e7b150a787
--- /dev/null
+++ b/src/qml/doc/snippets/qmltc/CMakeLists.txt
@@ -0,0 +1,62 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+set(application_name tst_qmltc_examples)
+#[[
+#! [qmltc-app-name]
+# Use "my_qmltc_example" as an application name:
+set(application_name my_qmltc_example)
+
+# Create a CMake target, add C++ source files, link libraries, etc...
+#! [qmltc-app-name]
+]]
+
+qt_internal_add_test(${application_name}
+ SOURCES
+ tst_qmltc_examples.cpp
+ colorpicker.h colorpicker.cpp
+ LIBRARIES
+ Qt::Core
+ Qt::Qml
+ Qt::Quick
+ Qt::QuickTemplates2Private # special
+ Qt::Gui
+)
+
+#! [qmltc-qml-files]
+# Specify a list of QML files to be compiled:
+set(application_qml_files
+ myApp.qml
+ MyButton.qml
+ MySlider.qml
+)
+#! [qmltc-qml-files]
+
+# files "invisible" to the documentation:
+list(APPEND application_qml_files
+ special/HelloWorld.qml
+)
+target_compile_definitions(${application_name} PRIVATE
+ QT_USE_QSTRINGBUILDER
+ QMLTC_TESTS_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
+ QMLTC_TESTS_BINARY_DIR="${CMAKE_CURRENT_BINARY_DIR}"
+)
+
+qt_policy(SET QTP0001 NEW)
+
+#! [qmltc-add-qml-module]
+# Make the application into a proper QML module:
+qt6_add_qml_module(${application_name}
+ URI QmltcExample
+ QML_FILES ${application_qml_files}
+
+ # Compile qml files (listed in QML_FILES) to C++ using qmltc and add these
+ # files to the application binary:
+ ENABLE_TYPE_COMPILER
+)
+#! [qmltc-add-qml-module]
+
+#! [qmltc-compile-to-cpp]
+# (qmltc-specific) Link *private* libraries that correspond to QML modules:
+target_link_libraries(${application_name} PRIVATE Qt::QmlPrivate Qt::QuickPrivate)
+#! [qmltc-compile-to-cpp]
diff --git a/src/qml/doc/snippets/qmltc/MyButton.qml b/src/qml/doc/snippets/qmltc/MyButton.qml
new file mode 100644
index 0000000000..5efbd7f88d
--- /dev/null
+++ b/src/qml/doc/snippets/qmltc/MyButton.qml
@@ -0,0 +1,30 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+Rectangle {
+ id: button
+ property alias text: textItem.text
+ signal clicked()
+
+ readonly property color constantColor: "#63ACBE"
+ color: mouseArea.pressed ? Qt.lighter(constantColor) : constantColor
+ width: textItem.implicitWidth + 5
+ height: textItem.implicitHeight + 5
+ radius: 10
+
+ Text {
+ id: textItem
+ font.pixelSize: 22
+ color: "black"
+ anchors.centerIn: button
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: button
+ anchors.margins: -5
+ onClicked: function(event) { button.clicked(); }
+ }
+}
diff --git a/src/qml/doc/snippets/qmltc/MySlider.qml b/src/qml/doc/snippets/qmltc/MySlider.qml
new file mode 100644
index 0000000000..4ceeb3579a
--- /dev/null
+++ b/src/qml/doc/snippets/qmltc/MySlider.qml
@@ -0,0 +1,50 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T // we cannot use QQC2 (yet), but we can use its backend
+
+T.Slider {
+ id: control
+
+ // QQC2-specific begin
+ implicitWidth: Math.max(control.implicitBackgroundWidth + control.leftInset
+ + control.rightInset,
+ control.implicitHandleWidth + control.leftPadding
+ + control.rightPadding)
+ implicitHeight: Math.max(control.implicitBackgroundHeight + control.topInset
+ + control.bottomInset,
+ control.implicitHandleHeight + control.topPadding
+ + control.bottomPadding)
+ padding: 6
+ // QQC2-specific end
+
+ background: Rectangle {
+ x: control.leftPadding
+ y: control.topPadding + control.availableHeight / 2 - height / 2
+ implicitWidth: 200
+ implicitHeight: 4
+ width: control.availableWidth
+ height: implicitHeight
+ radius: 2
+ border.color: "black"
+ color: "#F9F3EC"
+
+ Rectangle {
+ width: control.visualPosition * parent.width
+ height: parent.height
+ color: "#63ACBE"
+ radius: 2
+ }
+ }
+
+ handle: Rectangle {
+ x: control.leftPadding + control.visualPosition * (control.availableWidth - width)
+ y: control.topPadding + control.availableHeight / 2 - height / 2
+ implicitWidth: 26
+ implicitHeight: 26
+ radius: 13
+ color: control.pressed ? Qt.lighter("#63ACBE") : "#63ACBE"
+ border.color: Qt.darker("#63ACBE")
+ }
+}
diff --git a/src/qml/doc/snippets/qmltc/colorpicker.cpp b/src/qml/doc/snippets/qmltc/colorpicker.cpp
new file mode 100644
index 0000000000..096fbd2c74
--- /dev/null
+++ b/src/qml/doc/snippets/qmltc/colorpicker.cpp
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "colorpicker.h"
+
+#include <QtCore/qlogging.h>
+
+void MyColorPicker::setEncodedColor(double value)
+{
+ if (value < 0.0 || !(value < 1.0)) {
+ qWarning("Bad value, %f, cannot get color from it!", value);
+ return;
+ }
+ m_encodedColor = value;
+}
+
+QBindable<double> MyColorPicker::bindableEncodedColor()
+{
+ return QBindable<double>(&m_encodedColor);
+}
+
+QColor MyColorPicker::decodeColor()
+{
+ const double encodedValue = m_encodedColor;
+ constexpr int rgbFirst = 0;
+ constexpr int rgbLast = 256 * 256 * 256;
+ const QRgb rgb = rgbFirst + (rgbLast - rgbFirst) * encodedValue;
+ return QColor(rgb);
+}
diff --git a/src/qml/doc/snippets/qmltc/colorpicker.h b/src/qml/doc/snippets/qmltc/colorpicker.h
new file mode 100644
index 0000000000..84bc0caccf
--- /dev/null
+++ b/src/qml/doc/snippets/qmltc/colorpicker.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtCore/qobject.h>
+#include <QtCore/qproperty.h>
+#include <QtQml/qqmlregistration.h>
+#include <QtGui/qcolor.h>
+
+class MyColorPicker : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ // Stores a value in the range [0, 1); myApp.qml type sets this with
+ // Math.random()
+ Q_PROPERTY(double encodedColor READ encodedColor WRITE setEncodedColor BINDABLE bindableEncodedColor)
+
+ QProperty<double> m_encodedColor{0.5};
+public:
+ MyColorPicker(QObject *parent = nullptr) : QObject(parent) {}
+
+ double encodedColor() { return m_encodedColor; }
+ void setEncodedColor(double value);
+ QBindable<double> bindableEncodedColor();
+
+ // Returns a QColor "decoded" from encodedColor
+ Q_INVOKABLE QColor decodeColor();
+};
diff --git a/src/qml/doc/snippets/qmltc/myApp.qml b/src/qml/doc/snippets/qmltc/myApp.qml
new file mode 100644
index 0000000000..5fef927210
--- /dev/null
+++ b/src/qml/doc/snippets/qmltc/myApp.qml
@@ -0,0 +1,73 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QmltcExample // application's own QML module
+
+Rectangle {
+ id: window
+
+ width: 640
+ height: 480
+ focus: true
+ color: "#F9F4EC"
+
+ readonly property color textColor: "#601A4A"
+
+ Row {
+ id: row
+ anchors.centerIn: window
+ spacing: 10
+
+ Column {
+ id: column
+ spacing: 5
+
+ Text {
+ text: "Hello, QML World!"
+ font.pixelSize: slider.value
+ color: textColor
+ }
+
+ MySlider {
+ id: slider
+ from: 20
+ value: 20
+ to: 30
+ }
+ }
+
+ Column {
+ spacing: 5
+
+ Text {
+ id: rndText
+ font.pixelSize: 25
+ color: textColor
+ text: "0.00"
+ }
+
+ Rectangle {
+ id: rndColorRect
+ height: 20
+ width: rndButton.width
+ color: "black"
+
+ MyColorPicker { // comes from C++
+ id: colorPicker
+ onEncodedColorChanged: rndColorRect.color = colorPicker.decodeColor()
+ }
+ }
+
+ MyButton {
+ id: rndButton
+ text: "PICK"
+ onClicked: function() {
+ var value = Math.random();
+ rndText.text = value.toFixed(rndButton.text.length - 2);
+ colorPicker.encodedColor = value;
+ }
+ }
+ }
+ }
+}
diff --git a/src/qml/doc/snippets/qmltc/special/HelloWorld.qml b/src/qml/doc/snippets/qmltc/special/HelloWorld.qml
new file mode 100644
index 0000000000..ca2a4bc015
--- /dev/null
+++ b/src/qml/doc/snippets/qmltc/special/HelloWorld.qml
@@ -0,0 +1,19 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [qmltc-hello-world-qml]
+// HelloWorld.qml
+import QtQml
+
+QtObject {
+ id: me
+ property string hello: "Hello, qmltc!"
+
+ function printHello(prefix: string, suffix: string) {
+ console.log(prefix + me.hello + suffix);
+ }
+
+ signal created()
+ Component.onCompleted: me.created();
+}
+//! [qmltc-hello-world-qml]
diff --git a/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp b/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp
new file mode 100644
index 0000000000..0afbcbf0bf
--- /dev/null
+++ b/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+/* Disclaimer: This file is an "as is" copy of the C++ header generated for the
+ accompanying HelloWorld.qml. Its pieces are used to:
+
+ * verify that the generated code is similar to what is contained in this file
+ * provide documentation snippets for the qmltc docs
+
+ Note: all the stuff below MAGIC_QMLTC_TEST_DELIMITER_LINE comment
+ participates in the aforementioned activities. Prefer to put arbitrary stuff
+ before that comment.
+*/
+
+// MAGIC_QMLTC_TEST_DELIMITER_LINE
+
+//! [qmltc-hello-world-generated]
+class HelloWorld : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ Q_PROPERTY(QString hello WRITE setHello READ hello BINDABLE bindableHello)
+
+public:
+ HelloWorld(QQmlEngine* engine, QObject* parent = nullptr, [[maybe_unused]] qxp::function_ref<void(PropertyInitializer&)> initializer = [](PropertyInitializer&){});
+
+Q_SIGNALS:
+ void created();
+
+public:
+ void setHello(const QString& hello_);
+ QString hello();
+ QBindable<QString> bindableHello();
+ Q_INVOKABLE void printHello(passByConstRefOrValue<QString> prefix, passByConstRefOrValue<QString> suffix);
+
+ // ...
+};
+//! [qmltc-hello-world-generated]
diff --git a/src/qml/doc/snippets/qmltc/tst_qmltc_examples.cpp b/src/qml/doc/snippets/qmltc/tst_qmltc_examples.cpp
new file mode 100644
index 0000000000..8c2706531b
--- /dev/null
+++ b/src/qml/doc/snippets/qmltc/tst_qmltc_examples.cpp
@@ -0,0 +1,179 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+// Note: this file is published under a license that is different from a default
+// test sources license. This is intentional to comply with default
+// snippet license.
+
+#include <QtTest/qtest.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qtimer.h>
+#include <QtGui/qguiapplication.h>
+#include <QtQuick/qquickwindow.h>
+
+//! [qqmlcomponent-include]
+#include <QtQml/qqmlcomponent.h>
+//! [qqmlcomponent-include]
+
+//! [qmltc-include]
+#include "myapp.h" // include generated C++ header
+//! [qmltc-include]
+
+#include <algorithm>
+
+class tst_qmltc_examples : public QObject
+{
+ Q_OBJECT
+
+ static constexpr int m_argc = 1;
+ static constexpr char *m_argv[] = { const_cast<char *>("tst_qmltc_examples") };
+
+public:
+ tst_qmltc_examples(QObject *parent = nullptr) : QObject(parent) { }
+
+private slots:
+ void app();
+ void appComponent();
+
+ void helloWorld();
+};
+
+#define CREATE_DUMMY_ARGC_ARGV() \
+ int argc = 1; \
+ char *argv[] = { const_cast<char *>("tst_qmltc_examples") };
+
+void tst_qmltc_examples::app()
+{
+ CREATE_DUMMY_ARGC_ARGV()
+
+ //! [qmltc-app-code]
+ QGuiApplication app(argc, argv);
+ app.setApplicationDisplayName(QStringLiteral("This example is powered by qmltc!"));
+
+ QQmlEngine e;
+ QQuickWindow window;
+
+ QScopedPointer<QmltcExample::myApp> documentRoot(
+ new QmltcExample::myApp(&e, nullptr, [](auto& component){
+ component.setWidth(800);
+ }));
+
+ documentRoot->setParentItem(window.contentItem());
+ window.setHeight(documentRoot->height());
+ window.setWidth(documentRoot->width());
+ // ...
+ //! [qmltc-app-code]
+
+ QTimer::singleShot(1000, &app, QGuiApplication::quit);
+
+ //! [qmltc-app-exec]
+ window.show();
+ app.exec();
+ //! [qmltc-app-exec]
+}
+
+void tst_qmltc_examples::appComponent()
+{
+ CREATE_DUMMY_ARGC_ARGV()
+
+ //! [qqmlcomponent-app-code-0]
+ QGuiApplication app(argc, argv);
+ app.setApplicationDisplayName(QStringLiteral("This example is powered by QQmlComponent :("));
+
+ QQmlEngine e;
+ QQuickWindow window;
+
+ QQmlComponent component(&e);
+ component.loadUrl(
+ QUrl(QStringLiteral("qrc:/qt/qml/QmltcExample/myApp.qml")));
+ //! [qqmlcomponent-app-code-0]
+
+ QVERIFY2(!component.isError(), qPrintable(component.errorString()));
+
+ //! [qqmlcomponent-app-code-1]
+ QScopedPointer<QObject> documentRoot(component.create());
+ QQuickItem *documentRootItem = qobject_cast<QQuickItem *>(documentRoot.get());
+ //! [qqmlcomponent-app-code-1]
+
+ QVERIFY(documentRootItem);
+
+ //! [qqmlcomponent-app-code-2]
+ documentRootItem->setParentItem(window.contentItem());
+ window.setHeight(documentRootItem->height());
+ window.setWidth(documentRootItem->width());
+ // ...
+ //! [qqmlcomponent-app-code-2]
+
+ QTimer::singleShot(1000, &app, QGuiApplication::quit);
+
+ window.show();
+ app.exec();
+}
+
+#if !defined(QMLTC_TESTS_SOURCE_DIR) || !defined(QMLTC_TESTS_BINARY_DIR)
+# error "Tests assume that QMLTC_TESTS_{SOURCE,BINARY}_DIR are specified (through CMake)"
+#endif
+
+// Note: QtTest macros need to be in void-returning function, so use output arg.
+template<typename Predicate>
+void readFileContent(QStringList *content, const QString &url, Predicate filter)
+{
+ QVERIFY(content);
+
+ QFile file(url);
+ QVERIFY(file.exists());
+ QVERIFY(file.open(QIODeviceBase::ReadOnly | QIODeviceBase::Text));
+
+ QTextStream stream(&file);
+ while (!stream.atEnd()) {
+ QString line = stream.readLine();
+ if (filter(line))
+ content->append(std::move(line));
+ }
+}
+
+void tst_qmltc_examples::helloWorld()
+{
+#ifdef Q_OS_ANDROID
+ QSKIP("expected C++ files are not bundled with Android tests.");
+#endif
+ QStringList generatedCode;
+ readFileContent(&generatedCode,
+ QStringLiteral(QMLTC_TESTS_BINARY_DIR)
+ + u"/.qmltc/tst_qmltc_examples/helloworld.h",
+ [](const QString &) { return true; });
+ if (QTest::currentTestFailed())
+ QFAIL("Reading _generated_ C++ content for special/HelloWorld.qml failed");
+
+ QStringList documentationCode;
+ const auto filterDocumentationLines = [encounteredStart = false](QStringView line) mutable {
+ if (line.startsWith(u"// MAGIC_QMLTC_TEST_DELIMITER_LINE")) {
+ encounteredStart = true;
+ return false; // we don't need this specific line
+ }
+ if (!encounteredStart)
+ return false;
+ line = line.trimmed();
+ return !line.isEmpty() && !line.startsWith(u"//");
+ };
+ readFileContent(&documentationCode,
+ QStringLiteral(QMLTC_TESTS_SOURCE_DIR) + u"/special/HelloWorld.qml.cpp",
+ filterDocumentationLines);
+ if (QTest::currentTestFailed())
+ QFAIL("Reading special/HelloWorld.qml.cpp failed");
+
+ QVERIFY(!generatedCode.isEmpty());
+ QVERIFY(!documentationCode.isEmpty());
+
+ auto begin = generatedCode.cbegin();
+ for (const QString &existingString : std::as_const(documentationCode)) {
+ auto pos = std::find(begin, generatedCode.cend(), existingString);
+ QVERIFY2(pos != generatedCode.cend(), qPrintable(u"Could not find: " + existingString));
+ begin = std::next(pos);
+ }
+}
+
+#undef CREATE_DUMMY_ARGC_ARGV
+
+QTEST_APPLESS_MAIN(tst_qmltc_examples)
+#include "tst_qmltc_examples.moc"
diff --git a/src/qml/doc/snippets/qtjavascript/evaluation/main.cpp b/src/qml/doc/snippets/qtjavascript/evaluation/main.cpp
index 5ff0e5dbbd..58450de371 100644
--- a/src/qml/doc/snippets/qtjavascript/evaluation/main.cpp
+++ b/src/qml/doc/snippets/qtjavascript/evaluation/main.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtQml>
diff --git a/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsascontainer.cpp b/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsascontainer.cpp
new file mode 100644
index 0000000000..4164aa02dd
--- /dev/null
+++ b/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsascontainer.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+//! [qjs-as-container]
+
+ class Cache : public QObject
+ {
+ Q_OBJECT
+ QML_ELEMENT
+
+ public:
+ Q_INVOKABLE QJSValue lookup(const QString &key) {
+ if (auto it = m_cache.constFind(key); it != m_cache.constEnd()) {
+ return *it; // impicit conversion
+ } else {
+ return QJSValue::UndefinedValue; // implicit conversion
+ }
+ }
+
+ QHash<QString, QString> m_cache;
+ }
+
+//! [qjs-as-container]
diff --git a/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsengine.cpp b/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsengine.cpp
new file mode 100644
index 0000000000..289b61d871
--- /dev/null
+++ b/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsengine.cpp
@@ -0,0 +1,21 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//![qjs-engine-example]
+
+ QJSEngine engine;
+ // We create an object with a read-only property whose getter throws an exception
+ auto val = engine.evaluate("let o = { get f() {throw 42;} }; o");
+ val.property("f");
+ qDebug() << engine.hasError(); // prints false
+
+ // This time, we construct a QJSManagedValue before accessing the property
+ val = engine.evaluate("let o = { get f() {throw 42;} }; o");
+ QJSManagedValue managed(std::move(val), &engine);
+ managed.property("f");
+ qDebug() << engine.hasError(); // prints true
+
+ QJSValue error = engine.catchError();
+ Q_ASSERT(error.toInt(), 42);
+
+//![qjs-engine-example]
diff --git a/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/qjsengine.cpp b/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/qjsengine.cpp
new file mode 100644
index 0000000000..9e022c01d3
--- /dev/null
+++ b/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/qjsengine.cpp
@@ -0,0 +1,16 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//![qjs-engine]
+
+ QJSEngine engine;
+ QJSValue object = engine.newObject();
+ object.setProperty("num", 42);
+ QJSValue function = engine.evaluate("(o) => o.num *= 2 ");
+ QJSValueList args = { object };
+ QJSValue result = function.call(args);
+ QJSValue expected = "84";
+ Q_ASSERT(result.equals(expected) && !result.strictlyEquals(expected));
+
+//![qjs-engine]
+
diff --git a/src/qml/doc/snippets/qtjavascript/registeringobjects/main.cpp b/src/qml/doc/snippets/qtjavascript/registeringobjects/main.cpp
index 5c2acb2812..9a786f2f7b 100644
--- a/src/qml/doc/snippets/qtjavascript/registeringobjects/main.cpp
+++ b/src/qml/doc/snippets/qtjavascript/registeringobjects/main.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QObject>
#include <QtQml>
diff --git a/src/qml/doc/snippets/qtjavascript/registeringvalues/main.cpp b/src/qml/doc/snippets/qtjavascript/registeringvalues/main.cpp
index ceaca5f752..9caedf3b3a 100644
--- a/src/qml/doc/snippets/qtjavascript/registeringvalues/main.cpp
+++ b/src/qml/doc/snippets/qtjavascript/registeringvalues/main.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtQml>
diff --git a/src/qml/doc/src/cmake/cmake-properties.qdoc b/src/qml/doc/src/cmake/cmake-properties.qdoc
new file mode 100644
index 0000000000..297a094582
--- /dev/null
+++ b/src/qml/doc/src/cmake/cmake-properties.qdoc
@@ -0,0 +1,208 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\group cmake-global-properties-qtqml
+\title CMake Global Properties in Qt6 Qml
+
+\l{CMake Command Reference#Qt6::Qml}{CMake Commands} know about the following
+global CMake properties:
+
+\sa{CMake Property Reference}
+*/
+
+
+/*!
+\page cmake-global-property-qt-qmllinter-targets-folder.html
+\ingroup cmake-properties-qtqml
+\ingroup cmake-global-properties-qtqml
+
+\title QT_QMLLINTER_TARGETS_FOLDER
+
+\brief Sets the FOLDER property for targets that belong to the QML linter.
+
+\cmakepropertysince 6.5
+\preliminarycmakeproperty
+
+Name of the \l FOLDER for targets that are related to the QML linter.
+
+By default, this property is set to \c{QmlLinter}.
+
+This property only has an effect if CMake's \l USE_FOLDERS property is \c{ON}.
+
+You can enable folder support by calling
+\l{qt6_standard_project_setup}{qt_standard_project_setup}.
+*/
+
+
+/*!
+\group cmake-source-file-properties-qtqml
+\title CMake Source File Properties in Qt6 Qml
+
+\l{CMake Command Reference#Qt6::Qml}{CMake Commands} know about the following
+CMake source file properties:
+
+\sa{CMake Property Reference}
+*/
+
+
+/*!
+\page cmake-source-file-property-qt-qml-internal-type.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_INTERNAL_TYPE
+
+\summary {Marks a QML file as providing an internal type.}
+
+\cmakepropertysince 6.2
+
+Set this property to \c TRUE to indicate that the \c{.qml} file provides an internal type.
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-qt-qml-singleton-type.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_SINGLETON_TYPE
+
+\summary {Marks a QML file as providing a singleton type.}
+
+\cmakepropertysince 6.2
+
+A \c{.qml} file that provides a singleton type needs to have its \c QT_QML_SINGLETON_TYPE source
+property set to \c TRUE to ensure that the singleton command is written into the
+\l{Module Definition qmldir Files}{qmldir} file.
+This must be done in addition to the QML file containing the \c {pragma Singleton} statement.
+The source property must be set before \l{qt_add_qml_module}{creating} the module the
+singleton belongs to.
+
+See \l{qt_target_qml_sources_example}{qt_target_qml_sources()} for an example on
+how to set the \c QT_QML_SINGLETON_TYPE property.
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-qt-qml-skip-cachegen.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_SKIP_CACHEGEN
+
+\summary {Excludes a file from being compiled to byte code.}
+
+\cmakepropertysince 6.2
+
+Set this property to \c TRUE to prevent the \c{.qml} file from being compiled to byte code.
+The file will still be added to the \c target as a resource in uncompiled form
+(see \l{qmlcachegen-auto}{Caching compiled QML sources}).
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-qt-qml-skip-qmldir-entry.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_SKIP_QMLDIR_ENTRY
+
+\summary {Excludes a file from being added as a type to the QML module's typeinfo file.}
+
+\cmakepropertysince 6.2
+
+Set this property to \c TRUE to prevent
+the \c{.qml} file from being added as a type to the QML module's typeinfo file
+(see \l{qmldir-autogeneration}{Auto-generating \c{qmldir} and typeinfo files}).
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-qt-qml-skip-qmllint.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_SKIP_QMLLINT
+
+\summary {Prevents a file from being included in automatic qmllint processing.}
+
+\cmakepropertysince 6.2
+
+Set this property to \c TRUE to prevent the file from being included in
+\l{qmllint-auto}{automatic qmllint processing}.
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-qt-qml-source-typename.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_SOURCE_TYPENAME
+
+\summary {Overrides the type name provided by the file.}
+
+\cmakepropertysince 6.2
+
+Use this property to override the \c QML type name provided by this file.
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-qt-qml-source-versions.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_SOURCE_VERSIONS
+
+\summary {Specifies a custom set of versions for a type.}
+
+\cmakepropertysince 6.2
+
+When the file needs to provide type entries for a custom set of versions,
+for example when the QML types were first introduced in a minor patch
+version after the \c{.0} release, specify those versions using this property.
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-qt-qmltc-file-basename.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QMLTC_FILE_BASENAME
+
+\summary {Specifies a non-default .h and .cpp file name.}
+
+\cmakepropertysince 6.3
+\preliminarycmakeproperty
+
+Use this property to specify a non-default \c .h and \c .cpp file name, which helps to resolve
+conflicting file names.
+
+\sa{qmltc-cmake}
+*/
+
+/*!
+\page cmake-source-file-property-qt-qml-skip-type-compiler.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_SKIP_TYPE_COMPILER
+
+\summary {Excludes a file from being compiled to C++ using qmltc.}
+
+\cmakepropertysince 6.4
+\preliminarycmakeproperty
+
+Set this property to \c TRUE to prevent the \c{.qml} file from being compiled to
+C++ during qmltc compilation.
+
+\sa{qmltc-cmake}
+*/
diff --git a/src/qml/doc/src/cmake/cmake-variables.qdoc b/src/qml/doc/src/cmake/cmake-variables.qdoc
new file mode 100644
index 0000000000..de984c88ef
--- /dev/null
+++ b/src/qml/doc/src/cmake/cmake-variables.qdoc
@@ -0,0 +1,76 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\group cmake-variables-qtqml
+\title CMake Global Variables in Qt6 Qml
+
+\l{CMake Command Reference#Qt6::Qml}{CMake Commands} know about the following
+global CMake variables:
+
+*/
+
+/*!
+\page cmake-variable-qt-qml-output-directory.html
+\ingroup cmake-variables-qtqml
+
+\title QT_QML_OUTPUT_DIRECTORY
+
+\brief Base output directory below which QML modules will be created by default.
+
+The \l{qt6_add_qml_module}{qt6_add_qml_module()} command accepts an
+\c OUTPUT_DIRECTORY argument which specifies where the QML module's \c qmldir
+file, typeinfo file and plugin library will be created. When that argument is
+not used, the default value is based on the \c QT_QML_OUTPUT_DIRECTORY variable,
+if it is set. If \c QT_QML_OUTPUT_DIRECTORY is not set, the default value
+depends on the type of backing target (see the
+\l{qt6_add_qml_module#OUTPUT_DIRECTORY}{OUTPUT_DIRECTORY} documentation for
+details).
+
+When \c QT_QML_OUTPUT_DIRECTORY is set, the default output directory will be
+formed by appending the QML module's \e{target path} (which is based on the
+module URI) to \c QT_QML_OUTPUT_DIRECTORY.
+The \c QT_QML_OUTPUT_DIRECTORY will also be added to the import path of the
+\c qmllint and \c qmlcachegen tooling targets, allowing them to find other QML
+modules under the same base location. This allows the project to use a source
+directory structure that doesn't exactly match the URI structure of the QML
+modules, or to merge sets of QML modules under a common base point.
+*/
+
+/*!
+\page cmake-variable-qt-qml-generate-qmlls-ini.html
+\ingroup cmake-variables-qtqml
+
+\title QT_QML_GENERATE_QMLLS_INI
+
+\brief Enables autogeneration of .qmlls.ini files for \QMLLS.
+\cmakevariablesince 6.7
+
+\c QT_QML_GENERATE_QMLLS_INI is a boolean that describes whether
+\l{qt6_add_qml_module}{qt6_add_qml_module()} calls generate \c{.qmlls.ini} files inside
+the \b{source folder}, into each subdirectory with a CMakeLists.txt file creating a QML module.
+If \c{.qmlls.ini} files already exist there, then they are overwritten.
+
+\note Using \c QT_QML_GENERATE_QMLLS_INI requires a CMake version >= 3.19.
+
+These \c{.qmlls.ini} files contain the path to the last configured build directory,
+and is needed by \l{\QMLLS Reference}{\QMLLS} to find user defined modules. See also
+\l{\QMLLS Reference}{\QMLLS} about the other ways of passing build folders to \QMLLS.
+
+
+As this variable is used for IDE integration, it should normally not be set in a project itself, but
+passed to CMake via an IDE or manually by passing
+\badcode
+-DQT_QML_GENERATE_QMLLS_INI=ON
+\endcode
+to the cmake executable.
+
+\warning The files generated by \c QT_QML_GENERATE_QMLLS_INI are only valid for the current
+configuration and should be ignored by your version control system. For Git, add \tt{**\/.qmlls.ini}
+to your top-level project \c{.gitignore}, for example.
+The globbing is required because .qmlls.ini files are generated in \e{all source
+subdirectories} that define QML Modules.
+
+*/
+
+
diff --git a/src/qml/doc/src/cmake/policy/qtp0001.qdoc b/src/qml/doc/src/cmake/policy/qtp0001.qdoc
new file mode 100644
index 0000000000..a4e54ed1ae
--- /dev/null
+++ b/src/qml/doc/src/cmake/policy/qtp0001.qdoc
@@ -0,0 +1,39 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-cmake-policy-qtp0001.html
+\ingroup qt-cmake-policies
+
+\title QTP0001
+\keyword qt_cmake_policy_qtp0001
+
+\summary {':/qt/qml/' is the default resource prefix for QML modules.}
+
+This policy was introduced in Qt 6.5. It changes where
+\l{qt_add_qml_module}{qt_add_qml_module()} stores QML resources in
+the resource system.
+
+Enabling this policy ensures that your QML module is placed under
+a default \l {QML Import Path}{import path}, and its types can be
+found without manual calls to \l QQmlEngine::addImportPath.
+
+The \c OLD behavior of this policy is that, the \c RESOURCE_PREFIX argument for
+\c{qt_add_qml_module()} defaults to \c{":/"}.
+
+The \c NEW behavior of this policy is that the \c RESOURCE_PREFIX argument
+for \c{qt_add_qml_module()} defaults to \c{":/qt/qml/"}. The new behavior
+ensures that modules are put into the \l{QML Import Path} and can be
+found without further setup.
+
+Qt 6.5 issues warnings if you do not pass any of the following arguments to the
+\c qt_add_qml_module command: \c RESOURCE_PREFIX, \c NO_RESOURCE_TARGET_PATH.
+Use the \l qt_policy command to suppress the warning by explicitly setting
+the policy to \c OLD or \c NEW.
+
+\qtpolicydeprecatedbehavior
+
+\sa qt_policy, {qt6_standard_project_setup}{qt_standard_project_setup()},
+ qt_cmake_policies, qt_add_qml_module
+
+*/
diff --git a/src/qml/doc/src/cmake/policy/qtp0004.qdoc b/src/qml/doc/src/cmake/policy/qtp0004.qdoc
new file mode 100644
index 0000000000..9d3428e52b
--- /dev/null
+++ b/src/qml/doc/src/cmake/policy/qtp0004.qdoc
@@ -0,0 +1,34 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-cmake-policy-qtp0004.html
+\ingroup qt-cmake-policies
+
+\title QTP0004
+\keyword qt_cmake_policy_qtp0004
+
+\summary {Extra directories with QML files in a QML module need extra qmldir files.}
+
+This policy was introduced in Qt 6.8. It causes the build system to generate
+an extra qmldir file for each additional directory that contains QML files in
+a QML module.
+
+Enabling this policy ensures that the implicit import of each of the QML
+components in your module is the same as the module itself. This means that
+all the components can see each other without explicitly importing the module.
+
+The \c OLD behavior of this policy is that a qmldir file is only generated for
+the root directory of a module.
+
+The \c NEW behavior of this policy is that for each directory with QML files in
+a module a separate qmldir file is generated.
+
+Qt 6.8 issues warnings if you do not explicitly set the policy.
+
+\qtpolicydeprecatedbehavior
+
+\sa qt_policy, {qt6_standard_project_setup}{qt_standard_project_setup()},
+ qt_cmake_policies, qt_add_qml_module
+
+*/
diff --git a/src/qml/doc/src/cmake/qt_add_qml_module.qdoc b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
new file mode 100644
index 0000000000..4ca7635b9c
--- /dev/null
+++ b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
@@ -0,0 +1,759 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-add-qml-module.html
+\ingroup cmake-commands-qtqml
+
+\title qt_add_qml_module
+\target qt6_add_qml_module
+
+\brief Defines a QML module.
+
+\cmakecommandsince 6.2
+
+\section1 Synopsis
+
+\badcode
+qt_add_qml_module(
+ target
+ URI uri
+ [VERSION version]
+ [PAST_MAJOR_VERSIONS ...]
+ [STATIC | SHARED]
+ [PLUGIN_TARGET plugin_target]
+ [OUTPUT_DIRECTORY output_dir]
+ [RESOURCE_PREFIX resource_prefix]
+ [CLASS_NAME class_name]
+ [TYPEINFO typeinfo]
+ [IMPORTS ...]
+ [OPTIONAL_IMPORTS ...]
+ [DEFAULT_IMPORTS ...]
+ [DEPENDENCIES ...]
+ [IMPORT_PATH ...]
+ [SOURCES ...]
+ [QML_FILES ...]
+ [RESOURCES ...]
+ [OUTPUT_TARGETS out_targets_var]
+ [DESIGNER_SUPPORTED]
+ [FOLLOW_FOREIGN_VERSIONING]
+ [NAMESPACE namespace]
+ [NO_PLUGIN]
+ [NO_PLUGIN_OPTIONAL]
+ [NO_CREATE_PLUGIN_TARGET]
+ [NO_GENERATE_PLUGIN_SOURCE]
+ [NO_GENERATE_QMLTYPES]
+ [NO_GENERATE_QMLDIR]
+ [NO_LINT]
+ [NO_CACHEGEN]
+ [NO_RESOURCE_TARGET_PATH]
+ [NO_IMPORT_SCAN]
+ [ENABLE_TYPE_COMPILER]
+ [TYPE_COMPILER_NAMESPACE namespace]
+ [QMLTC_EXPORT_DIRECTIVE export_macro]
+ [QMLTC_EXPORT_FILE_NAME header_defining_export_macro]
+
+)
+
+\endcode
+
+\versionlessCMakeCommandsNote qt6_add_qml_module()
+
+See \l {Building a QML application} and \l {Building a reusable QML module}
+for examples that define QML modules.
+
+See \l {QT_QML_GENERATE_QMLLS_INI} for configuring your project such that information about
+QML modules is exposed to the \l{QML Language Server}.
+
+\section1 Description
+
+This command defines a QML module that can consist of C++ sources, \c{.qml}
+files, or both. It ensures that essential module details are provided and that
+they are consistent. It also sets up and coordinates things like cached
+compilation of \c{.qml} sources, resource embedding, linting checks, and
+auto-generation of some key module files.
+
+\section2 Target Structure
+
+A QML module can be structured in a few different ways. The following scenarios
+are the typical arrangements:
+
+\section3 Separate backing and plugin targets
+
+This is the recommended arrangement for most QML modules. All of the module's
+functionality is implemented in the \e backing target, which is given as the
+first command argument. C++ sources, \c{.qml} files, and resources should all
+be added to the backing target. The backing target is a library that should be
+installed in the same location as any other library defined by the project.
+
+The source directory structure under which the backing target is created should
+match the target path of the QML module (the target path is the module's URI
+with dots replaced by forward slashes). If the source directory structure
+doesn't match the target path, \c{qt_add_qml_module()} will issue a warning.
+
+The following example shows a suitable source directory structure for a QML
+module with a URI of \c{MyThings.Panels}. The call to \c{qt_add_qml_module()}
+would be in the \c{CMakeLists.txt} file shown.
+
+\badcode
+src
+ +-- MyThings
+ +-- Panels
+ +-- CMakeLists.txt
+\endcode
+
+A separate \e plugin target is associated with the QML module. It is used at
+runtime to load the module dynamically when the application doesn't already
+link to the backing target. The plugin target will also be a library and is
+normally installed to the same directory as the module's
+\l{Module Definition qmldir Files}{qmldir} file.
+
+The plugin target should ideally contain nothing more than a trivial
+implementation of the plugin class. This allows the plugin to be designated as
+optional in the \c qmldir file. Other targets can then link directly to the
+backing target and the plugin will not be needed at runtime, which can improve
+load-time performance. By default, a C++ source file that defines a minimal
+plugin class will be automatically generated and added to the plugin target.
+For cases where the QML module needs a custom plugin class implementation, the
+\l{NO_GENERATE_PLUGIN_SOURCE} and usually the \l{NO_PLUGIN_OPTIONAL} options
+will be needed.
+
+The \c STATIC QML modules also generate the static QML plugins if
+\c NO_PLUGIN is not specified. Targets that import such \c STATIC QML modules
+also need to explicitly link to corresponding QML plugins.
+
+\note
+When using static linking, it might be necessary to use
+\l {Q_IMPORT_QML_PLUGIN} to ensure that the QML plugin is correctly linked.
+
+\section3 Plugin target with no backing target
+
+A QML module can be defined with the plugin target serving as its own backing
+target. In this case, the module must be loaded dynamically at runtime and
+cannot be linked to directly by other targets. To create this arrangement,
+the \c PLUGIN_TARGET keyword must be used, with the \c target repeated as the
+plugin target name. For example:
+
+\badcode
+qt_add_qml_module(someTarget
+ PLUGIN_TARGET someTarget
+ ...
+)
+\endcode
+
+While this arrangement may seem marginally simpler to deploy, a separate
+backing target should be preferred where possible due to the potentially better
+load-time performance.
+
+\section3 Executable as a QML module
+
+An executable target can act as a backing target for a QML module. In this case,
+there will be no plugin library, since the QML module will always be loaded
+directly as part of the application. The \c{qt_add_qml_module()} command will
+detect when an executable is used as the backing target and will automatically
+disable the creation of a separate plugin. Do not use any of the options with
+\c{PLUGIN} in their name when using this arrangement.
+
+When an executable is used as the backing target, the source directory structure
+is not expected to match the QML module's target path.
+See \l{qmlcachegen-auto}{Caching compiled QML sources} for additional target
+path differences for compiled-in resources.
+
+
+\target qmldir-autogeneration
+\section2 Auto-generating \c{qmldir} and typeinfo files
+
+By default, a \l{Module Definition qmldir Files}{qmldir} file and a typeinfo
+file will be auto-generated for the QML module being defined. The contents of
+those files are determined by the various arguments given to this command, as
+well as the sources and \c{.qml} files added to the backing target.
+The \l OUTPUT_DIRECTORY argument determines where the \c qmldir and typeinfo
+files will be written to. If the QML module has a plugin, that plugin will also
+be created in the same directory as the \c qmldir file.
+
+If \l{QTP0004} policy is set to \c NEW, for each further directory that contains
+\c{.qml} files another \c qmldir file is generated. These extra \c qmldir files
+merely redirect to the module's base directory via a \c prefer directive. This
+is so that all the QML components in a module can access each other, no matter
+which directory they are stored in.
+
+If using a statically built Qt, the backing target's \c{.qml} files will be
+scanned during the CMake configure run to determine the imports used by the
+module and to set up linking relationships (the \c{NO_IMPORT_SCAN} keyword
+can be given to disable this). When a \c{.qml} file is added to or
+removed from the module, CMake will normally re-run automatically and the
+relevant files will be re-scanned, since a \c{CMakeLists.txt} file will have
+been modified. During the course of development, an existing \c{.qml} file may
+add or remove an import or a type. On its own, this would not cause CMake to
+re-run automatically, so you should explicitly re-run CMake to force the
+\c qmldir file to be regenerated and any linking relationships to be updated.
+
+The backing target's C++ sources are scanned at build time to generate a
+typeinfo file and a C++ file to register the associated types. The generated
+C++ file is automatically added to the backing target as a source.
+This requires \c AUTOMOC to be enabled on the target. The project is
+responsible for ensuring this, usually by setting the \c CMAKE_AUTOMOC variable
+to \c TRUE before calling \c qt_add_qml_module(), or by passing in an existing
+target with the \c AUTOMOC target property already set to \c TRUE. It isn't an
+error to have \c AUTOMOC disabled on the target, but the project is then
+responsible for handling the consequences. This may include having to manually
+generate the typeinfo file instead of allowing it to be auto-generated with
+missing details, and adding C++ code to register the types.
+
+Projects should prefer to use the auto-generated typeinfo and \c qmldir files
+where possible. They are easier to maintain and they don't suffer from the same
+susceptibility to errors that hand-written files do. Nevertheless, for
+situations where the project needs to provide these files itself, the
+auto-generation can be disabled. The \c NO_GENERATE_QMLDIR option disables the
+\c qmldir auto-generation and the \c NO_GENERATE_QMLTYPES option disables the
+typeinfo and C++ type registration auto-generation. If the auto-generated
+typeinfo file is acceptable, but the project wants to use a different name for
+that file, it can override the default name with the \c TYPEINFO option (but
+this should not typically be needed).
+
+\target qmlcachegen-auto
+\section2 Caching compiled QML sources
+
+All \c{.qml}, \c{.js}, and \c{.mjs} files added to the module via the
+\c QML_FILES argument will be compiled to bytecode and cached directly in the
+backing target. This improves load-time performance of the module. The original
+uncompiled files are also stored in the backing target's resources, as these
+may still be needed in certain situations by the QML engine.
+
+The resource path of each file is determined by its path relative to the
+current source directory (\c CMAKE_CURRENT_SOURCE_DIR). This resource path is
+appended to a prefix formed by concatenating the \l{RESOURCE_PREFIX} and
+the target path (but see \l NO_RESOURCE_TARGET_PATH for an exception to this).
+
+If \l{QTP0001} policy is set to \c NEW, the \l{RESOURCE_PREFIX} defaults
+to \c{/qt/qml/} which is the default import path of the QML engine.
+This ensures that modules are put into the \l{QML Import Path} and can be
+found without further setup.
+
+Ordinarily, the project should aim to place \c{.qml} files in
+the same relative location as they would have in the resources. If the \c{.qml}
+file is in a different relative directory to its desired resource path, its
+location in the resources needs to be explicitly specified. This is done by
+setting the \c QT_RESOURCE_ALIAS source file property, which must be set before
+the \c{.qml} file is added. For example:
+
+\badcode
+set_source_files_properties(path/to/somewhere/MyFrame.qml PROPERTIES
+ QT_RESOURCE_ALIAS MyFrame.qml
+)
+
+qt_add_qml_module(someTarget
+ URI MyCo.Frames
+ RESOURCE_PREFIX /my.company.com/imports
+ QML_FILES
+ path/to/somewhere/MyFrame.qml
+ AnotherFrame.qml
+)
+\endcode
+
+In the above example, the target path will be \c{MyCo/Frames}. After
+taking into account the source file properties, the two \c{.qml} files will be
+found at the following resource paths:
+
+\list
+\li \c{/my.company.com/imports/MyCo/Frames/MyFrame.qml}
+\li \c{/my.company.com/imports/MyCo/Frames/AnotherFrame.qml}
+\endlist
+
+In the rare case that you want to override the automatic selection of the
+qmlcachegen program to be used, you may set the \c QT_QMLCACHEGEN_EXECUTABLE
+target property on the module target. For example:
+
+\badcode
+set_target_properties(someTarget PROPERTIES
+ QT_QMLCACHEGEN_EXECUTABLE qmlcachegen
+)
+\endcode
+
+This explicitly selects qmlcachegen as the program to be used, even if
+better alternatives are available.
+
+Furthermore, you can pass extra arguments to qmlcachegen, by setting the
+\c QT_QMLCACHEGEN_ARGUMENTS option. In particular, the \c --only-bytecode
+option will turn off compilation of QML script code to C++. For example:
+
+\badcode
+set_target_properties(someTarget PROPERTIES
+ QT_QMLCACHEGEN_ARGUMENTS "--only-bytecode"
+)
+\endcode
+
+Another important argument is \c{--direct-calls}. You can use it to enable the
+direct mode of \l{The QML script compiler} in case the Qt Quick Compiler
+Extensions are installed. If the extensions are not installed, the argument is
+ignored. There is a shorthand called \c {QT_QMLCACHEGEN_DIRECT_CALLS} for it.
+
+\badcode
+set_target_properties(someTarget PROPERTIES
+ QT_QMLCACHEGEN_DIRECT_CALLS ON
+)
+\endcode
+
+Finally, the \c --verbose argument can be used to see diagnostic output from
+qmlcachegen:
+
+\badcode
+set_target_properties(someTarget PROPERTIES
+ QT_QMLCACHEGEN_ARGUMENTS "--verbose"
+)
+\endcode
+
+With this flag set, qmlcachegen will output warnings for each function it
+cannot compile to C++. Some of these warnings will point to problems in your
+QML code and some will tell you that certain features of the QML language are
+not implemented in the C++ code generator. In both cases, qmlcachegen will
+still generate byte code for such functions. If you want to see only the
+problems in your QML code, you should use qmllint and the targets generated
+for it instead.
+
+\target qmllint-auto
+\section2 Linting QML sources
+
+A separate linting target will be automatically created if any \c{.qml} files
+are added to the module via the \c QML_FILES keyword, or by a later call to
+\l{qt6_target_qml_sources}{qt_target_qml_sources()}. The name of the linting
+target will be the \c target followed by \c{_qmllint}. An \c{all_qmllint}
+target which depends on all the individual \c{*_qmllint} targets is also
+provided as a convenience.
+
+\target qml-naming-js-files
+\section2 Naming conventions for \c{.js} files
+
+JavaScript file names that are intended to be addressed as components should
+start with an uppercase letter.
+
+Alternatively, you may use lowercase file names and set the source file
+property \l QT_QML_SOURCE_TYPENAME to the desired type name.
+
+\target qml-cmake-singletons
+\section2 Singletons
+
+If a QML module has \c{.qml} files which provide singleton types, these files
+need to have their \c QT_QML_SINGLETON_TYPE source property set to \c TRUE, to
+ensure that the \c singleton command is written into the
+\l{Module Definition qmldir Files}{qmldir} file. This must be done in addition
+to the QML file containing the \c {pragma Singleton} statement.
+The source property must be set before creating the module the
+singleton belongs to.
+
+See \l{qt_target_qml_sources_example}{qt_target_qml_sources()} for an example on
+how to set the \c QT_QML_SINGLETON_TYPE property.
+
+\target qmltc-cmake
+\section2 Compiling QML to C++ with QML type compiler
+
+\note The \l{QML type compiler} \c{qmltc} does not guarantee that the generated
+C++ stays API-, source- or binary-compatible between past or future versions,
+even patch versions.
+Furthermore, qmltc-compiled apps using Qt's QML modules will require linking
+against private Qt API, see also
+\l{QML type compiler#compiling-qml-code-with-qmltc}{Compiling QML code with qmltc}.
+
+
+If a QML module has \c{.qml} files, you can compile them to C++ using \l{QML
+type compiler}{qmltc}. Unlike \l{qmlcachegen-auto}{bytecode compilation}, you
+have to explicitly enable qmltc via \l{ENABLE_TYPE_COMPILER} argument. In which
+case, \c{.qml} files specified under \c{QML_FILES} would be compiled. Files
+ending with \c{.js} and \c{.mjs} are ignored as qmltc does not compile
+JavaScript code. Additionally, files marked with QT_QML_SKIP_TYPE_COMPILER
+source file property are also skipped.
+
+By default, qmltc creates lower-case \c{.h} and \c{.cpp} files for a given
+\c{.qml} file. For example, \c{Foo.qml} ends up being compiled into \c{foo.h}
+and \c{foo.cpp}.
+
+The created C++ files are placed into a dedicated \c{.qmltc/<target>/}
+sub-directory of the \c BINARY_DIR of the \c target. These files are then
+automatically added to the target sources and compiled as Qt C++ code along with
+other source files.
+
+While processing QML_FILES, the following source file properties are respected:
+\list
+ \li \c{QT_QMLTC_FILE_BASENAME}: use this source file property to specify a
+ non-default .h and .cpp file name, which might be useful to e.g. resolve
+ conflicting file names (imagine you have main.qml that is being
+ compiled, but main.h already exists, so #include "main.h" might not do
+ what you expect it to do). QT_QMLTC_FILE_BASENAME is expected to be a
+ file name (without extension), so any preceding directory is ignored.
+ Unlike in the case of default behavior, the QT_QMLTC_FILE_BASENAME is
+ not lower-cased.
+ \li \c{QT_QML_SKIP_TYPE_COMPILER}: use this source file property to
+ specify that a QML file must be ignored by qmltc.
+\endlist
+
+\section1 Arguments
+
+\section2 Required arguments
+
+The \c target specifies the name of the backing target for the QML module.
+By default, it is created as a shared library if Qt was built as shared
+libraries, or as a static library otherwise. This choice can be explicitly
+overridden with the \c STATIC or \c SHARED options.
+
+Every QML module must define a \c URI. It should be specified in dotted URI
+notation, such as \c{QtQuick.Layouts}. Each segment must be a well-formed
+ECMAScript Identifier Name. This means, for example, the segments
+must not start with a number and they must not contain \e{-} (minus)
+characters. As the \c URI will be translated into directory names, you
+should restrict it to alphanumeric characters of the latin alphabet,
+underscores, and dots. Other QML modules may use this name in
+\l{qtqml-syntax-imports.html}{import statements} to import the module. The
+\c URI will be used in the \c module line of the generated
+\l{Module Definition qmldir Files}{qmldir} file. The \c URI is also used to
+form the \e{target path} by replacing dots with forward slashes.
+
+See \l{qtqml-modules-identifiedmodules.html}{Identified Modules} for further
+in-depth discussion of the module URI.
+
+\section2 Versions
+
+A QML module can also define a \c VERSION in the form \c{Major.Minor}, where
+both \c Major and \c Minor must be integers. An additional \c{.Patch}
+component may be appended, but will be ignored. A list of earlier major
+versions the module provides types for can also optionally be given after the
+\c PAST_MAJOR_VERSIONS keyword (see below).
+See \l{qtqml-modules-identifiedmodules.html}{Identified Modules} for further
+in-depth discussion of version numbering,
+\l{Registering past major versions} for registering past major versions, and
+\l{Keeping module versions in sync} for keeping module versions in sync.
+
+If you don't need versions you should omit the \c VERSION argument. It defaults
+to the highest possible version. Internal versioning of QML modules has some
+fundamental flaws. You should use an external package management mechanism to
+manage different versions of your QML modules.
+
+\section2 Adding sources and resources to the module
+
+\c SOURCES specifies a list of non-QML sources to be added to the backing
+target. It is provided as a convenience and is equivalent to adding the sources
+to the backing target with the built-in \c{target_sources()} CMake command.
+
+\c QML_FILES lists the \c{.qml}, \c{.js} and \c{.mjs} files for the module.
+These will be automatically \l{qmlcachegen-auto}{compiled into bytecode} and
+embedded in the backing target unless the \c NO_CACHEGEN option is given.
+The uncompiled file is always stored in the embedded resources of the backing
+target, even if \c NO_CACHEGEN is specified. Unless the \c NO_LINT option is
+given, the uncompiled files will also be
+\l{Linting QML sources}{processed by \c qmllint} via a separate custom build
+target. The files will also be used to populate type information in the
+generated \l{Module Definition qmldir Files}{qmldir} file by default.
+\c NO_GENERATE_QMLDIR can be given to disable the automatic generation of the
+\c qmldir file. This should normally be avoided, but for cases where the
+project needs to provide its own \c qmldir file, this option can be used.
+
+\note See \l{qt6_target_qml_sources}{qt_target_qml_sources()} for further details on
+how to add qmlfiles after \c qt_add_qml_module() was called.
+For example, you may wish to add files conditionally based on an if statement
+expression, or from subdirectories that will only be added if certain criteria
+are met.
+Furthermore, files added with \l{qt6_target_qml_sources}{qt_target_qml_sources()}
+also can specify if they should be skipped for the linting,
+\l{qmlcachegen-auto}{bytecode compilation} or \c qmldir file generation.
+
+\c RESOURCES lists any other files needed by the module, such as images
+referenced from the QML code. These files will be added as compiled-in
+resources (see \l RESOURCE_PREFIX for an explanation of the base point they
+will be located under). If needed, their relative location can
+be controlled by setting the \c QT_RESOURCE_ALIAS source property, just as for
+\c{.qml} files (see \l{qmlcachegen-auto}{Caching compiled QML sources}).
+
+\target RESOURCE_PREFIX
+\c RESOURCE_PREFIX is intended to encapsulate a namespace for the project and
+will often be the same for all QML modules that the project defines. It should
+be chosen to avoid clashing with the resource prefix of anything else used by
+the project or likely to be used by any other project that might consume it.
+A good choice is to incorporate the domain name of the organization the project
+belongs to. A common convention is to append \c{/imports} to the domain name to
+form the resource prefix. For example:
+
+\badcode
+qt_add_qml_module(someTarget
+ RESOURCE_PREFIX /my.company.com/imports
+ ...
+)
+\endcode
+
+\target NO_RESOURCE_TARGET_PATH
+When various files are added to the compiled-in resources, they are placed
+under a path formed by concatenating the \c RESOURCE_PREFIX and the target path.
+For the special case where the backing target is an executable, it may be
+desirable to place the module's \c{.qml} files and other resources directly
+under the \c RESOURCE_PREFIX instead. This can be achieved by specifying the
+\c NO_RESOURCE_TARGET_PATH option, which may only be used if the backing target
+is an executable.
+
+\target PAST_MAJOR_VERSIONS
+\section2 Registering past major versions
+
+\c PAST_MAJOR_VERSIONS contains a list of additional major version that the module
+provides. For each of those versions and each QML file
+without a \c QT_QML_SOURCE_VERSIONS setting an additional entry in the
+\l{Module Definition qmldir Files}{qmldir} file will be generated to specify
+the extra version. Furthermore, the generated module registration code will
+register the past major versions using \l{qmlRegisterModule()} on the C++ side.
+The module registration code is automatically generated for your QML module,
+unless you specify \c{NO_GENERATE_QMLTYPES} (but use of this option is strongly
+discouraged). Usage of \c PAST_MAJOR_VERSIONS adds some overhead when your
+module is imported. You should increment the major version of your module as
+rarely as possible. Once you can rely on all QML files importing this module to
+omit the version in their imports, you can safely omit \c{PAST_MAJOR_VERSIONS}.
+All the QML files will then import the latest version of your module. If you
+have to support versioned imports, consider supporting only a limited number of
+past major versions.
+
+\section2 Declaring module dependencies
+
+\c IMPORTS provides a list of other QML modules that this module imports. Each
+module listed here will be added as an \c{import} entry in the generated
+\l{Module Definition qmldir Files}{qmldir} file. If a QML file imports
+this module, it also imports all the modules listed under \c{IMPORTS}.
+Optionally, a version can be specified by appending it after a slash, such as
+\c{QtQuick/2.0}. Omitting the version will cause the greatest version available
+to be imported. You may only specify the major version, as in \c{QtQuick/2}. In
+that case the greatest minor version available with the given major version will
+be imported. Finally, \c{auto} may be given as version (\c{QtQuick/auto}). If
+\c{auto} is given, the version that the current module is being imported with is
+propagated to the module to be imported. Given an entry \c{QtQuick/auto} in a
+module \c{YourModule}, if a QML file specifies \c{import YourModule 3.14}, this
+results in importing version \c{3.14} of \c{QtQuick}. For related modules that
+follow a common versioning scheme, you should use \c{auto}.
+
+\c OPTIONAL_IMPORTS provides a list of other QML modules that this module
+\e may import at run-time. These are not automatically imported by the QML
+engine when importing the current module, but rather serve as hints to tools
+like \c qmllint. Versions can be specified in the same way as for \c IMPORTS.
+Each module listed here will be added as an \c{optional import} entry in the
+generated \l{Module Definition qmldir Files}{qmldir} file.
+
+\c DEFAULT_IMPORTS specifies which of the optional imports are the default entries
+that should be loaded by tooling. One entry should be specified for every group of
+\c OPTIONAL_IMPORTS in the module. As optional imports are only resolved at runtime,
+tooling like qmllint cannot in general know which of the optional imports should
+be resolved. To remedy this, you can specify one of the optional imports as the
+default import; tooling will then pick it. If you have one optional import that
+gets used at runtime without any further configuration, that is an ideal candidate
+for the default import.
+
+\c DEPENDENCIES provides a list of other QML modules that this module depends
+on, but doesn't necessarily import. It would typically be used for dependencies
+that only exist at the C++ level, such as a module registering a class to QML
+which is a subclass of one defined in another module.
+
+For example, if one would like to subclass \c QQuickItem as following:
+
+\badcode
+class MyItem: public QQuickItem { ... };
+\endcode
+
+then one has to make sure that the module containing \c QQuickItem, called
+\c Quick, is declared as a dependency via the \c DEPENDENCIES option. Not doing
+so might result in errors during type compilation with
+\l{QML type compiler}{qmltc} or during binding and function compilation to C++
+with \l{qmlcachegen-auto}{qmlcachegen}.
+
+\note Adding the module to \c DEPENDENCIES is not necessary if the module
+is already imported via the \c IMPORTS option. The recommended way is to
+use the lighter alternative \c DEPENDENCIES over \c IMPORTS.
+
+The module version of the
+dependencies must be specified along with the module name, in the same form as
+used for \c IMPORTS and \c OPTIONAL_IMPORTS. Each module listed here will be
+added as a \c{depends} entry in the generated
+\l{Module Definition qmldir Files}{qmldir} file.
+
+\target IMPORT_PATH
+\c IMPORT_PATH can be used to add to the search paths where other QML modules
+that this one depends on can be found. The other modules must have their
+\c qmldir file under their own target path below one of the search paths.
+
+If the backing target is a static library and that static library will be
+installed, \c OUTPUT_TARGETS should be given to provide a variable in which to
+store a list of additional targets that will also need to be installed.
+These additional targets are generated internally by \c{qt_add_qml_module()}
+and are referenced by the backing target's linking requirements as part of
+ensuring that resources are set up and loaded correctly.
+
+\target PLUGIN_TARGET
+\section2 Targets and plugin targets
+
+\c PLUGIN_TARGET specifies the plugin target associated with the QML module.
+The \c PLUGIN_TARGET can be the same as the backing
+\c target, in which case there will be no separate backing target.
+If \c PLUGIN_TARGET is not given, it defaults to \c target with \c plugin
+appended. For example, a backing target called \c mymodule would have a default
+plugin name of \c mymoduleplugin. The plugin target's name will be used to
+populate a \c{plugin} line in the generated
+\l{Module Definition qmldir Files}{qmldir} file. Therefore, you must not try to
+change the plugin's output name by setting target properties like
+\c OUTPUT_NAME or any of its related properties.
+
+The backing \c target and the plugin target (if different) will be created by
+the command, unless they already exist. Projects should generally let them be
+created by the command so that they are created as the appropriate target type.
+If the backing \c target is a static library, the plugin will also be created
+as a static library. If the backing \c target is a shared library, the plugin
+will be created as a module library. If an existing \c target is passed in and
+it is an executable target, there will be no plugin. If you intend to always
+link directly to the backing target and do not need a plugin, it can be
+disabled by adding the \c NO_PLUGIN option. Specifying both \c NO_PLUGIN and
+\c PLUGIN_TARGET is an error.
+
+\target NO_CREATE_PLUGIN_TARGET
+In certain situations, the project may want to delay creating the plugin target
+until after the call. The \c NO_CREATE_PLUGIN_TARGET option can be given in
+that situation. The project is then expected to call
+\l{qt6_add_qml_plugin}{qt_add_qml_plugin()} on the plugin target once it has
+been created. When \c NO_CREATE_PLUGIN_TARGET is given, \c PLUGIN_TARGET must
+also be provided to explicitly name the plugin target.
+
+\target CLASS_NAME
+\target NO_GENERATE_PLUGIN_SOURCE
+By default, \c{qt_add_qml_module()} will auto-generate a \c{.cpp} file that
+implements the plugin class named by the \c CLASS_NAME argument. The generated
+\c{.cpp} file will be automatically added to the plugin target as a source file
+to be compiled. If the project wants to provide its own implementation of the
+plugin class, the \c NO_GENERATE_PLUGIN_SOURCE option should be given. Where no
+\c CLASS_NAME is provided, it defaults to the \c URI with dots replaced by
+underscores, then \c Plugin appended. Unless the QML module has no plugin, the
+class name will be recorded as a \c classname line in the generated
+\l{Module Definition qmldir Files}{qmldir} file. You need to add any C++ files
+with custom plugin code to the plugin target. Since the plugin then likely
+contains functionality that goes beyond simply loading the backing library, you
+will probably want to add \l{NO_PLUGIN_OPTIONAL}, too. Otherwise the QML engine
+may skip loading the plugin if it detects that the backing library is already
+linked.
+
+\target NO_PLUGIN
+If the \c NO_PLUGIN keyword is given, then no plugin will be built. This
+keyword is thus incompatible with all the options that customize the plugin
+target, in particular \l{NO_GENERATE_PLUGIN_SOURCE}, \l{NO_PLUGIN_OPTIONAL},
+\l{PLUGIN_TARGET}, \l{NO_CREATE_PLUGIN_TARGET}, and \l{CLASS_NAME}. If you do
+not provide a plugin for your module, it will only be fully usable if its
+backing library has been linked into the executable. It is generally hard to
+guarantee that a linker preserves the linkage to a library it considers unused.
+
+\target NO_PLUGIN_OPTIONAL
+If the \c NO_PLUGIN_OPTIONAL keyword is given, then the plugin is recorded in
+the generated \c qmldir file as non-optional. If all of a QML module's
+functionality is implemented in its backing target and the plugin target is
+separate, then the plugin can be optional, which is the default and recommended
+arrangement. The auto-generated plugin source file satisfies this requirement.
+Where a project provides its own \c{.cpp} implementation for the plugin, that
+would normally mean the \c NO_PLUGIN_OPTIONAL keyword is also needed because
+the plugin will almost certainly contain functionality that the QML module
+requires.
+
+\section2 Automatic type registration
+
+Type registration is automatically performed for the backing target's C++
+sources that are processed by AUTOMOC. This will generate a typeinfo file in the
+\l{OUTPUT_DIRECTORY}{output directory}, the file name being the \c target name
+with \c{.qmltypes} appended. This file name can be changed using the
+\c TYPEINFO option if desired, but this should not normally be necessary.
+The file name is also recorded as a \c typeinfo entry in the generated
+\l{Module Definition qmldir Files}{qmldir} file. Automatic type registration
+can be disabled using the \c NO_GENERATE_QMLTYPES option, in which case no
+typeinfo file will be generated, but the project will still be expected to
+generate a typeinfo file and place it in the same directory as the generated
+\c qmldir file.
+
+\target OUTPUT_DIRECTORY
+\c OUTPUT_DIRECTORY specifies where the plugin library, \c qmldir and typeinfo
+files are generated. When this keyword is not given, the default value will be
+the target path (formed from the \c URI) appended to the value of the
+\l QT_QML_OUTPUT_DIRECTORY variable.
+If that variable is not defined, the default depends on the type of backing
+target. For executables, the value will be the target path appended to
+\c{${CMAKE_CURRENT_BINARY_DIR}}, whereas for other targets it will be just
+\c{${CMAKE_CURRENT_BINARY_DIR}}. When the structure of the source tree
+matches the structure of QML module target paths (which is highly recommended),
+\l QT_QML_OUTPUT_DIRECTORY often isn't needed. In order to match the structure
+of the target paths, you have to call your directories \e exactly like the
+segments of your module URI. For example, if your module URI is
+\c{MyUpperCaseThing.mylowercasething}, you need to put this in a directory
+called \c{MyUpperCaseThing/mylowercasething/}.
+
+The need for specifying the \c OUTPUT_DIRECTORY keyword should be rare, but if
+it is used, it is likely that the caller will also need to add to the
+\l IMPORT_PATH to ensure that \l{qmllint-auto}{linting},
+\l{qmlcachegen-auto}{cached compilation} of qml sources,
+\l{qt6_import_qml_plugins}{automatic importing} of plugins in static builds,
+and \l{qt_deploy_qml_imports}{deploying imported QML modules} for non-static
+builds all work correctly.
+
+\section2 Qt Quick Designer compatibility
+
+\c DESIGNER_SUPPORTED should be given if the QML module supports
+Qt Quick Designer. When present, the generated \c qmldir file will contain
+a \c designersupported line. See \l{Module Definition qmldir Files} for how
+this affects the way Qt Quick Designer handles the plugin.
+
+\section2 Keeping module versions in sync
+
+The \c FOLLOW_FOREIGN_VERSIONING keyword relates to base types of your own
+C++-defined QML types that live in different QML modules. Typically, the
+versioning scheme of your module does not match that of the module providing
+the base types. Therefore, by default all revisions of the base types are
+made available in any import of your module. If \c FOLLOW_FOREIGN_VERSIONING
+is given, the version information attached to the base types and their
+properties is respected. So, an \c {import MyModule 2.8} will then only make
+available versioned properties up to version \c{2.8} of any base types outside
+\c{MyModule}.
+This is mostly useful if you want to keep your module version in sync
+with other modules you're basing types on. In that case you might want your custom
+types to not expose properties from a module's base type version greater than the one being
+imported.
+
+\section2 C++ namespaces of generated code
+
+If a namespace is given with the \c NAMESPACE keyword, the plugin and registration
+code will be generated into a C++ namespace of this name.
+
+\section2 qmlimportscanner and NO_IMPORT_SCAN
+
+For static Qt builds, \c{qmlimportscanner} is run at configure time to scan the
+\c{.qml} files of a QML module and identify the QML imports it uses (see
+\l{qt6_import_qml_plugins}{qt_import_qml_plugins()}). For non-static Qt builds,
+if the target is an executable, a similar scan is performed at build time to
+provide the information needed by deployment scripts (see
+\l{qt6_deploy_qml_imports}{qt_deploy_qml_imports()}). Both scans can be
+disabled by providing the \c{NO_IMPORT_SCAN} option. Doing so means the project
+takes on the responsibility of ensuring all required plugins are instantiated
+and linked for static builds. For non-static builds the project must manually
+work out and deploy all QML modules used by an executable target.
+
+\section2 Arguments for qmltc
+
+\target ENABLE_TYPE_COMPILER
+\c ENABLE_TYPE_COMPILER can be used to compile \c{.qml} files to C++ source code
+with \l{QML type compiler}{qmltc}. Files with the source property
+\c{QT_QML_SKIP_TYPE_COMPILER} are not compiled to C++.
+
+\c TYPE_COMPILER_NAMESPACE argument allows to override the namespace in which
+\l{QML type compiler}{qmltc} generates code.
+By default, the namespace of the generated code follows the module
+hierarchy as depicted in the URI,
+e.g., \c MyModule for a module with URI \c MyModule or
+\c com::example::Module for URI \c com.example.MyModule.
+By specifying the \c TYPE_COMPILER_NAMESPACE option, the generated code
+can be put instead in a custom namespace, where different subnamespaces are to
+be separated by a "::", e.g. "MyNamespace::MySubnamespace" for the namespace MySubnamespace that
+is inside the MyNamespace. Apart from the "::", C++ namespace naming rules
+apply.
+
+\c QMLTC_QMLTC_EXPORT_DIRECTIVE should be used with \c QMLTC_EXPORT_FILE_NAME when
+the classes generated by \l{QML type compiler}{qmltc} should be exported from
+the qml library. By default, classes generated by qmltc are not exported from
+their library.
+The header defining the export macro for the current library
+can be specified as an optional argument to \c QMLTC_EXPORT_FILE_NAME while the
+exporting macro name should be specified as an argument to
+\c QMLTC_QMLTC_EXPORT_DIRECTIVE. If no additional include is required or wanted,
+e.g. when the header of the export macro is already indirectly included by a base
+class, then the \c QMLTC_EXPORT_FILE_NAME option can be left out.
+*/
diff --git a/src/qml/doc/src/cmake/qt_add_qml_plugin.qdoc b/src/qml/doc/src/cmake/qt_add_qml_plugin.qdoc
new file mode 100644
index 0000000000..2ce744559c
--- /dev/null
+++ b/src/qml/doc/src/cmake/qt_add_qml_plugin.qdoc
@@ -0,0 +1,120 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-add-qml-plugin.html
+\ingroup cmake-commands-qtqml
+
+\title qt_add_qml_plugin
+\target qt6_add_qml_plugin
+
+\brief Defines a plugin associated with a QML module.
+
+\section1 Synopsis
+
+\badcode
+qt_add_qml_plugin(
+ target
+ [BACKING_TARGET backing_target]
+ [STATIC | SHARED]
+ [OUTPUT_DIRECTORY]
+ [URI]
+ [CLASS_NAME]
+ [NO_GENERATE_PLUGIN_SOURCE]
+ [NAMESPACE namespace]
+)
+
+\endcode
+
+\versionlessCMakeCommandsNote qt6_add_qml_plugin()
+
+\section1 Description
+
+This command creates the plugin target associated with a QML module. It would
+normally be called internally by \l{qt6_add_qml_module}{qt_add_qml_module()} to
+create or update the plugin associated with its backing target. You should not
+call this function directly unless you have special circumstances that require
+you to create the target in a special way.
+
+The documentation for \l{qt6_add_qml_module}{qt_add_qml_module()} describes
+different structural patterns for how the CMake targets associated with a QML
+module can be arranged. Note that even if the QML module has no separate backing
+target and all functionality is implemented directly in the plugin (not the
+recommended arrangement), you should still call
+\l{qt6_add_qml_module}{qt_add_qml_module()} rather than \c{qt_add_qml_plugin()}.
+
+
+\section1 Arguments
+
+The \c target specifies the name of the target to use for the QML plugin. If it
+does not already exist, it will be created.
+
+\c BACKING_TARGET specifies the name of the backing target that the plugin is
+associated with. The backing target can be the same as the plugin \c target, in
+which case there is only the one merged target, but this is not typically
+recommended (see \l{qt6_add_qml_module}{qt_add_qml_module()} for more
+information). \c BACKING_TARGET should always be provided unless there are
+special circumstances that require the plugin target to be created before the
+backing target. If \c BACKING_TARGET is not provided, a \c URI option must be
+given.
+
+By default, the plugin is created with a type that is compatible with the
+backing target. If the backing target is a static library, the plugin will also
+be created as a static library. If the backing target is a shared library, the
+plugin will be created as a module library. Where no backing target is
+provided or the plugin has no separate backing target, the plugin type can be
+specified with either the \c STATIC or \c SHARED keywords. If the plugin type
+is not determined by any of the preceding conditions, a static plugin will be
+created if Qt was built as static libraries, or a module library plugin
+otherwise.
+
+\c OUTPUT_DIRECTORY specifies the directory where the plugin library will be
+created. It should always be the same location as the QML module's
+\l{Module Definition qmldir Files}{qmldir} file. When \c OUTPUT_DIRECTORY is
+not given, it will be obtained from information stored on the
+\c BACKING_TARGET, where available. Note that this could be different to the
+directory of the backing target's own library. If an output directory cannot be
+obtained from the backing target, the \c CMAKE_CURRENT_BINARY_DIR is used by
+default.
+
+\c URI declares the module identifier of the QML module this plugin is
+associated with. The module identifier is the (dotted URI notation) identifier
+for the QML module. If \c URI is not given, a \c BACKING_TARGET must be
+provided and the backing target must have its URI recorded on it (typically by
+an earlier call to \l{qt6_add_qml_module}{qt_add_qml_module()}).
+
+Each plugin should have a C++ class that registers the module with the QML
+engine. By default, \c{qt_add_qml_plugin()} auto-generates the sources for this
+C++ class, and adds them to the \c{target}'s list of sources. The generated
+plugin class satisfies the requirements of the plugin being optional (see
+\l{Module Definition qmldir Files}). The class name is determined as follows:
+
+\list
+ \li If \c CLASS_NAME has been given, it will be used. It must match the name
+ used in the QML module's \c qmldir file.
+ \li If \c CLASS_NAME has not been given, but \c BACKING_TARGET has, the C++
+ class name will be taken from details recorded on that backing target.
+ Those details are usually recorded by an earlier call to
+ \l{qt_add_qml_module}{qt_add_qml_module()}, and they will match the name
+ used in the generated \c qmldir file. This is the recommended way to
+ provide the class name in most scenarios.
+ \li If the class name still cannot be determined, it is set to the module's
+ URI with dots replaced by underscores, and \c Plugin appended.
+\endlist
+
+If a namespace is given with the \c NAMESPACE keyword, the plugin
+code will be generated into a C++ namespace of this name.
+
+Some plugins may require the plugin class to be written manually. For example,
+the plugin may need to perform additional initialization or register things
+not implemented by the default plugin class. In such cases, the
+\c NO_GENERATE_PLUGIN_SOURCE option can be given. You are then responsible for
+writing your own C++ plugin class and adding it to the \c target. Note that if
+you need to write your own plugin class, it is very unlikely that the plugin
+can be optional. This in turn means that the \c NO_PLUGIN_OPTIONAL keyword
+should be included in the call to \l{qt_add_qml_module}{qt_add_qml_module()}
+when defining the QML module, or else the generated \c qmldir file will be
+incorrect. Make sure your plugin class uses the same class name as determined
+from the logic just above.
+
+*/
diff --git a/src/qml/doc/src/cmake/qt_deploy_qml_imports.qdoc b/src/qml/doc/src/cmake/qt_deploy_qml_imports.qdoc
new file mode 100644
index 0000000000..87125cd0bf
--- /dev/null
+++ b/src/qml/doc/src/cmake/qt_deploy_qml_imports.qdoc
@@ -0,0 +1,116 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-deploy-qml-imports.html
+\ingroup cmake-commands-qtqml
+
+\title qt_deploy_qml_imports
+\keyword qt6_deploy_qml_imports
+
+\summary {Deploy the runtime components of QML modules needed by an executable.}
+
+\include cmake-find-package-qml.qdocinc
+
+Unlike most other CMake commands provided by Qt,
+\c{qt6_deploy_qml_imports} can only be called from a
+deployment script. It cannot be called directly by the project.
+
+\include cmake-qml-qt-finalize-target-warning.qdocinc warning
+
+\section1 Synopsis
+
+\badcode
+qt_deploy_qml_imports(
+ TARGET target
+ [QML_DIR qml_dir]
+ [PLUGINS_FOUND var_name]
+ [NO_QT_IMPORTS]
+)
+\endcode
+
+\section1 Description
+
+\note This command does not usually need to be called directly. It is used
+ internally by other higher level commands, but projects wishing to
+ implement more customized deployment logic may find it useful.
+
+When installing an application that uses QML, it may be non-trivial to work out
+which QML modules and which parts of those QML modules need to also be
+installed. Because QML plugins are not linked directly to an application's
+executable, \l{qt6_deploy_runtime_dependencies}{qt_deploy_runtime_dependencies()} won't find these QML modules.
+The \c{qt6_deploy_qml_imports} command provides the necessary logic which
+complements \l{qt6_deploy_runtime_dependencies}{qt_deploy_runtime_dependencies()} and deploys the runtime parts
+of all QML modules imported by the application.
+
+The \c{TARGET} option is mandatory and should specify a \c{target} that is an
+executable (on macOS, it should be an app bundle) and also a QML module.
+All QML sources that were added to the \c{target} via
+\l{qt6_add_qml_module}{qt_add_qml_module()} or
+\l{qt6_target_qml_sources}{qt_target_qml_sources()} will be recursively scanned
+for QML imports. The \c{NO_IMPORT_SCAN} option must not have been given to
+\l{qt6_add_qml_module}{qt_add_qml_module()}. The \c{qmldir} files and plugins
+from the imported QML modules will be deployed. The \c{NO_QT_IMPORTS} option
+can be given to skip deploying any QML modules provided by Qt.
+
+By default, the runtime parts of imported QML modules will be deployed to the
+\c{Resources/qml} directory for a macOS app bundle target, and to the \c{qml}
+directory under the base installation location for other platforms. For the
+non-macOS case, the \c{QML_DIR} option can be used to override this default
+choice.
+
+The command will store a list of all QML plugins it deploys in the variable
+named by the \c{PLUGINS_FOUND} option, if given. This is often passed as the
+\c{ADDITIONAL_MODULES} argument in a subsequent call to
+\l{qt6_deploy_runtime_dependencies}{qt_deploy_runtime_dependencies()}.
+
+\sa {qt6_generate_deploy_qml_app_script}{qt_generate_deploy_qml_app_script()},
+ {qt6_deploy_runtime_dependencies}{qt_deploy_runtime_dependencies()},
+ QT_DEPLOY_QML_DIR
+
+\section1 Example
+
+\badcode
+cmake_minimum_required(VERSION 3.16...3.22)
+project(MyThings)
+
+find_package(Qt6 6.3 REQUIRED COMPONENTS Core Qml)
+qt_standard_project_setup()
+
+qt_add_executable(MyApp main.cpp)
+qt_add_qml_module(MyApp
+ URI Application
+ VERSION 1.0
+ QML_FILES main.qml MyThing.qml
+)
+
+# The following script must only be executed at install time
+set(deploy_script "${CMAKE_CURRENT_BINARY_DIR}/deploy_MyApp.cmake")
+
+file(GENERATE OUTPUT ${deploy_script} CONTENT "
+include(\"${QT_DEPLOY_SUPPORT}\")
+qt_deploy_qml_imports(
+ # Deploy QML modules used by MyApp
+ TARGET MyApp
+
+ # The found QML plugins are stored in the plugins_found variable
+ PLUGINS_FOUND plugins_found
+
+ # The QML modules will be deployed into a custom directory
+ QML_DIR \"myqmldir\"
+
+ # Qt QML modules will be skipped, only project-created QML modules will be deployed
+ NO_QT_IMPORTS
+)
+# Deploy application runtime dependencies and runtime dependencies
+# of the found QML module plugins.
+qt_deploy_runtime_dependencies(
+ EXECUTABLE $<TARGET_FILE:MyApp>
+ ADDITIONAL_MODULES \${plugins_found}
+)
+")
+
+install(TARGETS MyApp)
+install(SCRIPT ${deploy_script})
+\endcode
+*/
diff --git a/src/qml/doc/src/cmake/qt_generate_deploy_qml_app_script.qdoc b/src/qml/doc/src/cmake/qt_generate_deploy_qml_app_script.qdoc
new file mode 100644
index 0000000000..0d5088e7e5
--- /dev/null
+++ b/src/qml/doc/src/cmake/qt_generate_deploy_qml_app_script.qdoc
@@ -0,0 +1,177 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-generate-deploy-qml-app-script.html
+\ingroup cmake-commands-qtqml
+
+\title qt_generate_deploy_qml_app_script
+\target qt6_generate_deploy_qml_app_script
+
+\summary {Generate a deployment script for a QML application.}
+
+\include cmake-find-package-qml.qdocinc
+
+\cmakecommandsince 6.3
+
+\include cmake-qml-qt-finalize-target-warning.qdocinc warning
+
+\section1 Synopsis
+
+\badcode
+qt_generate_deploy_qml_app_script(
+ TARGET <target>
+ OUTPUT_SCRIPT <var>
+ [NO_UNSUPPORTED_PLATFORM_ERROR]
+ [NO_TRANSLATIONS]
+ [NO_COMPILER_RUNTIME]
+ [DEPLOY_TOOL_OPTIONS ...]
+ [DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM]
+ [MACOS_BUNDLE_POST_BUILD]
+ [PRE_INCLUDE_REGEXES regexes...]
+ [PRE_EXCLUDE_REGEXES regexes...]
+ [POST_INCLUDE_REGEXES regexes...]
+ [POST_EXCLUDE_REGEXES regexes...]
+ [POST_INCLUDE_FILES files...]
+ [POST_EXCLUDE_FILES files...]
+)
+\endcode
+
+\versionlessCMakeCommandsNote qt6_generate_deploy_qml_app_script()
+
+\section1 Description
+
+Installing an executable target that is also a QML module requires deploying
+a number of things in addition to the target itself. Qt libraries and other
+libraries from the project, Qt plugins, and the runtime parts of all QML modules
+the application uses may all need to be installed too. The installed layout
+is also going to be different for macOS app bundles compared to other platforms.
+The \c{qt_generate_deploy_qml_app_script()} is a convenience command intended
+to simplify that process, similar to what
+\l{qt6_generate_deploy_app_script}{qt_generate_deploy_app_script()} does for
+non-QML applications.
+
+The command expects the application to follow Qt's recommended install
+directory structure fairly closely. That structure is based on CMake's default
+install layout, as determined by \l{GNUInstallDirs} (except for macOS app
+bundles, which follow Apple's requirements instead). QML modules are installed
+to the appropriate location for the platform. For macOS bundles, each QML
+module's \c{qmldir} file is installed under the appropriate subdirectory below
+\c{Resources/qml} and the module's plugin (if present) is installed under
+\c{PlugIns}. The app bundle is assumed to be installed directly to the base
+installation location (see the \l{Example} further below). For all other platforms,
+both the \c{qmldir} and the module's plugin are installed under the appropriate
+subdirectory below \c{qml}, which itself is relative to the base installation
+location.
+
+\c{qt_generate_deploy_qml_app_script()} generates a script whose name will be
+stored in the variable named by the \c{OUTPUT_SCRIPT} option. That script
+is only written at CMake generate-time. It is intended to be used with the
+\l{install(SCRIPT)} command, which should come after the application's target
+has been installed using \l{install(TARGETS)}.
+
+The deployment script will call
+\l{qt6_deploy_qml_imports}{qt_deploy_qml_imports()} with a suitable set of
+options for the standard install layout. For macOS app bundles and Windows
+targets, it will then also call
+\l{qt6_deploy_runtime_dependencies}{qt_deploy_runtime_dependencies()}, again
+with suitable options for the standard install layout.
+
+Calling \c{qt_generate_deploy_qml_app_script()} for a platform that is not
+supported by \c{qt_deploy_runtime_dependencies} will result in a fatal error,
+unless the \c{NO_UNSUPPORTED_PLATFORM_ERROR} option is given. When the option
+is given and the project is built for an unsupported platform, neither QML modules
+nor regular runtime dependencies will be installed.
+To ensure that the QML modules are still installed, specify both the
+\c{NO_UNSUPPORTED_PLATFORM_ERROR} and
+\c{DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM} options.
+The latter option will ensure that QML modules built as part of the project
+are still installed.
+
+The \c{MACOS_BUNDLE_POST_BUILD} option enables an extra step when \c{target}
+is a macOS app bundle. A post-build rule will be created which uses the
+deployment script to deploy enough of the imported QML modules to allow the
+application to run directly from the build directory (essentially just the
+\c{qmldir} files and symlinks to plugins). This is usually desirable to support
+development of the application. \c{MACOS_BUNDLE_POST_BUILD} is ignored for all
+other platforms.
+
+On platforms other than macOS, Qt translations are automatically deployed. To
+inhibit this behavior, specify \c{NO_TRANSLATIONS}. Use
+\l{qt_deploy_translations}{qt_deploy_translations()} to deploy translations in a
+customized way.
+
+For Windows desktop applications, the required runtime files for the compiler
+are also installed by default. To prevent this, specify \c{NO_COMPILER_RUNTIME}.
+
+Since Qt 6.7, you can use \c{DEPLOY_TOOL_OPTIONS} to pass additional options to
+the underlying deployment tool. This only has an effect if the underlying
+deployment tool is either macdeployqt or windeployqt.
+
+The options \c{PRE_INCLUDE_REGEXES}, \c{PRE_EXCLUDE_REGEXES},
+\c{POST_INCLUDE_REGEXES}, \c{POST_EXCLUDE_REGEXES}, \c{POST_INCLUDE_FILES}, and
+\c{POST_EXCLUDE_FILES} can be specified to control the deployment of runtime
+dependencies. These options do not apply to all platforms and are forwarded
+unmodified to
+\l{qt6_deploy_runtime_dependencies}{qt_deploy_runtime_dependencies()}.
+
+For deploying a non-QML application, use
+\l{qt6_generate_deploy_app_script}{qt_generate_deploy_app_script()}
+instead. It is an error to call both \c{qt_generate_deploy_qml_app_script()}
+and \l{qt6_generate_deploy_app_script}{qt_generate_deploy_app_script()} for the
+same target.
+
+\sa {qt6_standard_project_setup}{qt_standard_project_setup()},
+ {qt6_generate_deploy_app_script}{qt_generate_deploy_app_script()}
+
+\section1 Example
+
+The following example shows how to deploy a QtQuick app.
+
+\badcode
+cmake_minimum_required(VERSION 3.16...3.22)
+project(MyThings)
+
+find_package(Qt6 6.3 REQUIRED COMPONENTS Core Qml)
+qt_standard_project_setup()
+
+qt_add_executable(MyApp main.cpp)
+qt_add_qml_module(MyApp
+ URI Application
+ VERSION 1.0
+ QML_FILES main.qml MyThing.qml
+)
+
+install(TARGETS MyApp
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
+
+qt_generate_deploy_qml_app_script(
+ TARGET MyApp
+ OUTPUT_SCRIPT deploy_script
+ MACOS_BUNDLE_POST_BUILD
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM
+)
+install(SCRIPT ${deploy_script})
+\endcode
+
+The following example shows how to pass additional options to the underlying
+deployment tool.
+
+\badcode
+set(deploy_tool_options_arg "")
+if(APPLE)
+ set(deploy_tool_options_arg --hardened-runtime)
+elseif(WIN32)
+ set(deploy_tool_options_arg --no-compiler-runtime)
+endif()
+
+qt_generate_deploy_qml_app_script(
+ ...
+ DEPLOY_TOOL_OPTIONS ${deploy_tool_options_arg}
+)
+install(SCRIPT ${deploy_script})
+\endcode
+*/
diff --git a/src/qml/doc/src/cmake/qt_generate_foreign_qml_types.qdoc b/src/qml/doc/src/cmake/qt_generate_foreign_qml_types.qdoc
new file mode 100644
index 0000000000..22d72c101b
--- /dev/null
+++ b/src/qml/doc/src/cmake/qt_generate_foreign_qml_types.qdoc
@@ -0,0 +1,77 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-generate-foreign-qml-types.html
+\ingroup cmake-commands-qtqml
+
+\title qt_generate_foreign_qml_types
+\target qt6_generate_foreign_qml_types
+
+\summary{Registers types from one target in a QML module.}
+
+\include cmake-find-package-qml.qdocinc
+
+\section1 Synopsis
+
+\badcode
+qt_generate_foreign_qml_types(
+ source_target
+ destination_qml_target
+)
+
+\endcode
+
+\versionlessCMakeCommandsNote qt6_generate_foreign_qml_types()
+
+\section1 Description
+
+\c qt_generate_foreign_qml_types extracts types marked via QML registration
+macros (like \l QML_ELEMENT) from \c source_target and registers them as foreign
+types in the QML module \c destination_qml_target.
+
+This can be useful when one wants to create a library with optional QML integration, without
+depending directly on QML.
+
+\badcode
+// myclass.h
+#include <QtQmlIntegration/qqmlintegration.h>
+
+class MyClass : public QObject
+{
+ QML_ELEMENT
+ Q_OBJECT
+
+ // [...]
+};
+\endcode
+
+\badcode
+# CMakeLists.txt
+qt_add_library(mylib myclass.h ...)
+target_link_libraries(mylib PRIVATE Qt::Core Qt::QmlIntegration)
+
+qt_add_qml_module(mylib_declarative
+ VERSION 1.0
+ URI "mylib"
+ ...
+)
+qt_generate_foreign_qml_types(mylib mylib_declarative)
+\endcode
+
+\note In the example above, \c mylib does not depend on QtQml or QtQuick, but only on the
+header-only QmlIntegration target (for the QtQmlIntegration/qqmlintegration.h header, which provides
+the \c QML_ELEMENT macro).
+
+The effect is equivalent to using \c QML_FOREIGN with custom structs in the QML library to expose
+the types.
+
+\note In order to implement custom behavior, such as exposing an existing
+singleton instance with its own life cycle to QML, you should add custom types
+to your QML library (mylib_declarative in the above example). In turn, you
+should omit the \l QML_ELEMENT and similar macros from the original C++ classes
+so that qt_generate_foreign_qml_types() does not generate more QML integration
+structs for them. The QML macros, as well as any singleton factory functions,
+can be added to the structs that contain the \l QML_FOREIGN.
+
+*/
diff --git a/src/qml/doc/src/cmake/qt_import_qml_plugins.qdoc b/src/qml/doc/src/cmake/qt_import_qml_plugins.qdoc
new file mode 100644
index 0000000000..8d6b32f903
--- /dev/null
+++ b/src/qml/doc/src/cmake/qt_import_qml_plugins.qdoc
@@ -0,0 +1,55 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-import-qml-plugins.html
+\ingroup cmake-commands-qtqml
+
+\title qt_import_qml_plugins
+\target qt6_import_qml_plugins
+
+\brief Ensures QML plugins needed by a target are imported for static builds.
+
+\cmakecommandsince 6.0
+
+\section1 Synopsis
+
+\badcode
+qt_import_qml_plugins(target)
+\endcode
+
+\versionlessCMakeCommandsNote qt6_import_qml_plugins()
+
+\section1 Description
+
+\note This command only has any effect if Qt was built statically. If called
+ using a non-static Qt, it will do nothing and return immediately.
+
+\c{qt_import_qml_plugins()} runs \c{qmlimportscanner} on the \c target
+immediately as part of the call (unless the \c{NO_IMPORT_SCAN} option was
+passed to \l{qt6_add_qml_module}{qt_add_qml_module()} when defining the QML
+module). It finds the static QML plugins used by the
+\c target and links it to those plugins so that they are part of the executable
+or shared library that \c target represents. The search follows QML module
+imports recursively.
+
+Because the call to \c{qmlimportscanner} runs at configure time rather than
+generation or build time, \c{qt_import_qml_plugins()} only knows about the
+information recorded on the \c target (or other targets it links or imports)
+at the time \c{qt_import_qml_plugins()} is called. Any linking or import
+relationships added after this call will not be considered. Therefore, this
+command should be called as late as possible in the \c{target}'s directory
+scope so that all the linking and import relationships are known.
+
+If \c target was created using \l{qt6_add_executable}{qt_add_executable()},
+projects would not normally need to call \c{qt_import_qml_plugins()} directly.
+When Qt is built statically, the command is called automatically as part of
+\l{qt6_add_executable#Finalization}{target finalization} if \c target links to
+the Qml library. By default, this finalization occurs at the end of the same
+directory scope in which the \c target was created. If the \c target was
+created using the standard CMake \c{add_executable()} command instead, the
+project needs to call \c{qt_import_qml_plugins()} itself.
+
+\sa Q_IMPORT_QML_PLUGIN
+
+*/
diff --git a/src/qml/doc/src/cmake/qt_query_qml_module.qdoc b/src/qml/doc/src/cmake/qt_query_qml_module.qdoc
new file mode 100644
index 0000000000..c72626a52d
--- /dev/null
+++ b/src/qml/doc/src/cmake/qt_query_qml_module.qdoc
@@ -0,0 +1,213 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-query-qml-module.html
+\ingroup cmake-commands-qtqml
+
+\title qt_query_qml_module
+\target qt6_query_qml_module
+
+\summary {Retrieve information about a QML module.}
+
+\include cmake-find-package-qml.qdocinc
+
+\cmakecommandsince 6.3
+
+\section1 Synopsis
+
+\badcode
+qt_query_qml_module(
+ target
+ [URI uri_var]
+ [VERSION version_var]
+ [PLUGIN_TARGET plugin_target_var]
+ [TARGET_PATH target_path_var]
+ [MODULE_RESOURCE_PATH module_resource_path_var]
+ [QMLDIR qmldir_var]
+ [TYPEINFO typeinfo_var]
+ [QML_FILES qml_files_var]
+ [QML_FILES_DEPLOY_PATHS qml_files_deploy_paths_var]
+ [QML_FILES_PREFIX_OVERRIDES qml_files_prefix_overrides_var]
+ [RESOURCES resources_var]
+ [RESOURCES_DEPLOY_PATHS resources_deploy_paths_var]
+ [RESOURCES_PREFIX_OVERRIDES resources_prefix_overrides_var]
+)
+\endcode
+
+\versionlessCMakeCommandsNote qt6_query_qml_module()
+
+\section1 Description
+
+This command is used to obtain information about a QML module \c target.
+That \c target must have previously been created by or passed to an earlier
+call to \l{qt6_add_qml_module}{qt_add_qml_module()}. The \c target cannot be an
+imported target.
+
+The information provided by this command enables the caller to deploy all parts
+of a single QML module. The project should install the \c target and the
+associated plugin target (if the module has one and it is separate from the
+backing \c target) using the standard \l{install(TARGETS)} command.
+Everything else can be deployed with \l{install(FILES)}.
+
+\section1 Arguments
+
+Each of the optional arguments specifies the name of a variable in which to
+store the corresponding QML module property.
+
+\c URI and \c VERSION provide the module's uri and version respectively.
+
+\c PLUGIN_TARGET can be used to obtain the name of the plugin target for the
+QML module. Not all QML modules have a plugin, so the value returned for this
+option could be an empty string. If the QML module has no separate backing
+target, then \c target will be the same as the plugin target.
+
+\c TARGET_PATH is the \c URI with dots (.) replaced by forward slashes (/).
+It represents the path below the base QML module installation directory where
+this QML module's \c{qmldir} file (and possibly others) should be deployed.
+The QML module installation directory serves as a QML import path where
+the QML engine will look for QML modules.
+The default base QML module installation directory used by
+\l{qt6_generate_deploy_qml_app_script}{qt_generate_deploy_qml_app_script()}
+is \c{qml}. A project using a deployment script can use \l{QT_DEPLOY_QML_DIR}
+rather than hard-coding this location (also see \l{QT_DEPLOY_PREFIX}).
+
+\c MODULE_RESOURCE_PATH provides the resource path under which the QML module's
+compiled-in files can be found. It is formed from
+\l{qt6_add_qml_module}{qt_add_qml_module()}'s \c{RESOURCE_PREFIX} concatenated
+with the module's \c TARGET_PATH.
+The queried value should not be used for deployment, but may be helpful in
+matching up resource paths with file system locations, if needed.
+
+\c QMLDIR provides the path to the \c{qmldir} file. When deploying the QML
+module, this file should be copied to the target path. In a deployment script,
+this location can be obtained using \c{${QT_DEPLOY_PREFIX}/${QT_DEPLOY_QML_DIR}}.
+
+\c TYPEINFO provides the path to the module's typeinfo file, if it has one.
+It will be an empty string if the module has no typeinfo file. The typeinfo
+file should be deployed to the same path as the \c{qmldir} file.
+
+\c QML_FILES provides a list of all files added to the QML module through one
+of the following methods:
+
+\list
+\li As \c{QML_FILES} arguments in \l{qt6_add_qml_module}{qt_add_qml_module()}.
+\li As \c{FILES} arguments in \l{qt6_target_qml_sources}{qt_target_qml_sources()}.
+\endlist
+
+All files will be recorded with absolute paths.
+
+\c QML_FILES_DEPLOY_PATHS provides a list with exactly the same number of
+elements as \c QML_FILES. Each element of the \c QML_FILES_DEPLOY_PATHS list is
+the path below the target path where the corresponding element of \c QML_FILES
+should be deployed. The paths in \c QML_FILES_DEPLOY_PATHS include the file
+name, since this could be different to the file name in \c QML_FILES due to the
+use of resource aliases (see \l{QT_RESOURCE_ALIAS}).
+
+Entries in \c QML_FILES_DEPLOY_PATHS can also be an empty string. Any file
+added using \l{qt6_target_qml_sources}{qt_target_qml_sources()} with a custom
+\c PREFIX will have no deploy path, since using a custom prefix typically means
+the file sits outside of the QML module's target path.
+
+\c QML_FILES_PREFIX_OVERRIDES provides another list with exactly the same
+number of elements as \c QML_FILES. Where a file has been added with a custom
+prefix as described in the preceding paragraph, its corresponding entry in the
+\c QML_FILES_PREFIX_OVERRIDES list will contain the custom prefix used. For all
+other files, their list entries will be an empty string.
+
+\note As a special case, if there is only one file in the \c QML_FILES list,
+then \c QML_FILES_DEPLOY_PATHS or \c QML_FILES_PREFIX_OVERRIDES may be an empty
+string depending on whether that file has a custom prefix.
+This is because CMake's way of representing lists and strings means that
+it is impossible to distinguish between an empty string and a list with a single
+empty element.
+
+The \c RESOURCES, \c RESOURCES_DEPLOY_PATHS, and \c RESOURCES_PREFIX_OVERRIDES
+options are analogous to those for \c QML_FILES discussed above.
+\c RESOURCES provides a list of all files added to the QML module as
+\c RESOURCES arguments to either \l{qt6_add_qml_module}{qt_add_qml_module()} or
+\l{qt6_target_qml_sources}{qt_target_qml_sources()}. All paths will be
+absolute. The meaning and usage of \c RESOURCES_DEPLOY_PATHS and
+\c RESOURCES_PREFIX_OVERRIDES follows the same patterns as
+\c QML_FILES_DEPLOY_PATHS and \c QML_FILES_PREFIX_OVERRIDES respectively.
+
+\section1 Example
+
+\badcode
+cmake_minimum_required(VERSION 3.16...3.22)
+project(MyThings)
+
+find_package(Qt6 6.3 REQUIRED COMPONENTS Core Qml)
+
+set(module_name "MyThings")
+qt_add_qml_module(${module_name}
+ URI My.Things
+ VERSION 1.3
+ RESOURCE_PREFIX org.mycompany/imports
+ QML_FILES
+ First.qml
+ Second.qml
+ RESOURCES
+ Third.txt
+)
+
+qt_query_qml_module(${module_name}
+ URI module_uri
+ VERSION module_version
+ PLUGIN_TARGET module_plugin_target
+ TARGET_PATH module_target_path
+ QMLDIR module_qmldir
+ TYPEINFO module_typeinfo
+ QML_FILES module_qml_files
+ QML_FILES_DEPLOY_PATHS qml_files_deploy_paths
+ RESOURCES module_resources
+ RESOURCES_DEPLOY_PATHS resources_deploy_paths
+)
+
+message("My QML module URI is: ${module_uri}")
+message("My QML module version is: ${module_version}")
+
+# Install the QML module backing library
+set(staging_prefix "staging")
+install(TARGETS ${module_name}
+ ARCHIVE DESTINATION "${staging_prefix}/${CMAKE_INSTALL_LIBDIR}"
+ LIBRARY DESTINATION "${staging_prefix}/${CMAKE_INSTALL_LIBDIR}"
+ RUNTIME DESTINATION "${staging_prefix}/${CMAKE_INSTALL_BINDIR}"
+)
+set(module_dir "${staging_prefix}/qml/${module_target_path}")
+
+# Install the QML module runtime loadable plugin
+install(TARGETS "${module_plugin_target}"
+ LIBRARY DESTINATION "${module_dir}"
+ RUNTIME DESTINATION "${module_dir}"
+)
+
+# Install the QML module meta information.
+install(FILES "${module_qmldir}" DESTINATION "${module_dir}")
+install(FILES "${module_typeinfo}" DESTINATION "${module_dir}")
+
+# Install QML files, possibly renamed.
+list(LENGTH module_qml_files num_files)
+math(EXPR last_index "${num_files} - 1")
+foreach(i RANGE 0 ${last_index})
+ list(GET module_qml_files ${i} src_file)
+ list(GET qml_files_deploy_paths ${i} deploy_path)
+ get_filename_component(dst_name "${deploy_path}" NAME)
+ get_filename_component(dest_dir "${deploy_path}" DIRECTORY)
+ install(FILES "${src_file}" DESTINATION "${module_dir}/${dest_dir}" RENAME "${dst_name}")
+endforeach()
+
+# Install resources, possibly renamed.
+list(LENGTH module_resources num_files)
+math(EXPR last_index "${num_files} - 1")
+foreach(i RANGE 0 ${last_index})
+ list(GET module_resources ${i} src_file)
+ list(GET resources_deploy_paths ${i} deploy_path)
+ get_filename_component(dst_name "${deploy_path}" NAME)
+ get_filename_component(dest_dir "${deploy_path}" DIRECTORY)
+ install(FILES "${src_file}" DESTINATION "${module_dir}/${dest_dir}" RENAME "${dst_name}")
+endforeach()
+
+\endcode
+
+*/
diff --git a/src/qml/doc/src/cmake/qt_target_compile_qml_to_cpp.qdoc b/src/qml/doc/src/cmake/qt_target_compile_qml_to_cpp.qdoc
new file mode 100644
index 0000000000..0ef6e421ed
--- /dev/null
+++ b/src/qml/doc/src/cmake/qt_target_compile_qml_to_cpp.qdoc
@@ -0,0 +1,14 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-target-compile-qml-to-cpp.html
+\ingroup cmake-commands-qtqml
+
+\title qt_target_compile_qml_to_cpp
+\target qt6_target_compile_qml_to_cpp
+
+This command is removed in Qt 6.4 in favor of \l{qt6_add_qml_module} which can
+now invoke qmltc internally as described in the \l{qmltc-cmake}{qmltc section}.
+
+*/
diff --git a/src/qml/doc/src/cmake/qt_target_qml_sources.qdoc b/src/qml/doc/src/cmake/qt_target_qml_sources.qdoc
new file mode 100644
index 0000000000..336cd973f9
--- /dev/null
+++ b/src/qml/doc/src/cmake/qt_target_qml_sources.qdoc
@@ -0,0 +1,206 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-target-qml-sources.html
+\ingroup cmake-commands-qtqml
+
+\title qt_target_qml_sources
+\target qt6_target_qml_sources
+
+\brief Add qml files and resources to an existing QML module target.
+
+\cmakecommandsince 6.2
+
+\section1 Synopsis
+
+\badcode
+qt_target_qml_sources(
+ target
+ [QML_FILES ...]
+ [RESOURCES ...]
+ [PREFIX resource_path]
+ [OUTPUT_TARGETS out_targets_var]
+ [NO_LINT]
+ [NO_CACHEGEN]
+ [NO_QMLDIR_TYPES]
+)
+
+\endcode
+
+\versionlessCMakeCommandsNote qt6_target_qml_sources()
+
+\section1 Description
+
+\note This command requires CMake 3.19 or later.
+
+\c{qt_target_qml_sources()} provides the ability to add more files to a QML
+module after \l{qt6_add_qml_module}{qt_add_qml_module()} has been called.
+Typically, you pass the set of \c{.qml} files and resources to
+\l{qt6_add_qml_module}{qt_add_qml_module()} directly, but in some cases, it may
+be desirable, or even necessary, to add files after
+\l{qt6_add_qml_module}{qt_add_qml_module()} has been called. For example, you
+may wish to add files conditionally based on an \c{if} statement expression,
+or from subdirectories that will only be added if certain criteria are met.
+You might want to add a set of files with different characteristics to the
+others, such as a different resource prefix, or with linting and bytecode
+compilation disabled. The \c{qt_target_qml_sources()} command enables these
+scenarios.
+
+\section1 Arguments
+
+The \c target must be the backing target of a QML module, or if the QML module
+has no separate backing target, it must be the module's plugin target.
+
+\c QML_FILES is a list of \c{.qml}, \c{.js} and \c{.mjs} files to be added to
+the QML module. This option has exactly the same effect as the \c QML_FILES
+option of the \l{qt6_add_qml_module}{qt_add_qml_module()} command, including
+the automatic compilation to bytecode and lint processing.
+
+The \c NO_CACHEGEN and \c NO_LINT options also have the same effect as they do
+for \l{qt6_add_qml_module}{qt_add_qml_module()}. They disable the bytecode
+compilation and lint processing for the files listed with \c QML_FILES. This
+behavior can also be specified just for individual files using
+\l{qml-source-file-properties}{source file properties}.
+
+\c NO_QMLDIR_TYPES prevents the \c QML_FILES from being added as types to the
+generated \l{qmldir-autogeneration}{qmldir} file.
+
+\c RESOURCES has exactly the same effect as the \c RESOURCES option of the
+\l{qt6_add_qml_module}{qt_add_qml_module()} command. It provides a list of
+files to be added to the \c target as ordinary resources. These files are
+typically things like images, shaders, etc. that the QML code refers to in some
+way.
+
+\target PREFIX
+Files added to the module via \c QML_FILES or \c RESOURCES will be placed under
+the same resource prefix and target path as they would if they were added by the
+\l{qt6_add_qml_module}{qt_add_qml_module()} command. This can be overridden by
+providing a different location with the \c PREFIX option. The value following
+the \c PREFIX keyword will be used directly, without appending any target path.
+The final resource path of each file will be the prefix, plus the path of the
+file below the \c CMAKE_CURRENT_SOURCE_DIR. The \l{QT_RESOURCE_ALIAS} source
+file property can also be used to override that relative path.
+
+\badcode
+qt_add_qml_module(backing
+ URI Example
+ VERSION 1.0
+ RESOURCE_PREFIX /my.company.com/imports
+)
+
+qt_target_qml_sources(backing
+ QML_FILES special/First.qml
+ RESOURCES icons/logo.png
+)
+
+qt_target_qml_sources(backing
+ PREFIX /other.company.com/debugging
+ QML_FILES Inspector.qml
+)
+\endcode
+
+In the above example, the \c backing target's resources will end up with the
+following contents:
+
+\list
+\li \c{/my.company.com/imports/Example/special/First.qml}
+\li \c{/my.company.com/imports/Example/icons/logo.png}
+\li \c{/other.company.com/debugging/Inspector.qml}
+\endlist
+
+\c OUTPUT_TARGETS is also analogous to the same option for
+\l{qt6_add_qml_module}{qt_add_qml_module()}. Use it to specify the name of a
+variable in which to store any additional targets created for static builds.
+If the \c target will be installed, these additional targets will also need to
+be installed to satisfy linking requirements.
+
+\target qml-source-file-properties
+\section1 Source File Properties
+
+A number of source file properties can be used to influence how each individual
+\c{.qml} file is treated at various points in the QML module processing. These
+override any higher level options specified in calls to
+\c{qt_target_qml_sources()} or \l{qt6_add_qml_module}{qt_add_qml_module()}.
+All of these properties need to be set before the files are added with either
+of those two commands.
+
+\c QT_QML_SKIP_QMLLINT can be set to \c TRUE on a source file to prevent it
+from being included in the \l{qmllint-auto}{automatic qmllint processing}.
+By default, all \c{.qml} files will be included in the target's lint run, but
+this option can be used to exclude specific files.
+
+\c QT_QML_SKIP_CACHEGEN does a similar thing, preventing a source file from
+being compiled to byte code when this property is set to \c TRUE. Note that the
+file will still be added to the \c target as a resource in uncompiled form
+(see \l{qmlcachegen-auto}{Caching compiled QML sources}).
+
+Set the \c QT_QML_SKIP_QMLDIR_ENTRY source file property to \c TRUE to prevent
+that \c{.qml} file from being added as a type to the QML module's typeinfo file
+(see \l{qmldir-autogeneration}{Auto-generating \c{qmldir} and typeinfo files}).
+This would normally only be used for a file that does not expose a public type,
+such as a private JS file.
+
+By default, when \l{qmldir-autogeneration}{generating the \c qmldir file}, a
+single type entry will be generated for each \c{.qml} file that provides a type.
+It will be given a version number \c{X.0} where \c{X} is the major version of
+the QML module. If the QML module has any \c PAST_MAJOR_VERSIONS set, the same
+pattern will be applied to those too, appending \c{X.0} for each past major
+version \c{X}. For situations where a file needs to provide type entries for
+a different set of versions instead (e.g. it was first added in a minor patch
+version after the \c{.0} release), specify those versions in the source file's
+\c QT_QML_SOURCE_VERSIONS property. One type entry will be created for each
+version.
+
+If the type that a \c{.qml} file provides is a singleton, set its
+\c QT_QML_SINGLETON_TYPE property to \c TRUE. Similarly, the file's
+\c QT_QML_INTERNAL_TYPE source property can be set to \c TRUE to indicate that
+the type it provides is an internal one. The name of the type itself can also
+be overridden using the \c QT_QML_SOURCE_TYPENAME property. All three of these
+will be reflected in the file's type entries in the
+\l{qmldir-autogeneration}{generated \c qmldir file}.
+The source properties must be set before \l{qt_add_qml_module}{creating} the
+module the singleton belongs to.
+
+\target QT_RESOURCE_ALIAS
+All files listed with \c QML_FILES or \c RESOURCES will be added to the
+\c{target}'s resources. Their location in the resources consists of a base point
+and a relative path. The base point defaults to the concatenation of the QML
+module's resource prefix and its target path, but these can be overridden with
+the \l PREFIX argument. The relative path will default to the path of the file
+relative to the \c{target}'s \c SOURCE_DIR target property. This relative path
+can be overridden by setting the \c QT_RESOURCE_ALIAS property on the source
+file. This is commonly used to collect files from different directories and
+have them appear in the resources under a common location.
+
+\target qt_target_qml_sources_example
+\snippet cmake/qt_target_qml_sources/CMakeLists.txt 0
+
+In the above example, the \c qt_target_qml_sources_example target's resources
+will end up with the following contents:
+
+\list
+\li \c{/my.company.com/imports/Example/File.qml}
+\li \c{/my.company.com/imports/Example/FunnySingleton.qml}
+\li \c{/my.company.com/imports/Example/templates/File.qml}
+\li \c{/my.company.com/imports/Example/some_old_thing.qml}
+\li \c{/my.company.com/imports/Example/button-types.png}
+\li \c{/my.company.com/imports/Example/doc/README.txt}
+\endlist
+
+The generated \c qmldir file will contain the following type entries:
+
+\badcode
+File 2.0 File.qml
+singleton FunnySingleton 2.0 FunnySingleton.qml
+OldThing 1.1 some_old_thing.qml
+OldThing 2.0 some_old_thing.qml
+\endcode
+
+\note The source FunnySingleton.qml file must already contain
+the \c {pragma Singleton} statement. Setting the \c QT_QML_SINGLETON_TYPE source
+property does not automatically generate the pragma.
+
+\snippet cmake/qt_target_qml_sources/FunnySingleton.qml 0
+
+*/
diff --git a/src/qml/doc/src/cppclasses/topic.qdoc b/src/qml/doc/src/cppclasses/topic.qdoc
index 6b23dfd433..78595fa13a 100644
--- a/src/qml/doc/src/cppclasses/topic.qdoc
+++ b/src/qml/doc/src/cppclasses/topic.qdoc
@@ -1,35 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-cppclasses-topic.html
\title Important C++ Classes Provided By The Qt QML Module
\brief Overview of the C++ classes provided by the Qt QML module
-The \l{Qt QML} module provides C++ classes which implement the QML framework.
+The \l{Qt Qml} module provides C++ classes which implement the QML framework.
Clients can use these classes to interact with the QML run-time (for example,
by injecting data or invoking methods on objects), and to instantiate a
hierarchy of objects from a QML document. The Qt QML module provides more
@@ -119,7 +95,7 @@ These pages describe how to create QML applications which interact with the
C++ classes:
\list
-\li \l{qtqml-cppintegration-topic.html}{Integrating QML and C++}
+\li \l{Overview - QML and C++ Integration}
\list
\li \l{qtqml-cppintegration-exposecppattributes.html}{Exposing Attributes of C++ Classes to QML}
\li \l{qtqml-cppintegration-definetypes.html}{Defining QML Types from C++}
diff --git a/src/qml/doc/src/cppintegration/contextproperties.qdoc b/src/qml/doc/src/cppintegration/contextproperties.qdoc
index 869e01c69e..1783c0cdc8 100644
--- a/src/qml/doc/src/cppintegration/contextproperties.qdoc
+++ b/src/qml/doc/src/cppintegration/contextproperties.qdoc
@@ -1,34 +1,27 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-cppintegration-contextproperties.html
\title Embedding C++ Objects into QML with Context Properties
\brief Description of how to embed C++ data into QML using context properties
+\warning By using context properties in your QML code, you create a dependency from your QML code
+ to the specific context you have in mind when writing it. This limits re-usability of your
+ code since the context may be different in other places where it might be used.
+ Furthermore, the dependency is not declared. You never \c import the context or otherwise
+ state what you expect. Therefore, anyone trying to re-use your code will have difficulties
+ finding out whether the place of re-use has a context sufficient for your code.
+
+\warning Context properties are invisible to any tooling that processes QML code ahead of time,
+ before you load it into the QML engine. The \l{Qt Quick Compiler},
+ \l{qmllint Reference}{qmllint}, and the \l{\QMLLS Reference}{\QMLLS} do
+ not know anything about your context properties and will consider any access to context
+ properties as an \e{unqualified access}.
+
+\note Context properties can generally be replaced either by regular properties on the root object
+ of a component, or by singletons defined either in C++ using \l{QML_SINGLETON}{QML_SINGLETON}
+ or in QML using \l{Structure of a QML Document#Singleton}{pragma Singleton}.
+
When loading a QML object into a C++ application, it can be useful to directly embed some C++ data
that can be used from within the QML code. This makes it possible, for example, to invoke a C++
method on the embedded object, or use a C++ object instance as a data model for a QML view.
diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc
index 171b2b6a11..2822f4acee 100644
--- a/src/qml/doc/src/cppintegration/data.qdoc
+++ b/src/qml/doc/src/cppintegration/data.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-cppintegration-data.html
\title Data Type Conversion Between QML and C++
@@ -38,6 +14,10 @@ The QML engine provides built-in support for a large number of Qt C++ data
types. Additionally, custom C++ types may be registered with the QML type
system to make them available to the engine.
+For more information about C++ and the different QML integration methods,
+see the
+\l {Overview - QML and C++ Integration} {C++ and QML integration overview} page.
+
This page discusses the data types supported by the QML engine and how
they are converted between QML and C++.
@@ -59,13 +39,13 @@ has a parent.
\section1 Basic Qt Data Types
By default, QML recognizes the following Qt data types, which are
-automatically converted to a corresponding \l {QML Basic Types}{QML basic type}
+automatically converted to a corresponding \l {QML Value Types}{QML value type}
when passed from C++ to QML and vice-versa:
\table
\row
\li Qt Type
- \li QML Basic Type
+ \li QML Value Type
\row
\li bool
\li \l bool
@@ -112,7 +92,7 @@ when passed from C++ to QML and vice-versa:
\li QVector2D, QVector3D, QVector4D
\li \l vector2d, \l vector3d, \l vector4d
\row
- \li Enums declared with Q_ENUM() or Q_ENUMS()
+ \li Enums declared with Q_ENUM()
\li \l enumeration
\endtable
@@ -133,7 +113,7 @@ Item {
}
\endqml
-See documentation for each individual type under \l {QML Basic Types} for more
+See documentation for each individual type under \l {QML Value Types} for more
information.
@@ -197,6 +177,25 @@ type or method parameter, the value can be created as a JavaScript array or
object in QML, and is automatically converted to a QVariantList or QVariantMap
when it is passed to C++.
+Mind that QVariantList and QVariantMap properties of C++ types are stored as
+values and cannot be changed in place by QML code. You can only replace the
+whole map or list, but not manipulate its contents. The following code does
+not work if the property \c l is a QVariantList:
+
+\code
+MyListExposingItem {
+ l: [1, 2, 3]
+ Component.onCompleted: l[0] = 10
+}
+\endcode
+
+The following code does work:
+\code
+MyListExposingItem {
+ l: [1, 2, 3]
+ Component.onCompleted: l = [10, 2, 3]
+}
+\endcode
\section2 QDateTime to JavaScript Date
@@ -247,6 +246,51 @@ Similarly, if a C++ type uses a QDateTime for a property type or method
parameter, the value can be created as a JavaScript \c Date object in QML, and
is automatically converted to a QDateTime value when it is passed to C++.
+\note Watch out for the difference in month numbering: JavaScript numbers
+January as 0 through 11 for December, off by one from Qt's numbering
+of January as 1 through 12 for December.
+
+\note When using a string in JavaScript as the value of a \c Date object,
+note that a string with no time fields (so a simple date) is
+interpreted as the UTC start of the relevant day, in contrast
+to \c{new Date(y, m, d)} which uses the local time start of the day.
+Most other ways of constructing a \c Date object in JavaScript produce
+a local time, unless methods with UTC in their names are used. If your
+program is run in a zone behind UTC (nominally west of The Prime
+Meridian), use of a date-only string will lead to a \c Date object
+whose \c getDate() is one less than the day-number in your string; it
+will typically have a large value for \c getHours(). The UTC variants
+of these methods, \c getUTCDate() and \c getUTCHours(), will give the
+results you expect for such a \c Date objects. See also the next
+section.
+
+\section2 QDate and JavaScript Date
+
+The QML engine converts automatically between \l QDate and the
+JavaScript \c Date type by representing the date by the UTC start of
+its day. A date is mapped back to QDate via QDateTime, selecting
+its \l {QDateTime::}{date()} method, using the local time form of the
+date unless the UTC form of it coincides with the start of the next
+day, in which case the UTC form is used.
+
+This slighly eccentric arrangement is a work-around for the fact that
+JavaScript's construction of a \c Date object from a date-only string
+uses the UTC start of the day, but \c{new Date(y, m, d)} uses the
+local time start of the indicated date, as discussed in a note at the
+end of the previous section.
+
+As a result, where a QDate property or parameter is exposed to QML,
+care should be taken in reading its value: the \c
+Date.getUTCFullYear(), \c Date.getUTCMonth() and \c Date.getUTCDate()
+methods are more likely to deliver the results users expect than the
+corresponding methods without UTC in their names.
+
+It is thus commonly more robust to use a \l QDateTime property. This
+makes it possible to take control, on the QDateTime side, of whether
+the date (and time) is specified in terms of UTC or local time; as
+long as the JavaScript code is written to work with the same standard,
+it should be possible to avoid trouble.
+
//! Target adds an anchor, so renaming the section won't break incoming links.
\target QTime to JavaScript Date
\section2 QTime and JavaScript Date
@@ -256,97 +300,20 @@ JavaScript \c Date objects. As QTime values do not contain a date component,
one is created for the conversion only. Thus, you should not rely on the date
component of the resulting Date object.
-Under the hood, conversion from a JavaScript \c Date object to QTime is done by
-converting to a QDateTime object and calling its \l {QDateTime::}{time()}
-method.
+Under the hood, conversion from a JavaScript \c Date object to QTime
+is done by converting to a QDateTime object (using local time) and
+calling its \l {QDateTime::}{time()} method.
\section2 Sequence Type to JavaScript Array
-Certain C++ sequence types are supported transparently in QML to behave like
-JavaScript \c Array types.
-
-In particular, QML currently supports:
-\list
- \li \c {QList<int>}
- \li \c {QList<qreal>}
- \li \c {QList<bool>}
- \li \c {QList<QString>} and \c{QStringList}
- \li \c {QVector<QString>}
- \li \c {std::vector<QString>}
- \li \c {QList<QUrl>}
- \li \c {QVector<QUrl>}
- \li \c {std::vector<QUrl>}
- \li \c {QVector<int>}
- \li \c {QVector<qreal>}
- \li \c {QVector<bool>}
- \li \c {std::vector<int>}
- \li \c {std::vector<qreal>}
- \li \c {std::vector<bool>}
-\endlist
-
-and all registered QList, QVector, QQueue, QStack, QSet, QLinkedList, std::list,
-std::vector that contain a type marked with \l Q_DECLARE_METATYPE.
-
-These sequence types are implemented directly in terms of the underlying C++
-sequence. There are two ways in which such sequences can be exposed to QML:
-as a Q_PROPERTY of the given sequence type; or as the return type of a
-Q_INVOKABLE method. There are some differences in the way these are
-implemented, which are important to note.
-
-If the sequence is exposed as a Q_PROPERTY, accessing any value in the
-sequence by index will cause the sequence data to be read from the QObject's
-property, then a read to occur. Similarly, modifying any value in the
-sequence will cause the sequence data to be read, and then the modification
-will be performed and the modified sequence will be written back to the
-QObject's property.
-
-If the sequence is returned from a Q_INVOKABLE function, access and mutation
-is much cheaper, as no QObject property read or write occurs; instead, the
-C++ sequence data is accessed and modified directly.
-
-In both the Q_PROPERTY and return from Q_INVOKABLE cases, the elements
-of a std::vector are copied. This copying may be an expensive operation,
-so std::vector should be used judiciously.
-
-Other sequence types are not supported transparently, and instead an
-instance of any other sequence type will be passed between QML and C++ as an
-opaque QVariantList.
-
-\b {Important Note:} There are some minor differences between the
-semantics of such sequence Array types and default JavaScript Array types
-which result from the use of a C++ storage type in the implementation. In
-particular, deleting an element from an Array will result in a
-default-constructed value replacing that element, rather than an Undefined
-value. Similarly, setting the length property of the Array to a value larger
-than its current value will result in the Array being padded out to the
-specified length with default-constructed elements rather than Undefined
-elements. Finally, the Qt container classes support signed (rather than
-unsigned) integer indexes; thus, attempting to access any index greater
-than INT_MAX will fail.
-
-The default-constructed values for each sequence type are as follows:
-\table
-\row \li QList<int> \li integer value 0
-\row \li QList<qreal> \li real value 0.0
-\row \li QList<bool> \li boolean value \c {false}
-\row \li QList<QString> and QStringList \li empty QString
-\row \li QVector<QString> \li empty QString
-\row \li std::vector<QString> \li empty QString
-\row \li QList<QUrl> \li empty QUrl
-\row \li QVector<QUrl> \li empty QUrl
-\row \li std::vector<QUrl> \li empty QUrl
-\row \li QVector<int> \li integer value 0
-\row \li QVector<qreal> \li real value 0.0
-\row \li QVector<bool> \li boolean value \c {false}
-\row \li std::vector<int> \li integer value 0
-\row \li std::vector<qreal> \li real value 0.0
-\row \li std::vector<bool> \li boolean value \c {false}
-\endtable
+See \l{QML Sequence Types} for a general description of sequence types. The
+\l{Qt QML QML Types}{QtQml module} contains a few sequence types
+you may want to use.
-If you wish to remove elements from a sequence rather than simply replace
-them with default constructed values, do not use the indexed delete operator
-("delete sequence[i]") but instead use the \c {splice} function
-("sequence.splice(startIndex, deleteCount)").
+You can also create a list-like data structure by constructing a QJSValue using
+QJSEngine::newArray(). Such a JavaScript array does not need any conversion
+when passing it between QML and C++. See \l{QJSValue#Working With Arrays} for
+details on how to manipulate JavaScript arrays from C++.
\section2 QByteArray to JavaScript ArrayBuffer
@@ -381,6 +348,14 @@ properties:
Q_DECLARE_METATYPE(Actor)
\endcode
+The usual pattern is to use a gadget class as the type of a property, or to
+emit a gadget as a signal argument. In such cases, the gadget instance is
+passed by value between C++ and QML (because it's a value type). If QML code
+changes a property of a gadget property, the entire gadget is re-created and
+passed back to the C++ property setter. In Qt 5, gadget types cannot be
+instantiated by direct declaration in QML. In contrast, a QObject instance can
+be declared; and QObject instances are always passed by pointer from C++ to QML.
+
\section1 Enumeration Types
To use a custom enumeration as a data type, its class must be registered and
@@ -465,6 +440,62 @@ class Message : public QObject
};
\endcode
+Enums from related types are usually registered in the scope of the relating
+type. For example any enum from a different type used in a \l{Q_PROPERTY}
+declaration causes all enums from that type to be made available in QML. This
+is usually more of a liability than a feature. In order to prevent it from
+happening, annotate your class with a special \l{Q_CLASSINFO} macro.
+Use the name \c RegisterEnumsFromRelatedTypes with the value \c false to prevent
+enums from related types from being registered in this type.
+
+You should explicitly register the enclosing types of any enums you want to use
+in QML, using \l{QML_ELEMENT} or \l{QML_NAMED_ELEMENT}, rather than rely on
+their enums to be injected into other types.
+
+\code
+class OtherType : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+
+public:
+ enum SomeEnum { A, B, C };
+ Q_ENUM(SomeEnum)
+
+ enum AnotherEnum { D, E, F };
+ Q_ENUM(AnotherEnum)
+};
+
+class Message : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+
+ // This would usually cause all enums from OtherType to be registered
+ // as members of Message ...
+ Q_PROPERTY(OtherType::SomeEnum someEnum READ someEnum CONSTANT)
+
+ // ... but this way it doesn't.
+ Q_CLASSINFO("RegisterEnumsFromRelatedTypes", "false")
+
+public:
+ OtherType::SomeEnum someEnum() const { return OtherType::B; }
+};
+\endcode
+
+The important difference is the scope for the enums in QML. If an enum from a
+related class is automatically registered, the scope is the type it is
+imported into. In the above case, without the extra \l{Q_CLASSINFO}, you would
+use \c {Message.A}, for example. If C++ type holding the enums is explicitly
+registered, and the registration of enums from related types is suppressed, the
+QML type for the C++ type holding the enums is the scope for all of its enums.
+You would use \c {OtherType.A} instead of \c {Message.A} in QML.
+
+Mind that you can use \l QML_FOREIGN to register a type you cannot modify. You
+can also use \l QML_FOREIGN_NAMESPACE to register the enumerators of a C++ type
+into a QML namespace of any upper-case name, even if the same C++ type is
+also registered as a QML value type.
+
\section2 Enumeration Types as Signal and Method Parameters
C++ signals and methods with enumeration-type parameters can be used from QML
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 2e8102bd65..feb9053632 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-cppintegration-definetypes.html
\title Defining QML Types from C++
@@ -40,12 +16,17 @@ as an instantiable \l{qtqml-typesystem-objecttypes.html}{QML object type} from
QML, or enabling a singleton instance of the class to be imported and used
from QML.
-Additionally, the \l {Qt QML} module provides mechanisms for implementing QML-specific
+Additionally, the \l {Qt Qml} module provides mechanisms for implementing QML-specific
features such as \e{attached properties} and \e{default properties} in C++.
(Note that a number of the important concepts covered in this document are
demonstrated in the \l{Writing QML Extensions with C++} tutorial.)
+\b{NOTE:} All headers that declare QML types need to be accessible without any prefix from the project's include path.
+
+For more information about C++ and the different QML integration methods,
+see the
+\l {Overview - QML and C++ Integration} {C++ and QML integration overview} page.
\section1 Registering C++ Types with the QML Type System
@@ -69,6 +50,21 @@ exposed to QML but the type itself should not be instantiable.
For a quick guide to choosing the correct approach to expose C++ types to QML,
see \l {Choosing the Correct Integration Method Between C++ and QML}.
+\section2 Preconditions
+
+All the macros mentioned below are available from the \c qqmlregistration.h
+header. You need to add the following code to the files using them in order to
+make the macros available:
+
+\code
+#include <QtQml/qqmlregistration.h>
+\endcode
+
+Furthermore, your class declarations have to live in headers reachable via your
+project's include path. The declarations are used to generate registration code
+at compile time, and the registration code needs to include the headers that
+contain the declarations.
+
\section2 Registering an Instantiable Object Type
\b{Any QObject-derived C++ class can be registered as the definition of a
@@ -80,9 +76,20 @@ class instance can be manipulated from QML; as
Types to QML} explains, the properties, methods and signals of any
QObject-derived class are accessible from QML code.
-To register a QObject-derived class as an instantiable QML object type, call
-qmlRegisterType() to register the class as QML type into a particular type
-namespace. Clients can then import that namespace in order to use the type.
+To register a QObject-derived class as an instantiable QML object type, add
+\c QML_ELEMENT or \c QML_NAMED_ELEMENT(<name>) to the class declaration. You
+also need to make adjustments in the build system. For qmake, add
+\c {CONFIG += qmltypes}, a \c {QML_IMPORT_NAME}, and a
+\c QML_IMPORT_MAJOR_VERSION to your project file. For CMake, the file containing
+the class should be part of a target set-up with
+\l{qt_add_qml_module}{qt_add_qml_module()}.
+This will register the class into the type namespace under the given major version,
+using either the class name or an explicitly given name as QML type name. The
+minor version(s) will be derived from any revisions attached to properties,
+methods, or signals. The default minor version is \c 0. You can explicitly
+restrict the type to be available only from specific minor versions by adding
+the \c QML_ADDED_IN_VERSION() macro to the class declaration. Clients can
+import suitable versions of the namespace in order to use the type.
For example, suppose there is a \c Message class with \c author and
\c creationDate properties:
@@ -93,25 +100,62 @@ class Message : public QObject
Q_OBJECT
Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
+ QML_ELEMENT
public:
// ...
};
\endcode
-This type can be registered by calling qmlRegisterType() with an appropriate
-type namespace and version number. For example, to make the type available in
-the \c com.mycompany.messaging namespace with version 1.0:
+This type can be registered by adding an appropriate type namespace and version
+number to the project file. For example, to make the type available in the
+\c com.mycompany.messaging namespace with version 1.0:
+
+\if defined(onlinedocs)
+ \tab {build-qt-app}{tab-cmake}{CMake}{selected}
+ \tab {build-qt-app}{tab-qmake}{qmake}{}
+ \tabcontent {tab-cmake}
+ \else
+ \section3 Using CMake
+\endif
+ \badcode
+ qt_add_qml_module(messaging
+ URI com.mycompany.messaging
+ VERSION 1.0
+ SOURCES
+ message.cpp message.h
+ )
+ \endcode
+\if defined(onlinedocs)
+ \endtabcontent
+ \tabcontent {tab-qmake}
+\else
+ \section3 Using QMake
+\endif
+ \code
+ CONFIG += qmltypes
+ QML_IMPORT_NAME = com.mycompany.messaging
+ QML_IMPORT_MAJOR_VERSION = 1
+ \endcode
+
+ If the header the class is declared in is not accessible from your project's
+ include path, you may have to amend the include path so that the generated
+ registration code can be compiled.
+
+ \code
+ INCLUDEPATH += com/mycompany/messaging
+ \endcode
+\if defined(onlinedocs)
+ \endtabcontent
+\endif
+
-\code
-qmlRegisterType<Message>("com.mycompany.messaging", 1, 0, "Message");
-\endcode
The type can be used in an \l{qtqml-syntax-basics.html#object-declarations}
{object declaration} from QML, and its properties can be read and written to,
as per the example below:
\qml
-import com.mycompany.messaging 1.0
+import com.mycompany.messaging
Message {
author: "Amelie"
@@ -119,6 +163,102 @@ Message {
}
\endqml
+\section2 Registering Value Types
+
+Any type with a \l{Q_GADGET} macro can the registered as a
+\l{qtqml-typesystem-valuetypes.html}{QML value type}. Once such a type is
+registered with the QML type system it can be used as property type in QML
+code. Such an instance can be manipulated from QML; as
+\l{qtqml-cppintegration-exposecppattributes.html}{Exposing Attributes of C++
+Types to QML} explains, the properties and methods of any value type are
+accessible from QML code.
+
+In contrast to object types, value types require \b{lower case} names. The
+preferred way to register them is using the \l{QML_VALUE_TYPE} or
+\l{QML_ANONYMOUS} macros. There is no equivalent to \l{QML_ELEMENT} as your
+C++ classes are typically going to have upper case names. Otherwise the
+registration is very similar to the registration of object types.
+
+For example, suppose you want to register a value type \c{person} that consists
+of two strings for first and last name:
+
+\code
+class Person
+{
+ Q_GADGET
+ Q_PROPERTY(QString firstName READ firstName WRITE setFirstName)
+ Q_PROPERTY(QString lastName READ lastName WRITE setLastName)
+ QML_VALUE_TYPE(person)
+public:
+ // ...
+};
+\endcode
+
+There are some further limitations on what you can do with value types:
+\list
+\li Value types cannot be singletons.
+\li Value types need to be default-constructible and copy-constructible.
+\li Using QProperty as a member of a value type is problematic. Value types get
+ copied, and you would need to decide what to do with any bindings on the
+ QProperty at that point. You should not use QProperty in value types.
+\li Value types cannot provide attached properties.
+\li The API to define extensions to value types (\l{QML_EXTENDED}) is not public
+ and subject to future changes.
+\endlist
+
+\section2 Value Types with Enumerations
+
+Exposing enumerations from a value type to QML requires some extra steps.
+
+Value types have lower case names in QML and types with lower case
+names are generally not addressable in JavaScript code (unless you specify
+\l{ValueTypeBehavior}{pragma ValueTypeBehavior: Addressable}). If you have
+a value type in C++ with an enumeration you want to expose to QML, you
+need to expose the enumeration separately.
+
+This can be solved by using \l{QML_FOREIGN_NAMESPACE}. First, derive from
+your value type to create a separate C++ type:
+
+\code
+class Person
+{
+ Q_GADGET
+ Q_PROPERTY(QString firstName READ firstName WRITE setFirstName)
+ Q_PROPERTY(QString lastName READ lastName WRITE setLastName)
+ QML_VALUE_TYPE(person)
+public:
+ enum TheEnum { A, B, C };
+ Q_ENUM(TheEnum)
+ //...
+};
+
+class PersonDerived: public Person
+{
+ Q_GADGET
+};
+\endcode
+
+Then expose the derived type as a foreign namespace:
+
+\code
+namespace PersonDerivedForeign
+{
+ Q_NAMESPACE
+ QML_NAMED_ELEMENT(Person)
+ QML_FOREIGN_NAMESPACE(PersonDerived)
+}
+\endcode
+
+This produces a \l{qtqml-typesystem-namespaces.html}{QML Namespace}
+called \c Person (upper case) with an enumeration called \c TheEnum and
+values \c{A}, \c{B}, and \c{C}. Then you can write the following in QML:
+
+\qml
+ someProperty: Person.A
+\endqml
+
+At the same time you can still use your value type called \c person
+(lower case) exactly as before.
\section2 Registering Non-Instantiable Types
@@ -135,23 +275,25 @@ not be instantiable
should not be instantiable from QML
\endlist
-The \l {Qt QML} module provides several methods for registering non-instantiable
+The \l {Qt Qml} module provides several macros for registering non-instantiable
types:
\list
-\li qmlRegisterType() (with no parameters) registers a C++ type that is not
-instantiable and cannot be referred to from QML. This enables the engine to
-coerce any inherited types that are instantiable from QML.
-\li qmlRegisterInterface() registers an existing Qt interface type. The type is
+\li QML_ANONYMOUS registers a C++ type that is not instantiable and cannot be
+referred to from QML. This enables the engine to coerce any inherited types that
+are instantiable from QML.
+\li QML_INTERFACE registers an existing Qt interface type. The type is
not instantiable from QML, and you cannot declare QML properties with it. Using
C++ properties of this type from QML will do the expected interface casts,
though.
-\li qmlRegisterUncreatableType() registers a named C++ type that is not
-instantiable but should be identifiable as a type to the QML type system. This
-is useful if a type's enums or attached properties should be accessible from QML
-but the type itself should not be instantiable.
-\li qmlRegisterSingletonType() registers a singleton type that can be imported
-from QML, as discussed below.
+\li QML_UNCREATABLE(reason) combined with with QML_ELEMENT or QML_NAMED_ELEMENT
+registers a named C++ type that is not instantiable but should be identifiable
+as a type to the QML type system. This is useful if a type's enums or attached
+properties should be accessible from QML but the type itself should not be
+instantiable. The parameter should be an error message to be emitted if an
+attempt at creating an instance of the type is detected.
+\li QML_SINGLETON combined with QML_ELEMENT or QML_NAMED_ELEMENT registers a
+singleton type that can be imported from QML, as discussed below.
\endlist
Note that all C++ types registered with the QML type system must be
@@ -195,11 +337,26 @@ Rectangle {
A QJSValue may also be exposed as a singleton type, however clients should
be aware that properties of such a singleton type cannot be bound to.
-See \l{qmlRegisterSingletonType()} for more information on how implement and
+See \l{QML_SINGLETON} for more information on how implement and
register a new singleton type, and how to use an existing singleton type.
+See \l{Singletons in QML} for more in-depth information about singletons.
\note Enum values for registered types in QML should start with a capital.
+\section2 Final properties
+
+Properties declared final using the \c FINAL modifier to \l Q_PROPERTY cannot
+be overridden. This means that any properties or functions of the same name,
+declared either in QML or in C++ on derived types, are ignored by the QML
+engine. You should declare properties \c FINAL when possible, in order to avoid
+accidental overrides. An override of a property is visible not only in
+derived classes, but also to QML code executing the context of the base class.
+Such QML code, typically expects the original property, though. This is a
+frequent source of mistakes.
+
+Properties declared \c FINAL can also not be overridden by functions in QML, or
+by \l Q_INVOKABLE methods in C++.
+
\section2 Type Revisions and Versions
Many of the type registration functions require versions to be specified
@@ -245,30 +402,20 @@ class CppType : public BaseType
{
Q_OBJECT
Q_PROPERTY(int root READ root WRITE setRoot NOTIFY rootChanged REVISION 1)
+ QML_ELEMENT
signals:
Q_REVISION(1) void rootChanged();
};
\endcode
-To register the new class revision to a particular version the following
-function is used:
-
-\code
-template<typename T, int metaObjectRevision>
-int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
-\endcode
-
-To register \c CppType version 1 for \c {MyTypes 1.1}:
-
-\code
-qmlRegisterType<CppType,1>("MyTypes", 1, 1, "CppType")
-\endcode
+The revisions given this way are automatically interpreted as minor versions to
+the major version given in the project file. In this case, \c root is only
+available when \c MyTypes version 1.1 or higher is imported. Imports of
+\c MyTypes version 1.0 remain unaffected.
-\c root is only available when \c MyTypes version 1.1 is imported.
-
-For the same reason, new types introduced in later versions should use
-the minor version argument of qmlRegisterType.
+For the same reason, new types introduced in later versions should be tagged
+with the QML_ADDED_IN_VERSION macro.
This feature of the language allows for behavioural changes to be made
without breaking existing applications. Consequently QML module authors
@@ -276,29 +423,10 @@ should always remember to document what changed between minor versions, and
QML module users should check that their application still runs correctly
before deploying an updated import statement.
-You may also register the revision of a base class that your type depends
-upon using the qmlRegisterRevision() function:
-
-\code
-template<typename T, int metaObjectRevision>
-int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
-
-template<typename T, int metaObjectRevision>
-int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
-
-template<typename T, typename E, int metaObjectRevision>
-int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
-\endcode
-
-For example, if \c BaseType is changed and now has a revision 1, you can
-specify that your type uses the new revision:
-
-\code
-qmlRegisterRevision<BaseType,1>("MyTypes", 1, 1);
-\endcode
-
-This is useful when deriving from base classes provided by other authors,
-e.g. when extending classes from the Qt Quick module.
+Revisions of a base class that your type depends upon are automatically
+registered when registering the type itself. This is useful when deriving
+from base classes provided by other authors, e.g. when extending classes from
+the Qt Quick module.
\note The QML engine does not support revisions for properties or signals of
grouped and attached property objects.
@@ -312,32 +440,27 @@ classes directly, if this is either not possible or is complicated by some
other concerns, extension objects allow limited extension possibilities
without direct modifications.
-\e{Extension objects} add additional properties to an existing type. Extension
-objects can only add properties, not signals or methods. An extended type
-definition allows the programmer to supply an additional type, known as the
-\e{extension type}, when registering the class. The properties are transparently
+\e{Extension objects} add additional properties to an existing type. An extended
+type definition allows the programmer to supply an additional type, known as the
+\e{extension type}, when registering the class. Its members are transparently
merged with the original target class when used from within QML. For example:
-\snippet referenceexamples/extended/example.qml 0
+\qml
+QLineEdit {
+ leftMargin: 20
+}
+\endqml
The \c leftMargin property is a new property added to an existing C++ type, \l
QLineEdit, without modifying its source code.
-The \l {QQmlEngine::}{qmlRegisterExtendedType()} function is for registering extended types.
-Note that it has two forms.
-
-\code
-template<typename T, typename ExtendedT>
-int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
-
-template<typename T, typename ExtendedT>
-int qmlRegisterExtendedType()
-\endcode
+The QML_EXTENDED(extension) macro is for registering extended types. The
+argument is the name of another class to be used as extension.
-This functions should be used instead of the regular \c qmlRegisterType()
-variations. The arguments are identical to the corresponding non-extension
-registration functions, except for the ExtendedT parameter which is the type of
-the extension object.
+You can also use QML_EXTENDED_NAMESPACE(namespace) to register a namespace, and
+especially the enumerations declared within, as an extension to a type. If the
+type you are extending is itself a namespace, you need to use
+QML_NAMESPACE_EXTENDED(namespace) instead.
An extension class is a regular QObject, with a constructor that takes a QObject
pointer. However, the extension class creation is delayed until the first
@@ -345,9 +468,32 @@ extended property is accessed. The extension class is created and the target
object is passed in as the parent. When the property on the original is
accessed, the corresponding property on the extension object is used instead.
-The \l{Extending QML - Extension Objects Example}{Extension Objects Example}
-demonstrates a usage of extension objects.
+\section2 Registering Foreign Types
+
+There may be C++ types that cannot be modified to hold the above mentioned
+macros. Those may be types from 3rdparty libraries, or types that need to
+fulfill some contract that contradicts the presence of those macros. You can
+still expose those types to QML, though, using the QML_FOREIGN macro. In order
+to do this, create a separate struct that consists entirely of the registration
+macros, like this:
+
+\code
+// Contains class Immutable3rdParty
+#include <3rdpartyheader.h>
+
+struct Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(Immutable3rdParty)
+ QML_NAMED_ELEMENT(Accessible3rdParty)
+ QML_ADDED_IN_VERSION(2, 4)
+ // QML_EXTENDED, QML_SINGLETON ...
+};
+\endcode
+From this code, you get a QML type with the methods and properties of
+Immutable3rdParty, and the QML traits (e.g.: singleton, extended) specified in
+Foreign.
\section1 Defining QML-Specific Types and Attributes
@@ -425,8 +571,9 @@ the attributes to be made accessible to \e attachee objects. For the
attached property accesses. Consequently the attachment object may not be
deleted until the attachee \c object is destroyed.
-\li is declared as an attaching type, by calling the QML_DECLARE_TYPEINFO()
- macro with the QML_HAS_ATTACHED_PROPERTIES flag
+\li is declared as an attaching type, by adding the QML_ATTACHED(attached) macro
+ to the class declaration. The argument is the name of the
+ \e{attached object type}
\endlist
@@ -441,6 +588,7 @@ class Message : public QObject
Q_OBJECT
Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
+ QML_ELEMENT
public:
// ...
};
@@ -472,6 +620,7 @@ class MessageBoardAttachedType : public QObject
{
Q_OBJECT
Q_PROPERTY(bool expired READ expired WRITE setExpired NOTIFY expiredChanged)
+ QML_ANONYMOUS
public:
MessageBoardAttachedType(QObject *parent);
bool expired() const;
@@ -485,20 +634,21 @@ signals:
Then the \e {attaching type}, \c MessageBoard, must declare a \c
qmlAttachedProperties() method that returns an instance of the
\e {attached object type} as implemented by MessageBoardAttachedType.
-Additionally, \c Message board must be declared as an attached type
-through the QML_DECLARE_TYPEINFO() macro:
+Additionally, \c MessageBoard must be declared as an attaching type
+via the QML_ATTACHED() macro:
\code
class MessageBoard : public QObject
{
Q_OBJECT
+ QML_ATTACHED(MessageBoardAttachedType)
+ QML_ELEMENT
public:
static MessageBoardAttachedType *qmlAttachedProperties(QObject *object)
{
return new MessageBoardAttachedType(object);
}
};
-QML_DECLARE_TYPEINFO(MessageBoard, QML_HAS_ATTACHED_PROPERTIES)
\endcode
Now, a \c Message type can access the properties and signals of the attached
@@ -530,6 +680,14 @@ qDebug() << "Value of MessageBoard.expired:" << attached->expired();
\endcode
+\section3 Propagating Attached Properties
+
+\l QQuickAttachedPropertyPropagator can be subclassed to propagate attached properties
+from a parent object to its children, similar to \l {Control::}{font} and
+\l {Item::}{palette} propagation. It supports propagation through
+\l {Item}{items}, \l {Popup}{popups}, and \l {Window}{windows}.
+
+
\section2 Property Modifier Types
A property modifier type is a special kind of QML object type. A property
@@ -577,6 +735,8 @@ Item {
}
\endqml
+This is commonly referred to as "on" syntax.
+
Clients can register their own property value source types, but currently not
property value write interceptors.
@@ -607,6 +767,7 @@ class RandomNumberGenerator : public QObject, public QQmlPropertyValueSource
Q_OBJECT
Q_INTERFACES(QQmlPropertyValueSource)
Q_PROPERTY(int maxValue READ maxValue WRITE setMaxValue NOTIFY maxValueChanged);
+ QML_ELEMENT
public:
RandomNumberGenerator(QObject *parent)
: QObject(parent), m_maxValue(100)
@@ -672,7 +833,7 @@ assignment fails does the engine call the \l
the type to also be used in contexts other than just as a value source.
-\section2 Specifying Default Properties for QML Object Types
+\section2 Specifying Default and Parent Properties for QML Object Types
Any QObject-derived type that is registered as an instantiable QML object type
can optionally specify a \e {default property} for the type. A default
@@ -690,6 +851,7 @@ class MessageBoard : public QObject
Q_OBJECT
Q_PROPERTY(QQmlListProperty<Message> messages READ messages)
Q_CLASSINFO("DefaultProperty", "messages")
+ QML_ELEMENT
public:
QQmlListProperty<Message> messages();
@@ -728,6 +890,37 @@ objects added to this \c data property are also added to the list of
to be declared for an item without explicitly assigning them to the
\l{Item::}{children} property.)
+Additionally, you can declare a "ParentProperty" Q_CLASSINFO() to inform the QML
+engine which property should denote the parent object in the QML hierarchy. For
+example, the Message type might be declared as follows:
+
+\code
+class Message : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject* board READ board BINDABLE boardBindable)
+ Q_PROPERTY(QString author READ author BINDABLE authorBindable)
+ Q_CLASSINFO("ParentProperty", "board")
+ QML_ELEMENT
+
+public:
+ Message(QObject *parent = nullptr) : QObject(parent) { m_board = parent; }
+
+ QObject *board() const { return m_board.value(); }
+ QBindable<QObject *> boardBindable() { return QBindable<QObject *>(&m_board); }
+
+ QString author() const { return m_author.value(); }
+ QBindable<QString> authorBindable() { return QBindable<QString>(&m_author); }
+
+private:
+ QProperty<QObject *> m_board;
+ QProperty<QString> m_author;
+};
+\endcode
+
+Defining the parent property affords \l qmllint and other tools better insight
+into the intention of your code and avoids false positive warnings on some
+property accesses.
\section2 Defining Visual Items with the Qt Quick Module
@@ -753,7 +946,7 @@ its properties have been set. For example, this may be the case if the
initialization is costly, or if the initialization should not be performed until
all property values have been initialized.
-The \l {Qt QML} module provides the QQmlParserStatus to be subclassed for these
+The \l {Qt Qml} module provides the QQmlParserStatus to be subclassed for these
purposes. It defines a number of virtual methods that are invoked at
various stages during component instantiation. To receive these notifications, a
C++ class should inherit QQmlParserStatus and also notify the Qt meta system
@@ -766,6 +959,7 @@ class MyQmlType : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
+ QML_ELEMENT
public:
virtual void componentComplete()
{
diff --git a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
index 52534b4a62..6031d0eebb 100644
--- a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
+++ b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-cppintegration-exposecppattributes.html
\title Exposing Attributes of C++ Types to QML
@@ -32,9 +8,9 @@
QML can easily be extended with functionality defined in C++ code. Due to the
tight integration of the QML engine with the \l{The Meta-Object System}{Qt
meta-object system}, any functionality that is appropriately exposed by a
-QObject-derived class is accessible from QML code. This enables C++ data and
-functions to be accessible directly from QML, often with little or no
-modification.
+QObject-derived class or a Q_GADGET type is accessible from QML code. This
+enables C++ data and functions to be accessible directly from QML, often with
+little or no modification.
The QML engine has the ability to introspect QObject instances through the
meta-object system. This means any QML code can access the following members of
@@ -46,7 +22,7 @@ an instance of a QObject-derived class:
\li Signals
\endlist
-(Additionally, enums are available if they have been declared with Q_ENUMS.
+(Additionally, enums are available if they have been declared with Q_ENUM.
See \l{qtqml-cppintegration-data.html}{Data Type Conversion Between QML and C++}
for more details.)
@@ -56,11 +32,27 @@ system}{registered with the QML type system}. However, if a class is to be
used in a way that requires the engine to access additional type information
— for example, if the class itself is to be used as a method parameter or
property, or if one of its enum types is to be used in this way — then the
-class may need to be registered.
+class may need to be registered. Registration is recommended for all types you
+use in QML, as only registered types can be analyzed at compile time.
+
+Registration is required for Q_GADGET types, as they don't derive from a known
+common base and can't be made available automatically. Without registration,
+their properties and methods are inaccessible.
+
+You can make C++ types from a different module available in your own module by
+adding a dependency to your \l{qt_add_qml_module} call using the \e DEPENDENCIES
+option. You may, for example, want to depend on QtQuick so that your QML-exposed
+C++ types can use \l QColor as method arguments and return values. QtQuick
+exposes \l QColor as a \l {QML Value Types}{value type} \e color. Such
+dependencies may be automatically inferred at run time, but you should not rely
+on this.
Also note that a number of the important concepts covered in this document are
demonstrated in the \l{Writing QML Extensions with C++} tutorial.
+For more information about C++ and the different QML integration methods,
+see the
+\l {Overview - QML and C++ Integration} {C++ and QML integration overview} page.
\section1 Data Type Handling and Ownership
@@ -85,37 +77,70 @@ A \e property can be specified for any QObject-derived class using the
Q_PROPERTY() macro. A property is a class data member with an associated read
function and optional write function.
-All properties of a QObject-derived class are accessible from QML.
+All properties of a QObject-derived or Q_GADGET class are accessible from QML.
For example, below is a \c Message class with an \c author property. As
specified by the Q_PROPERTY macro call, this property is readable through
the \c author() method, and writable through the \c setAuthor() method:
+\note Do not use \e typedef or \e using for Q_PROPERTY types as these
+will confuse moc. This may make certain type comparisons fail.
+
+Instead of:
+
+\badcode
+using FooEnum = Foo::Enum;
+
+class Bar : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(FooEnum enum READ enum WRITE setEnum NOTIFY enumChanged)
+};
+\endcode
+
+Refer to the type directly:
+
+\code
+class Bar : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(Foo::Enum enum READ enum WRITE setEnum NOTIFY enumChanged)
+};
+\endcode
+
+In order to make \c Message available you need to use \l{QML_ELEMENT} in C++
+and \l{qt_add_qml_module} in CMake.
+
\code
class Message : public QObject
{
Q_OBJECT
+ QML_ELEMENT
Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
public:
- void setAuthor(const QString &a) {
+ void setAuthor(const QString &a)
+ {
if (a != m_author) {
m_author = a;
emit authorChanged();
}
}
- QString author() const {
+
+ QString author() const
+ {
return m_author;
}
+
signals:
void authorChanged();
+
private:
QString m_author;
};
\endcode
-If an instance of this class was \l{Embedding C++ Objects into QML with Context
-Properties}{set as a context property} when loading a file named \c MyItem.qml
-from C++:
+An instance of \c Message can be passed as required property to a file called
+\c MyItem.qml to make it available:
\code
int main(int argc, char *argv[]) {
@@ -123,7 +148,7 @@ from C++:
QQuickView view;
Message msg;
- view.engine()->rootContext()->setContextProperty("msg", &msg);
+ view.setInitialProperties({{"msg", &msg}});
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
view.show();
@@ -135,9 +160,11 @@ Then, the \c author property could be read from \c MyItem.qml:
\qml
// MyItem.qml
-import QtQuick 2.0
+import QtQuick
Text {
+ required property Message msg
+
width: 100; height: 100
text: msg.author // invokes Message::author() to get this value
@@ -374,6 +401,8 @@ that is a public slot:
class MessageBoard : public QObject
{
Q_OBJECT
+ QML_ELEMENT
+
public:
Q_INVOKABLE bool postMessage(const QString &msg) {
qDebug() << "Called the C++ method with" << msg;
@@ -387,7 +416,7 @@ that is a public slot:
};
\endcode
-If an instance of \c MessageBoard was set as the context data for a file \c
+If an instance of \c MessageBoard was set as the required property for a file \c
MyItem.qml, then \c MyItem.qml could invoke the two methods as shown in the
examples below:
@@ -401,7 +430,7 @@ examples below:
MessageBoard msgBoard;
QQuickView view;
- view.engine()->rootContext()->setContextProperty("msgBoard", &msgBoard);
+ view.setInitialProperties({{"msgBoard", &msgBoard}});
view.setSource(QUrl::fromLocalFile("MyItem.qml"));
view.show();
@@ -416,6 +445,8 @@ examples below:
import QtQuick 2.0
Item {
+ required property MessageBoard msgBoard
+
width: 100; height: 100
MouseArea {
@@ -441,6 +472,54 @@ be called according to the number and the types of arguments that are provided.
Values returned from C++ methods are converted to JavaScript values when
accessed from JavaScript expressions in QML.
+\section2 C++ methods and the 'this' object
+
+You may want to retrieve a C++ method from one object and call it on a different
+object. Consider the following example, within a QML module called \c{Example}:
+
+\table
+\row
+\li C++
+\li
+\code
+class Invokable : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+public:
+ Invokable(QObject *parent = nullptr) : QObject(parent) {}
+
+ Q_INVOKABLE void invoke() { qDebug() << "invoked on " << objectName(); }
+};
+\endcode
+\row
+\li QML
+\li
+\qml
+import QtQml
+import Example
+
+Invokable {
+ objectName: "parent"
+ property Invokable child: Invokable {}
+ Component.onCompleted: child.invoke.call(this)
+}
+\endqml
+\endtable
+
+If you load the QML code from a suitable main.cpp, it should print
+"invoked on parent". However, due to a long standing bug, it doesn't.
+Historically, the 'this' object of C++-based methods is inseparably bound to
+the method. Changing this behavior for existing code would cause subtle errors
+since the 'this' object is implicit in many places. Since Qt 6.5 you can
+explicitly opt into the correct behavior and allow C++ methods to accept a
+'this' object. To do so, add the following pragma to your QML documents:
+
+\qml
+pragma NativeMethodBehavior: AcceptThisObject
+\endqml
+
+With this line added, the example above will work as expected.
\section1 Exposing Signals
@@ -475,7 +554,7 @@ value:
\qml
MessageBoard {
- onNewMessagePosted: console.log("New message received:", subject)
+ onNewMessagePosted: (subject)=> console.log("New message received:", subject)
}
\endqml
diff --git a/src/qml/doc/src/cppintegration/exposecppstate.qdoc b/src/qml/doc/src/cppintegration/exposecppstate.qdoc
new file mode 100644
index 0000000000..8abd498c49
--- /dev/null
+++ b/src/qml/doc/src/cppintegration/exposecppstate.qdoc
@@ -0,0 +1,66 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+/*!
+\page qtqml-cppintegration-exposecppstate.html
+\title Exposing State from C++ to QML
+\brief Description of how to expose global state from C++ to QML
+
+It is often desirable to expose some properties from C++ to all QML elements in a
+particular component, all QML elements in a module, or even all QML elements
+overall. You can do this by introducing singletons or by adding properties to the
+root objects of select components.
+
+\section1 Using Singletons
+
+If you want to expose a number of global properties to all elements in a module
+or all elements overall, you can define a singleton in C++. To do this, add the
+\l{QML_ELEMENT} or \l{QML_NAMED_ELEMENT} macros and the \l{QML_SINGLETON} macro
+to a class containing the properties you want to expose as \l{Q_PROPERTY}
+declarations:
+
+\snippet qml/exposing-state/singleton.h 0
+
+Now you can access the \e thing property of the singleton from any QML code that
+imports this module:
+
+\snippet qml/exposing-state/useSingleton.qml 0
+
+If you have placed your QML files in the same directory as the module (which
+is highly recommended), the singleton is available from the implicit import
+within your module. You don't need to import anything explicitly. If not, or if
+you want to access the \e thing property from other modules, you do need to
+import the module the singleton belongs to.
+
+In order to set the value of the property from C++, you may need to retrieve the
+singleton instance. For this purpose you may use
+\l{QQmlEngine::singletonInstance}. The preferred way to do this is by giving a
+module and type name as parameters:
+
+\snippet qml/exposing-state/singleton.h 1
+
+\section1 Using Object Properties
+
+If you want to expose some properties to only the QML elements in a specific
+component, you can add them as regular properties to the root object of the
+component. In order to make sure they are actually set in all cases, you can
+make them \l{Required Properties}. You might write your QML component as
+follows:
+
+\snippet qml/exposing-state/RequiredProperties.qml 0
+
+We use an ID for the root element of the component and reference the property
+by ID and name from any inner objects. In order to safely make the ID of
+the root element available to any nested components, we use
+\l{ComponentBehavior}.
+
+Then, in C++, when you create an object from such a component, you need to make
+sure to call the \l{QQmlComponent::createWithInitialProperties},
+\l{QQmlApplicationEngine::setInitialProperties}, or
+\l{QQuickView::setInitialProperties} in order to initialize the properties. For
+example:
+
+\snippet qml/exposing-state/createWithInitialProperties.cpp 0
+
+This is assuming your module URI is \e MyModule and the module is available in
+the QML import path.
+*/
diff --git a/src/qml/doc/src/cppintegration/extending-tutorial-advanced.qdoc b/src/qml/doc/src/cppintegration/extending-tutorial-advanced.qdoc
new file mode 100644
index 0000000000..7e489276ac
--- /dev/null
+++ b/src/qml/doc/src/cppintegration/extending-tutorial-advanced.qdoc
@@ -0,0 +1,380 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-tutorials-extending-qml-advanced-example.html
+\meta tags{qml,extensions,advanced}
+
+\title Writing advanced QML Extensions with C++
+\brief Tutorial about advanced extensions to QML with Qt C++.
+
+
+\section1 BirthdayParty Base Project
+\c extending-qml-advanced/advanced1-Base-project
+
+This tutorial uses the example of a birthday party to demonstrate some of
+the features of QML. The code for the various features explained below is
+based on this birthday party project and relies on some of the material in the
+first tutorial on \l {Writing QML Extensions with C++}{QML extensions}. This
+simple example is then expanded upon to illustrate the various QML extensions
+explained below. The complete code for each new extension to the code can be
+found in the tutorials at the location specified under each section's title or
+by following the link to the code at the very end of this page.
+
+\image extending-qml-advanced-word-cloud.png
+
+The base project defines the \c Person class and the \c BirthdayParty class,
+which model the attendees and the party itself respectively.
+\quotefromfile tutorials/extending-qml-advanced/advanced1-Base-project/person.h
+ \skipto class
+ \printuntil QML_ELEMENT
+ \dots
+ \skipuntil private:
+ \printuntil /\};/
+
+\quotefromfile tutorials/extending-qml-advanced/advanced1-Base-project/birthdayparty.h
+ \skipto class
+ \printuntil QML_ELEMENT
+ \dots
+ \skipto Person *m_host = nullptr;
+ \printuntil /\};/
+
+All the information about the party can then be stored in the corresponding QML
+file.
+\quotefromfile tutorials/extending-qml-advanced/advanced1-Base-project/Main.qml
+ \skipto BirthdayParty
+ \printuntil /^\}/
+
+The \c main.cpp file creates a simple shell application that displays whose
+birthday it is and who is invited to their party.
+\quotefromfile tutorials/extending-qml-advanced/advanced1-Base-project/main.cpp
+ \skipto engine
+ \printuntil }
+
+The app outputs the following summary of the party.
+\badcode
+"Bob Jones" is having a birthday!
+They are inviting:
+ "Leo Hodges"
+ "Jack Smith"
+ "Anne Brown"
+\endcode
+
+The following sections go into how to add support for \c Boy and \c Girl
+attendees instead of just \c Person by using inheritance and coercion, how to
+make use of default properties to implicitly assign attendees of the party as
+guests, how to assign properties as groups instead of one by one, how to use
+attached objects to keep track of invited guests' reponses, how to use a
+property value source to display the lyrics of the happy birthday song over
+time, and how to expose third party objects to QML.
+
+
+
+\section1 Inheritance and Coercion
+\c extending-qml-advanced/advanced2-Inheritance-and-coercion
+
+Right now, each attendant is being modelled as a person. This is a bit too
+generic and it would be nice to be able to know more about the attendees. By
+specializing them as boys and girls, we can already get a better idea of who's
+coming.
+
+To do this, the \c Boy and \c Girl classes are introduced, both inheriting from
+\c Person.
+\quotefromfile tutorials/extending-qml-advanced/advanced2-Inheritance-and-coercion/person.h
+ \skipto Boy
+ \printuntil /^\};/
+
+\quotefromfile tutorials/extending-qml-advanced/advanced2-Inheritance-and-coercion/person.h
+ \skipto Girl
+ \printuntil /^\};/
+
+The \c Person class remains unaltered and the \c Boy and \c Girl C++ classes
+are trivial extensions of it. The types and their QML name are registered with
+the QML engine with \l QML_ELEMENT.
+
+Notice that the \c host and \c guests properties in \c BirthdayParty still take
+instances of \c Person.
+\quotefromfile tutorials/extending-qml-advanced/advanced2-Inheritance-and-coercion/birthdayparty.h
+ \skipto BirthdayParty
+ \printuntil QML_ELEMENT
+ \dots
+ \skipto /^\};/
+ \printuntil /^\};/
+
+The implementation of the \c Person class itself has not been changed. However,
+as the \c Person class was repurposed as a common base for \c Boy and \c Girl,
+\c Person should no longer be instantiable from QML directly. An explicit
+\c Boy or \c Girl should be instantiated instead.
+\quotefromfile tutorials/extending-qml-advanced/advanced2-Inheritance-and-coercion/person.h
+ \skipto Person
+ \printto Q_OBJECT
+ \dots
+ \skipto QML_ELEMENT
+ \printuntil QML_UNCREATABLE
+ \dots
+ \skipto /^\};/
+ \printuntil /^\};/
+
+While we want to disallow instantiating \c Person from within QML, it still
+needs to be registered with the QML engine so that it can be used as a property
+type and other types can be coerced to it. This is what the QML_UNCREATABLE
+macro does. As all three types, \c Person, \c Boy and \c Girl, have been
+registered with the QML system, on assignment, QML automatically (and type-safely)
+converts the \c Boy and \c Girl objects into a \c Person.
+
+With these changes in place, we can now specify the birthday party with the
+extra information about the attendees as follows.
+\quotefromfile tutorials/extending-qml-advanced/advanced2-Inheritance-and-coercion/Main.qml
+ \skipto BirthdayParty
+ \printuntil /^\}/
+
+
+
+\section1 Default Properties
+\c extending-qml-advanced/advanced3-Default-properties
+
+Currently, in the QML file, each property is assigned explicitly. For example,
+the \c host property is assigned a \c Boy and the \c guests property is
+assigned a list of \c Boy or \c Girl. This is easy but it can be made a bit
+simpler for this specific use case. Instead of assigning the \c guests property
+explicitly, we can add \c Boy and \c Girl objects inside the party directly
+and have them assigned to \c guests implicitly. It makes sense that all the
+attendees that we specify, and that are not the host, are guests. This change
+is purely syntactical but it can add a more natural feel in many situations.
+
+The \c guests property can be designated as the default property of
+\c BirthdayParty. Meaning that each object created inside of a \c BirthdayParty
+is implicitly appended to the default property \c guests. The resulting QML
+looks like this.
+\quotefromfile tutorials/extending-qml-advanced/advanced3-Default-properties/Main.qml
+ \skipto BirthdayParty
+ \printuntil /^\}/
+
+The only change required to enable this behavior is to add the \c DefaultProperty
+class info annotation to \c BirthdayParty to designate \c guests as its default
+property.
+\quotefromfile tutorials/extending-qml-advanced/advanced3-Default-properties/birthdayparty.h
+ \skipto class
+ \printuntil QML_ELEMENT
+ \dots
+ \skipto /^\};/
+ \printuntil /^\};/
+
+You may already be familiar with this mechanism. The default property for all
+descendants of \c Item in QML is the \c data property. All elements not
+explicitly added to a property of an \c Item will be added to \c data. This
+makes the structure clear and reduces unnecessary noise in the code.
+
+\sa {Specifying Default and Parent Properties for QML Object Types}
+
+
+
+\section1 Grouped Properties
+\c extending-qml-advanced/advanced4-Grouped-properties
+
+More information is needed about the shoes of the guests. Aside from their
+size, we also want to store the shoes' color, brand, and price. This
+information is stored in a \c ShoeDescription class.
+\quotefromfile tutorials/extending-qml-advanced/advanced4-Grouped-properties/person.h
+ \skipto ShoeDescription
+ \printuntil price
+ \dots
+ \skipto /^\};/
+ \printuntil /^\};/
+
+Each person now has two properties, a \c name and a shoe description \c shoe.
+\quotefromfile tutorials/extending-qml-advanced/advanced4-Grouped-properties/person.h
+ \skipto Person
+ \printuntil shoe
+ \dots
+ \skipto /^\};/
+ \printuntil /^\};/
+
+Specifying the values for each element of the shoe description works but is a
+bit repetitive.
+\quotefromfile tutorials/extending-qml-advanced/advanced4-Grouped-properties/Main.qml
+ \skipto Girl
+ \printuntil }
+
+Grouped properties provide a more elegant way of assigning these properties.
+Instead of assigning the values to each property one-by-one, the individual
+values can be passed as a group to the \c shoe property making the code more
+readable. No changes are required to enable this feature as it is available by
+default for all of QML.
+\quotefromfile tutorials/extending-qml-advanced/advanced4-Grouped-properties/Main.qml
+ \skipto host
+ \printuntil /^....}/
+
+\sa {Grouped Properties}
+
+
+
+\section1 Attached Properties
+\c extending-qml-advanced/advanced5-Attached-properties
+
+The time has come for the host to send out invitations. To keep track of which
+guests have responded to the invitation and when, we need somewhere to store
+that information. Storing it in the \c BirthdayParty object iself would not
+really fit. A better way would be to store the responses as attached objects to
+the party object.
+
+First, we declare the \c BirthdayPartyAttached class which holds the guest reponses.
+\quotefromfile tutorials/extending-qml-advanced/advanced5-Attached-properties/birthdayparty.h
+ \skipto BirthdayPartyAttached
+ \printuntil QML_ANONYMOUS
+ \dots
+ \skipto /^\};/
+ \printuntil /^\};/
+
+And we attach it to the \c BirthdayParty class and define
+\c qmlAttachedProperties() to return the attached object.
+\quotefromfile tutorials/extending-qml-advanced/advanced5-Attached-properties/birthdayparty.h
+ \skipto /BirthdayParty : public QObject/
+ \printuntil /^{/
+ \dots
+ \skipto QML_ATTACHED
+ \printuntil QML_ATTACHED
+ \dots
+ \skipto qmlAttachedProperties
+ \printuntil qmlAttachedProperties
+ \skipto /^\};/
+ \printuntil /^\};/
+
+Now, attached objects can be used in the QML to hold the rsvp information of the invited guests.
+\quotefromfile tutorials/extending-qml-advanced/advanced5-Attached-properties/Main.qml
+ \skipto BirthdayParty
+ \printuntil /^}/
+
+Finally, the information can be accessed in the following way.
+\quotefromfile tutorials/extending-qml-advanced/advanced5-Attached-properties/main.cpp
+ \skipto rsvpDate
+ \printuntil attached->property("rsvp").toDate();
+
+The program outputs the following summary of the party to come.
+\badcode
+"Jack Smith" is having a birthday!
+He is inviting:
+ "Robert Campbell" RSVP date: "Wed Mar 1 2023"
+ "Leo Hodges" RSVP date: "Mon Mar 6 2023"
+\endcode
+
+\sa {Providing Attached Properties}
+
+
+
+\section1 Property Value Source
+\c extending-qml-advanced/advanced6-Property-value-source
+
+During the party the guests have to sing for the host. It would be handy if the
+program could display the lyrics customized for the occasion to help the
+guests. To this end, a property value source is used to generate the verses of
+the song over time.
+\quotefromfile tutorials/extending-qml-advanced/advanced6-Property-value-source/happybirthdaysong.h
+ \skipto class
+ \printuntil Q_INTERFACES
+ \dots
+ \skipto setTarget
+ \printuntil setTarget
+ \skipto /^\};/
+ \printuntil /^\};/
+
+The class \c HappyBirthdaySong is added as a value source. It must inherit from
+\c QQmlPropertyValueSource and implement the QQmlPropertyValueSource interface
+with the Q_INTERFACES macro. The \c setTarget() function is used to define
+which property this source acts upon. In this case, the value source writes to
+the \c announcement property of the \c BirthdayParty to display the lyrics
+over time. It has an internal timer that causes the \c announcement
+property of the party to be set to the next line of the lyrics repeatedly.
+
+In QML, a \c HappyBirthdaySong is instantiated inside the \c BirthdayParty. The
+\c on keyword in its signature is used to specify the property that the value
+source targets, in this case \c announcement. The \c name property of the
+\c HappyBirthdaySong object is also \l {Property Binding}{bound} to the name of
+the host of the party.
+\quotefromfile tutorials/extending-qml-advanced/advanced6-Property-value-source/Main.qml
+ \skipto BirthdayParty
+ \printuntil }
+ \dots
+ \skipto /^\}/
+ \printuntil /^\}/
+
+The program displays the time at which the party started using the
+\c partyStarted signal and then prints the following happy birthday verses
+over and over.
+\badcode
+Happy birthday to you,
+Happy birthday to you,
+Happy birthday dear Bob Jones,
+Happy birthday to you!
+\endcode
+
+\sa {Property Value Sources}
+
+
+
+\section1 Foreign objects integration
+\c extending-qml-advanced/advanced7-Foreign-objects-integration
+
+Instead of just printing the lyrics out to the console, the attendees would
+like to use a more fancy display with support for colors. They would like to
+integrate it in the project but currently it is not possible to configure the
+screen from QML because it comes from a third party library. To solve this, the
+necessary types need to be exposed to the QML engine so its properties are
+available for modification in QML directly.
+
+The display can be controlled by the \c ThirdPartyDisplay class. It has
+properties to define the content and the foreground and background colors of the text
+to display.
+\quotefromfile tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/ThirdPartyDisplay.h
+ \skipto ThirdPartyDisplay
+ \printuntil backgroundColor
+ \dots
+ \skipto };
+ \printuntil };
+
+To expose this type to QML, we can register it with the engine with
+QML_ELEMENT. However, since the class isn't accessible for modification,
+QML_ELEMENT cannot simply be added to it. To register the type with the engine,
+the type needs to be registered from the outside. This is what QML_FOREIGN is
+for. When used in a type in conjunction with other QML macros, the other macros
+apply not to the type they reside in but to the foreign type designated by
+QML_FOREIGN.
+\quotefromfile tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/foreigndisplay.h
+ \skipto ForeignDisplay
+ \printuntil };
+
+This way, the BirthdayParty now has a new property with the display.
+\quotefromfile tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/birthdayparty.h
+ \skipuntil BirthdayPartyAttached
+ \skipto BirthdayParty
+ \printto Q_CLASSINFO
+ \dots
+ \skipto };
+ \printuntil };
+
+And, in QML, the colors of the text on the fancy third display can be set explicitly.
+\quotefromfile tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/Main.qml
+ \skipto BirthdayParty
+ \printuntil BirthdayParty
+ \skipto display:
+ \printuntil }
+ \dots
+ \skipto /^}/
+ \printuntil /^}/
+
+Setting the \c announcement property of the BirthdayParty now sends the
+message to the fancy display instead of printing it itself.
+\quotefromfile tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/birthdayparty.cpp
+ \skipto setAnnouncement
+ \printuntil /^}/
+
+The output then looks like this over and over similar to the previous section.
+\badcode
+[Fancy ThirdPartyDisplay] Happy birthday to you,
+[Fancy ThirdPartyDisplay] Happy birthday to you,
+[Fancy ThirdPartyDisplay] Happy birthday dear Bob Jones,
+[Fancy ThirdPartyDisplay] Happy birthday to you!
+\endcode
+
+\sa {Registering Foreign Types}
+*/
diff --git a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
index 43987354ae..156ad47089 100644
--- a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
+++ b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
@@ -1,36 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
-\example tutorials/extending-qml
+\page qtqml-tutorials-extending-qml-example.html
\title Writing QML Extensions with C++
\brief Tutorial about extending QML with Qt C++.
-The \l {Qt QML} module provides a set of APIs for extending QML through
+The \l {Qt Qml} module provides a set of APIs for extending QML through
C++ extensions. You can write extensions to add your own QML types, extend existing
Qt types, or call C/C++ functions that are not accessible from ordinary QML code.
@@ -39,18 +15,24 @@ core QML features, including properties, signals and bindings. It also shows how
extensions can be deployed through plugins.
Many of the topics covered in this tutorial are documented in further detail in
-\l {qtqml-cppintegration-topic.html}{Integrating QML and C++} and its documentation
-sub-topics. In particular, you may be interested in the sub-topics
+\l{Overview - QML and C++ Integration} and its documentation sub-topics. In
+particular, you may be interested in the sub-topics
\l{qtqml-cppintegration-exposecppattributes.html}{Exposing Attributes of C++ Classes to QML}
and \l {qtqml-cppintegration-definetypes.html}{Defining QML Types from C++}.
-\section1 Running the Tutorial Examples
+\section1 Opening the Tutorial Sources
-The code in this tutorial is available as an example project with subprojects
-associated with each tutorial chapter. In \l{Qt Creator Manual}{Qt Creator}, open
-the \uicontrol Welcome mode and select the tutorial from \uicontrol Examples. In
-\uicontrol Edit mode, expand the \e extending-qml project, right-click on the
-subproject (chapter) you want to run and select \uicontrol Run.
+The code in this tutorial is available as part of the Qt sources.
+If you installed Qt with the \QOI, you can
+find the sources in the Qt installation directory under
+Examples/Qt-\QtVersion/qml/tutorials/extending-qml/.
+
+\section1 Creating Project from Scratch
+
+Alternatively, you can follow the tutorial by creating the sources from scratch:
+For each chapter, create a new project using the \e {Qt Quick Application} template
+in Qt Creator, as instructed in \l {Qt Creator: Creating Qt Quick Projects}.
+Then follow along by adapting and extending the generated skeleton code.
\section1 Chapter 1: Creating a New Type
\c extending-qml/chapter1-basics
@@ -72,15 +54,15 @@ a version of 1.0.
We want this \c PieChart type to be usable from QML like this:
-\badcode
- import Charts 1.0
+\qml
+ import Charts
PieChart {
width: 100; height: 100
name: "A simple pie chart"
color: "red"
}
-\endcode
+\endqml
To do this, we need a C++ class that encapsulates this \c PieChart type and its two
properties. Since QML makes extensive use of Qt's \l{Meta-Object System}{meta object system},
@@ -91,77 +73,103 @@ this new class must:
\li Declare its properties using the Q_PROPERTY macro
\endlist
+\section2 Class Declaration
+
Here is our \c PieChart class, defined in \c piechart.h:
\snippet tutorials/extending-qml/chapter1-basics/piechart.h 0
The class inherits from QQuickPaintedItem because we want to override
-QQuickPaintedItem::paint() in perform drawing operations with the QPainter API.
+QQuickPaintedItem::paint() to perform drawing operations with the QPainter API.
If the class just represented some data type and was not an item that actually needed
to be displayed, it could simply inherit from QObject. Or, if we want to extend the
functionality of an existing QObject-based class, it could inherit from that class instead.
Alternatively, if we want to create a visual item that doesn't need to perform drawing
operations with the QPainter API, we can just subclass QQuickItem.
-The \c PieChart class defines the two properties, \c name and \c color, with the Q_PROPERTY macro,
-and overrides QQuickPaintedItem::paint(). The class implementation in \c piechart.cpp
-simply sets and returns the \c m_name and \c m_color values as appropriate, and
-implements \c paint() to draw a simple pie chart. It also turns off the
-QGraphicsItem::ItemHasNoContents flag to enable painting:
+The \c PieChart class defines the two properties, \c name and \c color, with the
+Q_PROPERTY macro, and overrides QQuickPaintedItem::paint(). The \c PieChart
+class is registered using the QML_ELEMENT macro, to allow it to be used from
+QML. If you don't register the class, \c App.qml won't be able to create a
+\c PieChart.
+
+\section2 qmake Setup
+
+For the registration to take effect, the \c qmltypes option is added to
+\c CONFIG in the project file and a \c QML_IMPORT_NAME and
+\c QML_IMPORT_MAJOR_VERSION are given:
+
+\snippet tutorials/extending-qml/chapter1-basics/chapter1-basics.pro 0
+
+\section2 CMake Setup
+
+Similarly, for the registration to take effect when using CMake, use the
+\l{qt6_add_qml_module} {qt_add_qml_module} command:
+
+\snippet tutorials/extending-qml/chapter1-basics/CMakeLists.txt 0
+
+\section2 Class Implementation
+
+The class implementation in \c piechart.cpp simply sets and returns the
+\c m_name and \c m_color values as appropriate, and implements \c paint() to
+draw a simple pie chart:
\snippet tutorials/extending-qml/chapter1-basics/piechart.cpp 0
\dots 0
\snippet tutorials/extending-qml/chapter1-basics/piechart.cpp 1
-Now that we have defined the \c PieChart type, we will use it from QML. The \c app.qml
-file creates a \c PieChart item and display the pie chart's details
+\section2 QML Usage
+
+Now that we have defined the \c PieChart type, we will use it from QML. The \c
+App.qml file creates a \c PieChart item and displays the pie chart's details
using a standard QML \l Text item:
-\snippet tutorials/extending-qml/chapter1-basics/app.qml 0
+\snippet tutorials/extending-qml/chapter1-basics/App.qml 0
Notice that although the color is specified as a string in QML, it is automatically
converted to a QColor object for the PieChart \c color property. Automatic conversions are
-provided for various other \l {QML Basic Types}{basic types}; for example, a string
+provided for various other \l {QML Value Types}{value types}. For example, a string
like "640x480" can be automatically converted to a QSize value.
We'll also create a C++ application that uses a QQuickView to run and
-display \c app.qml. The application must register the \c PieChart type
-using the qmlRegisterType() function, to allow it to be used from QML. If
-you don't register the type, \c app.qml won't be able to create a \c PieChart.
+display \c App.qml.
Here is the application \c main.cpp:
\snippet tutorials/extending-qml/chapter1-basics/main.cpp 0
-This call to qmlRegisterType() registers the \c PieChart type as a type called "PieChart",
-in a type namespace called "Charts", with a version of 1.0.
+\section2 Project Build
-Lastly, we write a \c .pro project file that includes the files and the \c declarative library:
+To build the project we include the files, link against the libraries, and
+define a type namespace called "Charts" with version 1.0 for any types exposed
+to QML.
+
+Using qmake:
\quotefile tutorials/extending-qml/chapter1-basics/chapter1-basics.pro
+Using CMake:
+
+\quotefile tutorials/extending-qml/chapter1-basics/CMakeLists.txt
+
Now we can build and run the application:
\image extending-tutorial-chapter1.png
-\note You may see a warning \e {Expression ... depends on non-NOTIFYable properties:
+\note You may see a warning \e {Expression ... depends on non-NOTIFYable properties:
PieChart::name}. This happens because we add a binding to the writable \c name
property, but haven't yet defined a notify signal for it. The QML engine therefore
cannot update the binding if the \c name value changes. This is addressed in
the following chapters.
-The source code from the following files are referred to in this chapter:
-\noautolist
-\generatelist examplefiles .*chapter1.*
-
\section1 Chapter 2: Connecting to C++ Methods and Signals
\c extending-qml/chapter2-methods
Suppose we want \c PieChart to have a "clearChart()" method that erases the
-chart and then emits a "chartCleared" signal. Our \c app.qml would be able
+chart and then emits a "chartCleared" signal. Our \c App.qml would be able
to call \c clearChart() and receive \c chartCleared() signals like this:
-\snippet tutorials/extending-qml/chapter2-methods/app.qml 0
+\snippet tutorials/extending-qml/chapter2-methods/App.qml 0
\image extending-tutorial-chapter2.png
@@ -193,8 +201,7 @@ disappears, and the application outputs:
qml: The chart has been cleared
\endcode
-The source code from the following files are referred to in this chapter:
-\generatelist examplefiles .*chapter2.*
+
\section1 Chapter 3: Adding Property Bindings
\c extending-qml/chapter3-bindings
@@ -206,7 +213,7 @@ other types' values when property values are changed.
Let's enable property bindings for the \c color property. That means
if we have code like this:
-\snippet tutorials/extending-qml/chapter3-bindings/app.qml 0
+\snippet tutorials/extending-qml/chapter3-bindings/App.qml 0
\image extending-tutorial-chapter3.png
@@ -229,7 +236,7 @@ is emitted whenever the value changes.
\dots
\snippet tutorials/extending-qml/chapter3-bindings/piechart.h 3
-Then, we emit this signal in \c setPieSlice():
+Then, we emit this signal in \c setColor():
\snippet tutorials/extending-qml/chapter3-bindings/piechart.cpp 0
@@ -244,8 +251,7 @@ automatically updated and cannot be used as flexibly in QML. Also, since
bindings are invoked so often and relied upon in QML usage, users of your
custom QML types may see unexpected behavior if bindings are not implemented.
-The source code from the following files are referred to in this chapter:
-\generatelist examplefiles .*chapter3.*
+
\section1 Chapter 4: Using Custom Property Types
@@ -289,7 +295,7 @@ For example, let's replace the use of the \c property with a type called
"PieSlice" that has a \c color property. Instead of assigning a color,
we assign an \c PieSlice value which itself contains a \c color:
-\snippet tutorials/extending-qml/chapter4-customPropertyTypes/app.qml 0
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/App.qml 0
Like \c PieChart, this new \c PieSlice type inherits from QQuickPaintedItem and declares
its properties with Q_PROPERTY():
@@ -314,18 +320,27 @@ item when its contents are drawn:
\snippet tutorials/extending-qml/chapter4-customPropertyTypes/piechart.cpp 0
-Like the \c PieChart type, the \c PieSlice type has to be registered
-using qmlRegisterType() to be used from QML. As with \c PieChart, we'll add the
-type to the "Charts" type namespace, version 1.0:
+Like the \c PieChart type, the \c PieSlice type has to be exposted to QML
+using QML_ELEMENT.
-\snippet tutorials/extending-qml/chapter4-customPropertyTypes/main.cpp 0
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/pieslice.h 0
\dots
-\snippet tutorials/extending-qml/chapter4-customPropertyTypes/main.cpp 1
+
+As with \c PieChart, we add the "Charts" type namespace, version 1.0, to our
+build file:
+
+Using qmake:
+
+\quotefile tutorials/extending-qml/chapter4-customPropertyTypes/chapter4-customPropertyTypes.pro
+
+Using CMake:
+
\dots
-\snippet tutorials/extending-qml/chapter4-customPropertyTypes/main.cpp 2
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/CMakeLists.txt 0
+\snippet tutorials/extending-qml/chapter4-customPropertyTypes/CMakeLists.txt 1
+\dots
+
-The source code from the following files are referred to in this chapter:
-\generatelist examplefiles .*chapter4.*
\section1 Chapter 5: Using List Property Types
\c extending-qml/chapter5-listproperties
@@ -334,7 +349,7 @@ Right now, a \c PieChart can only have one \c PieSlice. Ideally a chart would
have multiple slices, with different colors and sizes. To do this, we could
have a \c slices property that accepts a list of \c PieSlice items:
-\snippet tutorials/extending-qml/chapter5-listproperties/app.qml 0
+\snippet tutorials/extending-qml/chapter5-listproperties/App.qml 0
\image extending-tutorial-chapter5.png
@@ -369,14 +384,13 @@ The \c PieSlice class has also been modified to include \c fromAngle and \c angl
properties and to draw the slice according to these values. This is a straightforward
modification if you have read the previous pages in this tutorial, so the code is not shown here.
-The source code from the following files are referred to in this chapter:
-\generatelist examplefiles .*chapter5.*
+
\section1 Chapter 6: Writing an Extension Plugin
\c extending-qml/chapter6-plugins
-Currently the \c PieChart and \c PieSlice types are used by \c app.qml,
+Currently the \c PieChart and \c PieSlice types are used by \c App.qml,
which is displayed using a QQuickView in a C++ application. An alternative
way to use our QML extension is to create a plugin library to make it available
to the QML engine as a new QML import module. This allows the \c PieChart and
@@ -385,32 +399,33 @@ by any QML application, instead of restricting these types to be only used by
the one application.
The steps for creating a plugin are described in \l {Creating C++ Plugins for QML}.
-To start with, we create a plugin class named \c ChartsPlugin. It subclasses QQmlExtensionPlugin
-and registers our QML types in the inherited \l{QQmlExtensionPlugin::}{registerTypes()} method.
+To start with, we create a plugin class named \c ChartsPlugin. It subclasses
+QQmlEngineExtensionPlugin and uses the Q_PLUGIN_METADATA() macro to register the
+plugin with the Qt meta object system.
Here is the \c ChartsPlugin definition in \c chartsplugin.h:
-\snippet tutorials/extending-qml/chapter6-plugins/import/chartsplugin.h 0
+\snippet tutorials/extending-qml/chapter6-plugins/Charts/chartsplugin.h 0
+
+Then, we configure the build file to define the project as a plugin library.
-And its implementation in \c chartsplugin.cpp:
+Using qmake:
-\snippet tutorials/extending-qml/chapter6-plugins/import/chartsplugin.cpp 0
+\quotefile tutorials/extending-qml/chapter6-plugins/Charts/Charts.pro
-Then, we write a \c .pro project file that defines the project as a plugin library
-and specifies with DESTDIR that library files should be built into a \c {../Charts}
-directory.
+Using CMake:
-\quotefile tutorials/extending-qml/chapter6-plugins/import/import.pro
+\quotefile tutorials/extending-qml/chapter6-plugins/Charts/CMakeLists.txt
When building this example on Windows or Linux, the \c Charts directory will be
located at the same level as the application that uses our new import module.
This way, the QML engine will find our module as the default search path for QML
imports includes the directory of the application executable. On \macos, the
-plugin binary is copied to \c Contents/PlugIns in the the application bundle;
-this path is set in \c {chapter6-plugins/app.pro}:
+plugin binary is copied to \c Contents/PlugIns in the the application bundle.
+With qmake, this path is set in \c {chapter6-plugins/app.pro}:
\quotefromfile tutorials/extending-qml/chapter6-plugins/app.pro
-\skipto osx
+\skipto macos
\printuntil }
To account for this, we also need to add this location as a
@@ -429,23 +444,22 @@ to the same location as the plugin binary.
The \c qmldir file declares the module name and the plugin that is made available
by the module:
-\quotefile tutorials/extending-qml/chapter6-plugins/import/qmldir
+\quotefile tutorials/extending-qml/chapter6-plugins/Charts/qmldir
Now we have a QML module that can be imported to any application, provided that the
QML engine knows where to find it. The example contains an executable that loads
-\c app.qml, which uses the \c {import Charts 1.0} statement. Alternatively, you can
-load the QML file using the \l{Prototyping with qmlscene}{qmlscene tool}, setting the
-import path to the current directory so that it finds the \c qmldir file:
+\c App.qml, which uses the \c {import Charts 1.0} statement. Alternatively, you can
+load the QML file using the \l {Prototyping with the QML Runtime Tool}{qml tool},
+setting the import path to the current directory so that it finds the \c qmldir file:
\code
- qmlscene -I . app.qml
+ qml -I . App.qml
\endcode
The module "Charts" will be loaded by the QML engine, and the types provided by that
module will be available for use in any QML document which imports it.
-The source code from the following files are referred to in this chapter:
-\generatelist examplefiles .*chapter6.*
+
\section1 Chapter 7: Summary
@@ -453,7 +467,7 @@ In this tutorial, we've shown the basic steps for creating a QML extension:
\list
\li Define new QML types by subclassing QObject and registering them with
- qmlRegisterType()
+ QML_ELEMENT or QML_NAMED_ELEMENT()
\li Add callable methods using \l Q_INVOKABLE or Qt slots, and connect to Qt signals
with an \c onSignal syntax
\li Add property bindings by defining \l{Qt's Property System}{NOTIFY} signals
@@ -463,9 +477,9 @@ In this tutorial, we've shown the basic steps for creating a QML extension:
\l {Module Definition qmldir Files}{qmldir} file
\endlist
-The \l{Integrating QML and C++} documentation shows
-other useful features that can be added to QML extensions. For example, we
-could use \l{Default Properties}{default properties} to allow
+The \l{Overview - QML and C++ Integration}{QML and C++ Integration overview}
+documentation shows other useful features that can be added to QML extensions.
+For example, we could use \l{Default Properties}{default properties} to allow
slices to be added without using the \c slices property:
\badcode
@@ -484,5 +498,6 @@ Or randomly add and remove slices from time to time using \l{Property Value Sour
}
\endcode
-\sa {Integrating QML and C++}
+\note To continue learning about QML extensions and features follow the
+\l {Writing advanced QML Extensions with C++} tutorial.
*/
diff --git a/src/qml/doc/src/cppintegration/integrating-with-js-values-from-cpp.qdoc b/src/qml/doc/src/cppintegration/integrating-with-js-values-from-cpp.qdoc
new file mode 100644
index 0000000000..aac9c080d8
--- /dev/null
+++ b/src/qml/doc/src/cppintegration/integrating-with-js-values-from-cpp.qdoc
@@ -0,0 +1,162 @@
+// Copyright (C) 2012 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+/*!
+\page qtqml-integrating-with-js-values-from-cpp.html
+\title Integrating with JavaScript values from C++
+\brief Description of how to load and access JavaScript from C++ code.
+
+The following classes can be used to load and access JavaSript from C++ code:
+
+\list
+
+ \li \l QJSValue, which acts as a container for Qt/JavaScript data types.
+ \li \l QJSManagedValue, which represents a value on the JavaScript heap
+ belonging to a \l QJSEngine.
+ \li \l QJSPrimitiveValue, which operates on primitive types in JavaScript semantics.
+\endlist
+
+Use QJSValue to transfer values to and from the engine, and use QJSManagedValue
+to interact with JavaScript values. Only use QJSPrimitiveValues if you have to
+emulate the semantics of JS primitive values in C++.
+
+\table
+ \header
+ \li QJSValue
+ \li QJSManagedValue
+ \li QJSPrimitiveValue
+ \row
+ \li Persistently store values
+ \li Short lived
+ \li Short lived
+ \row
+ \li Transport values to/from engine
+ \li Access properties
+ \li Only Primitives
+ \row
+ \li
+ \li Call methods
+ \li Basic arithmetic and comparison
+\endtable
+
+\section1 QJSValue as a Container Type
+
+\l QJSValue stores the Qt/JavaScript data types supported in ECMAScript including
+function, array and arbitrary object types as well as anything supported by
+QVariant. As a container, it can be used to pass values to and receive values
+from a QJSEngine.
+
+\snippet qtjavascript/integratingjswithcpp/exampleqjsascontainer.cpp qjs-as-container
+
+In case of a cache miss, \c undefined is returned. Otherwise, the cached value is
+returned. Note that implicit conversions (from QString and QJSValue::SpecialValue respectively)
+occur when the value is returned.
+
+QJSValue also has an API to interact with the contained value, but using
+QJSManagedValue is recommended.
+
+\section1 Primitive and Managed Values
+
+QJSValue and QJSManagedValue store values that can be either managed or primitive.
+In QML’s JS engine, a managed value can be thought of as a pointer to some data
+structure on the heap, whose memory is managed by the engine’s garbage collector.
+The actual content of primitive values is stored directly, using a technique
+called NaN-boxing that enables you to represent a NaN-value in multiple ways, even
+though only two are actually needed; one for signalling and one for quiet NaN-value.
+
+\table
+\header
+ \li Primitive Values
+ \li Managed Values
+\row
+ \li int
+ \li Function
+\row
+ \li double
+ \li Array
+\row
+ \li undefined
+ \li QVariant
+\row
+ \li null
+ \li string object
+\row
+ \li QString
+ \li
+\endtable
+
+A pointer to the engine can be obtained from a managed value, but not from a
+primitive one. When using QJSValue for its JavaScript API, you need access
+to the engine to evaluate JavaScript. For example, to run the \c call(args) function,
+you have to interpret it in the engine. This works, as the function is a managed
+value, and you can obtain the engine from it.
+
+Similarly, where the engine is needed when you call a function or
+access a property on a primitive number or string. Whenever you call a method on
+a primitive, an instance of its corresponding non-primitive objects is created.
+This is referred as boxing. When you write \c (42).constructor, that is equivalent
+to \c (new Number(42)).constructor, and it returns the constructor method of the
+global number object. Accordingly, if you write \c QJSValue(42).property("constructor"),
+you would expect to obtain a QJSValue containing that function. However, what you
+get is instead a QJSValue containing \c undefined.
+
+The QJSValue that you constructed contains only a primitive value, and thus you have
+no way to access the engine. You also can’t simply hardcode the property lookup
+for primitive values in QJSEngine, as in one engine you might set
+\e {Number.prototype.constructor.additionalProperty = "the Spanish Inquisition"}
+whereas in another \e {Number.prototype.constructor.additionalProperty = 42}.
+The end result would then clearly be unexpected.
+
+To ensure that property accesses always work, you would need to always store boxed
+values in QJSValue or store an additional pointer to the engine.
+
+However, this would be incompatible with how QJSValue is currently used, lead to
+pointless JS heap allocations when passing around primitives, and increase the
+size needed to store a QJSValue. Therefore, you should use \l QJSValue only for
+storage and \l QJSManagedValue to obtain the engine.
+
+\section1 QJSManagedValue
+
+QJSManagedValue is similar to QJSValue, with a few differences:
+
+\list
+\li The constructors (except for the default and move constructor2) require
+ passing a QJSEngine pointer.
+\li Methods like \l {QJSManagedValue::}{deleteProperty} and
+ \l {QJSManagedValue::}{isSymbol} are added.
+\li If QJSManagedValue methods encounter an exception, they leave it intact.
+\endlist
+
+To obtain the engine in code, either you are in a scripting context where you’ve
+already got access to an engine to create new objects with \c QJSEngine::newObject
+and to evaluate expressions with \c QJSEngine::evaluate, or you want to evaluate
+some JavaScript in a QObject that has been registered with the engine. In the
+latter case, you can use \c qjsEngine(this) to obtain the currently active
+QJSEngine.
+
+QJSManagedValue also provides a few methods that have no equivalent in QJSEngine.
+
+In the example below, QJSManagedValue methods encounter an exception, and
+QJSEngine::catchError is used to handle the exception.
+
+\snippet qtjavascript/integratingjswithcpp/exampleqjsengine.cpp qjs-engine-example
+
+However, inside a method of a registered object, you might want to instead let
+the exception bubble up the call stack.
+
+QJSManagedValue should be temporarily created on the stack,
+and discarded once you don’t need to work any longer on the contained value.
+Since QJSValue can store primitive values in a more efficient way, QJSManagedValue
+should also not be used as an interface type which is the return or parameter type of
+functions, and the type of properties, as the engine does not treat it in a
+special way, and will not convert values to it (in contrast to QJSValue).
+
+\section1 QJSPrimitiveValue
+
+\l QJSPrimitiveValue can store any of the primitive types, and supports arithmetic
+operations and comparisons according to the ECMA-262 standard. It allows for
+low-overhead operations on primitives in contrast to QJSManagedValue, which always goes
+through the engine, while still yielding results that are indistinguishable
+from what the engine would return. As QJSPrimitiveValue is comparatively large, it
+is not recommended to store values.
+
+*/
diff --git a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
index 0a824bb5b5..eb866eb843 100644
--- a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
+++ b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-cppintegration-interactqmlfromcpp.html
\title Interacting with QML Objects from C++
@@ -41,6 +17,9 @@ into a C++ application. Once a QML object is created, it can be inspected from
C++ in order to read and write to properties, invoke methods and receive signal
notifications.
+For more information about C++ and the different QML integration methods,
+see the
+\l {Overview - QML and C++ Integration} {C++ and QML integration overview} page.
\section1 Loading QML Objects from C++
@@ -105,6 +84,88 @@ You can also connect to any signals or call methods defined in the component
using QMetaObject::invokeMethod() and QObject::connect(). See \l {Invoking QML Methods}
and \l {Connecting to QML Signals} below for further details.
+\section1 Accessing QML Objects via well-defined C++ Interfaces
+
+The best way of interacting with QML from C++ is to define an interface for
+doing so in C++ and accessing it in QML itself. With other methods, refactoring
+your QML code can easily lead to your QML / C++ interaction breaking. It also
+helps to reason about the interaction of QML and C++ code, as having it driven
+via QML can be more easily reasoned about by both users and tooling such as
+qmllint. Accessing QML from C++ will lead to QML code that cannot be understood
+without manually verifying that no outside C++ code is modifying a given QML
+component, and even then the extent of the access might change over time, making
+continued use of this strategy a maintenance burden.
+
+To let QML drive the interaction, first you need to define a C++ interface:
+
+\code
+class CppInterface : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ // ...
+};
+\endcode
+
+Using a QML-driven approach, this interface can be interacted with in two ways:
+
+\section2 Singletons
+
+One option is to register the interface as a singleton by adding the \l
+QML_SINGLETON macro to the interface, exposing it to all components. Following
+that, the interface becomes available via a simple import statement:
+
+\code
+import my.company.module
+
+Item {
+ Component.onCompleted: {
+ CppInterface.foo();
+ }
+}
+\endcode
+
+Use this approach if you need your interface in more places than the root component, as
+simply passing down an object would require explicitly passing it on to other
+components via a property or utilizing the slow and not recommended method of
+using \l {Unqualified access}{unqualified access}.
+
+\section2 Initial properties
+
+Another option is to mark the interface as uncreatable via \l QML_UNCREATABLE
+and supplying it to the root QML Component by using \l
+QQmlComponent::createWithInitialProperties() and a \l {Required
+Properties}{required property} on the QML end.
+
+Your root component may look something like this:
+
+\code
+import QtQuick
+
+Item {
+ required property CppInterface interface
+ Component.onCompleted: {
+ interface.foo();
+ }
+}
+\endcode
+
+Marking the property as required here protects the component against being
+created without the interface property being set.
+
+You can then initialize your component in the same way as outlined in \l
+{Loading QML Objects from C++} except using \c {createWithInitialProperties()}:
+
+\code
+ component.createWithInitialProperties(QVariantMap{{u"interface"_s, QVariant::fromValue<CppInterface *>(new CppInterface)}});
+\endcode
+
+This method is to be preferred if you know that your interface only needs to be
+available to the root component. It also allows for connecting to signals and
+slots of the interface more easily on the C++ side.
+
+If neither of these methods suit your needs you may want to investigate the usage of
+\l {Using C++ Models with Qt Quick Views}{C++ models} instead.
\section1 Accessing Loaded QML Objects by Object Name
@@ -186,12 +247,12 @@ QMetaObject::invokeMethod():
\endtable
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
+{QML Value Types}{value 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.
-
+If the type is omitted or specified as \c var in QML, then you must pass
+QVariant as type with Q_RETURN_ARG() and Q_ARG() when calling
+QMetaObject::invokeMethod.
\section2 Connecting to QML Signals
diff --git a/src/qml/doc/src/cppintegration/topic.qdoc b/src/qml/doc/src/cppintegration/topic.qdoc
index fbb654378d..b14c54a24e 100644
--- a/src/qml/doc/src/cppintegration/topic.qdoc
+++ b/src/qml/doc/src/cppintegration/topic.qdoc
@@ -1,96 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-/*!
-\page qtqml-cppintegration-topic.html
-\title Integrating QML and C++
-\brief Provides instruction to integrate QML and C++
-
-QML applications often need to handle more advanced and performance-intensive
-tasks in C++. The most common and quickest way to do this is to expose the C++
-class to the QML runtime, provided the C++ implementation is derived from
-QObject. Assuming that you have Qt 5.7 or later installed, the following
-step-by-step instructions guide you through the process of using the C++ class,
-BackEnd, in a QML application:
-
-\list 1
-
-\li Create a new project using the "Qt Quick Application" template in Qt Creator
-
-\note Uncheck the \uicontrol {With ui.qml file} option in the
-\uicontrol {Define Project Details} section of \uicontrol {New Project Wizard}.
-
-\li Add a new C++ class called \c BackEnd to the project and replace its header
-file contents with:
-
-\snippet code/backend/backend.h backend_header
-
-The \c Q_PROPERTY macro declares a property that could be accessed from QML.
-
-\li Replace its C++ file contents with:
-
-\snippet code/backend/backend.cpp backend_cpp
-
-The \c setUserName function emits the \c userNameChanged signal every time
-\c m_userName value changes. The signal can be handled from QML using the
-\c onUserNameChanged handler.
-
-\li Include \c "backend.h" in \c main.cpp and register the class as a QML type
-under a import URL as shown below:
-
-\snippet code/backend/main.cpp main_cpp
-
-The BackEnd class is registered as a type, which is accessible from QML by
-importing the URL, "\c{io.qt.examples.backend 1.0}".
-
-\li Replace the contents of \c main.qml with the following code:
-
-\snippet code/backend/main.qml main_qml
-
-The \c BackEnd instance lets you access the \c userName property, which
-is updated when the TextField's \c text property changes.
-
-\endlist
-
-Now the application can be run.
-
-\borderedimage cppintegration-ex.png
-\caption Application running on Ubuntu
-
-Qt offers several methods to integrate C++ with QML, and the method discussed
-in this tutorial is just one of them. For more details about these methods,
-refer to \l{Overview - QML and C++ Integration}.
-*/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-cppintegration-overview.html
\title Overview - QML and C++ Integration
\brief Highlights important points about integrating C++ with QML.
+\ingroup explanations-programminglanguages
-QML is designed to be easily extensible through C++ code. The classes in the \l {Qt QML} module
+QML is designed to be easily extensible through C++ code. The classes in the \l {Qt Qml} module
enable QML objects to be loaded and manipulated from C++, and the nature of QML engine's
integration with Qt's \l{Meta Object System}{meta object system} enables C++ functionality to be
invoked directly from QML. This allows the development of hybrid applications which are implemented
@@ -104,7 +21,7 @@ with QML and JavaScript within \l{qtqml-documents-topic.html}{QML documents}, an
C++
\li Use and invoke some C++ functionality from QML (for example, to invoke your application logic,
use a data model implemented in C++, or call some functions in a third-party C++ library)
-\li Access functionality in the \l {Qt QML} or \l {Qt Quick} C++ API (for example, to dynamically generate
+\li Access functionality in the \l {Qt Qml} or \l {Qt Quick} C++ API (for example, to dynamically generate
images using QQuickImageProvider)
\li Implement your own \l{qtqml-typesystem-objecttypes.html}{QML object types} from C++
\unicode{0x2014} whether for use within your own specific application, or for distribution to others
@@ -132,11 +49,15 @@ methods and signals to be accessed from QML
These are the most common methods of accessing C++ functionality from QML code; for more options and
details, see the main documentation pages that are described in the sections further below.
-Additionally, aside from the ability to access C++ functionality from QML, the \l {Qt QML} module also
+Additionally, aside from the ability to access C++ functionality from QML, the \l {Qt Qml} module also
provides ways to do the reverse and manipulate QML objects from C++ code. See
\l{qtqml-cppintegration-interactqmlfromcpp.html}{Interacting with QML Objects from C++} for more
details.
+It is often desirable to expose some state as global properties to QML.
+\l{qtqml-cppintegration-exposecppstate.html}{Exposing State from C++ to QML}
+describes how to do this.
+
Finally, the C++ code may be integrated into either a C++ application or a C++ plugin depending on
whether it is to be distributed as a standalone application or a library. A plugin can be integrated
with a QML module that can then be imported and used by QML code in other applications; see
@@ -148,7 +69,10 @@ information.
To quickly determine which integration method is appropriate for your situation, the following
flowchart can be used:
-\image cpp-qml-integration-flowchart
+\image cpp-qml-integration-flowchart.png
+
+For a description of the macros in the flowchart, see the
+\l {qtqml-cppintegration-definetypes.html}{Defining QML Types from C++} documentation.
\section1 Exposing Attributes of C++ Classes to QML
@@ -171,7 +95,7 @@ registered for other purposes: for example, it could be registered as a \e {Sing
single class instance to be imported by QML code, or it could be registered to enable the
enumeration values of a non-instantiable class to be accessible from QML.
-Additionally, the \l {Qt QML} module provides mechanisms to define QML types that integrate with QML
+Additionally, the \l {Qt Qml} module provides mechanisms to define QML types that integrate with QML
concepts like attached properties and default properties.
For more information on registering and creating custom QML types from C++, see the \l
@@ -182,7 +106,7 @@ For more information on registering and creating custom QML types from C++, see
C++ objects and values can be embedded directly into the context (or \e scope) of loaded QML objects
using \e {context properties} and \e {context objects}. This is achieved through the QQmlContext
-class provided by the \l {Qt QML} module, which exposes data to the context of a QML component, allowing
+class provided by the \l {Qt Qml} module, which exposes data to the context of a QML component, allowing
data to be injected from C++ into QML.
See \l{qtqml-cppintegration-contextproperties.html}{Embedding C++ Objects into QML with Context
@@ -199,7 +123,8 @@ dynamically load and introspect objects through the Qt meta object system.
\include warning.qdocinc
For more information on accessing QML objects from C++, see the documentation on
-\l{qtqml-cppintegration-interactqmlfromcpp.html}{Interacting with QML Objects from C++}.
+\l{qtqml-cppintegration-interactqmlfromcpp.html}{Interacting with QML Objects from C++},
+and the \l {Exposing Data from C++ to QML} section of the Best Practices page.
\section1 Data Type Conversion Between QML and C++
diff --git a/src/qml/doc/src/examples.qdoc b/src/qml/doc/src/examples.qdoc
deleted file mode 100644
index 7aad09ecee..0000000000
--- a/src/qml/doc/src/examples.qdoc
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
-\group qmlextendingexamples
-\title Qt QML Examples
-\brief List of Qt QML examples for reference.
-
-The list of examples demonstrating how to extend C++ to QML or the other way
-around.
-
-\noautolist
-
-\table
- \row
- \li \l {Extending QML - Adding Types Example}
- \li Exporting C++ Classes
- \row
- \li \l {Extending QML - Object and List Property Types Example}
- \li Exporting C++ Properties
- \row
- \li \l {Extending QML - Extension Objects Example}
- \li Extension Objects
- \row
- \li \l {Extending QML - Inheritance and Coercion Example}
- \li C++ Inheritance and Coercion
- \row
- \li \l {Extending QML - Methods Example}
- \li Methods Support
- \row
- \li \l {Extending QML - Attached Properties Example}
- \li Attached Properties
- \row
- \li \l {Extending QML - Signal Support Example}
- \li Signal Support
- \row
- \li \l {Extending QML - Property Value Source Example}
- \li Property Value Source
- \row
- \li \l {Extending QML - Default Property Example}
- \li Default Property
- \row
- \li \l {Extending QML - Grouped Properties Example}
- \li Grouped Properties
-\endtable
-
-*/
diff --git a/src/qml/doc/src/external-resources.qdoc b/src/qml/doc/src/external-resources.qdoc
index 68c5ab4664..ac22729d63 100644
--- a/src/qml/doc/src/external-resources.qdoc
+++ b/src/qml/doc/src/external-resources.qdoc
@@ -1,78 +1,76 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- \externalpage http://www.ecma-international.org/publications/standards/Ecma-262.htm
+ \externalpage https://www.ecma-international.org/publications-and-standards/standards/ecma-262/
\title ECMA-262
*/
/*!
- \externalpage http://qmlbook.github.io/
- \title Qt5 Cadaques
+ \externalpage https://www.w3schools.com/jsref/default.asp
+ \title W3Schools JavaScript Reference
*/
/*!
- \externalpage http://www.w3schools.com/jsref/default.asp
- \title W3Schools JavaScript Reference
+ \externalpage https://tc39.es/ecma262/#sec-date-objects
+ \title ECMAScript Specification of Date
*/
/*!
- \externalpage https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
- \title Mozilla Developer Network Date Reference
+ \externalpage https://www.qt.io/product/testing-tools#squish
+ \title Squish GUI Test Automation Tool
*/
/*!
- \externalpage hhttps://www.froglogic.com/squish/gui-testing
- \title Squish
+ \externalpage https://doc.qt.io/GammaRay
+ \title GammaRay Manual
*/
/*!
- \externalpage http://doc.qt.io/GammaRay
- \title GammaRay
+ \externalpage https://doc.qt.io/QtQmlLive
+ \title QmlLive Manual
*/
/*!
- \externalpage http://doc.qt.io/QtQmlLive
- \title QmlLive
+ \externalpage https://doc.qt.io/qtcreator/creator-debugging-qml.html
+ \title Qt Creator: QML Debugger
*/
/*!
- \externalpage http://doc.qt.io/qtcreator/creator-debugging-qml.html
- \title QML Debugger
+ \externalpage https://doc.qt.io/qtcreator/creator-qml-performance-monitor.html
+ \title Qt Creator: QML Profiler
*/
/*!
- \externalpage http://doc.qt.io/qtcreator/creator-qml-performance-monitor.html
- \title QML Profiler
+ \externalpage https://doc.qt.io/qtcreator/creator-live-preview-desktop.html
+ \title Qt Creator: QML Preview On Desktop
*/
/*!
- \externalpage http://doc.qt.io/qtcreator/index.html
- \title Qt Creator Manual
+ \externalpage https://fontawesome.com/
+ \title Font Awesome
*/
/*!
- \externalpage https://doc.qt.io/qtcreator/creator-project-creating.html#creating-resource-files
- \title Creating Resource Files
+ \externalpage https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
+ \title Nullish Coalescing
*/
/*!
- \externalpage https://fontawesome.com/
- \title Font Awesome
+ \externalpage https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
+ \title Optional Chaining
+*/
+
+/*!
+ \externalpage https://cmake.org/cmake/help/latest/command/install.html#files
+ \title install(FILES)
*/
+/*!
+ \externalpage https://developer.android.com/reference/android/view/View
+ \title Android: View
+*/
+/*!
+ \externalpage https://developer.android.com/reference/java/security/InvalidParameterException
+ \title Android: InvalidParameterException
+*/
+/*!
+ \externalpage https://developer.android.com/reference/java/lang/ClassCastException
+ \title Android: ClassCastException
+*/
+/*!
+ \externalpage https://developer.android.com/topic/libraries/view-binding
+ \title Android: View binding
+*/
+
diff --git a/src/qml/doc/src/includes/cmake-find-package-qml.qdocinc b/src/qml/doc/src/includes/cmake-find-package-qml.qdocinc
new file mode 100644
index 0000000000..f92b87592e
--- /dev/null
+++ b/src/qml/doc/src/includes/cmake-find-package-qml.qdocinc
@@ -0,0 +1,6 @@
+The command is defined in the \c Qml component of the \c Qt6 package, which
+can be loaded like so:
+
+\badcode
+find_package(Qt6 REQUIRED COMPONENTS Qml)
+\endcode
diff --git a/src/qml/doc/src/includes/cmake-qml-qt-finalize-target-warning.qdocinc b/src/qml/doc/src/includes/cmake-qml-qt-finalize-target-warning.qdocinc
new file mode 100644
index 0000000000..0125a1c4c2
--- /dev/null
+++ b/src/qml/doc/src/includes/cmake-qml-qt-finalize-target-warning.qdocinc
@@ -0,0 +1,9 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+//! [warning]
+\warning If you are using a CMake version lower than 3.19, make sure that you
+pass the \c MANUAL_FINALIZATION option to
+\l{qt_add_executable}{qt6_add_executable()}, and then call
+\l{qt_finalize_target}{qt6_finalize_target()} before calling this function.
+//! [warning]
diff --git a/src/qml/doc/src/includes/qqmlcomponent.qdoc b/src/qml/doc/src/includes/qqmlcomponent.qdoc
index 6949d8823a..fcc6fdc802 100644
--- a/src/qml/doc/src/includes/qqmlcomponent.qdoc
+++ b/src/qml/doc/src/includes/qqmlcomponent.qdoc
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
//! [url-note]
Ensure that the URL provided is full and correct, in particular, use
diff --git a/src/qml/doc/src/includes/qualified-class-name.qdocinc b/src/qml/doc/src/includes/qualified-class-name.qdocinc
new file mode 100644
index 0000000000..fce8b45cc0
--- /dev/null
+++ b/src/qml/doc/src/includes/qualified-class-name.qdocinc
@@ -0,0 +1,7 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+//! [class name must be qualified]
+\note The class name needs to be fully qualified, even if you're already
+ inside the namespace.
+//! [class name must be qualified]
diff --git a/src/qml/doc/src/javascript/date.qdoc b/src/qml/doc/src/javascript/date.qdoc
index 431f9649a0..26ce1d5d29 100644
--- a/src/qml/doc/src/javascript/date.qdoc
+++ b/src/qml/doc/src/javascript/date.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\qmltype Date
@@ -31,98 +7,48 @@
\brief Provides date functions.
The QML Date object extends the
- \l{Mozilla Developer Network Date Reference}{JS Date object} with
+ \l{ECMAScript Specification of Date}{JS Date object} with
locale aware functions.
- Functions that accept a locale format may be either an enumeration
- value:
- \table
- \row \li Locale.LongFormat \li The long version of the string; for example, returning "January" as a month name.
- \row \li Locale.ShortFormat \li The short version of the string; for example, returning "Jan" as a month name.
- \row \li Locale.NarrowFormat \li A special version for use when space is limited;
- for example, returning "J" as a month name. Note that the narrow format might contain
- the same text for different months and days or it can even be an empty string if the
- locale doesn't support narrow names, so you should avoid using it for date formatting.
- Also, for the system locale this format is the same as ShortFormat.
- \endtable
+ Functions that accept a \c format argument take either Locale.LongFormat,
+ Locale.ShortFormat, Locale.NarrowFormat enumeration values,
+ or a string specifying the format.
- or a string specifying the format These expressions may be used for format dates:
- \table
- \header \li Expression \li Output
- \row \li d \li the day as number without a leading zero (1 to 31)
- \row \li dd \li the day as number with a leading zero (01 to 31)
- \row \li ddd
- \li the abbreviated localized day name (e.g. 'Mon' to 'Sun').
- \row \li dddd
- \li the long localized day name (e.g. 'Monday' to 'Sunday').
- \row \li M \li the month as number without a leading zero (1 to 12)
- \row \li MM \li the month as number with a leading zero (01 to 12)
- \row \li MMM
- \li the abbreviated localized month name (e.g. 'Jan' to 'Dec').
- \row \li MMMM
- \li the long localized month name (e.g. 'January' to 'December').
- \row \li yy \li the year as two digit number (00 to 99)
- \row \li yyyy \li the year as four digit number. If the year is negative,
- a minus sign is prepended in addition.
- \endtable
+ The form of the supported format strings is as described in the
+ documentation of \l QDate::toString(), \l QTime::toString() and \l
+ QDateTime::toString().
- All other input characters will be ignored. Any sequence of characters that
- are enclosed in singlequotes will be treated as text and not be used as an
- expression. Two consecutive singlequotes ("''") are replaced by a singlequote
- in the output.
+ If the date is invalid, an empty string is returned.
- Example format strings (assuming that the Date is the 20 July
- 1969):
-
- \table
- \header \li Format \li Result
- \row \li dd.MM.yyyy \li 20.07.1969
- \row \li ddd MMMM d yy \li Sun July 20 69
- \row \li 'The day is' dddd \li The day is Sunday
- \endtable
+ \section1 Format Enumeration Values
- These expressions may be used for formatting time:
+ Use the enumeration values when you want a format that matches the locale
+ preferences.
\table
- \header \li Expression \li Output
- \row \li h
- \li the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
- \row \li hh
- \li the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
- \row \li H
- \li the hour without a leading zero (0 to 23, even with AM/PM display)
- \row \li HH
- \li the hour with a leading zero (00 to 23, even with AM/PM display)
- \row \li m \li the minute without a leading zero (0 to 59)
- \row \li mm \li the minute with a leading zero (00 to 59)
- \row \li s \li the second without a leading zero (0 to 59)
- \row \li ss \li the second with a leading zero (00 to 59)
- \row \li z \li the milliseconds without leading zeroes (0 to 999)
- \row \li zzz \li the milliseconds with leading zeroes (000 to 999)
- \row \li AP or A
- \li use AM/PM display. \e AP will be replaced by either "AM" or "PM".
- \row \li ap or a
- \li use am/pm display. \e ap will be replaced by either "am" or "pm".
- \row \li t \li the timezone (for example "CEST")
+ \row \li Locale.LongFormat \li Longer format
+ \row \li Locale.ShortFormat \li Shorter format
+ \row \li Locale.NarrowFormat \li In this context same as Locale.ShortFormat
\endtable
- All other input characters will be ignored. Any sequence of characters that
- are enclosed in singlequotes will be treated as text and not be used as an
- expression. Two consecutive singlequotes ("''") are replaced by a singlequote
- in the output.
+ The format that the enumerations represent will depend on your locale, but also
+ the method that the enumeration is used for.
- Example format strings (assuming that the QTime is 14:13:09.042)
+ For example, for the \c en_US locale, these format strings are used:
\table
- \header \li Format \li Result
- \row \li hh:mm:ss.zzz \li 14:13:09.042
- \row \li h:m:s ap \li 2:13:9 pm
- \row \li H:m:s a \li 14:13:9 pm
+ \header \li Function \li Locale Enum \li Format String
+ \row \li fromLocaleDateString, toLocaleDateString \li Locale.LongFormat \li \c{dddd, MMMM d, yyyy}
+ \row \li fromLocaleDateString, toLocaleDateString \li Locale.ShortFormat \li \c{M/d/yy}
+ \row \li fromLocaleTimeString, toLocaleTimeString \li Locale.LongFormat \li \c{h:mm:ss AP t}
+ \row \li fromLocaleTimeString, toLocaleTimeString \li Locale.ShortFormat \li \c{h:mm AP}
+ \row \li fromLocaleString, toLocaleString \li Locale.LongFormat \li \c{dddd, MMMM d, yyyy h:mm:ss AP t}
+ \row \li fromLocaleString, toLocaleString \li Locale.ShortFormat \li \c{M/d/yy h:mm AP}
\endtable
- If the date is invalid, an empty string will be returned.
+ \section1 Further Notes
- Note: Using the locale-aware functions to perform date or time formatting can
+ Using the locale-aware functions to perform date or time formatting can
result in incorrectly formatted times, due to an inconsistency in specification
between Qt and JS. ECMA-262 specifies that historical dates should be intrepreted
by projecting the current rules for daylight-saving onto past years, while Qt uses
@@ -132,7 +58,7 @@
hour, if DST is currently in effect, while it was not for the time specified, or
vice versa.
- Note: There are different date formats with different understandings of negative years. Common
+ There are different date formats with different understandings of negative years. Common
human language does not have a year 0. The year after 1BC is 1AD. This understanding is
reflected when printing or parsing dates in one of the formats not standardized by ECMAScript.
That is: toString(), toLocaleString(), toUTCString() and friends. ECMAScript does standardize
diff --git a/src/qml/doc/src/javascript/dynamicobjectcreation.qdoc b/src/qml/doc/src/javascript/dynamicobjectcreation.qdoc
index be4db4c917..f20111d154 100644
--- a/src/qml/doc/src/javascript/dynamicobjectcreation.qdoc
+++ b/src/qml/doc/src/javascript/dynamicobjectcreation.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-javascript-dynamicobjectcreation.html
@@ -35,10 +11,6 @@ useful to delay instantiation of objects until necessary, thereby improving
application startup time. It also allows visual objects to be dynamically
created and added to the scene in reaction to user input or other events.
-See the \l {QML Example - Dynamic Scene}{Dynamic Scene example} for a
-demonstration of the concepts discussed on this page.
-
-
\section1 Creating Objects Dynamically
There are two ways to create objects dynamically from JavaScript. You can
@@ -126,6 +98,12 @@ It is also possible to instantiate components without blocking via the
\section2 Creating an Object from a String of QML
+\warning Creating objects from a string of QML is extremely slow since the engine has to compile the
+passed QML string every time you do it. Furthermore, it's very easy to produce invalid QML when
+programmatically constructing QML code. It's much better to keep your QML components as separate
+files and add properties and methods to customize their behavior than to produce new components by
+string manipulation.
+
If the QML is not defined until runtime, you can create a QML object from
a string of QML using the \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}
function, as in the following example:
diff --git a/src/qml/doc/src/javascript/expressions.qdoc b/src/qml/doc/src/javascript/expressions.qdoc
index b83127389a..d4f0115033 100644
--- a/src/qml/doc/src/javascript/expressions.qdoc
+++ b/src/qml/doc/src/javascript/expressions.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-javascript-expressions.html
\title JavaScript Expressions in QML Documents
@@ -147,7 +123,7 @@ Rectangle {
TapHandler {
id: inputHandler
- onTapped: {
+ onTapped: {
// arbitrary JavaScript expression
console.log("Tapped!")
}
@@ -310,14 +286,14 @@ signal just before being destroyed.
resources in Qt 5.0.0, so mark this section as internal for now.
It should eventually become public API
- There is another section about scarce resources in basictypes.qdoc. It should
+ There is another section about scarce resources in valuetypes.qdoc. It should
be enabled at the same time.
\section1 Scarce Resources in JavaScript
-As described in the documentation for \l{QML Basic Types}, a \c var type
+As described in the documentation for \l{QML Value Types}, a \c var type
property may hold a \e{scarce resource} (image or pixmap). There are several
important semantics of scarce resources which should be noted:
@@ -339,7 +315,7 @@ For the following examples, imagine that we have defined the following class:
and that we have registered it with the QML type-system as follows:
-\snippet qml/integrating-javascript/scarceresources/avatarExample.cpp 0
+\snippet qml/integrating-javascript/scarceresources/scarceresources.pro 0
The AvatarExample class has a property which is a pixmap. When the property
is accessed in JavaScript scope, a copy of the resource will be created and
diff --git a/src/qml/doc/src/javascript/finetuning.qdoc b/src/qml/doc/src/javascript/finetuning.qdoc
index fcd710db8b..0e8a913a2a 100644
--- a/src/qml/doc/src/javascript/finetuning.qdoc
+++ b/src/qml/doc/src/javascript/finetuning.qdoc
@@ -1,33 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-javascript-finetuning.html
-\title Fine-tuning the JavaScript Engine
+\title Configuring the JavaScript Engine
\brief Describes the environment variables available, to control how Javascript is run.
Running JavaScript code can be influenced by a few environment variables, particularly:
@@ -44,8 +20,11 @@ Running JavaScript code can be influenced by a few environment variables, partic
considered for JIT compilation. The default value is 3 times.
\row
\li \c{QV4_FORCE_INTERPRETER}
- \li Setting this environment variable disables the JIT and runs all
- functions through the interpreter, no matter how often they are called.
+ \li Setting this environment variable runs all functions and expressions through the
+ interpreter. The JIT is never used, no matter how often a function or expression is
+ called. Functions and expressions may still be compiled ahead of time using
+ \l{qmlcachegen} or \l{qmlsc}, but only the generated byte code is used at run time. Any
+ generated C++ code and the machine code resulting from it is ignored.
\row
\li \c{QV4_JS_MAX_STACK_SIZE}
\li The JavaScript engine reserves a special memory area as a stack to run JavaScript.
@@ -82,9 +61,12 @@ Running JavaScript code can be influenced by a few environment variables, partic
\li \c{QV4_MAX_CALL_DEPTH}
\li Stack overflows when running (as opposed to compiling) JavaScript are prevented by
controlling the call depth: the number of nested function invocations. By
- default, an exception is generated if the call depth exceeds 1234. If it contains a
- number, this environment variable overrides the maximum call depth. Beware that the
- recursion limit when compiling JavaScript is not affected.
+ default, an exception is generated if the call depth exceeds a maximum number tuned
+ to the platform's default stack size. If the \c{QV4_MAX_CALL_DEPTH} environment
+ variable contains a number, this number is used as maximum call depth. Beware that
+ the recursion limit when compiling JavaScript is not affected. The default maximum
+ call depth is 1234 on most platforms. On QNX it is 640 because on QNX the default
+ stack size is smaller than on most platforms.
\row
\li \c{QV4_MM_AGGRESSIVE_GC}
\li Setting this environment variable runs the garbage collector before each memory
@@ -98,7 +80,28 @@ Running JavaScript code can be influenced by a few environment variables, partic
provide this information, there's a convention to create a special file called
\c{perf-<pid>.map} in \e{/tmp} which perf then reads. This environment variable, if
set, causes the JIT to generate this file.
+ \row
+ \li \c{QV4_SHOW_BYTECODE}
+ \li Outputs the IR bytecode generated by Qt to the console.
+ Has to be combined with \c{QML_DISABLE_DISK_CACHE} or already cached bytecode will not
+ be shown.
+ \row
+ \li \c{QV4_DUMP_BASIC_BLOCKS}
+ \li Outputs the basic blocks of each function compiled ahead of time. The details of the
+ blocks are printed to the console. Additionally, control flow graphs with the byte code
+ for each block are generated in the DOT format for each compiled function. The value of
+ \c {QV4_DUMP_BASIC_BLOCKS} is used as the path to the folder where the DOT files should
+ be generated. If the path is any of ["-", "1", "true"] or if files can't be opened,
+ the graphs are dumped to stdout instead.
+ \row
+ \li \c{QV4_VALIDATE_BASIC_BLOCKS}
+ \li Performs checks on the basic blocks of a function compiled ahead of time to validate
+ its structure and coherence. If the validation fails, an error message is printed to
+ the console.
\endtable
+\l{The QML Disk Cache} accepts further environment variables that allow fine tuning its behavior.
+In particular \c{QML_DISABLE_DISK_CACHE} may be useful for debugging.
+
*/
diff --git a/src/qml/doc/src/javascript/functionlist.qdoc b/src/qml/doc/src/javascript/functionlist.qdoc
index 7a6a922480..d656bc2234 100644
--- a/src/qml/doc/src/javascript/functionlist.qdoc
+++ b/src/qml/doc/src/javascript/functionlist.qdoc
@@ -1,37 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-javascript-functionlist.html
\title List of JavaScript Objects and Functions
\brief A list of objects, functions, and properties supported in QML.
This reference contains a list of objects, functions and
- properties supported by the \l{QQmlEngine}{QML engine}. For a detailed
- description, see the \l{ECMA-262} specification.
+ properties supported by the \l{QJSEngine}{JavaScript engine} in Qt.
+ For a detailed description, see the \l{ECMA-262} specification.
\section1 The Global Object
@@ -233,9 +209,9 @@
\li [Symbol.iterator]()
\endlist
- Additionally, the QML engine adds the following functions to the \l String prototype:
+ Additionally, the QML engine adds the following functions to the \c String prototype:
\list
- \li \l {String::arg}{arg()}
+ \li \l {string}{string::arg()}
\endlist
diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc
index c22c392b80..a27fe48fbe 100644
--- a/src/qml/doc/src/javascript/hostenvironment.qdoc
+++ b/src/qml/doc/src/javascript/hostenvironment.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-javascript-hostenvironment.html
\title JavaScript Host Environment
@@ -42,6 +18,9 @@ Like a browser or server-side JavaScript environment, the QML runtime implements
all of the built-in types and functions defined by the standard, such as Object, Array, and Math.
The QML runtime implements the 7th edition of the standard.
+\l{Nullish Coalescing} (\c{??}) (since Qt 5.15) and \l{Optional Chaining} (\c{?.}) (since Qt 6.2)
+are also implemented in the QML runtime.
+
The standard ECMAScript built-ins are not explicitly documented in the QML documentation. For more
information on their use, please refer to the ECMA-262 7th edition standard or one of the many online
JavaScript reference and tutorial sites, such as the \l{W3Schools JavaScript Reference} (JavaScript Objects
@@ -51,6 +30,47 @@ specific to the browser environment. In the case of the W3Schools link above, th
Reference} section generally covers the standard, while the \c{Browser Objects Reference} and \c{HTML DOM
Objects Reference} sections are browser specific (and thus not applicable to QML).
+\section1 Type annotations and assertions
+
+Function declarations in QML documents can, and should, contain type
+annotations. Type annotations are appended to the declaration of arguments and
+to the function itself, for annotating the return type. The following function
+takes an \c int and a \c string parameter, and returns a \c QtObject:
+
+\qml
+function doThings(a: int, b: string) : QtObject { ... }
+\endqml
+
+Type annotations help tools like \l{Qt Creator} and \l{qmllint Reference}{qmllint} to make sense
+of the code and provide better diagnostics. Moreover, they make functions easier
+to use from C++. See
+\l {qtqml-cppintegration-interactqmlfromcpp.html}{Interacting with QML Objects from C++}
+for more information.
+
+Type assertions (sometimes called \e as-casts) can also be used in order to cast an object to a
+different object type. If the object is actually of the given type, then the type assertion returns
+the same object. If not, it returns \c null. In the following snippet we assert that the \c parent
+object is a \c Rectangle before accessing a specific member of it.
+
+\qml
+Item {
+ property color parentColor: (parent as Rectangle)?.color || "red"
+}
+\endqml
+
+The optional chaining (\c{?.}) avoids throwing an exception if the parent is
+actually not a rectangle. In that case "red" is chosen as \c parentColor.
+
+Since Qt 6.7 type annotations are always enforced when calling functions. Values
+are coerced to the required types as necessary. Previously, type annotations were
+ignored by the interpreter and the JIT compiler, but enforced by \l{qmlcachegen}
+and \l{qmlsc} when compiling to C++. This could lead to differences in behavior in
+some corner cases. In order to explicitly request the old behavior of the
+interpreter and JIT you can add the following to your QML document:
+
+\qml
+pragma FunctionSignatureBehavior: Ignored
+\endqml
\section1 QML Global Object
@@ -69,7 +89,7 @@ QML engine can be found in the \l{List of JavaScript Objects and Functions}.
Note that QML makes the following modifications to native objects:
\list
-\li An \l {String::arg}{arg()} function is added to the \l String prototype.
+\li An \l {string}{arg()} function is added to the \c String prototype.
\li Locale-aware conversion functions are added to the \l Date and \l Number prototypes.
\endlist
diff --git a/src/qml/doc/src/javascript/imports.qdoc b/src/qml/doc/src/javascript/imports.qdoc
index 8e26c4aadd..ef5376cb54 100644
--- a/src/qml/doc/src/javascript/imports.qdoc
+++ b/src/qml/doc/src/javascript/imports.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-javascript-imports.html
\title Importing JavaScript Resources in QML
@@ -64,7 +40,7 @@ objects such as \c Date and \c Math).
The functions defined in an imported JavaScript file are available to objects
defined in the importing QML document, via the
\c{"Qualifier.functionName(params)"} syntax. Functions in JavaScript resources
-may take parameters whose type can be any of the supported QML basic types or
+may take parameters whose types can be any QML value types or
object types, as well as normal JavaScript types. The normal
\l{qtqml-cppintegration-data.html}{data type conversion rules} will apply to
parameters and return values when calling such functions from QML.
@@ -95,17 +71,18 @@ or modules).
A JavaScript resource may import another in the following fashion:
\code
-.import "filename.js" as Qualifier
+import * as MathFunctions from "factorial.mjs";
\endcode
-For example:
+Or:
\code
-import * as MathFunctions from "factorial.mjs";
+.import "filename.js" as Qualifier
\endcode
-The latter is standard ECMAScript syntax for importing ECMAScript modules, and
+The former is standard ECMAScript syntax for importing ECMAScript modules, and
only works from within ECMAScript modules as denoted by the \c mjs file
-extension. The former is an extension to JavaScript provided by the \c QML
-engine and will work also with non-modules.
+extension. The latter is an extension to JavaScript provided by the \c QML
+engine and will work also with non-modules. As an extension superseded by the
+ECMAScript standard, its usage is discouraged.
When a JavaScript file is imported this way, it is imported with a qualifier.
The functions in that file are then accessible from the importing script via the
@@ -154,7 +131,15 @@ var importedEnumValue = JsQtTest.MyQmlObject.EnumValue3
\endcode
In particular, this may be useful in order to access functionality provided
-via a singleton type; see qmlRegisterSingletonType() for more information.
+via a singleton type; see QML_SINGLETON for more information.
+
+Your JavaScript resource by default can access all imports of the component
+that imports the resource. It does not have access to the componpents's imports
+if it is declared as a stateless library (using \c{.pragma library}) or contains
+an explicit \c{.import} statment.
+
+\note The .import syntax doesn't work for scripts used in \l {WorkerScript}
+
+\sa {Defining JavaScript Resources in QML}
-\note The .import syntax doesn't work for scripts used in the \l {WorkerScript}
*/
diff --git a/src/qml/doc/src/javascript/memory.qdoc b/src/qml/doc/src/javascript/memory.qdoc
new file mode 100644
index 0000000000..54f48f48df
--- /dev/null
+++ b/src/qml/doc/src/javascript/memory.qdoc
@@ -0,0 +1,211 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+/*!
+
+\page qtqml-javascript-memory.html
+\title Memory Management in the JavaScript Engine
+\brief Describes how the JavaScript Engine manages memory.
+
+\section1 Introduction
+
+This document describes the \e dynamic memory management of the JavaScript
+Engine in QML. It is a rather technical, in depth description. You only need
+to read this if you care about the exact characteristics of JavaScript memory
+management in QML. In particular, it can be helpful if you're trying to
+optimize your application for maximum performance.
+
+\note By compiling your QML code to C++ using the \l{Qt Quick Compiler}
+you can avoid much of the JavaScript heap usage. The generated C++ code uses the
+familiar C++ stack and heap for storing objects and values. The
+\l{JavaScript Host Environment}, however, always uses some JavaScript-managed
+memory, no matter if you use it or not. If you use features that cannot be
+compiled to C++, the engine will fall back to interpretation or JIT compilation
+and use JavaScript objects stored on the JavaScript heap, though.
+
+\section1 Basic Principles
+
+The JavaScript engine in QML has a dedicated memory manager that requests
+address space in units of multiple pages from the operating system. Objects,
+strings, and other managed values created in JavaScript are then placed in this
+address space, using the JavaScript engine's own allocation scheme. The
+JavaScript engine does not use the C library's malloc() and free(), nor the
+default implementations of C++'s new and delete to allocate memory for
+JavaScript objects.
+
+Requests for address space are generally done with mmap() on Unix-like systems
+and with VirtualAlloc() on windows. There are several platform-specific
+implementations of those primitives. Address space reserved this way is not
+immediately committed to physical memory. Rather, the operating system notices
+when a page of memory is actually accessed and only then commits it. Therefore,
+the address space is practically free and having a lot of it gives the
+JavaScript memory manager the leverage it needs to place objects in an efficient
+way on the JavaScript heap. Furthermore, there are platform-specific techniques
+to tell the operating system that a chunk of address space, though still
+reserved, does not have to be mapped into physical memory for the time being.
+The operating system can then decommit the memory as needed and use it for other
+tasks. Crucially, most operating systems do not guarantee immediate action on
+such a decommit request. They will only decommit the memory when it is actually
+needed for something else. On Unix-like systems we generally use madvise() for
+this. Windows has specific flags to VirtualFree() to do the equivalent.
+
+\note There are memory profiling tools that do not understand this mechanism and
+over-report JavaScript memory usage.
+
+All values stored on the JavaScript heap are subject to garbage collection.
+None of the values are immediately "deleted" when they go out of scope or are
+otherwise "dropped". Only the garbage collector may remove values from the
+JavaScript heap and return memory (see \l{Garbage Collection} below for how
+this works).
+
+\section1 QObject-based Types
+
+QObject-based types, and in particular everything you can phrase as a QML
+element, are allocated on the C++ heap. Only a small wrapper around the pointer
+is placed on the JavaScript heap when a QObject is accessed from JavaScript.
+Such a wrapper, however, can own the QObject it points to. See
+\l{QJSEngine::ObjectOwnership}. If the wrapper owns the object, it will be
+deleted when the wrapper is garbage-collected. You can then also manually
+trigger the deletion by calling the destroy() method on it. destroy() internally
+calls \l{QObject::deleteLater()}. It will therefore not immediately delete the
+object, but wait for the next event loop iteration.
+
+QML-declared \e properties of objects are stored on the JavaScript heap. They
+live as long as the object they belong to lives. Afterwards they are removed the
+next time the garbage collector runs.
+
+\section1 Object Allocation
+
+In JavaScript, any structured type is an object. This includes function objects,
+arrays, regular expressions, date objects and much more. QML has a number of
+internal object types, such as the above mentioned QObject wrapper. Whenever
+an object is created, the memory manager locates some storage for it on the
+JavaScript heap.
+
+JavaScript strings are also managed values, but their string data is not
+allocated on the JavaScript heap. Similar to QObject wrappers, the heap objects
+for strings are just thin wrappers around a pointer to string data.
+
+When allocating memory for an object, the size of the object is first rounded up
+to 32 byte alignment. Each 32 byte piece of address space is called a "slot".
+For objects smaller than a "huge size" threshold, the memory manager performs
+a series of attempts to place the object in memory:
+\list
+\li The memory manager keeps linked lists of previously freed pieces of heap,
+ called "bins". Each bin holds pieces of heap with a fixed per-bin size in
+ slots. If the bin for the right size is not empty, it picks the first entry
+ and places the object there.
+\li The memory that hasn't been used yet is managed via a bumper allocator. A
+ bumper pointer points to the byte beyond the occupied address space. If
+ there is still enough unused address space, the bumper is increased
+ accordingly, and the object is placed in unused space.
+\li A separate bin is kept for previously freed pieces of heap of varying sizes
+ larger than the specific sizes mentioned above. The memory manager
+ traverses this list and tries to find a piece it can split to accommodate
+ the new object.
+\li The memory manager searches the lists of specifically sized bins
+ larger than the object to be allocated and tries to split one of those.
+\li Finally, if none of the above works, the memory manager reserves more
+ address space and allocates the object using the bumper allocator.
+\endlist
+
+Huge objects are handled by their own allocator. For each of those one or more
+separate memory pages are obtained from the OS and managed separately.
+
+Additionally, each new chunk of address space the memory manager obtains from
+the OS gets a header that holds a number of flags for each slot:
+\list
+\li \e{object}: The first slot occupied by an object is flagged with this bit.
+\li \e{extends}: Any further slots occupied by an object are flagged with this
+ bit.
+\li \e{mark}: When the garbage collector runs, it sets this bit if the object is
+ still in use.
+\endlist
+
+\section1 Internal Classes
+
+In order to minimize the required storage for metadata on what members
+an object holds, the JavaScript engine assigns an "internal class" to each
+object. Other JavaScript engines call this "hidden class" or "shape".
+Internal classes are deduplicated and kept in a tree. If a property is
+added to an object, the children of the current internal class are checked to
+see if the same object layout has occurred before. If so, we can use the
+resulting internal class right away. Otherwise we have to create a new one.
+
+Internal classes are stored in their own section of the JavaScript heap that
+otherwise works the same way as the general object allocation described above.
+This is because internal classes have to be kept alive while the objects using
+them are collected. Internal classes are then collected in a separate pass.
+
+The actual property attributes stored in internal classes are \e not kept on
+the JavaScript heap, though, but rather managed using new and delete.
+
+\section1 Garbage Collection
+
+The garbage collector used in the JavaScript engine is a non-moving,
+stop-the-world Mark and Sweep design. In the \e mark phase we traverse all the
+known places where live references to objects can be found. In particular:
+
+\list
+\li JavaScript globals
+\li Undeletable parts of QML and JavaScript compilation units
+\li The JavaScript stack
+\li The persistent value storage. This is where QJSValue and similar classes
+ keep references to JavaScript objects.
+\endlist
+
+For any object found in those places the mark bits are set recursively for
+anything it references.
+
+In the \e sweep phase the garbage collector then traverses the whole heap and
+frees any objects not marked before. The resulting released memory is sorted
+into the bins to be used for further allocations. If a chunk of address space
+is completely empty, it is decommitted, but the address space is retained
+(see \l{Basic Principles} above). If the memory usage grows again, the same
+address space is re-used.
+
+The garbage collector is triggered either manually by calling the \l [QML] {Qt::}{gc()} function
+or by a heuristic that takes the following aspects into account:
+
+\list
+\li The amount of memory managed by object on the JavaScript heap, but not
+ directly allocated on the JavaScript heap, such as strings and internal
+ class member data. A dynamic threshold is maintained for those. If it is
+ surpassed, the garbage collector runs and the threshold is increased. If
+ the amount of managed external memory falls far below the threshold, the
+ threshold is decreased.
+\li The total address space reserved. The internal memory allocation on the
+ JavaScript heap is only considered after at least some address space has
+ been reserved.
+\li The additional address space reservation since the last garbage collector
+ run. If the amount of address space is more than double the amount of
+ used memory after the last garbage collector run, we run the garbage
+ collector again.
+\endlist
+
+\section1 Analyzing Memory Usage
+
+In order to observe the development of both the address space and the number
+of objects allocated in it, it is best to use a specialized tool. The
+\l{Qt Creator: QML Profiler}{QML Profiler} provides a visualization that
+helps here. More generic tools cannot see what the JavaScript memory manager
+does within the address space it reserves and may not even notice that part
+of the address space is not committed to physical memory.
+
+Another way to debug memory usage are the
+\l{QLoggingCategory}{logging categories} \e{qt.qml.gc.statistics} and
+\e{qt.qml.gc.allocatorStats}. If you enable the \e{Debug} level for
+qt.qml.gc.statistics, the garbage collector will print some information every
+time it runs:
+
+\list
+\li How much total address space is reserved
+\li How much memory was in use before and after the garbage collection
+\li How many objects of various sizes were allocated so far
+\endlist
+
+The \e{Debug} level for qt.qml.gc.allocatorStats prints more detailed
+statistics that also include how the garbage collector was triggered, timings
+for the mark and sweep phases and a detailed breakdown of memory usage by bytes
+and chunks of address space.
+
+*/
diff --git a/src/qml/doc/src/javascript/number.qdoc b/src/qml/doc/src/javascript/number.qdoc
index 288232255c..a37fd8051b 100644
--- a/src/qml/doc/src/javascript/number.qdoc
+++ b/src/qml/doc/src/javascript/number.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\qmltype Number
@@ -58,21 +34,32 @@
If \a locale is not specified, the default locale will be used.
The following example shows a number formatted for the German locale:
- \code
+ \qml
import QtQuick 2.0
Text {
text: "The value is: " + Number(4742378.423).toLocaleString(Qt.locale("de_DE"))
}
- \endcode
+ \endqml
+
+ You can customize individual fields of the \a{locale} to tightly control
+ the output:
+ \qml
+ let locale = Qt.locale("de_DE");
+ let a = Number(1000).toLocaleString(locale)); // a == 1.000,00
+ locale.numberOptions = Locale.OmitGroupSeparator;
+ let b = Number(1000).toLocaleString(locale)); // b == 1000,00
+ \endqml
You can apply toLocaleString() directly to constants, provided the decimal
is included in the constant, e.g.
- \code
+ \qml
123.0.toLocaleString(Qt.locale("de_DE")) // OK
123..toLocaleString(Qt.locale("de_DE")) // OK
123.toLocaleString(Qt.locale("de_DE")) // fails
- \endcode
+ \endqml
+
+ \sa {QtQml::Locale}{Locale}
*/
/*!
@@ -93,12 +80,14 @@
If \a locale is not supplied the default locale will be used.
For example, using the German locale:
- \code
+ \qml
var german = Qt.locale("de_DE");
var d;
d = Number.fromLocaleString(german, "1234,56") // d == 1234.56
d = Number.fromLocaleString(german, "1.234,56") // d == 1234.56
d = Number.fromLocaleString(german, "1234.56") // throws exception
d = Number.fromLocaleString(german, "1.234") // d == 1234.0
- \endcode
+ \endqml
+
+ \sa {QtQml::Locale}{Locale}
*/
diff --git a/src/qml/doc/src/javascript/qmlglobalobject.qdoc b/src/qml/doc/src/javascript/qmlglobalobject.qdoc
index bba796f9ea..15b9996ff3 100644
--- a/src/qml/doc/src/javascript/qmlglobalobject.qdoc
+++ b/src/qml/doc/src/javascript/qmlglobalobject.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-javascript-qmlglobalobject.html
\title QML Global Object
@@ -31,100 +7,27 @@
The QML JavaScript host environment implements the following host objects and functions.
-These are built in and can be used from any JavaScript code loaded in QML, without
+They are built-in, so you can use them from any JavaScript code loaded in QML, without
additional imports:
\list
-\li The \l{QmlGlobalQtObject}{Qt object}: This object is specific to QML, and provides helper methods
+\li The \l{QmlGlobalQtObject}{Qt object}: A QML object that offers helper methods
and properties specific to the QML environment.
-\li qsTr(), qsTranslate(), qsTrId(), QT_TR_NOOP(), QT_TRANSLATE_NOOP(), and QT_TRID_NOOP() functions:
- These functions are specific to QML, and provide \l{Overview of the Translation Process}{translation capabilities} to the QML environment.
-\li gc() function: This function is specific to QML, and provides a way to manually trigger garbage collection.
-\li print() function: This function is specific to QML, and provides a simple way to output information to the console.
-\li The \l{Console API}{console object}: This object implements a subset of the \l{http://getfirebug.com/wiki/index.php/Console_API}{FireBug Console API}.
-\li \l{XMLHttpRequest}, DOMException: These objects implement a subset of the \l{http://www.w3.org/TR/XMLHttpRequest/}{W3C XMLHttpRequest specification}.
-\endlist
-
-\note The \l {QJSEngine::}{globalObject()} function cannot be used to modify
-the global object of a \l QQmlEngine. For more information about this, see
+\li \l {Qt::}{qsTr()}, \l {Qt::}{qsTranslate()}, \l {Qt::}{qsTrId()}, \l {Qt::}{qsTrNoOp()},
+ \l {Qt::}{qsTranslateNoOp()}, \l {Qt::}{qsTrIdNoOp()} functions:
+ QML functions that let you translate \l{Mark Strings for Translation}
+ {strings} and \l{Mark Translatable Data Text Strings}{string literals} in the
+ QML environment.
+\li gc() function: A QML function that manually triggers garbage collection.
+\li print() function: A QML function that prints output to the console.
+\li The \l{Console API}{console object}: Implements a subset of the
+ \l{http://getfirebug.com/wiki/index.php/Console_API}{FireBug Console API}.
+\li \l{XMLHttpRequest}, DOMException: Implements a subset of the
+ \l{http://www.w3.org/TR/XMLHttpRequest/}{W3C XMLHttpRequest specification}.
+\endlist
+
+\note You cannot use the \l {QJSEngine::}{globalObject()} function to change
+the global object of a \l QQmlEngine. For more information, see
\l {JavaScript Environment Restrictions}.
-\target XMLHttpRequest
-\section1 XMLHttpRequest
-
-The XMLHttpRequest object, which can be used to asynchronously obtain
-data from over a network.
-
-The XMLHttpRequest API implements the same \l {http://www.w3.org/TR/XMLHttpRequest/}{W3C standard}
-as many popular web browsers with following exceptions:
-\list
-\li QML's XMLHttpRequest does not enforce the same origin policy.
-\endlist
-
-Additionally, the \c responseXML XML DOM tree currently supported by QML is a reduced subset
-of the \l {http://www.w3.org/TR/DOM-Level-3-Core/}{DOM Level 3 Core} API supported in a web
-browser. The following objects and properties are supported by the QML implementation:
-
-\table
-\header
-\li \b {Node}
-\li \b {Document}
-\li \b {Element}
-\li \b {Attr}
-\li \b {CharacterData}
-\li \b {Text}
-
-\row
-\li
-\list
-\li nodeName
-\li nodeValue
-\li nodeType
-\li parentNode
-\li childNodes
-\li firstChild
-\li lastChild
-\li previousSibling
-\li nextSibling
-\li attributes
-\endlist
-
-\li
-\list
-\li xmlVersion
-\li xmlEncoding
-\li xmlStandalone
-\li documentElement
-\endlist
-
-\li
-\list
-\li tagName
-\endlist
-
-\li
-\list
-\li name
-\li value
-\li ownerElement
-\endlist
-
-\li
-\list
-\li data
-\li length
-\endlist
-
-\li
-\list
-\li isElementContentWhitespace
-\li wholeText
-\endlist
-
-\endtable
-
-The \l{Qt Quick Examples - XMLHttpRequest}{XMLHttpRequest example} demonstrates
-how to use the XMLHttpRequest object to make a request and read the response
-headers.
-
*/
diff --git a/src/qml/doc/src/javascript/qtjavascript.qdoc b/src/qml/doc/src/javascript/qtjavascript.qdoc
index aa4dce6a37..d226b4428e 100644
--- a/src/qml/doc/src/javascript/qtjavascript.qdoc
+++ b/src/qml/doc/src/javascript/qtjavascript.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtjavascript.html
diff --git a/src/qml/doc/src/javascript/resources.qdoc b/src/qml/doc/src/javascript/resources.qdoc
index 60f97c2007..d60101806a 100644
--- a/src/qml/doc/src/javascript/resources.qdoc
+++ b/src/qml/doc/src/javascript/resources.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-javascript-resources.html
\title Defining JavaScript Resources in QML
diff --git a/src/qml/doc/src/javascript/string.qdoc b/src/qml/doc/src/javascript/string.qdoc
deleted file mode 100644
index 47922ff17a..0000000000
--- a/src/qml/doc/src/javascript/string.qdoc
+++ /dev/null
@@ -1,50 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
- \qmltype String
- \inqmlmodule QtQml
- \brief The String object represents a string value.
-
- The QML String object extends the JS String object with
- the arg() function.
-
- \sa {ECMA-262}{ECMAScript Language Specification}
-*/
-
-/*!
- \qmlmethod string String::arg(value)
-
- Returns a copy of this string with the lowest numbered place marker replaced by \a value,
- i.e., %1, %2, ..., %99. The following example prints "There are 20 items":
-
- \code
- var message = "There are %1 items"
- var count = 20
- console.log(message.arg(count))
- \endcode
-*/
diff --git a/src/qml/doc/src/javascript/topic.qdoc b/src/qml/doc/src/javascript/topic.qdoc
index 05fb1ddfdc..2302f90fbe 100644
--- a/src/qml/doc/src/javascript/topic.qdoc
+++ b/src/qml/doc/src/javascript/topic.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-javascript-topic.html
\title Integrating QML and JavaScript
@@ -48,6 +24,25 @@ See the documentation page titled
\l{qtqml-javascript-expressions.html}{JavaScript Expressions in QML Documents}
for more information about using JavaScript expressions in QML.
+\section1 Dynamic QML Object Creation from JavaScript
+
+QML supports the dynamic creation of objects from within JavaScript. This is
+useful to delay instantiation of objects until necessary, thereby improving
+application startup time. It also allows visual objects to be dynamically
+created and added to the scene in reaction to user input or other events. This
+functionality can be used in two main ways.
+
+Object can be created dynamically from JavaScript in an imperative way using
+\l{qtqml-javascript-dynamicobjectcreation.html}{dynamic creation of objects}.
+This can be useful, for example, when QML is used as an application scripting
+language.
+
+\note When creating user interfaces, the preferred way of creating objects
+dynamically is to use declarative constructs as these integrate best with the
+QML engine and tooling. Various types exist to enable this functionality such
+as the \l{Loader}, \l{Instantiator}, \l{Repeater} types.
+
+
\section1 JavaScript Resources
Application logic defined in JavaScript functions may be separated into
@@ -81,11 +76,15 @@ These limitations and extensions are documented in the description of the
\l{qtqml-javascript-hostenvironment.html}{JavaScript Host Environment} provided
by the QML engine.
-\section1 Fine Tuning the JavaScript engine
+There is also an in depth description of the
+\l{qtqml-javascript-memory.html}{memory management} employed by the JavaScript
+engine.
+
+\section1 Configuring the JavaScript engine
For specific use cases you may want to override some of the parameters the
JavaScript engine uses for handling memory and compiling JavaScript. See
-\l{qtqml-javascript-finetuning.html}{Fine Tuning the JavaScript engine} for
+\l{qtqml-javascript-finetuning.html}{Configuring the JavaScript engine} for
more information on these parameters.
*/
diff --git a/src/qml/doc/src/javascript/xmlhttprequest.qdoc b/src/qml/doc/src/javascript/xmlhttprequest.qdoc
new file mode 100644
index 0000000000..b8624073c5
--- /dev/null
+++ b/src/qml/doc/src/javascript/xmlhttprequest.qdoc
@@ -0,0 +1,301 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \qmltype XMLHttpRequest
+ \inqmlmodule QtQml
+ \brief Object for sending requests to a server.
+
+ The \c XMLHttpRequest object allows scripts to perform HTTP client functionality,
+ such as submitting form data or loading data asynchronously from a server.
+
+ The \c XMLHttpRequest API is a partial implementation of the
+ \l {https://www.w3.org/TR/2014/WD-XMLHttpRequest-20140130/}{W3C XHR Level 1 standard}
+ with the following exception:
+ \list
+ \li It does not enforce the same origin policy.
+ \endlist
+
+ \section1 Sending requests
+
+ Use the following steps to send a request using the \c XMLHttpRequest API:
+ \list 1
+ \li Create a \c XMLHttpRequest object.
+ \li Assign a callback function to the \l {XMLHttpRequest::onreadystatechange}{onreadystatechange} signal handler.
+ \li Call \l {XMLHttpRequest::open}{open()} with the appropriate HTTP method and URL to request.
+ \li Call \l {XMLHttpRequest::send}{send()}
+ \endlist
+
+ The callback function handles the HTTP response for a request.
+ It's a good practice to check if the \l{XMLHttpRequest::readyState}{readyState} is \c DONE in the handler,
+ before you use one of the following methods to read the response:
+ \list
+ \li \l {XMLHttpRequest::response}{response}
+ \li \l {XMLHttpRequest::responseText}{responseText}
+ \li \l {XMLHttpRequest::responseXML}{responseXML}
+ \endlist
+
+ The following example demonstrates how to send a request and read the response:
+
+ \snippet qml/XHRForm.qml 0
+
+ The earlier snippet connects the button's clicked signal to an external \c sendRequest function.
+ A resource URL is passed as the first argument, and a callback function to handle UI updates is passed as the second.
+ The \c sendRequest function, which exists in an external \c request.js file, can be implemented like this:
+
+ \snippet qml/xmlhttprequest.js 0
+
+ The earlier snippet follows the four simple steps mentioned at the beginning.
+ It instantiates the \c XMLHttpRequest object first, and assigns a callback function to handle the response.
+ It also calls \l {XMLHttpRequest::open}{open()} with an HTTP method and URL, before it sends the request to the server.
+ Notice that the second argument to \c sendRequest is called at the end of \l {XMLHttpRequest::onreadystatechange}{onreadystatechange},
+ in order to handle UI updates based on the HTTP response.
+
+ Set the \c QML_XHR_DUMP environment variable to \c 1 if you want to debug a request.
+ This will log the following information:
+ \list
+ \li Method type (GET or POST), URL, and body of sent requests.
+ \li URL and body of responses received.
+ \li Network error, if any.
+ \endlist
+
+ \section1 Accessing local files
+
+ By default, you cannot use the \c XMLHttpRequest object to read files from your local file system.
+ If you wish to use this feature to access local files, you can set the following environment variables to \c 1.
+ \list
+ \li QML_XHR_ALLOW_FILE_READ
+ \li QML_XHR_ALLOW_FILE_WRITE
+ \endlist
+ \warning Use this feature only if you know that the application runs trusted QML and JavaScript code.
+
+ \section1 responseXML document
+
+ The \c responseXML XML DOM tree currently supported by QML is a reduced subset of
+ the \l {http://www.w3.org/TR/DOM-Level-3-Core/}{DOM Level 3 Core} API supported in a web browser.
+ The following objects and properties are supported by the QML implementation:
+
+ \table
+ \header
+ \li \b {Node}
+ \li \b {Document}
+ \li \b {Element}
+ \li \b {Attr}
+ \li \b {CharacterData}
+ \li \b {Text}
+
+ \row
+ \li
+ \list
+ \li nodeName
+ \li nodeValue
+ \li nodeType
+ \li parentNode
+ \li childNodes
+ \li firstChild
+ \li lastChild
+ \li previousSibling
+ \li nextSibling
+ \li attributes
+ \endlist
+
+ \li
+ \list
+ \li xmlVersion
+ \li xmlEncoding
+ \li xmlStandalone
+ \li documentElement
+ \endlist
+
+ \li
+ \list
+ \li tagName
+ \endlist
+
+ \li
+ \list
+ \li name
+ \li value
+ \li ownerElement
+ \endlist
+
+ \li
+ \list
+ \li data
+ \li length
+ \endlist
+
+ \li
+ \list
+ \li isElementContentWhitespace
+ \li wholeText
+ \endlist
+
+ \endtable
+*/
+
+/*!
+ \qmlmethod void XMLHttpRequest::abort()
+
+ Cancels the current request.
+
+ It changes the \l {XMLHttpRequest::readyState}{readyState} property to be \c XMLHttpRequest.UNSENT and emits the \c readystatechange signal.
+*/
+
+/*!
+ \qmlmethod string XMLHttpRequest::getAllResponseHeaders()
+
+ Returns a \c String of headers received from the last response.
+
+ The following is an example response header:
+ \code
+ content-encoding: gzip
+ content-type: text/html; charset=UTF-8
+ date: Mon, 06 Feb 2023 09:00:08 GMT
+ expires: Mon, 13 Feb 2023 09:00:08 GMT
+ last-modified: Thu, 17 Oct 2019 07:18:26 GMT
+ \endcode
+
+ \sa {XMLHttpRequest::getResponseHeader}{getResponseHeader()}
+*/
+
+/*!
+ \qmlmethod string XMLHttpRequest::getResponseHeader(headerName)
+
+ Returns either the \a headerName value from the last response, or an empty \c String, if the \a headerName is missing.
+
+ \sa {XMLHttpRequest::getAllResponseHeaders}{getAllResponseHeaders()}
+*/
+
+/*!
+ \qmlmethod void XMLHttpRequest::open(method, url, async)
+
+ Specify the HTTP \a method you want the request to use, as well as the \a url you wish to request.
+ You should make sure to always call this function before \l {XMLHttpRequest::send}{send()}.
+ An optional third parameter \a async can be used to decide whether the request should be asynchronous or not.
+ The default value is \c true.
+
+ Emits the \c readystatechange signal, which calls the \l {XMLHttpRequest::onreadystatechange}{onreadystatechange} handler with
+ the \l {XMLHttpRequest::readyState}{readyState} property set to \c XMLHttpRequest.OPENED.
+*/
+
+/*!
+ \qmlmethod void XMLHttpRequest::send(data)
+
+ Sends the request to the server.
+ You can use the optional argument \a data to add extra data to the body of the request.
+ This can be useful for POST requests, where you typically want the request to contain extra data.
+
+ The \l {XMLHttpRequest::readyState}{readyState} property is updated once a response has been received from the server,
+ and while the response is being processed. It will first be set to \c HEADERS_RECEIVED, then to \c LOADING,
+ and finally \c DONE, once the response has been fully processed.
+ The \c readystatechange signal is emitted every time \l {XMLHttpRequest::readyState}{readyState} is updated.
+*/
+
+/*!
+ \qmlmethod void XMLHttpRequest::setRequestHeader(header, value)
+
+ Adds a new header to the next request you wish to send.
+ This is a key-value pair, which has the name \a header and the corresponding \a value.
+*/
+
+/*!
+ \qmlmethod void XMLHttpRequest::overrideMimeType(mime)
+ \since 6.6
+
+ Forces the \c XMLHttpRequest to interpret the data received in the next HTTP response,
+ as if it had the MIME type \a mime, rather than the one provided by the server.
+*/
+
+/*!
+ \qmlproperty function XMLHttpRequest::onreadystatechange
+
+ Choose a callback function you want to get invoked whenever the \l {XMLHttpRequest::readyState}{readyState} of the \c XMLHttpRequest object changes.
+
+ \sa {XMLHttpRequest::readyState}{readyState}
+*/
+
+/*!
+ \qmlproperty enumeration XMLHttpRequest::readyState
+ \readonly
+
+ Indicates the current state of the \c XMLHttpRequest object.
+
+ The value can be one of the following:
+ \value XMLHttpRequest.UNSENT The request is not initialized, which is the state before calling \l {XMLHttpRequest::open}{open()}.
+ \value XMLHttpRequest.OPENED The request is initialized, meaning \l {XMLHttpRequest::open}{open()} was previously called, but no further progress.
+ \value XMLHttpRequest.HEADERS_RECEIVED Received a reply from the sever, but the request is not fully processed yet.
+ \value XMLHttpRequest.LOADING Downloading data from the server.
+ \value XMLHttpRequest.DONE Finished processing the request.
+
+ \sa {XMLHttpRequest::onreadystatechange}{onreadystatechange}
+*/
+
+/*!
+ \qmlproperty string XMLHttpRequest::responseURL
+ \readonly
+ \since 6.6
+
+ Returns the url that was used to retrieve the response data, after any redirects have occurred.
+*/
+
+/*!
+ \qmlproperty string XMLHttpRequest::responseText
+ \readonly
+
+ Returns a \c String containing the data received from the last response.
+
+ \sa {XMLHttpRequest::responseXML}{responseXML}
+*/
+
+/*!
+ \qmlproperty var XMLHttpRequest::responseXML
+ \readonly
+
+ Returns either a \c Document, or \c null, if the response content cannot be parsed as XML or HTML.
+ See the \l {responseXML document}{responseXML document} section for more information.
+
+ \sa {XMLHttpRequest::responseText}{responseText}
+*/
+
+/*!
+ \qmlproperty var XMLHttpRequest::response
+ \readonly
+
+ Returns either a \c String, an \c ArrayBuffer, or a \c Document,
+ depending on the \l {XMLHttpRequest::responseType}{responseType} of the last request.
+
+ \sa {XMLHttpRequest::responseType}{responseType}, {XMLHttpRequest::responseText}{responseText}, {XMLHttpRequest::responseXML}{responseXML}
+*/
+
+/*!
+ \qmlproperty string XMLHttpRequest::responseType
+
+ Returns a \c String describing the content type of the last response received.
+ \list
+ \li If the response type is "text" or an empty \c String, the response content is a UTF-16 encoded \c String.
+ \li If the response type is "arraybuffer", it means that the response content is an \c ArrayBuffer containing binary data.
+ \li If the response type is "json", the response content should be a JSON \c Document.
+ \li If the response type is "document", it means that the response content is an XML \c Document, which can be safely read with the \l {XMLHttpRequest::responseXML}{responseXML} property.
+ \endlist
+
+ \sa {XMLHttpRequest::response}{response}
+*/
+
+/*!
+ \qmlproperty int XMLHttpRequest::status
+ \readonly
+
+ Returns the status code for the last response received.
+
+ \sa {XMLHttpRequest::statusText}{statusText}
+*/
+
+/*!
+ \qmlproperty string XMLHttpRequest::statusText
+ \readonly
+
+ Returns a \c String that has the status message associated with the status code for the last response received.
+
+ \sa {XMLHttpRequest::status}{status}
+*/
diff --git a/src/qml/doc/src/qmldiskcache.qdoc b/src/qml/doc/src/qmldiskcache.qdoc
new file mode 100644
index 0000000000..90d9aee723
--- /dev/null
+++ b/src/qml/doc/src/qmldiskcache.qdoc
@@ -0,0 +1,120 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmldiskcache.html
+\title The QML Disk Cache
+\brief QML documents are generally pre-compiled or cached after compilation.
+
+You should define your QML modules using \l{qt_add_qml_module} that makes sure
+that the \l{Qt Quick Compiler} processes your QML and JavaScript files ahead of
+time. Also, it guarantees optimum performance at run time. The
+\l{Qt Quick Compiler} generates byte code for
+each function and binding. This byte code can be used by the QML interpreter,
+and the Just-in-time (JIT) compiler in the QML engine. In addition, the
+\l{Qt Quick Compiler} generates native code for suitable functions and
+bindings. The native code can be executed directly, which results in better
+performance than interpreting or just-in-time compiling the byte code. Both,
+byte code and native code are then compiled into your binary.
+
+When using \l{qmake} you can specify \c{CONFIG += qtquickcompiler} to
+give similar treatment to QML and JavaScript files added as resources to your
+project. \l{Qt Creator} has a setting that allows passing
+\c{CONFIG += qtquickcompiler} to the qmake command line. By default, it is
+enabled for release and profile builds. \l{qmake} cannot pass as much
+information to the \l{Qt Quick Compiler} as CMake. Therefore, the compilation
+will contain less native code.
+
+You should make sure to load your QML documents from the resource file system
+where possible. Otherwise the QML engine won't be able to find the code compiled
+ahead of time.
+
+If no byte code or native code can be found for a QML document at run time, or
+if the code is found but cannot be used, the QML engine compiles the document
+into a byte code representation on the fly. The compiling process can be time
+consuming, and the result will contain only byte code. Subsequent loads of the
+same document will yield the same byte code. The QML engine can optimize this
+step by caching the result of the compilation. It stores the byte code in a
+cache file and later loads the cache file instead of re-compiling when the same
+QML document is requested again. Usually, the cache files are stored in a
+subdirectory \c{qmlcache} of the system's cache directory, as denoted by
+QStandardPaths::CacheLocation.
+
+Checks are in place to make sure that any cache files and any code compiled
+ahead of time are only loaded if all of the following conditions are met:
+\list
+ \li The Qt version has not changed
+ \li The source code in the original file has not changed
+ \li The QML debugger is not running
+\endlist
+
+Only the \c{QML_FORCE_DISK_CACHE} variable (see below) overrides only the
+condition regarding the QML debugger. The other environment variables do not
+influence these conditions.
+
+The primary way of fine tuning the behavior regarding ahead of time compiled
+code and caching is via the environment variable \c{QML_DISK_CACHE}. This
+variable takes a comma-separated list of options, for example:
+
+\badcode
+QML_DISK_CACHE=aot,qmlc-read
+\endcode
+
+The available options are as follows:
+
+\table
+ \header
+ \li Option
+ \li Description
+ \row
+ \li aot-native
+ \li Load the compilation units compiled ahead of time and allow
+ execution of any native code found in them.
+ \row
+ \li aot-bytecode
+ \li Load the compilation units compiled ahead of time and allow
+ interpretation and just-in-time compilation of byte code found
+ in them.
+ \row
+ \li aot
+ \li Shorthand for \c{aot-native,aot-bytecode}.
+ \row
+ \li qmlc-read
+ \li Load any cached compilation units for QML and JavaScript files from
+ the host file system and allow interpretation and just-in-time
+ compilation of byte code found in them.
+ \row
+ \li qmlc-write
+ \li When compiling a QML or JavaScript file on the fly, create a cache
+ file afterward. The cache file can be loaded when the same
+ document is requested again.
+ \row
+ \li qmlc
+ \li Shorthand for \c{qmlc-read,qmlc-write}.
+\endtable
+
+Furthermore, you can use the following environment variables:
+
+\table
+ \header
+ \li Environment Variable
+ \li Description
+ \row
+ \li \c{QML_DISABLE_DISK_CACHE}
+ \li Disables the disk cache and forces re-compilation from source for
+ all QML and JavaScript files. \c{QML_DISABLE_DISK_CACHE} overrides
+ \c{QML_DISK_CACHE}.
+ \row
+ \li \c{QML_FORCE_DISK_CACHE}
+ \li Enables the disk cache even when debugging QML. You cannot use the
+ JavaScript debugger this way. It may fail to stop at breakpoints,
+ for example. You can still use the QML inspector to explore the
+ object hierarchy, though. \c{QML_FORCE_DISK_CACHE} overrides
+ \c{QML_DISABLE_DISK_CACHE} and \c{QML_DISK_CACHE}.
+ \row
+ \li \c{QML_DISK_CACHE_PATH}
+ \li Specifies a custom location where the cache files shall be stored
+ instead of using the default location.
+\endtable
+
+*/
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index b2d322465d..ecb13f160d 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -1,29 +1,688 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \macro QML_ELEMENT
+ \relates QQmlEngine
+
+ Declares the enclosing type or namespace to be available in QML, using its
+ class or namespace name as the QML element name.
+
+ For example, this makes the C++ class \c Slider available as a QML type
+ named \c Slider. All its properties, invokable methods and enums are exposed.
+
+ \code
+ class Slider : public QObject
+ {
+ Q_OBJECT
+ QML_ELEMENT
+ Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged FINAL)
+ // ...
+ public:
+ enum Slippiness {
+ Dry, Wet, Icy
+ };
+ Q_ENUM(Slippiness)
+
+ Q_INVOKABLE void slide(Slippiness slippiness);
+
+ // ...
+ }
+ \endcode
+
+ You can use the build system to register the type in the type namespace
+ \e {com.mycompany.qmlcomponents} with major version \c 1.
+ For qmake, specify the following in your project file:
+
+ \badcode
+ CONFIG += qmltypes
+ QML_IMPORT_NAME = com.mycompany.qmlcomponents
+ QML_IMPORT_MAJOR_VERSION = 1
+ \endcode
+
+ With CMake, you pass the URI and version to qt_add_qml_module
+
+ \badcode
+ qt6_add_qml_module(myapp
+ URI com.mycompany.qmlcomponents
+ VERSION 1.0
+ )
+ \endcode
+
+ Once registered, the type can be used in QML by importing the
+ same type namespace and version number:
+
+ \qml
+ import com.mycompany.qmlcomponents 1.0
+
+ Slider {
+ value: 12
+ Component.onCompleted: slide(Slider.Icy)
+
+ // ...
+ }
+ \endqml
+
+ You can also make namespaces tagged with Q_NAMESPACE available this way, in
+ order to expose any enums tagged with Q_ENUM_NS they contain:
+
+ \code
+ namespace MyNamespace {
+ Q_NAMESPACE
+ QML_ELEMENT
+
+ enum MyEnum {
+ Key1,
+ Key2,
+ };
+ Q_ENUM_NS(MyEnum)
+ }
+ \endcode
+
+ In QML, you can then use the enums:
+
+ \qml
+ Component.onCompleted: console.log(MyNamespace.Key2)
+ \endqml
+
+ \b{NOTE:} When classes have the same name but are located in different namespaces using
+ \l QML_ELEMENT on both of them will cause a conflict.
+ Make sure to use \l QML_NAMED_ELEMENT() for one of them instead.
+
+ \include {qualified-class-name.qdocinc} {class name must be qualified}
+
+ \sa {Choosing the Correct Integration Method Between C++ and QML}, QML_NAMED_ELEMENT(),
+ Q_REVISION(), QML_ADDED_IN_VERSION()
+*/
+
+/*!
+ \macro QML_NAMED_ELEMENT(name)
+ \relates QQmlEngine
+
+ Declares the enclosing type or namespace to be available in QML, using \a name
+ as the element name. Otherwise behaves the same as QML_ELEMENT.
+
+ \code
+ class SqlEventDatabase : public QObject
+ {
+ Q_OBJECT
+ QML_NAMED_ELEMENT(EventDatabase)
+
+ // ...
+ };
+ \endcode
+
+ \sa {Choosing the Correct Integration Method Between C++ and QML}, QML_ELEMENT
+*/
+
+/*!
+ \macro QML_ANONYMOUS
+ \relates QQmlEngine
+
+ Declares the enclosing type to be available, but anonymous in QML. The type
+ cannot be created or used to declare properties in QML, but when passed from
+ C++, it is recognized. In QML, you can use properties of this type if they
+ are declared in C++.
+
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_UNCREATABLE(), QML_INTERFACE
+*/
+
+/*!
+ \macro QML_INTERFACE
+ \relates QQmlEngine
+
+ This macro registers the enclosing C++ type in the QML system as an interface.
+
+ Types registered as an interface in QML should also declare themselves as an
+ interface with the \l {The Meta-Object System}{meta object system}. For
+ example:
+
+ \code
+ struct FooInterface
+ {
+ QML_INTERFACE
+ public:
+ virtual ~FooInterface();
+ virtual void doSomething() = 0;
+ };
+
+ Q_DECLARE_INTERFACE(FooInterface, "org.foo.FooInterface")
+ \endcode
+
+ When registered with QML in this way, they can be used as property types:
+
+ Q_PROPERTY(FooInterface *foo READ foo WRITE setFoo)
+
+ When you assign a \l QObject sub-class to this property, the QML engine does
+ the interface cast to \c FooInterface* automatically.
+
+ Interface types are implicitly anonymous and uncreatable in QML.
+
+ \b{NOTE:} When inheriting from types using QML_INTERFACE, use \l QML_IMPLEMENTS_INTERFACES
+ instead of \l Q_INTERFACES.
+
+ \sa QML_IMPLEMENTS_INTERFACES(), QML_ELEMENT, QML_NAMED_ELEMENT(), QML_UNCREATABLE(), QML_ANONYMOUS
+*/
+
+/*!
+ \macro QML_IMPLEMENTS_INTERFACES(interfaces)
+ \relates QQmlEngine
+
+ This macro tells Qt which QML \a interfaces the class implements.
+ This macro should only be used for interfacing with classes using \l QML_INTERFACE, use \l Q_INTERFACES otherwise.
+ It's required in order for declarative registration via \l QML_ELEMENT to
+ function properly.
+
+ \sa QML_INTERFACE, Q_INTERFACES
+*/
+
+/*!
+ \macro QML_UNCREATABLE(reason)
+ \relates QQmlEngine
+
+ Declares that the enclosing type shall not be creatable from QML. This takes
+ effect if the type is available in QML, by having a \l QML_ELEMENT or
+ \l QML_NAMED_ELEMENT() macro. The \a reason will be emitted as error message if an
+ attempt to create the type from QML is detected.
+
+ Some QML types are implicitly uncreatable, in particular types exposed with
+ \l QML_ANONYMOUS or namespaces exposed with \l QML_ELEMENT or
+ \l QML_NAMED_ELEMENT().
+
+ Since Qt 6.0 you can use "" instead of a reason to use a standard message
+ instead.
+
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_ANONYMOUS
+*/
+
+/*!
+ \macro QML_SINGLETON
+ \relates QQmlEngine
+
+ Declares the enclosing type to be a singleton in QML. This only takes effect
+ if the type is a \l Q_OBJECT and is available in QML (by having a
+ \l QML_ELEMENT or \l QML_NAMED_ELEMENT() macro). By default, each QQmlEngine
+ will try to create a singleton instance using either the type's default
+ constructor or a static factory function of the signature
+ \c{T *create(QQmlEngine *, QJSEngine *)} when the type is first accessed.
+ If both do exist and are accessible, the default constructor is preferred.
+ If there is no default constructor and no factory function the singleton is
+ inaccessible. The QML engine generally assumes ownership of the singleton and
+ will delete it when the engine itself is destroyed. You can prevent this by
+ calling QJSEngine::setObjectOwnership() on the singleton.
+
+ In order to declare a default-constructible class as singleton, all you have
+ to do is add \l QML_SINGLETON:
+
+ \code
+ class MySingleton : public QObject
+ {
+ Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+ // Q_PROPERTY( ... )
+ public:
+ // members, Q_INVOKABLE functions, etc.
+ };
+ \endcode
+
+ If the singleton class is not default-constructible, but you can modify it,
+ you can add a factory function to it, in order to make it accessible:
+
+ \code
+ class MySingleton : public QObject
+ {
+ Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+ // Q_PROPERTY( ... )
+
+ public:
+ static MySingleton *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine)
+ {
+ MySingleton *result = nullptr;
+ // Create the object using some custom constructor or factory.
+ // The QML engine will assume ownership and delete it, eventually.
+ return result;
+ }
+
+ // members, Q_INVOKABLE functions, etc
+ };
+ \endcode
+
+ If you cannot modify the class and it does not have a default constructor or a
+ suitable factory function, you can provide a \l QML_FOREIGN wrapper to define
+ the factory function:
+
+ \code
+ struct SingletonForeign
+ {
+ Q_GADGET
+ QML_FOREIGN(MySingleton)
+ QML_SINGLETON
+ QML_NAMED_ELEMENT(MySingleton)
+ public:
+
+ static MySingleton *create(QQmlEngine *, QJSEngine *engine)
+ {
+ MySingleton *result = nullptr;
+ // Create the instance using some custom constructor or factory.
+ // The QML engine will assume ownership and delete it, eventually.
+ return result;
+ }
+ };
+ \endcode
+
+ Finally, if you want to provide one specific singleton object, the creation of
+ which you cannot control, you can return that from a factory function. This is
+ a replacement for the \l qmlRegisterSingletonInstance function.
+ If you were calling
+
+ \code
+ qmlRegisterSingletonInstance("MyModule", 1, 0, "MySingleton", myObject);
+ \endcode
+
+ with myObject being of type \c{MySingleton *}, you can do the following
+ instead:
+
+ \code
+ struct SingletonForeign
+ {
+ Q_GADGET
+ QML_FOREIGN(MySingleton)
+ QML_SINGLETON
+ QML_NAMED_ELEMENT(MySingleton)
+ public:
+
+ // Initialize this using myObject where you would previously
+ // call qmlRegisterSingletonInstance().
+ inline static MySingleton *s_singletonInstance = nullptr;
+
+ static MySingleton *create(QQmlEngine *, QJSEngine *engine)
+ {
+ // The instance has to exist before it is used. We cannot replace it.
+ Q_ASSERT(s_singletonInstance);
+
+ // The engine has to have the same thread affinity as the singleton.
+ Q_ASSERT(engine->thread() == s_singletonInstance->thread());
+
+ // There can only be one engine accessing the singleton.
+ if (s_engine)
+ Q_ASSERT(engine == s_engine);
+ else
+ s_engine = engine;
+
+ // Explicitly specify C++ ownership so that the engine doesn't delete
+ // the instance.
+ QJSEngine::setObjectOwnership(s_singletonInstance,
+ QJSEngine::CppOwnership);
+ return s_singletonInstance;
+ }
+
+ private:
+ inline static QJSEngine *s_engine = nullptr;
+ };
+ \endcode
+
+ This way, the pre-existing class \c MySingleton is declared to be a QML
+ singleton, called \c MySingleton. You can specify an instance for it any time
+ before it is used by setting the \c s_singletonInstance member. None of this
+ requires modification of \c MySingleton itself.
+
+ \note This pattern doesn't work if either the singleton is accessed by
+ multiple QML engines, or if the QML engine accessing it has a different thread
+ affinity than the singleton object itself. As shown above, you can check the
+ parameters to the \c create() method for identity and thread affinity of the
+ engine in order to assert on that.
+
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT(),
+ qmlRegisterSingletonInstance(), QQmlEngine::singletonInstance(), {Singletons in QML}
+*/
+
+/*!
+ \macro QML_ADDED_IN_VERSION(MAJOR, MINOR)
+ \relates QQmlEngine
+
+ Declares that the enclosing type or namespace was added in the specified
+ \a{MAJOR}.\a{MINOR} version. The version is assumed to be in line with any
+ revisions given by \l Q_REVISION() macros on methods, slots, or signals,
+ and any REVISION() attributes on properties declared with \l Q_PROPERTY().
+
+ \l QML_ADDED_IN_VERSION() only takes effect if the type or namespace is
+ available in QML, by having a \l QML_ELEMENT, \l QML_NAMED_ELEMENT(),
+ \l QML_ANONYMOUS, or \l QML_INTERFACE macro.
+
+ If the QML module the type belongs to is imported with a lower version than
+ the one determined this way, the QML type is invisible.
+
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT
+*/
+
+/*!
+ \macro QML_ADDED_IN_MINOR_VERSION(VERSION)
+ \relates QQmlEngine
+ \deprecated [6.7] Use QML_ADDED_IN_VERSION and specify the full version
+
+ Declares that the enclosing type or namespace was added in the specified minor
+ \a VERSION, relative to the module major version. The minor version is assumed
+ to be in line with any revisions given by \l Q_REVISION() macros on methods,
+ slots, or signals, and any REVISION() attributes on properties declared with
+ \l Q_PROPERTY().
+
+ \l QML_ADDED_IN_MINOR_VERSION() only takes effect if the type or namespace is
+ available in QML, by having a \l QML_ELEMENT, \l QML_NAMED_ELEMENT(),
+ \l QML_ANONYMOUS, or \l QML_INTERFACE macro.
+
+ If the QML module the type belongs to is imported with a lower version than
+ the one determined this way, the QML type is invisible.
+
+ \sa QML_ADDED_IN_VERSION, QML_ELEMENT, QML_NAMED_ELEMENT
+*/
+
+/*!
+ \macro QML_REMOVED_IN_VERSION(MAJOR, MINOR)
+ \relates QQmlEngine
+
+ Declares that the enclosing type or namespace was removed in the specified
+ \a{MAJOR}.\a{MINOR} version. This is primarily useful when replacing the
+ implementation of a QML type. If a corresponding \l QML_ADDED_IN_VERSION()
+ is present on a different type or namespace of the same QML name, then the
+ removed type is used when importing versions of the module lower than
+ \a{MAJOR}.\a{MINOR}, and the added type is used when importing
+ versions of the module greater or equal \a{MAJOR}.\a{MINOR}.
+
+ \l QML_REMOVED_IN_VERSION() only takes effect if type or namespace is
+ available in QML, by having a \l QML_ELEMENT, \l QML_NAMED_ELEMENT(),
+ \l QML_ANONYMOUS, or \l QML_INTERFACE macro.
+
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT
+*/
+
+/*!
+ \macro QML_REMOVED_IN_MINOR_VERSION(VERSION)
+ \relates QQmlEngine
+ \deprecated [6.7] Use QML_REMOVED_IN_VERSION and specify the full version
+
+ Declares that the enclosing type or namespace was removed in the specified
+ minor \a VERSION, relative to the module major version. This is primarily
+ useful when replacing the implementation of a QML type. If a corresponding
+ \l QML_ADDED_IN_VERSION() is present on a different type or namespace of
+ the same QML name, then the removed type is used when importing versions of
+ the module lower than \a VERSION, and the added type is used when importing
+ versions of the module greater or equal \a VERSION.
+
+ \l QML_REMOVED_IN_MINOR_VERSION() only takes effect if type or namespace is
+ available in QML, by having a \l QML_ELEMENT, \l QML_NAMED_ELEMENT(),
+ \l QML_ANONYMOUS, or \l QML_INTERFACE macro.
+
+ \sa QML_REMOVED_IN_VERSION, QML_ELEMENT, QML_NAMED_ELEMENT
+*/
+
+/*!
+ \macro QML_EXTRA_VERSION(MAJOR, MINOR)
+ \relates QQmlEngine
+
+ Declare that the type should also be available in version \a{MAJOR}.\a{MINOR}.
+ This can be helpful if a type should be available in multiple major versions.
+
+ Types are automatically registered for:
+ \list
+ \li The major version they were introduced in, see \l{QML_ADDED_IN_VERSION}.
+ \li Any major versions any their members were introduced in.
+ \li The current major version of their module, unless they were
+ \l{QML_REMOVED_IN_VERSION} before that.
+ \endlist
+
+ Notably, they are not automatically registered in any \l{PAST_MAJOR_VERSIONS}
+ between the above. You can use QML_EXTRA_VERSION to manually register your
+ types in further major versions.
+
+ \note Keeping multiple \l{PAST_MAJOR_VERSIONS} around is computationally
+ expensive.
+
+ \sa QML_ELEMENT, QML_ADDED_IN_VERSION
+*/
+
+/*!
+ \macro QML_ATTACHED(ATTACHED_TYPE)
+ \relates QQmlEngine
+
+ Declares that the enclosing type attaches \a ATTACHED_TYPE as an
+ \l {Attached Properties and Attached Signal Handlers}
+ {attached property} to other types. This takes effect if the type
+ is exposed to QML using a \l QML_ELEMENT or \l QML_NAMED_ELEMENT() macro.
+
+ \include {qualified-class-name.qdocinc} {class name must be qualified}
+
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT(), qmlAttachedPropertiesObject(),
+ {Providing Attached Properties}
+*/
+
+/*!
+ \macro QML_EXTENDED(EXTENDED_TYPE)
+ \relates QQmlEngine
+
+ Declares that the enclosing type uses \a EXTENDED_TYPE as an extension to
+ provide further properties, methods, and enumerations in QML. This takes
+ effect if the type is exposed to QML using a \l QML_ELEMENT or
+ \l QML_NAMED_ELEMENT() macro.
+
+ \warning Members of \a EXTENDED_TYPE are implicitly treated as FINAL.
+
+ \include {qualified-class-name.qdocinc} {class name must be qualified}
+
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_EXTENDED_NAMESPACE(),
+ {Registering Extension Objects}
+*/
+
+/*!
+ \macro QML_EXTENDED_NAMESPACE(EXTENDED_NAMESPACE)
+ \relates QQmlEngine
+
+ Declares that the enclosing type uses \a EXTENDED_NAMESPACE as an extension to
+ provide further enumerations in QML. This takes effect if the type
+ is exposed to QML using a \l QML_ELEMENT or \l QML_NAMED_ELEMENT() macro.
+ The enumerations need to be exposed to the metaobject system for this to work.
+
+ For example, give the following C++ code
+ \code
+ namespace MyNamespace {
+ Q_NAMESPACE
+ enum MyEnum { MyEnumerator = 10 };
+ Q_ENUM_NS(MyEnum)
+ }
+
+ class QmlType : public QObject
+ {
+ Q_OBJECT
+ QML_ELEMENT
+ QML_EXTENDED_NAMESPACE(MyNamespace)
+ }
+ \endcode
+
+ we can access the enum in QML:
+ \qml
+ QmlType {
+ property int i: QmlType.MyEnumerator // i will be 10
+ }
+ \endqml
+
+ \note EXTENDED_NAMESPACE can also be a QObject or QGadget; in that case - and in contrast to
+ QML_EXTENDED, which also exposes methods and properties - only its enumerations
+ are exposed.
+
+ \note \a EXTENDED_NAMESPACE must have a metaobject; i.e. it must either be a namespace which
+ contains the Q_NAMESPACE macro or a QObject/QGadget.
+
+ \include {qualified-class-name.qdocinc} {class name must be qualified}
+
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_EXTENDED(),
+ {Registering Extension Objects}, Q_ENUM, Q_ENUM_NS
+*/
+
+/*!
+ \macro QML_FOREIGN(FOREIGN_TYPE)
+ \relates QQmlEngine
+
+ Declares that any \l QML_ELEMENT, \l QML_NAMED_ELEMENT(), \l QML_ANONYMOUS,
+ \l QML_INTERFACE, \l QML_UNCREATABLE(), \l QML_SINGLETON,
+ \l QML_ADDED_IN_VERSION(), \l QML_REMOVED_IN_VERSION(),
+ \l QML_ADDED_IN_MINOR_VERSION(), \l QML_REMOVED_IN_MINOR_VERSION(),
+ \l QML_EXTENDED(), or \l QML_EXTENDED_NAMESPACE() macros
+ in the enclosing C++ type do not apply to the enclosing type but instead to
+ \a FOREIGN_TYPE. The enclosing type still needs to be registered with the
+ \l {The Meta-Object System}{meta object system} using a \l Q_GADGET or
+ \l Q_OBJECT macro.
+
+ This is useful for registering types that cannot be amended to add the macros,
+ for example because they belong to 3rdparty libraries.
+ To register a namespace, see \l QML_FOREIGN_NAMESPACE().
+
+ \note You may want to use \l QML_NAMED_ELEMENT() instead of \l QML_ELEMENT.
+ With QML_ELEMENT, the element is named after the struct it is contained in,
+ not the foreign type. The \l {Foreign objects integration} chapter in
+ \l {Writing advanced QML Extensions with C++} demonstrates this.
+
+ \note QML_ATTACHED() can currently not be redirected like this. It has to be
+ specificed in the same type that implements qmlAttachedProperties().
+
+ \include {qualified-class-name.qdocinc} {class name must be qualified}
+
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_FOREIGN_NAMESPACE()
+*/
+
+/*!
+ \macro QML_FOREIGN_NAMESPACE(FOREIGN_NAMESPACE)
+ \relates QQmlEngine
+
+ Declares that any \l QML_ELEMENT, \l QML_NAMED_ELEMENT(), \l QML_ANONYMOUS,
+ \l QML_INTERFACE, \l QML_UNCREATABLE(), \l QML_SINGLETON,
+ \l QML_ADDED_IN_VERSION(), \l QML_REMOVED_IN_VERSION(),
+ \l QML_ADDED_IN_MINOR_VERSION(), or \l QML_REMOVED_IN_MINOR_VERSION()
+ macros in the enclosing C++ namespace do not apply to the enclosing type but
+ instead to \a FOREIGN_NAMESPACE. The enclosing namespace still needs to be
+ registered with the \l {The Meta-Object System}{meta object system} using a
+ \l Q_NAMESPACE macro.
+
+ This is useful for registering namespaces that cannot be amended to add the macros,
+ for example because they belong to 3rdparty libraries.
+
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_FOREIGN()
+*/
+
+/*!
+ \macro QML_UNAVAILABLE
+ \relates QQmlEngine
+
+ This macro declares the enclosing type to be unavailable in QML. It registers
+ an internal dummy type called \c QQmlTypeNotAvailable as \l QML_FOREIGN()
+ type, using any further QML macros you specify.
+
+ Normally, the types exported by a module should be fixed. However, if a C++
+ type is not available, you should at least "reserve" the QML type name, and
+ give the user of the unavailable type a meaningful error message.
+
+ Example:
+
+ \code
+ #ifdef NO_GAMES_ALLOWED
+ struct MinehuntGame
+ {
+ Q_GADGET
+ QML_NAMED_ELEMENT(Game)
+ QML_UNAVAILABLE
+ QML_UNCREATABLE("Get back to work, slacker!");
+ };
+ #else
+ class MinehuntGame : public QObject
+ {
+ Q_OBJECT
+ QML_NAMED_ELEMENT(Game)
+ // ...
+ };
+ #endif
+ \endcode
+
+ This will cause any QML which attempts to use the "Game" type to produce an
+ error message:
+
+ \badcode
+ fun.qml: Get back to work, slacker!
+ Game {
+ ^
+ \endcode
+
+ Using this technique, you only need a \l Q_GADGET struct to customize the error
+ message, not a full-blown \l QObject. Without \l QML_UNCREATABLE(),
+ \l QML_UNAVAILABLE still results in a more specific error message than the usual
+ "is not a type" for completely unknown types.
+
+ \include {qualified-class-name.qdocinc} {class name must be qualified}
+
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_UNCREATABLE(), QML_FOREIGN()
+*/
+
+/*!
+ \macro QML_SEQUENTIAL_CONTAINER(VALUE_TYPE)
+ \relates QQmlEngine
+
+ This macro declares the enclosing or referenced type as a sequential container
+ managing a sequence of \a VALUE_TYPE elements. \a VALUE_TYPE can be an actual
+ \l{QML Value Types}{value type} or a pointer to an
+ \l{QML Object Types}{object type}. You will rarely be able to add this macro
+ to the actual container declaration since containers are usually templates.
+ You should use \l{QML_FOREIGN} to attach the type registration to a template
+ instantiation. Using this technique you can, for example, declare sequential
+ containers like this:
+
+ \code
+ class IntDequeRegistration
+ {
+ Q_GADGET
+ QML_FOREIGN(std::deque<int>)
+ QML_ANONYMOUS
+ QML_SEQUENTIAL_CONTAINER(int)
+ };
+ \endcode
+
+ After this, you can use the container like a JavaScript array in QML.
+
+ \code
+ class Maze
+ {
+ Q_OBJECT
+ Q_ELEMENT
+ // 0: North, 1: East, 2: South, 3: West
+ Q_PROPERTY(std::deque<int> solution READ solution CONSTANT FINAL)
+ [...]
+ }
+ \endcode
+
+ \code
+ Item {
+ Maze {
+ id: maze
+ }
+
+ function showSolution() {
+ maze.solution.forEach([...])
+ }
+ }
+ \endcode
+
+ \note For \l{QML Value Types} \l{QList} is automatically registered as
+ sequential container. For \l{QML Object Types} \l{QQmlListProperty} is.
+ You don't have to add these registrations.
+
+ \note You cannot currently give the container a custom name. Any argument
+ passed to \l{QML_NAMED_ELEMENT} is ignored. The automatically registered
+ sequential containers are available under the familiar \e{list<...>} names,
+ for example \e{list<QtObject>} or \e{list<font>}.
+
+ \include {qualified-class-name.qdocinc} {class name must be qualified}
+
+ \sa QML_ANONYMOUS, QML_FOREIGN()
+*/
/*!
\macro QML_DECLARE_TYPE()
@@ -41,7 +700,8 @@
Current the only supported type info is \c QML_HAS_ATTACHED_PROPERTIES which
declares that the \a Type supports \l {Attached Properties and Attached Signal Handlers}
- {attached properties}.
+ {attached properties}. QML_DECLARE_TYPEINFO() is not necessary if \a Type contains the
+ QML_ATTACHED macro.
*/
/*!
@@ -58,7 +718,7 @@
/*!
- \fn int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+ \fn template <typename T> int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
\relates QQmlEngine
This template function registers the C++ type in the QML system with
@@ -106,11 +766,12 @@
QML written to previous versions to continue to work, even if more advanced versions of
some of its types are available.
- \sa {Choosing the Correct Integration Method Between C++ and QML}
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT(),
+ {Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
- \fn int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
+ \fn template<typename T, int metaObjectRevision> int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
\relates QQmlEngine
This template function registers the specified revision of a C++ type in the QML system with
@@ -129,7 +790,7 @@
*/
/*!
- \fn int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message)
+ \fn template <typename T> int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message)
\relates QQmlEngine
This template function registers the C++ type in the QML system with
@@ -143,12 +804,12 @@
Returns the QML type id.
- \sa qmlRegisterTypeNotAvailable(),
+ \sa QML_UNCREATABLE(), qmlRegisterTypeNotAvailable(),
{Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
- \fn int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+ \fn template <typename T, typename E> int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
\relates QQmlEngine
This template function registers the C++ type and its extension object in the
@@ -158,12 +819,12 @@
Returns the QML type id.
- \sa qmlRegisterType(), {Registering Extension Objects}
+ \sa QML_EXTENDED(), qmlRegisterType(), {Registering Extension Objects}
*/
/*!
- \fn int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
+ \fn template <typename T, typename E> int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
\relates QQmlEngine
This template function registers the C++ type and its extension
@@ -180,7 +841,7 @@
Returns the QML type id.
- \sa qmlRegisterUncreatableType()
+ \sa QML_EXTENDED(), QML_UNCREATABLE(), qmlRegisterUncreatableType()
*/
/*!
@@ -209,7 +870,7 @@
Key1,
Key2,
};
- Q_ENUMS(MyEnum)
+ Q_ENUM_NS(MyEnum)
}
//...
@@ -220,6 +881,8 @@
\code
Component.onCompleted: console.log(MyNamespace.Key2)
\endcode
+
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_UNCREATABLE()
*/
/*!
@@ -235,6 +898,8 @@
the \a parser provided.
Returns the QML type id.
+
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_EXTENDED()
*/
/*!
@@ -269,12 +934,13 @@
Without this, a generic "Game is not a type" message would be given.
- \sa qmlRegisterUncreatableType(),
+ \sa QML_UNAVAILABLE, qmlRegisterUncreatableType(),
{Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
- \fn int qmlRegisterAnonymousType(const char *uri, int versionMajor)
+ \fn template <typename T> int qmlRegisterAnonymousType(const char *uri, int versionMajor)
+ \relates QQmlEngine
This template function registers the C++ type in the QML system as an anonymous type. The
resulting QML type does not have a name. Therefore, instances of this type cannot be created from
@@ -352,17 +1018,7 @@
Returns the QML type id.
\since 5.14
- \sa {Choosing the Correct Integration Method Between C++ and QML}
-*/
-
-/*!
- \fn int qmlRegisterType()
- \relates QQmlEngine
- \overload
- \deprecated
-
- Do not use this function. For anonymous type registrations, use \l qmlRegisterAnonymousType(),
- and make sure to provide a URI and a major version.
+ \sa QML_ANONYMOUS, {Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
@@ -396,10 +1052,12 @@
the interface cast to \c FooInterface* automatically.
Returns the QML type id.
+
+ \sa QML_INTERFACE
*/
/*!
- \fn int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, QJSValue (*callback)(QQmlEngine *, QJSEngine *))
+ \fn int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QJSValue(QQmlEngine *, QJSEngine *)> callback)
\relates QQmlEngine
This function may be used to register a singleton type provider \a callback in a particular \a uri
@@ -454,7 +1112,7 @@
}
\endqml
- \sa {Choosing the Correct Integration Method Between C++ and QML}
+ \sa QML_SINGLETON, {Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
@@ -473,15 +1131,24 @@
If \a create is true and type \e T is a valid attaching type, this creates and returns a new
attached object instance.
- Returns 0 if type \e T is not a valid attaching type, or if \a create is false and no
+ Returns \nullptr if type \e T is not a valid attaching type, or if \a create is false and no
attachment object instance has previously been created for \a attachee.
- \sa {Providing Attached Properties}
+ \sa QML_ATTACHED(), {Providing Attached Properties}
+*/
+/*!
+ \fn QObject *qmlExtendedObject(const QObject *base)
+ \relates QQmlEngine
+
+ This function returns the extension object that belongs to \a base, if there is any.
+ Otherwise it returns \c nullptr.
+
+ \sa QML_EXTENDED
*/
/*!
- \fn int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *(*callback)(QQmlEngine *, QJSEngine *))
+ \fn template <typename T> int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QObject*(QQmlEngine *, QJSEngine *)> callback)
\relates QQmlEngine
This function may be used to register a singleton type provider \a callback in a particular \a uri
@@ -511,7 +1178,7 @@
Q_PROPERTY (int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged)
public:
- SingletonTypeExample(QObject* parent = 0)
+ SingletonTypeExample(QObject *parent = nullptr)
: QObject(parent), m_someProperty(0)
{
}
@@ -570,15 +1237,7 @@
}
\endqml
- \sa {Choosing the Correct Integration Method Between C++ and QML}
-*/
-
-
-/*!
- \fn int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, std::function<QObject*(QQmlEngine *, QJSEngine *)> callback)
- \relates QQmlEngine
-
- \overload qmlRegisterSingletonType
+ \sa QML_SINGLETON, {Choosing the Correct Integration Method Between C++ and QML}
*/
/*!
@@ -625,10 +1284,12 @@
That can be done by adding a pragma Singleton statement among the imports of the type's QML file. In addition
the type must be defined in a qmldir file with a singleton keyword and the qmldir must be imported by the QML
files using the singleton.
+
+ \sa QML_SINGLETON
*/
/*!
- \fn int qmlRegisterSingletonInstance(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject* cppObject)
+ \fn int qmlRegisterSingletonInstance(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *cppObject)
\relates QQmlEngine
\since 5.14
@@ -656,6 +1317,8 @@
\l {qmlRegisterSingletonType}. See \l{Threads and QObjects} for more
information about thread safety.
+ \b{NOTE:} qmlRegisterSingleton can only be used when all types of that module are registered procedurally.
+
Usage:
\code
// First, define your QObject which provides the functionality.
@@ -717,7 +1380,7 @@
}
\endqml
- \sa qmlRegisterSingletonType
+ \sa QML_SINGLETON, qmlRegisterSingletonType
*/
/*!
@@ -738,20 +1401,25 @@
\fn bool qmlProtectModule(const char* uri, int majVersion);
\relates QQmlEngine
- This function protects a module from having types registered into it. This
- can be used to prevent other plugins from injecting types into your module.
- It can also be a performance improvement, as it allows the engine to skip
- checking for the possibility of new types or plugins when this import is
- reached.
-
- The performance benefit is primarily seen when registering application
- specific types from within the application instead of through a plugin.
- Using qmlProtectModule allows the engine to skip checking for a plugin when
- that uri is imported, which can be noticeable with slow file systems.
-
- After this function is called, any attempt to register C++ types into this
- uri, major version combination will lead to a runtime error. Call this after
- you have registered all of your types with the engine.
+ This function protects a module from further modification. This can be used
+ to prevent other plugins from injecting types into your module. It can also
+ be a performance improvement, as it allows the engine to skip checking for
+ the possibility of new types or plugins when this import is reached.
+
+ Once qmlProtectModule has been called, a QML engine will not search for a new
+ \c qmldir file to load the module anymore. It will re-use any \c qmldir files
+ it has loaded before, though. Therefore, types present at this point continue
+ to work. Mind that different QML engines may load different modules. The
+ module protection, however, is global and affects all engines. The overhead
+ of locating \c qmldir files and loading plugins may be noticeable with slow file
+ systems. Therefore, protecting a module once you are sure you won't need to
+ load it anymore can be a good optimization. Mind also that the module lock
+ not only affects plugins but also any other qmldir directives, like \c import
+ or \c prefer, as well as any composite types or scripts declared in a \c qmldir
+ file.
+
+ In addition, after this function is called, any attempt to register C++ types
+ into this uri, major version combination will lead to a runtime error.
Returns true if the module with \a uri as a \l{Identified Modules}
{module identifier} and \a majVersion as a major version number was found
@@ -791,5 +1459,150 @@
Returns -1 if no matching type was found or one of the given parameters
was invalid.
- \sa qmlRegisterType(), qmlRegisterSingletonType()
+ \sa QML_ELEMENT, QML_NAMED_ELEMENT, QML_SINGLETON, qmlRegisterType(), qmlRegisterSingletonType()
+*/
+
+/*!
+ \macro QML_VALUE_TYPE(name)
+ \relates QQmlEngine
+
+ Declares the enclosing type or namespace to be available in QML, using \a name
+ as the name. The type has to be a value type and the name has to be lower case.
+
+ \code
+ class MyValueType
+ {
+ Q_GADGET
+ QML_VALUE_TYPE(myValueType)
+
+ // ...
+ };
+ \endcode
+
+ \sa {Choosing the Correct Integration Method Between C++ and QML}, QML_NAMED_ELEMENT
+*/
+
+/*!
+ \macro QML_CONSTRUCTIBLE_VALUE
+ \since 6.5
+ \relates QQmlEngine
+
+ Marks the surrounding value type as constructible. That is, any \l Q_INVOKABLE
+ constructors of the type that take exactly one argument can be used when
+ assigning a JavaScript value to a property of this type.
+
+ You can declare a constructible value type as follows:
+
+ \code
+ class MyValueType
+ {
+ Q_GADGET
+ QML_VALUE_TYPE(myValueType)
+ QML_CONSTRUCTIBLE_VALUE
+ public:
+ Q_INVOKABLE MyValueType(double d);
+
+ // ...
+ };
+ \endcode
+
+ With the above type, the following QML code will produce a \c MyValueType
+ value using the given constructor and assign it to the property.
+
+ \qml
+ QtObject {
+ property myValueType v: 5.4
+ }
+ \endqml
+
+ You can also construct lists of values this way:
+
+ \qml
+ QtObject {
+ property list<myValueType> v: [5.4, 4.5, 3.3]
+ }
+ \endqml
+
+ If you make value types \l{ValueTypeBehavior}{addressable}, you can
+ use such a type in a \l{Type annotations and assertions}{type assertion}
+ to explicitly construct it:
+
+ \qml
+ pragma ValueTypeBehavior: Addressable
+
+ QtObject {
+ function process(d: real) {
+ let v = d as myValueType;
+ // v is a myValueType now, not a number
+ }
+ }
+ \endqml
+
+ \sa QML_VALUE_TYPE
+*/
+
+/*!
+ \macro QML_STRUCTURED_VALUE
+ \since 6.5
+ \relates QQmlEngine
+
+ Marks the surrounding value type as structured. Structured value types can
+ and will preferably be constructed property-by-property from a JavaScript
+ object. A structured value type, however is always \l QML_CONSTRUCTIBLE_VALUE,
+ too. This means, you can still provide \l Q_INVOKABLE constructors in order to
+ handle construction from primitive types.
+
+ You can declare a structured value type as follows:
+
+ \code
+ class MyValueType
+ {
+ Q_GADGET
+ QML_VALUE_TYPE(myValueType)
+ QML_STRUCTURED_VALUE
+ Q_PROPERTY(double d READ d WRITE setD)
+ Q_PROPERTY(string e READ e WRITE setE)
+
+ // ...
+ };
+ \endcode
+
+ Then you can populate a property of this type as follows:
+
+ \qml
+ QtObject {
+ property myValueType v: ({d: 4.4, e: "a string"})
+ }
+ \endqml
+
+ The extra parentheses are necessary to disambiguate the JavaScript object
+ from what might be interpreted as a JavaScript code block.
+
+ You can also construct lists of values this way:
+
+ \qml
+ QtObject {
+ property list<myValueType> v: [
+ {d: 4.4, e: "a string"},
+ {d: 7.1, e: "another string"}
+ ]
+ }
+ \endqml
+
+ If you make value types \l{ValueTypeBehavior}{addressable}, you can
+ use such a type in a \l{Type annotations and assertions}{type assertion}
+ to explicitly construct it:
+
+ \qml
+ pragma ValueTypeBehavior: Addressable
+
+ QtObject {
+ function process(d: real) {
+ let v = {d: d, e: objectName} as myValueType;
+ // v is a myValueType now
+ }
+ }
+ \endqml
+
+ \sa QML_VALUE_TYPE QML_CONSTRUCTIBLE_VALUE
*/
diff --git a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc
index 2de4eb0c18..df609fb3b9 100644
--- a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc
@@ -1,53 +1,45 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-documents-definetypes.html
\title Defining Object Types through QML Documents
\brief Description of how a QML document is a reusable type definition
-One of the core features of QML is that it enables QML object types to be easily defined in a lightweight manner through QML documents to suit the needs of individual QML applications. The standard \l {Qt Quick} module provides various types like \l Rectangle, \l Text and \l Image for building a QML application; beyond these, you can easily define your own QML types to be reused within your application. This ability to create your own types forms the building blocks of any QML application.
+One of the core features of QML is that it enables QML object types to be
+easily defined in a lightweight manner through QML documents to suit the needs
+of individual QML applications. The standard \l {Qt Quick} module provides
+various types like \l Rectangle, \l Text and \l Image for building a QML
+application; beyond these, you can easily define your own QML types to be
+reused within your application. This ability to create your own types forms the
+building blocks of any QML application.
\section1 Defining an Object Type with a QML File
\section2 Naming Custom QML Object Types
-To create an object type, a QML document should be placed into a text file named as \e <TypeName>.qml where \e <TypeName> is the desired name of the type. The type name has the following requirements:
+To create an object type, a QML document should be placed into a text file
+named as \e <TypeName>.qml where \e <TypeName> is the desired name of the type.
+The type name has the following requirements:
\list
\li It must be comprised of alphanumeric characters or underscores.
\li It must begin with an uppercase letter.
\endlist
-This document is then automatically recognized by the engine as a definition of a QML type. Additionally, a type defined in this manner is automatically made available to other QML files within the same directory as the engine searches within the immediate directory when resolving QML type names.
+This document is then automatically recognized by the engine as a definition of
+a QML type. Additionally, a type defined in this manner is automatically made
+available to other QML files within the same local directory as the engine
+searches within the immediate directory when resolving QML type names.
+
+\note The QML engine does not automatically search remote directories this way.
+You have to add a qmldir file if your documents are loaded over the network. See
+\l{Importing QML Document Directories}.
\section2 Custom QML Type Definition
-For example, below is a document that declares a \l Rectangle with a child \l MouseArea. The document has been saved to file named \c SquareButton.qml:
+For example, below is a document that declares a \l Rectangle with a child \l
+MouseArea. The document has been saved to file named \c SquareButton.qml:
\qml
// SquareButton.qml
@@ -65,7 +57,10 @@ Rectangle {
}
\endqml
-Since the file is named \c SquareButton.qml, \b {this can now be used as a type named \c SquareButton by any other QML file within the same directory}. For example, if there was a \c myapplication.qml file in the same directory, it could refer to the \c SquareButton type:
+Since the file is named \c SquareButton.qml, \b {this can now be used as a type
+named \c SquareButton by any other QML file within the same directory}. For
+example, if there was a \c myapplication.qml file in the same directory, it
+could refer to the \c SquareButton type:
\qml
// myapplication.qml
@@ -76,23 +71,80 @@ SquareButton {}
\image documents-definetypes-simple.png
-This creates a 100 x 100 red \l Rectangle with an inner \l MouseArea, as defined in \c SquareButton.qml. When this \c myapplication.qml document is loaded by the engine, it loads the SquareButton.qml document as a component and instantiates it to create a \c SquareButton object.
+This creates a 100 x 100 red \l Rectangle with an inner \l MouseArea, as
+defined in \c SquareButton.qml. When this \c myapplication.qml document is
+loaded by the engine, it loads the SquareButton.qml document as a component and
+instantiates it to create a \c SquareButton object.
+
+The \c SquareButton type encapsulates the tree of QML objects declared in \c
+SquareButton.qml. When the QML engine instantiates a \c SquareButton object
+from this type, it is instantiating an object from the \l Rectangle tree
+declared in \c SquareButton.qml.
+
+\note the letter case of the file name is significant on some (notably UNIX)
+filesystems. It is recommended the file name case matches the case of the
+desired QML type name exactly - for example, \c Box.qml and not \c BoX.qml -
+regardless of the platform to which the QML type will be deployed.
+
+\section2 Inline Components
+
+Sometimes, it can be inconvenient to create a new file for a type, for
+instance when reusing a small delegate in multiple views. If you don't actually
+need to expose the type, but only need to create an instance,
+\l{QtQml::Component}{Component} is an option.
+But if you want to declare properties with the component types, or if you
+want to use it in multiple files, \c Component is not an option. In that case,
+you can use \e {inline components}. Inline components declare a new component
+inside of a file. The syntax for that is
+\code
+component <component name> : BaseType {
+ // declare properties and bindings here
+}
+\endcode
+
+Inside the file which declares the inline component, the type can be referenced
+simply by its name.
+
+\snippet qml/qml-documents/Images.qml document
+
+In other files, it has to be prefixed with the name of its containing component.
-The \c SquareButton type encapsulates the tree of QML objects declared in \c SquareButton.qml. When the QML engine instantiates a \c SquareButton object from this type, it is instantiating an object from the \l Rectangle tree declared in \c SquareButton.qml.
+\snippet qml/qml-documents/LabeledImageBox.qml document
-\note the letter case of the file name is significant on some (notably UNIX) filesystems. It is recommended the file name case matches the case of the desired QML type name exactly - for example, \c Box.qml and not \c BoX.qml - regardless of the platform to which the QML type will be deployed.
+\note Inline components don't share their scope with the component they are
+declared in. In the following example, when \c A.MyInlineComponent in file
+B.qml gets created, a ReferenceError will occur, as \c root does not exist as
+an id in B.qml.
+It is therefore advisable not to reference objects in an inline component
+which are not part of it.
+
+\snippet qml/qml-documents/A.qml document
+\snippet qml/qml-documents/B.qml document
+
+\note Inline components cannot be nested.
\section2 Importing Types Defined Outside the Current Directory
If \c SquareButton.qml was not in the same directory as \c myapplication.qml,
-the \c SquareButton type would need to be specifically made available through an \e import statement in \c myapplication.qml. It could be imported from a relative path on the file system, or as an installed module; see \l {QML Modules}{module} for more details.
+the \c SquareButton type would need to be specifically made available through
+an \e import statement in \c myapplication.qml. It could be imported from a
+relative path on the file system, or as an installed module; see \l {QML
+Modules}{module} for more details.
\section1 Accessible Attributes of Custom Types
-The \b {root object} definition in a .qml file \b {defines the attributes that are available for a QML type}. All properties, signals and methods that belong to this root object - whether they are custom declared, or come from the QML type of the root object - are externally accessible and can be read and modified for objects of this type.
+The \b {root object} definition in a .qml file \b {defines the attributes that
+are available for a QML type}. All properties, signals and methods that belong
+to this root object - whether they are custom declared, or come from the QML
+type of the root object - are externally accessible and can be read and
+modified for objects of this type.
-For example, the root object type in the \c SquareButton.qml file above is \l Rectangle. This means any properties defined by the \l Rectangle type can be modified for a \c SquareButton object. The code below defines three \c SquareButton objects with customized values for some of the properties of the root \l Rectangle object of the \c SquareButton type:
+For example, the root object type in the \c SquareButton.qml file above is \l
+Rectangle. This means any properties defined by the \l Rectangle type can be
+modified for a \c SquareButton object. The code below defines three \c
+SquareButton objects with customized values for some of the properties of the
+root \l Rectangle object of the \c SquareButton type:
\qml
// application.qml
@@ -107,7 +159,12 @@ Column {
\image documents-definetypes-attributes.png
-The attributes that are accessible to objects of the custom QML type include any \l{Defining Property Attributes}{custom properties}, \l{Defining Method Attributes}{methods} and \l{Defining Signal Attributes}{signals} that have additionally been defined for an object. For example, suppose the \l Rectangle in \c SquareButton.qml had been defined as follows, with additional properties, methods and signals:
+The attributes that are accessible to objects of the custom QML type include
+any \l{Defining Property Attributes}{custom properties}, \l{Defining Method
+Attributes}{methods} and \l{Defining Signal Attributes}{signals} that have
+additionally been defined for an object. For example, suppose the \l Rectangle
+in \c SquareButton.qml had been defined as follows, with additional properties,
+methods and signals:
\qml
// SquareButton.qml
@@ -131,12 +188,14 @@ Rectangle {
MouseArea {
id: mouseArea
anchors.fill: parent
- onClicked: root.buttonClicked(mouse.x, mouse.y)
+ onClicked: (mouse)=> root.buttonClicked(mouse.x, mouse.y)
}
}
\endqml
-Any \c SquareButton object could make use of the \c pressed property, \c buttonClicked signal and \c randomizeColor() method that have been added to the root \l Rectangle:
+Any \c SquareButton object could make use of the \c pressed property, \c
+buttonClicked signal and \c randomizeColor() method that have been added to the
+root \l Rectangle:
\qml
// application.qml
@@ -145,7 +204,7 @@ import QtQuick 2.0
SquareButton {
id: squareButton
- onButtonClicked: {
+ onButtonClicked: (xPos, yPos)=> {
console.log("Clicked", xPos, yPos)
randomizeColor()
}
@@ -154,7 +213,12 @@ SquareButton {
}
\endqml
-Note that any of the \c id values defined in \c SquareButton.qml are not accessible to \c SquareButton objects, as id values are only accessible from within the component scope in which a component is declared. The \c SquareButton object definition above cannot refer to \c mouseArea in order to refer to the \l MouseArea child, and if it had an \c id of \c root rather than \c squareButton, this would not conflict with the \c id of the same value for the root object defined in \c SquareButton.qml as the two would be declared within separate scopes.
-
-
+Note that any of the \c id values defined in \c SquareButton.qml are not
+accessible to \c SquareButton objects, as id values are only accessible from
+within the component scope in which a component is declared. The \c
+SquareButton object definition above cannot refer to \c mouseArea in order to
+refer to the \l MouseArea child, and if it had an \c id of \c root rather than
+\c squareButton, this would not conflict with the \c id of the same value for
+the root object defined in \c SquareButton.qml as the two would be declared
+within separate scopes.
*/
diff --git a/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc b/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc
index d762621d6c..2107522cf0 100644
--- a/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-documents-networktransparency.html
\title Resource Loading and Network Transparency
@@ -51,7 +27,8 @@ Image {
Network transparency is supported throughout QML, for example, both the FontLoader
and Image elements support loading resources from a remote server.
-Even QML types themselves can be on the network - if the \l {Prototyping with qmlscene} is used to load
+Even QML types themselves can be on the network: if the
+\l {Prototyping with the QML Runtime Tool}{qml tool} is used to load
\tt http://example.com/mystuff/Hello.qml and that content refers to a type "World", the engine
will load \tt http://example.com/mystuff/qmldir and resolve the type just as it would for a local file.
For example if the qmldir file contains the line "World World.qml", it will load
diff --git a/src/qml/doc/src/qmllanguageref/documents/scope.qdoc b/src/qml/doc/src/qmllanguageref/documents/scope.qdoc
index 7ecf0b0a0a..0bbbcae178 100644
--- a/src/qml/doc/src/qmllanguageref/documents/scope.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/scope.qdoc
@@ -1,33 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-documents-scope.html
\title Scope and Naming Resolution
\brief overview of scope and naming resolution
+\ingroup explanations-programminglanguages
QML property bindings, inline functions, and imported JavaScript files all
run in a JavaScript scope. Scope controls which variables an expression can
diff --git a/src/qml/doc/src/qmllanguageref/documents/structure.qdoc b/src/qml/doc/src/qmllanguageref/documents/structure.qdoc
index 666039c73a..5a43ae2028 100644
--- a/src/qml/doc/src/qmllanguageref/documents/structure.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/structure.qdoc
@@ -1,38 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-documents-structure.html
\title Structure of a QML Document
\brief Description of the structure of QML documents
-A QML document is a self contained piece of QML source code that consists of two parts:
+A QML document is a self contained piece of QML source code that consists of three parts:
\list
+ \li An optional list of pragmas
\li Its \e import statements
\li A single root object declaration
\endlist
@@ -43,6 +20,294 @@ QML documents are always encoded in UTF-8 format.
+\section1 Pragmas
+
+Pragmas are instructions to the QML engine itself that can be used to specify
+certain characteristics of objects in the current file or to modify how the
+engine interprets code. The following pragmas are exaplained in details below.
+
+\list
+\li \c Singleton
+\li \c ListPropertyAssignBehavior
+\li \c ComponentBehavior
+\li \c FunctionSignatureBehavior
+\li \c NativeMethodBehavior
+\li \c ValueTypeBehavior
+\li \c Translator
+\endlist
+
+\section2 Singleton
+
+\c{pragma Singleton} declares the component defined in the QML document as
+singleton. Singletons are created only once per QML engine. In order to use
+a QML-declared singleton you also have to register it with its module. See
+\l{qt_target_qml_sources} for how to do this with CMake.
+
+\section2 ListPropertyAssignBehavior
+
+With this pragma you can define how assignments to list properties shall be
+handled in components defined in the QML document. By default, assigning to a
+list property appends to the list. You can explicitly request this behavior
+using the value \c{Append}. Alternatively, you can request the contents of list
+properties to always be replaced using \c{Replace}, or replaced if the property
+is not the default property using \c{ReplaceIfNotDefault}. For example:
+
+\qml
+pragma ListPropertyAssignBehavior: ReplaceIfNotDefault
+\endqml
+
+\note The same declaration can also be given for C++-defined types, by adding
+the \l{QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND},
+\l{QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE}, and
+\l{QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT} macros to the
+class declaration.
+
+\section2 ComponentBehavior
+
+You may have multiple components defined in the same QML file. The root
+scope of the QML file is a component, and you may additionally have
+elements of type \l QQmlComponent, explicitly or implicitly created
+as properties, or inline components. Those components are nested. Each
+of the inner components is within one specific outer component. Most of
+the time, IDs defined in an outer component are accessible within all
+its nested inner components. You can, however, create elements from a
+component in any a different context, with different IDs available.
+Doing so breaks the assumption that outer IDs are available. Therefore,
+the engine and the QML tooling cannot generally know in advance what
+type, if any, such IDs will resolve to at run time.
+
+With the ComponentBehavior pragma you can restrict all inner components
+defined in a file to only create objects within their original context.
+If a component is bound to its context, you can safely use IDs from
+outer components in the same file within the component. QML tooling will
+then assume the outer IDs with their specific types to be available.
+
+In order to bind the components to their context specify the \c{Bound}
+argument:
+
+\qml
+pragma ComponentBehavior: Bound
+\endqml
+
+This implies that, in case of name clashes, IDs defined outside a bound
+component override local properties of objects created from the
+component. Otherwise it wouldn't actually be safe to use the IDs since
+later versions of a module might add more properties to the component.
+If the component is not bound, local properties override IDs defined
+outside the component, but not IDs defined inside the component.
+
+The example below prints the \e r property of the ListView object with
+the id \e color, not the \e r property of the rectangle's color.
+
+\qml
+pragma ComponentBehavior: Bound
+import QtQuick
+
+ListView {
+ id: color
+ property int r: 12
+ model: 1
+
+ delegate: Rectangle {
+ Component.onCompleted: console.log(color.r)
+ }
+}
+\endqml
+
+The default value of \c ComponentBehavior is \c{Unbound}. You can also
+specify it explicitly. In a future version of Qt the default will change
+to \c{Bound}.
+
+Delegate components bound to their context don't receive their own
+private contexts on instantiation. This means that model data can only
+be passed via \l{Required Properties}{required properties} in this case.
+Passing model data via context properties will not work. This concerns
+delegates to e.g. \l{Instantiator}, \l{Repeater}, \l{ListView},
+\l{TableView}, \l{GridView}, \l{TreeView} and in general anything that
+uses \l{DelegateModel} internally.
+
+For example, the following will \e{not} work:
+
+\qml
+pragma ComponentBehavior: Bound
+import QtQuick
+
+ListView {
+ delegate: Rectangle {
+ color: model.myColor
+ }
+}
+\endqml
+
+The \c{delegate} property of \l{ListView} is a component. Therefore, a
+\l{Component} is implicitly created around the \l{Rectangle} here. That
+component is bound to its context. It doesn't receive the context property
+\c{model} provided by \l{ListView}. To make it work, you'd have to write
+it this way:
+
+\qml
+pragma ComponentBehavior: Bound
+import QtQuick
+
+ListView {
+ delegate: Rectangle {
+ required property color myColor
+ color: myColor
+ }
+}
+\endqml
+
+You can nest components in a QML file. The pragma holds for all components in
+the file, no matter how deeply nested.
+
+\section2 FunctionSignatureBehavior
+
+With this pragma you can change the way type annotations on functions
+are handled. Since Qt 6.7 type annotations are enforced when calling
+functions. Before, only the \l{QML script compiler} enforced the type
+annotations. The interpreter and JIT compiler ignored them. Always
+enforcing the type annotations is a behavior change in comparison to
+earlier versions since you could call functions with mismatched
+arguments before.
+
+Specifying \c{Ignored} as value makes the QML engine and the
+\l{QML script compiler} ignore any type annotations and therefore
+restores the pre-6.7 behavior of the interpreter and JIT. As a result
+less code is compiled to C++ ahead of time, and more code has to be
+interpreted or JIT-compiled.
+
+Specifying \c{Enforced} as value explicitly states the default: Type
+annotations are always enforced.
+
+\sa {Type annotations and assertions}
+
+\section2 NativeMethodBehavior
+
+Calling C++ methods with \c this objects different from the one they were
+retrieved from is broken, due to historical reasons. The original object is
+used as \c this object. You can allow the given \c this object to be used by
+setting \c {pragma NativeMethodBehavior: AcceptThisObject}. Specifying
+\c RejectThisObject keeps the historical behavior.
+
+An example of this can be found under \l {C++ methods and the 'this' object}.
+
+\section2 ValueTypeBehavior
+
+With this pragma you can change the way value types and sequences are handled.
+
+Usually lower case names cannot be type names in JavaScript code. This is a
+problem because value type names are lower case. You can specify \c{Addressable}
+as value for this pragma to change this. If \c{Addressable} is specified a
+JavaScript value can be explicitly coerced to a specific, named, value type. This is
+done using the \c as operator, like you would do with object types. Furthermore,
+you can also check for value types using the \c instanceof operator:
+
+\qml
+pragma ValueTypeBehavior: Addressable
+import QtQml
+
+QtObject {
+ property var a
+ property real b: (a as rect).x
+ property bool c: a instanceof rect
+
+ property var rect // inaccessible. "rect" is a type name.
+}
+\endqml
+
+If the type does not match, casting returns \c undefined. \c instanceof
+only checks for inheritance, not for all possible type coercions. So, for
+example, a \l{QRect} is not a \c rect value type since \c rect is \l{QRectF}
+in C++, and therefore not related by inheritance. With \c as you can cast
+to any type compatible via coercion.
+
+Since \c rect in the above example is now a type name, it will shadow any
+properties called \c{rect}.
+
+Explicitly casting to the desired type helps tooling. It can allow the
+\l{Qt Quick Compiler} generate efficient code where it otherwise would not be
+able to. You can use \l{qmllint Reference}{qmllint} to find such occurrences.
+
+There is also a \c{Inaddressable} value you can use to explicitly specify the
+default behavior.
+
+Value types and sequences are generally treated as references. This means, if
+you retrieve a value type instance from a property into a local value, and then
+change the local value, the original property is also changed. Furthermore,
+if you write the original property explicitly, the local value is also updated.
+This behavior is rather unintuitive in many places, and you should not rely on
+it. The \c{Copy} and \c{Reference} values for the \c{ValueTypeBehavior} pragma
+are experimental options to change this behavior. You should not use them.
+Specifying \c{Copy} causes all value types to be treated as actual copies.
+Specifying \c{Reference} explicitly states the default behavior.
+
+Rather than using \c{Copy} you should explicitly re-load references to value
+types and sequences any time they can have been affected by side effects. Side
+effects can happen whenever you call a function or imperatively set a property.
+\l qmllint provides guidance on this. For example, in the following code
+the variable \c f is affected by side effects after writing \c width. This is
+because there may be a binding in a derived type or in a \c Binding element
+that updates \c font when \c width is changed.
+
+\qml
+import QtQuick
+Text {
+ function a() : real {
+ var f = font;
+ width = f.pixelSize;
+ return f.pointSize;
+ }
+}
+\endqml
+
+In order to address this, you can avoid holding \c f across the write operation
+on \c width:
+
+\qml
+import QtQuick
+Text {
+ function a() : real {
+ var f = font;
+ width = f.pixelSize;
+ f = font;
+ return f.pointSize;
+ }
+}
+\endqml
+
+This, in turn can be shortened to:
+
+\qml
+import QtQuick
+Text {
+ function a() : real {
+ width = font.pixelSize;
+ return font.pointSize;
+ }
+}
+\endqml
+
+You might assume that re-retrieving the \c font property is costly, but actually
+the QML engine automatically refreshes value type references each time you read
+from them. So this is not more expensive than the first version, but a clearer
+way to express the same operations.
+
+\sa {Type annotations and assertions}
+
+\section2 Translator
+
+With this pragma you can set the context for the translations in the file.
+
+\qml
+pragma Translator: myTranslationContext
+\endqml
+
+\qml
+pragma Translator: "myTranslationContext"
+\endqml
+
+For more information on internationalization with QML, see \l{QML: Use qsTr()}{Use qsTr}.
+
\section1 Imports
A document must import the necessary modules or type namespaces to enable the
diff --git a/src/qml/doc/src/qmllanguageref/documents/topic.qdoc b/src/qml/doc/src/qmllanguageref/documents/topic.qdoc
index 47130ce39e..3b07bf0c16 100644
--- a/src/qml/doc/src/qmllanguageref/documents/topic.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/topic.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-documents-topic.html
\title QML Documents
@@ -44,9 +20,9 @@ code.
Since Qt 5.4, a document can also have the file extension \c ".ui.qml". The QML
engine handles these files like standard .qml files and ignores the \c .ui part
-of the extension. Qt Creator handles those files as
-\l{Qt Creator: Qt Quick UI Forms}{UI forms} for the Qt Quick Designer. The files
-can contain only a subset of the QML language that is defined by Qt Creator.
+of the extension. Qt Design Studio handles those files as
+\l{Qt Design Studio: UI Files}{UI files}. The files can contain only a subset
+of the QML language features.
\section1 Structure of a QML Document
diff --git a/src/qml/doc/src/qmllanguageref/modules/cppplugins.qdoc b/src/qml/doc/src/qmllanguageref/modules/cppplugins.qdoc
index 32ba948359..1bbc51bf2a 100644
--- a/src/qml/doc/src/qmllanguageref/modules/cppplugins.qdoc
+++ b/src/qml/doc/src/qmllanguageref/modules/cppplugins.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-modules-cppplugins.html
@@ -34,9 +10,8 @@
The \l{QQmlEngine}{QML engine} loads C++ plugins for QML.
Such plugins are usually provided in a QML extension module, and can
- provide types for use by clients in QML documents which import the module.
- A module requires at least one type registered in order to be considered
- valid.
+ provide types for use by clients in QML documents that import the module.
+ A module requires at least one registered type to be considered valid.
\include qqmlextensionplugin.qdocinc
diff --git a/src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc b/src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc
index 914a40599c..93461f1ed7 100644
--- a/src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc
+++ b/src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-modules-identifiedmodules.html
\title Identified Modules
@@ -35,8 +11,8 @@ specified by the module in its \c qmldir file. This enables such modules to
be imported with a unique identifier that remains the same no matter where the
module is located on the local file system.
-When importing an identified module, an unquoted identifier is used, with a
-mandatory version number:
+When importing an identified module, an unquoted identifier is used, with an
+optional version number:
\snippet qml/imports/installed-module.qml imports
@@ -44,6 +20,12 @@ Identified modules must be installed into the
\l{qtqml-syntax-imports.html#qml-import-path}{import path} in order to be found
by the QML engine.
+Syntactically, each dot-separated segment of the URI must be a well-formed
+ECMAScript Identifier Name. This means, for example, the segments must not start
+with a number and they must not contain \e{-} (minus) characters. As the URI
+will be translated into directory names, you should restrict it to alphanumeric
+characters of the latin alphabet, underscores, and dots.
+
\section1 Locally Installed Identified Modules
A directory of QML and/or C++ files can be shared as an identified module if it
@@ -171,27 +153,25 @@ An identified module has several restrictions upon it:
\li the module must register its types into the module identifier type
namespace
\li the module may not register types into any other module's namespace
-\li clients must specify a version when importing the module
\endlist
For example, if an identified module is installed into
-\c{$QML2_IMPORT_PATH/ExampleModule}, the module identifier directive must be:
+\c{$QML_IMPORT_PATH/ExampleModule}, the module identifier directive must be:
\code
module ExampleModule
\endcode
If the strict module is installed into
-\c{$QML2_IMPORT_PATH/com/example/CustomUi}, the module identifier directive
+\c{$QML_IMPORT_PATH/com/example/CustomUi}, the module identifier directive
must be:
\code
module com.example.CustomUi
\endcode
Clients will then be able to import the above module with the following import
-statement (assuming that the module registers types into version 1.0 of its
-namespace):
+statement:
\qml
-import com.example.CustomUi 1.0
+import com.example.CustomUi
\endqml
*/
diff --git a/src/qml/doc/src/qmllanguageref/modules/legacymodules.qdoc b/src/qml/doc/src/qmllanguageref/modules/legacymodules.qdoc
index a84f8f07a1..51bb424d22 100644
--- a/src/qml/doc/src/qmllanguageref/modules/legacymodules.qdoc
+++ b/src/qml/doc/src/qmllanguageref/modules/legacymodules.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-modules-legacymodules.html
diff --git a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
index f7d71030b5..ac82d8136e 100644
--- a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
+++ b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-modules-qmldir.html
\title Module Definition qmldir Files
@@ -43,240 +19,287 @@ module. For more information about the first form of \c qmldir file, see
\section1 Contents of a Module Definition qmldir File
-A \c qmldir file is a plain-text file that contains
-the following commands:
-
-\table 70%
- \header
- \li Syntax
- \li Usage
- \row
- \li
- \code
-module <ModuleIdentifier>
- \endcode
- \li Declares the module identifier of the module.
- The <ModuleIdentifier> is the (dotted URI notation) identifier
- for the module, which must match the module's install path.
-
- The \l{Identified Modules#Semantics of Identified Modules}
- {module identifier directive} must be the first line of the file.
- Exactly one module identifier directive may exist in the \c qmldir
- file.
-
- Example:
- \code
-module ExampleModule
- \endcode
-
- \row
- \li
- \code
-[singleton] <TypeName> <InitialVersion> <File>
- \endcode
- \li Declares a \l{qtqml-typesystem-objecttypes.html}{QML object type}
- to be made available by the module.
- \list
- \li \c [singleton] Optional. Used to declare a singleton type.
- \li \c <TypeName> is the type being made available
- \li \c <InitialVersion> is the module version for which the type is to be made available
- \li \c <File> is the (relative) file name of the QML file that defines the type
- \endlist
-
- Zero or more object type declarations may exist in the \c qmldir
- file, however each object type must have a unique type name within
- any particular version of the module.
- \note To declare a \c singleton type, the QML file defining the
- type must include the \c {pragma Singleton} statement.
-
- Example:
- \code
-//Style.qml with custom singleton type definition
-pragma Singleton
-import QtQuick 2.0
+A \c qmldir file is a plain-text file that contains the following commands:
-QtObject {
- property int textSize: 20
- property color textColor: "green"
-}
+\list
+ \li \l {Module Identifier Declaration}
+ \li \l {Object Type Declaration}
+ \li \l {Internal Object Type Declaration}
+ \li \l {JavaScript Resource Declaration}
+ \li \l {Plugin Declaration}
+ \li \l {Plugin Classname Declaration}
+ \li \l {Type Description File Declaration}
+ \li \l {Module Dependencies Declaration}
+ \li \l {Module Import Declaration}
+ \li \l {Designer Support Declaration}
+ \li \l {Preferred Path Declaration}
+\endlist
-// qmldir declaring the singleton type
-module CustomStyles
-singleton Style 1.0 Style.qml
+\note Each command in a \c qmldir file must be on a separate line.
-// singleton type in use
-import QtQuick 2.0
-import CustomStyles 1.0
+In addition to commands, you can also add comments, which are lines starting
+with \c {#}.
-Text {
- font.pixelSize: Style.textSize
- color: Style.textColor
- text: "Hello World"
-}
- \endcode
-
- \row
- \li
- \code
-internal <TypeName> <File>
- \endcode
- \li Declares an object type that is in the module but should not be
- made available to users of the module.
-
- Zero or more internal object type declarations may exist in the
- \c qmldir file.
-
- Example:
- \code
-internal MyPrivateType MyPrivateType.qml
- \endcode
-
- This is necessary if the module may be imported remotely (see
- \l{Identified Modules#Remotely Installed Identified Modules}
- {Remotely Installed Identified Modules}) because if an exported type depends
- on an non-exported type within the module, the engine must also
- load the non-exported type.
-
- \row
- \li
- \code
-<ResourceIdentifier> <InitialVersion> <File>
- \endcode
- \li Declares a JavaScript file to be made available by the module.
- The resource will be made available via the specified identifier
- with the specified version number.
-
- Zero or more JavaScript resource declarations may exist in the
- \c qmldir file, however each JavaScript resource must have a unique
- identifier within any particular version of the module.
-
- Example:
- \code
-MyScript 1.0 MyScript.js
- \endcode
-
- See the documentation about \l{qtqml-javascript-resources.html}
- {defining JavaScript resources} and
- \l{qtqml-javascript-imports.html}
- {Importing JavaScript Resources In QML} for more information.
-
- \row
- \li
- \code
-plugin <Name> [<Path>]
- \endcode
- \li Declares a plugin to be made available by the module.
-
- \list
- \li \c <Name> is the plugin library name. This is usually not the
- same as the file name of the plugin binary, which is platform
- dependent; e.g. the library \c MyAppTypes would produce
- \c libMyAppTypes.so on Linux and \c MyAppTypes.dll on Windows.
- \li \c <Path> (optional) specifies either:
- \list
- \li an absolute path to the directory containing the plugin
- file, or
- \li a relative path from the directory containing the \c qmldir
- file to the directory containing the plugin file.
- \endlist
-
- By default the engine searches for the plugin library in the
- directory that contains the \c qmldir file. (The plugin search
- path can be queried with QQmlEngine::pluginPathList() and
- modified using QQmlEngine::addPluginPath().)
- \endlist
-
- Zero or more C++ plugin declarations may exist in the \c qmldir
- file, however since plugin loading is a relatively expensive
- operation, clients are advised to specify at most a single plugin.
-
- Example:
- \code
-plugin MyPluginLibrary
- \endcode
- \row
- \li
- \code
-classname <C++ plugin class>
- \endcode
- \li Provides the class name of the C++ plugin used by the module.
-
- This information is required for all the QML modules that depend
- on a C++ plugin for additional functionality. Qt Quick applications
- built with static linking cannot resolve the module imports without
- this information.
-
- \row
- \li
- \code
-typeinfo <File>
- \endcode
- \li Declares a \l{Writing a qmltypes file}{type description file} for
- the module that can be read by QML tools such as Qt Creator to
- access information about the types defined by the module's plugins.
- \c <File> is the (relative) file name of a \c .qmltypes file.
-
- Example:
- \code
-typeinfo mymodule.qmltypes
- \endcode
-
- Without such a file, QML tools may be unable to offer features such
- as code completion for the types defined in your plugins.
-
- \row
- \li
- \code
-depends <ModuleIdentifier> <InitialVersion>
- \endcode
- \li Declares that this module depends on another.
-
- Example:
- \code
-depends MyOtherModule 1.0
- \endcode
-
- This declaration is necessary only in cases when the dependency is
- hidden: for example, when the C++ code for one module is used to
- load QML (perhaps conditionally) which then depends on other
- modules. In such cases, the \c depends declaration is necessary
- to include the other modules in application packages.
-
- \row
- \li
- \code
-# <Comment>
- \endcode
- \li Declares a comment. These are ignored by the engine.
-
- Example:
- \code
-# this is a comment
- \endcode
-
- \row
- \li
- \code
-designersupported
- \endcode
-
- \li Set this property if the plugin is supported by Qt Quick Designer.
- By default, the plugin will not be supported.
-
- A plugin that is supported by Qt Quick Designer has to be properly
- tested. This means that the plugin does not crash when running inside
- the qml2puppet that is used by Qt Quick Designer to execute QML.
- Generally the plugin should work well in the Qt Quick Designer
- and not cause any show stoppers, like taking huge amounts of memory,
- slowing down the qml2puppet heavily or anything else that renders
- the plugin effectively unusable in the Qt Quick Designer.
-
- The items of an unsupported plugin are not painted in the Qt Quick Designer,
- but they are still available as empty boxes and the properties can be edited.
-
-\endtable
-
-Each command in a \c qmldir file must be on a separate line.
+\section2 Module Identifier Declaration
+
+\code
+ module <ModuleIdentifier>
+\endcode
+
+Declares the module identifier of the module. The <ModuleIdentifier> is the
+(dotted URI notation) identifier for the module, which must match the module's
+install path.
+
+The \l{Identified Modules#Semantics of Identified Modules}
+{module identifier directive} must be the first line of the file. Exactly one
+module identifier directive may exist in the \c qmldir file.
+
+Example:
+\code
+ module ExampleModule
+\endcode
+
+\section2 Object Type Declaration
+\code
+ [singleton] <TypeName> <InitialVersion> <File>
+\endcode
+
+Declares a \l{qtqml-typesystem-objecttypes.html}{QML object type}
+to be made available by the module.
+\list
+ \li \c [singleton] Optional. Used to declare a singleton type.
+ \li \c <TypeName> is the type being made available
+ \li \c <InitialVersion> is the module version for which the type is to be
+ made available
+ \li \c <File> is the (relative) file name of the QML file that defines
+ the type
+\endlist
+
+Zero or more object type declarations may exist in the \c qmldir
+file. However, each object type must have a unique type name within
+any particular version of the module.
+\note To declare a \c singleton type, the QML file defining the
+type must include the \c {pragma Singleton} statement.
+
+Example:
+\code
+ //Style.qml with custom singleton type definition
+ pragma Singleton
+ import QtQuick 2.0
+
+ QtObject {
+ property int textSize: 20
+ property color textColor: "green"
+ }
+
+ // qmldir declaring the singleton type
+ module CustomStyles
+ singleton Style 1.0 Style.qml
+
+ // singleton type in use
+ import QtQuick 2.0
+ import CustomStyles 1.0
+
+ Text {
+ font.pixelSize: Style.textSize
+ color: Style.textColor
+ text: "Hello World"
+ }
+\endcode
+
+\section2 Internal Object Type Declaration
+
+\code
+ internal <TypeName> <File>
+\endcode
+
+Declares an object type that is in the module but should not be
+made available to users of the module.
+
+Zero or more internal object type declarations may exist in the
+\c qmldir file.
+
+Example:
+\code
+ internal MyPrivateType MyPrivateType.qml
+\endcode
+
+This is necessary if the module is imported remotely
+(see \l{Identified Modules#Remotely Installed Identified Modules}
+{Remotely Installed Identified Modules}) because if an exported type depends
+on a non-exported type within the module, the engine must also
+load the non-exported type.
+
+\section2 JavaScript Resource Declaration
+
+\code
+ <ResourceIdentifier> <InitialVersion> <File>
+\endcode
+
+Declares a JavaScript file to be made available by the module.
+The resource will be made available via the specified identifier
+with the specified version number.
+
+Zero or more JavaScript resource declarations may exist in the
+\c qmldir file. However, each JavaScript resource must have a unique
+identifier within any particular version of the module.
+
+Example:
+\code
+ MyScript 1.0 MyScript.js
+\endcode
+
+See the documentation about \l{qtqml-javascript-resources.html}
+{defining JavaScript resources} and
+\l{qtqml-javascript-imports.html}
+{Importing JavaScript Resources In QML} for more information.
+
+\section2 Plugin Declaration
+
+\code
+ [optional] plugin <Name> [<Path>]
+\endcode
+
+Declares a plugin to be made available by the module.
+
+\list
+ \li \c optional denotes that the plugin itself does not contain
+ any relevant code and only serves to load a library it links
+ to. If given, and if any types for the module are already
+ available, indicating that the library has been loaded by some
+ other means, QML will not load the plugin.
+ \li \c <Name> is the plugin library name. This is usually not the
+ same as the file name of the plugin binary, which is platform
+ dependent. For example, the library \c MyAppTypes would produce
+ \c libMyAppTypes.so on Linux and \c MyAppTypes.dll on Windows.
+ \li \c <Path> (optional) specifies either:
+ \list
+ \li an absolute path to the directory containing the plugin
+ file, or
+ \li a relative path from the directory containing the \c qmldir
+ file to the directory containing the plugin file.
+ \endlist
+\endlist
+
+By default, the engine searches for the plugin library in the
+directory that contains the \c qmldir file. (The plugin search
+path can be queried with QQmlEngine::pluginPathList() and
+modified using QQmlEngine::addPluginPath().)
+
+Zero or more C++ plugin declarations may exist in the \c qmldir
+file. However, since plugin loading is a relatively expensive
+operation, clients are advised to specify at most a single plugin.
+
+Example:
+\code
+ plugin MyPluginLibrary
+\endcode
+
+\section2 Plugin Classname Declaration
+
+\code
+ classname <C++ plugin class>
+\endcode
+
+Provides the class name of the C++ plugin used by the module.
+
+This information is required for all the QML modules that depend
+on a C++ plugin for additional functionality. Qt Quick applications
+built with static linking cannot resolve the module imports without
+this information.
+
+\section2 Type Description File Declaration
+
+\code
+ typeinfo <File>
+\endcode
+
+Declares a \l{Type Description Files}{type description file} for
+the module that can be read by QML tools such as Qt Creator to
+access information about the types defined by the module's plugins.
+\c <File> is the (relative) file name of a \c .qmltypes file.
+
+Example:
+\code
+ typeinfo mymodule.qmltypes
+\endcode
+
+Without such a file, QML tools may be unable to offer features such
+as code completion for the types defined in your plugins.
+
+\section2 Module Dependencies Declaration
+
+\code
+ depends <ModuleIdentifier> <InitialVersion>
+\endcode
+
+Declares that this module depends on another.
+
+Example:
+\code
+ depends MyOtherModule 1.0
+\endcode
+
+This declaration is necessary only in cases when the dependency is
+hidden: for example, when the C++ code for one module is used to
+load QML (perhaps conditionally), which then depends on other
+modules. In such cases, the \c depends declaration is necessary
+to include the other modules in application packages.
+
+\section2 Module Import Declaration
+
+\code
+ import <ModuleIdentifier> [<Version>]
+\endcode
+
+Declares that this module imports another.
+
+Example:
+\code
+ import MyOtherModule 1.0
+\endcode
+
+The types from the other module are made available in the same type
+namespace as this module is imported into. Omitting the version
+imports the latest version available of the other module. Specifying
+\c auto as version imports the same version as the version of this
+module specified in the QML \c import statement.
+
+\section2 Designer Support Declaration
+
+\code
+ designersupported
+\endcode
+
+Set this property if the plugin is supported by Qt Quick Designer.
+By default, the plugin will not be supported.
+
+A plugin that is supported by Qt Quick Designer has to be properly
+tested. This means that the plugin does not crash when running inside
+the qml2puppet that is used by Qt Quick Designer to execute QML.
+Generally, the plugin should work well in the Qt Quick Designer
+and not cause any show stoppers, like taking excessive amounts of memory,
+slowing down the qml2puppet heavily, or anything else that renders
+the plugin effectively unusable in the Qt Quick Designer.
+
+The items of an unsupported plugin are not painted in the Qt Quick Designer,
+but they are still available as empty boxes and the properties can be edited.
+
+\section2 Preferred Path Declaration
+
+\code
+ prefer <Path>
+\endcode
+
+This property directs the QML engine to load any further files for this
+module from <path>, rather than the current directory. This can be used
+to load files compiled with qmlcachegen.
+
+For example, you can add a module's QML files as resources to a resource
+path \c{:/my/path/MyModule/}. Then, add \c{prefer :/my/path/MyModule} to
+the qmldir file in order to use the files in the resource system, rather
+than the ones in the file system. If you then use qmlcachegen for those,
+the pre-compiled files will be available to any clients of the module.
\section1 Versioning Semantics
@@ -376,125 +399,34 @@ The \c CustomButton type used above would come from the definition specified in
the \c CustomButton21.qml file, and the JavaScript resource identified by the
\c MathFunctions identifier would be defined in the \c mathfuncs.js file.
-\section1 Writing a qmltypes File
+\section1 Type Description Files
QML modules may refer to one or more type information files in their
\c qmldir file. These usually have the \c .qmltypes
extension and are read by external tools to gain information about
-types defined in plugins.
+types defined in C++ and typically imported via plugins.
As such qmltypes files have no effect on the functionality of a QML module.
Their only use is to allow tools such as Qt Creator to provide code completion,
error checking and other functionality to users of your module.
-Any module that uses plugins should also ship a type description file.
+Any module that defines QML types in C++ should also ship a type description
+file.
The best way to create a qmltypes file for your module is to generate it
-using the \c qmlplugindump tool that is provided with Qt.
+using the build system and the \l QML_ELEMENT macros. If you follow the
+documentation on this, no further action is needed. qmltyperegistrar will
+automatically generate the \c .qmltypes files.
Example:
-If your module is in \c /tmp/imports/My/Module, you could run
-\code
-qmlplugindump My.Module 1.0 /tmp/imports > /tmp/imports/My/Module/mymodule.qmltypes
-\endcode
-to generate type information for your module. Afterwards, add the line
+If your module is in \c /tmp/imports/My/Module, a file called \c plugins.qmltypes
+should be generated alongside the actual plugin binary.
+
+Add the line
\code
-typeinfo mymodule.qmltypes
+typeinfo plugins.qmltypes
\endcode
to \c /tmp/imports/My/Module/qmldir to register it.
-While the qmldump tool covers most cases, it does not work if:
-\list
-\li The plugin uses a \c{QQmlCustomParser}. The component that uses
- the custom parser will not get its members documented.
-\li The plugin can not be loaded. In particular if you cross-compiled
- the plugin for a different architecture, qmldump will not be able to
- load it.
-\endlist
-
-In case you have to create a qmltypes file manually or need to adjust
-an existing one, this is the file format:
-
-\qml
-import QtQuick.tooling 1.1
-
-// There always is a single Module object that contains all
-// Component objects.
-Module {
- // A Component object directly corresponds to a type exported
- // in a plugin with a call to qmlRegisterType.
- Component {
-
- // The name is a unique identifier used to refer to this type.
- // It is recommended you simply use the C++ type name.
- name: "QQuickAbstractAnimation"
-
- // The name of the prototype Component.
- prototype: "QObject"
-
- // The name of the default property.
- defaultProperty: "animations"
-
- // The name of the type containing attached properties
- // and methods.
- attachedType: "QQuickAnimationAttached"
-
- // The list of exports determines how a type can be imported.
- // Each string has the format "URI/Name version" and matches the
- // arguments to qmlRegisterType. Usually types are only exported
- // once, if at all.
- // If the "URI/" part of the string is missing that means the
- // type should be put into the package defined by the URI the
- // module was imported with.
- // For example if this module was imported with 'import Foo 4.8'
- // the Animation object would be found in the package Foo and
- // QtQuick.
- exports: [
- "Animation 4.7",
- "QtQuick/Animation 1.0"
- ]
-
- // The meta object revisions for the exports specified in 'exports'.
- // Describes with revisioned properties will be visible in an export.
- // The list must have exactly the same length as the 'exports' list.
- // For example the 'animations' propery described below will only be
- // available through the QtQuick/Animation 1.0 export.
- exportMetaObjectRevisions: [0, 1]
-
- Property {
- name: "animations";
- type: "QQuickAbstractAnimation"
- // defaults to false, whether this property is read only
- isReadonly: true
- // defaults to false, whether the type of this property was a pointer in C++
- isPointer: true
- // defaults to false: whether the type actually is a QQmlListProperty<type>
- isList: true
- // defaults to 0: the meta object revision that introduced this property
- revision: 1
- }
- Property { name: "loops"; type: "int" }
- Property { name: "name"; type: "string" }
- Property { name: "loopsEnum"; type: "Loops" }
-
- Enum {
- name: "Loops"
- values: [ "Infinite", "OnceOnly" ]
- }
-
- // Signal and Method work the same way. The inner Parameter
- // declarations also support the isReadonly, isPointer and isList
- // attributes which mean the same as for Property
- Method { name: "restart" }
- Signal { name: "started"; revision: 2 }
- Signal {
- name: "runningChanged"
- Parameter { type: "bool" }
- Parameter { name: "foo"; type: "bool" }
- }
- }
-}
-\endqml
-
*/
diff --git a/src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc b/src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc
index 01e81e7c19..771d520f8a 100644
--- a/src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc
+++ b/src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc
@@ -1,21 +1,36 @@
-QQmlExtensionPlugin is a plugin interface that makes it possible to
+\l QQmlEngineExtensionPlugin is a plugin interface that lets you
create QML extensions that can be loaded dynamically into QML applications.
These extensions allow custom QML types to be made available to the
QML engine.
To write a QML extension plugin:
\list 1
-\li Subclass QQmlExtensionPlugin
- \list
- \li Use the Q_PLUGIN_METADATA() macro to register the plugin with
- the Qt meta object system
- \li Override the \l{QQmlExtensionPlugin::}{registerTypes()} method
- and call qmlRegisterType() to register the types to be exported
- by the plugin
- \endlist
-\li Write a project file for the plugin
-\li Create a \l{Module Definition qmldir Files}{qmldir file} to
- describe the plugin
+\li Subclass \l QQmlEngineExtensionPlugin and use the Q_PLUGIN_METADATA() macro
+ to register the plugin with the Qt meta object system.
+\li Use the \l QML_ELEMENT and \l QML_NAMED_ELEMENT() macros to declare
+ QML types.
+\li Configure your build file.
+
+ CMake:
+ \badcode
+ qt_add_qml_module(<target>
+ URI <my.import.name>
+ VERSION 1.0
+ QML_FILES <app.qml>
+ NO_RESOURCE_TARGET_PATH
+ )
+ \endcode
+
+ qmake:
+ \badcode
+ CONFIG += qmltypes
+ QML_IMPORT_NAME = <my.import.name>
+ QML_IMPORT_MAJOR_VERSION = <version>
+ \endcode
+\li If you're using qmake, create a
+ \l {Module Definition qmldir Files} {qmldir file} to describe the plugin.
+ Note that CMake will, by default, automatically generate the
+ \l {Module Definition qmldir Files} {qmldir file}.
\endlist
QML extension plugins are for either application-specific or library-like
@@ -23,72 +38,27 @@ plugins. Library plugins should limit themselves to registering types, as
any manipulation of the engine's root context may cause conflicts or other
issues in the library user's code.
-\section1 TimeExample QML extension plugin
+\note When using the CMake \l qt_add_qml_module API, a plugin will be generated
+automatically for you. It will take care of type registration.
+You only need to write a custom plugin if you have special
+requirements, such as registering custom image
+providers. In that case, pass
+\l{NO_GENERATE_PLUGIN_SOURCE} to the \c qt_add_qml_module
+call to disable the generation of the default plugin.
-Suppose there is a new \c TimeModel C++ class that should be made available
-as a new QML type. It provides the current time through \c hour and \c minute
-properties.
-
-\snippet qmlextensionplugins/plugin.cpp 0
-\dots
-
-To make this type available, we create a plugin class named \c QExampleQmlPlugin
-which is a subclass of \l QQmlExtensionPlugin. It overrides the
-\l{QQmlExtensionPlugin::}{registerTypes()} method in order to register the \c TimeModel
-type using qmlRegisterType(). It also uses the Q_PLUGIN_METADATA() macro in the class
-definition to register the plugin with the Qt meta object system using a unique
-identifier for the plugin.
-
-\snippet qmlextensionplugins/plugin.cpp plugin
-
-This registers the \c TimeModel class with version \c{1.0} of this plugin library, as
-a QML type called \c Time. The Q_ASSERT() macro can ensure the type namespace is
-imported correctly by any QML components that use this plugin. The
-\l{Defining QML Types from C++} article has more information about registering C++
-types into the runtime.
-
-\section1 Project settings for the plugin
-
-Additionally, the project file (\c .pro) defines the project as a plugin library,
-specifies it should be built into the \c imports/TimeExample directory, and registers
-the plugin target name and various other details:
+The linker might erroneously remove the generated type registration
+function as an optimization. You can prevent that by declaring a synthetic
+volatile pointer to the function somewhere in your code. If your module is
+called "my.module", you would add the forward declaration in global scope:
\code
-TEMPLATE = lib
-CONFIG += qt plugin
-QT += qml
-
-DESTDIR = imports/TimeExample
-TARGET = qmlqtimeexampleplugin
-SOURCES += qexampleqmlplugin.cpp
+void qml_register_types_my_module();
\endcode
-\section1 Plugin definition in the qmldir
-
-Finally, a \l{Module Definition qmldir Files}{qmldir file} is required
-in the \c imports/TimeExample directory to describe the plugin and the types that it
-exports. The plugin includes a \c Clock.qml file along with the \c qmlqtimeexampleplugin
-that is built by the project (as shown above in the \c .pro file) so both of these
-need to be specified in the \c qmldir file:
+Then add the following snippet of code in the implementation of any function
+that's part of the same binary as the registration:
-\quotefile qmlextensionplugins/imports/TimeExample/qmldir
-
-To make things easier for this example, the TimeExample source directory is in
-\c{imports/TimeExample}, and we build
-\l{Source, Build, and Install Directories}{in-source}. However, the structure
-of the source directory is not so important, as the \c qmldir file can specify
-paths to installed QML files.
-
-What is important is the name of the directory that the qmldir is installed
-into. When the user imports our module, the QML engine uses the
-\l{Contents of a Module Definition qmldir File}{module identifier}
-(\c TimeExample) to find the plugin, and so the directory in which it is
-installed must match the module identifier.
-
-Once the project is built and installed, the new \c Time component is
-accessible by any QML component that imports the \c TimeExample
-module
-
-\snippet qmlextensionplugins/plugins.qml 0
-
-The full source code is available in the \l {qmlextensionplugins}{plugins example}.
+\code
+volatile auto registration = &qml_register_types_my_module;
+Q_UNUSED(registration);
+\endcode
diff --git a/src/qml/doc/src/qmllanguageref/modules/topic.qdoc b/src/qml/doc/src/qmllanguageref/modules/topic.qdoc
index 3462e474c2..449acb3f81 100644
--- a/src/qml/doc/src/qmllanguageref/modules/topic.qdoc
+++ b/src/qml/doc/src/qmllanguageref/modules/topic.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-modules-topic.html
diff --git a/src/qml/doc/src/qmllanguageref/qmlreference.qdoc b/src/qml/doc/src/qmllanguageref/qmlreference.qdoc
index 901a4a57fe..7f92129fcf 100644
--- a/src/qml/doc/src/qmllanguageref/qmlreference.qdoc
+++ b/src/qml/doc/src/qmllanguageref/qmlreference.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qmlreference.html
@@ -38,7 +14,7 @@ In addition, QML heavily uses Qt, which allows types and other Qt features to
be accessible directly from QML applications.
This reference guide describes the features of the QML language. Many of the
-QML types in the guide originate from the \l{Qt QML} or \l{Qt Quick}
+QML types in the guide originate from the \l{Qt Qml} or \l{Qt Quick}
modules.
\list
@@ -73,17 +49,20 @@ modules.
\li \l{qtqml-javascript-resources.html}{Defining JavaScript Resources In QML}
\li \l{qtqml-javascript-imports.html}{Importing JavaScript Resources In QML}
\li \l{qtqml-javascript-hostenvironment.html}{JavaScript Host Environment}
+ \li \l{qtqml-javascript-finetuning.html}{Configuring the JavaScript engine}
\endlist
\li \l{qtqml-typesystem-topic.html}{The QML Type System}
\list
- \li \l{qtqml-typesystem-basictypes.html}{Basic Types}
+ \li \l{qtqml-typesystem-valuetypes.html}{QML Value Types}
\li \l{qtqml-typesystem-topic.html#javascript-types}{JavaScript Types}
\li \l{qtqml-typesystem-objecttypes.html}{QML Object Types}
\list
\li \l{qtqml-documents-definetypes.html}{Defining Object Types from QML}
\li \l{qtqml-cppintegration-definetypes.html}{Defining Object Types from C++}
\endlist
+ \li \l{qtqml-typesystem-sequencetypes.html}{QML Sequence Types}
+ \li \l{qtqml-typesystem-namespaces.html}{QML Namespaces}
\endlist
\li \l{qtqml-modules-topic.html}{QML Modules}
diff --git a/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc b/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc
index 9eb8f72cf2..ce2e48d41a 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-syntax-basics.html
\title QML Syntax Basics
@@ -48,7 +24,7 @@ A QML document may have one or more imports at the top of the file.
An import can be any one of:
\list
-\li a versioned namespace into which types have been registered (e.g., by a plugin)
+\li a QML Module
\li a relative directory which contains type-definitions as QML documents
\li a JavaScript file
\endlist
@@ -57,10 +33,9 @@ JavaScript file imports must be qualified when imported, so that the properties
The generic form of the various imports are as follows:
\list
-\li \tt{import Namespace VersionMajor.VersionMinor}
-\li \tt{import Namespace VersionMajor.VersionMinor as SingletonTypeIdentifier}
-\li \tt{import "directory"}
-\li \tt{import "file.js" as ScriptIdentifier}
+\li \tt{import <ModuleIdentifier> [<Version.Number>] [as <Qualifier>]}
+\li \tt{import "<Directory>"}
+\li \tt{import "<JavaScriptFile>" [as <ScriptIdentifier>]}
\endlist
Examples:
diff --git a/src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc b/src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc
index 7ec8a4ff34..f653ba452b 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-syntax-directoryimports.html
\title Importing QML Document Directories
@@ -51,6 +27,11 @@ filenames of the QML documents. Only filenames beginning with an uppercase
letter and ending with ".qml" will be exposed as types if no \c qmldir file
is specified in the directory.
+Directory Imports rank below any
+\l{qtqml-modules-identifiedmodules.html}{module imports} in precedence. If the
+same name is defined in a module and in a directory that are both imported into
+the same namespace, only the module's type is made available.
+
\section2 An Example
Consider the following QML project directory structure. Under the top level directory \c myapp,
@@ -104,11 +85,30 @@ as an installed module is imported with a unique identifier string rather than
a file system path.
+\section1 The Implicit Import
+
+The directory a QML document resides in is automatically imported. You do
+not have to explicitly import \c{"."} or similar.
+
+\note You should make sure that the qmldir file that specifies the module a QML
+document belongs to resides in the same directory as the QML document itself.
+Otherwise the implicit import is different from the module the document belongs
+to. Then, for example, another QML document may be a singleton in the context of
+the module, but not a singleton in the context of the implicit import. This is a
+frequent source of mistakes.
+
+
\section1 Remotely Located Directories
A directory of QML files can also be imported from a remote location if the
directory contains a directory listing \c qmldir file.
+\note This also holds for the \l{The Implicit Import}{implicit import} of the
+directory a QML document resides in. If your QML documents are loaded from a
+remote location, you need to add qmldir files even if they don't contain any
+explicit directory import statements. Otherwise your QML documents won't see
+each other.
+
For example, if the \c myapp directory in the previous example was hosted at
"http://www.my-example-server.com", and the \c mycomponents directory
contained a \c qmldir file defined as follows:
diff --git a/src/qml/doc/src/qmllanguageref/syntax/imports.qdoc b/src/qml/doc/src/qmllanguageref/syntax/imports.qdoc
index 57e0ba1a14..c19ac3eeec 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/imports.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/imports.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-syntax-imports.html
\title Import Statements
@@ -36,12 +12,10 @@ resources and component directories are used within a QML document. The types
which may be used within a document depends on which modules, resources and
directories are imported by the document.
-\section2 Import Types
-
There are three different types of imports. Each import type has a slightly
different syntax, and different semantics apply to different import types.
-\section3 Module (Namespace) Imports
+\section2 Module (Namespace) Imports
The most common type of import is a module import. Clients can import
\l{qtqml-modules-identifiedmodules.html}{QML modules} which register QML object
@@ -49,7 +23,7 @@ types and JavaScript resources into a given namespace.
The generic form of a module import is as follows:
\code
-import <ModuleIdentifier> <Version.Number> [as <Qualifier>]
+import <ModuleIdentifier> [<Version.Number>] [as <Qualifier>]
\endcode
\list
@@ -59,7 +33,9 @@ import <ModuleIdentifier> <Version.Number> [as <Qualifier>]
\li The \c <Version.Number> is a version of the form
\c {MajorVersion.MinorVersion} which specifies which definitions of
various object types and JavaScript resources will be made available due
- to the import.
+ to the import. It can be omitted, in which case the latest version of the
+ module is imported. It is also possible to only omit the minor version.
+ Then the latest minor version of the given major version is imported.
\li The \c <Qualifier> is an optional local namespace identifier into which
the object types and JavaScript resources provided by the module will be
installed, if given. If omitted, the object types and JavaScript
@@ -69,7 +45,7 @@ import <ModuleIdentifier> <Version.Number> [as <Qualifier>]
An example of an unqualified module import is as follows:
\code
-import QtQuick 2.0
+import QtQuick
\endcode
This import allows the use of all of the types provided by the \c QtQuick
@@ -77,7 +53,7 @@ module without needing to specify a qualifier. For example, the client code to
create a rectangle is as follows:
\qml
-import QtQuick 2.0
+import QtQuick
Rectangle {
width: 200
@@ -86,9 +62,16 @@ Rectangle {
}
\endqml
+An example of an unqualified import with version would be
+\code
+import QtQuick 2.10
+\endcode
+In that case, any types defined in QtQuick 2.11 and higher or in any higher major
+version, like 6.0, would not be available to the file.
+
An example of a qualified module import is as follows:
\code
-import QtQuick 2.0 as Quick
+import QtQuick as Quick
\endcode
This import allows multiple modules which provide conflicting type names to be
@@ -100,7 +83,7 @@ An example of client code which creates a rectangle after using a qualified
module import is as follows:
\qml
-import QtQuick 2.0 as Quick
+import QtQuick as Quick
Quick.Rectangle {
width: 200
@@ -127,17 +110,17 @@ Rectangle {
In this case, the engine will emit an error and refuse to load the file.
-\section4 Non-module Namespace Imports
+\section3 C++ Module Imports
-Types can also be registered into namespaces directly via the various
-registration functions in C++ (such as qmlRegisterType()). The types which
-have been registered into a namespace in this way may be imported by importing
-the namespace, as if the namespace was a module identifier.
+Usually, C++ types are declared using the QML_ELEMENT and QML_NAMED_ELEMENT()
+macros and registered via the build system using QML_IMPORT_NAME and
+QML_IMPORT_MAJOR_VERSION. The import name and version given this way form a
+module that can be imported to access the types.
This is most common in client applications which define their own QML object
-types in C++ and register them with the QML type system manually.
+types in C++.
-\section4 Importing into a Qualified Local Namespace
+\section3 Importing into a Qualified Local Namespace
The \c import statement may optionally use the \c as keyword to specify that
the types should be imported into a particular document-local namespace. If a
@@ -149,7 +132,7 @@ references to types from the \c QtQuick module must be prefixed with the
\c CoreItems name:
\qml
-import QtQuick 2.0 as CoreItems
+import QtQuick as CoreItems
CoreItems.Rectangle {
width: 100; height: 100
@@ -171,7 +154,7 @@ two modules can be imported into different namespaces to ensure the code is
referring to the correct type:
\qml
-import QtQuick 2.0 as CoreItems
+import QtQuick as CoreItems
import "../textwidgets" as MyModule
CoreItems.Rectangle {
@@ -187,7 +170,7 @@ way that multiple modules can be imported into the global namespace. For example
\snippet qml/imports/merged-named-imports.qml imports
-\section3 Directory Imports
+\section2 Directory Imports
A directory which contains QML documents may also be imported directly in a
QML document. This provides a simple way for QML types to be segmented into
@@ -213,7 +196,7 @@ section about \l{Importing into a Qualified Local Namespace}.
For more information about directory imports, please see the in-depth
documentation about \l{qtqml-syntax-directoryimports.html}{directory imports}.
-\section3 JavaScript Resource Imports
+\section2 JavaScript Resource Imports
JavaScript resources may be imported directly in a QML document. Every
JavaScript resource must have an identifier by which it is accessed.
@@ -226,7 +209,7 @@ import "<JavaScriptFile>" as <Identifier>
Note that the \c <Identifier> must be unique within a QML document, unlike the
local namespace qualifier which can be applied to module imports.
-\section4 JavaScript Resources from Modules
+\section3 JavaScript Resources from Modules
Javascript files can be provided by modules, by adding identifier
definitions to the \c qmldir file which specifies the module.
@@ -244,8 +227,8 @@ module by importing the module and using the identifier associated with a
declared resource:
\qml
-import QtQuick 2.0
-import projects.MyQMLProject.MyFunctions 1.0
+import QtQuick
+import projects.MyQMLProject.MyFunctions
Item {
Component.onCompleted: { SystemFunctions.cleanUp(); }
@@ -257,9 +240,9 @@ resource identifiers must be prefixed with the namespace qualifier in order
to be used:
\qml
-import QtQuick 2.0
-import projects.MyQMLProject.MyFunctions 1.0 as MyFuncs
-import org.example.Functions 1.0 as TheirFuncs
+import QtQuick
+import projects.MyQMLProject.MyFunctions as MyFuncs
+import org.example.Functions as TheirFuncs
Item {
Component.onCompleted: {
@@ -269,7 +252,7 @@ Item {
}
\endqml
-\section4 Further Information
+\section3 Further Information
For more information about JavaScript resources, please see the documentation
about \l{qtqml-javascript-resources.html}
@@ -289,15 +272,28 @@ default locations to be searched by the engine. By default, this list contains:
\list
\li The directory of the current file
-\li The location specified by QLibraryInfo::Qml2ImportsPath
-\li Paths specified by the \c QML2_IMPORT_PATH environment variable
+\li The location specified by QLibraryInfo::QmlImportsPath
+\li Paths specified by the \c QML_IMPORT_PATH environment variable
\li The qrc:/qt-project.org/imports path inside the resources.
+\li The qrc:/qt/qml path inside the resources (since Qt 6.5).
\endlist
Additional import paths can be added through QQmlEngine::addImportPath() or the
-\c QML2_IMPORT_PATH environment variable. When running the
-\l{Prototyping with qmlscene}{qmlscene} tool, you can also use the \c -I option
-to add an import path.
+\c QML_IMPORT_PATH environment variable. When running the
+\l {Prototyping with the QML Runtime Tool}{qml tool}, you can also use the
+\c -I option to add an import path.
+
+You can specify multiple import paths in the \c QML_IMPORT_PATH environment
+variable by joining them using the path separator. On Windows the path separator
+is a semicolon (;), on other platforms it is a colon (:). This means that you
+cannot specify resource paths or URLs in QML_IMPORT_PATH, as they contain
+colons themselves. However, you can add resource paths and URLs by calling
+QQmlEngine::addImportPath() programatically.
+
+\note It is recommended that applications and libraries put their modules
+under "qrc:/qt/qml". This happens by default when the module is created
+with \l{qt_add_qml_module}{qt_add_qml_module()} and \l{QTP0001} is
+enabled.
\section1 Debugging
diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
index c4ecaf367c..2b1803042e 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-syntax-objectattributes.html
@@ -56,6 +32,7 @@ The set of QML object-type attribute types is as follows:
These attributes are discussed in detail below.
\section2 The \e id Attribute
+\keyword QML.id
Every QML object type has exactly one \e id attribute. This attribute is
provided by the language itself, and cannot be redefined or overridden by any
@@ -73,7 +50,7 @@ by referring to \c myTextInput.text. Now, both items will display the same
text:
\qml
-import QtQuick 2.0
+import QtQuick
Column {
width: 200; height: 200
@@ -112,7 +89,7 @@ Alternatively, a custom property of an object type may be defined in
an object declaration in a QML document with the following syntax:
\code
- [default] property <propertyType> <propertyName>
+ [default] [required] [readonly] property <propertyType> <propertyName>
\endcode
In this way an object declaration may \l {Defining Object Types from QML}
@@ -121,10 +98,13 @@ state more easily.
Property names must begin with a lower case letter and can only contain
letters, numbers and underscores. \l {JavaScript Reserved Words}
-{JavaScript reserved words} are not valid property names. The \c default
-keyword is optional, and modifies the semantics of the property being declared.
-See the upcoming section on \l {Default Properties}{default properties} for
-more information about the \c default property modifier.
+{JavaScript reserved words} are not valid property names. The \c default,
+\c required, and \c readonly keywords are optional, and modify the semantics
+of the property being declared.
+See the upcoming sections on \l {Default Properties}{default properties},
+\l {Required Properties}{required properties} and,
+\l {Read-Only Properties}{read-only properties} for more information
+about their respective meaning.
Declaring a custom property implicitly creates a value-change
\l{Signal attributes}{signal} for that property, as well as an associated
@@ -147,7 +127,7 @@ Rectangle {
\section4 Valid Types in Custom Property Definitions
-Any of the \l {QML Basic Types} aside from the \l enumeration type can be used
+Any of the \l {QML Value Types} aside from the \l enumeration type can be used
as custom property types. For example, these are all valid property declarations:
\qml
@@ -161,11 +141,11 @@ Item {
(Enumeration values are simply whole number values and can be referred to with
the \l int type instead.)
-Some basic types are provided by the \c QtQuick module and thus cannot be used
-as property types unless the module is imported. See the \l {QML Basic Types}
+Some value types are provided by the \c QtQuick module and thus cannot be used
+as property types unless the module is imported. See the \l {QML Value Types}
documentation for more details.
-Note the \l var basic type is a generic placeholder type that can hold any
+Note the \l var value type is a generic placeholder type that can hold any
type of value, including lists and objects:
\code
@@ -220,7 +200,7 @@ definition becomes:
An example of property value initialization follows:
\qml
-import QtQuick 2.0
+import QtQuick
Rectangle {
color: "red"
@@ -242,7 +222,7 @@ assignment operator, as shown below:
An example of imperative value assignment follows:
\qml
-import QtQuick 2.0
+import QtQuick
Rectangle {
id: rect
@@ -282,7 +262,7 @@ also known as \l{Property Binding}{property bindings}.
Here is an example that shows both kinds of values being assigned to properties:
\qml
-import QtQuick 2.0
+import QtQuick
Rectangle {
// both of these are static value assignments on initialization
@@ -326,7 +306,7 @@ even though properties of the \c color type store colors and not strings,
you are able to assign the string \c "red" to a color property, without an
error being reported.
-See \l {QML Basic Types} for a list of the types of properties that are
+See \l {QML Value Types} for a list of the types of properties that are
supported by default. Additionally, any available \l {QML Object Types}
{QML object type} may also be used as a property type.
@@ -347,7 +327,7 @@ used to hold a list of \l State type objects. The code below initializes the
value of this property to a list of three \l State objects:
\qml
-import QtQuick 2.0
+import QtQuick
Item {
states: [
@@ -361,7 +341,7 @@ Item {
If the list contains a single item, the square brackets may be omitted:
\qml
-import QtQuick 2.0
+import QtQuick
Item {
states: State { name: "running" }
@@ -372,20 +352,20 @@ A \l list type property may be specified in an object declaration with the
following syntax:
\code
- [default] property list<<objectType>> propertyName
+ [default] property list<<ObjectType>> propertyName
\endcode
and, like other property declarations, a property initialization may be
combined with the property declaration with the following syntax:
\code
- [default] property list<<objectType>> propertyName: <value>
+ [default] property list<<ObjectType>> propertyName: <value>
\endcode
An example of list property declaration follows:
\qml
-import QtQuick 2.0
+import QtQuick
Rectangle {
// declaration without initialization
@@ -427,11 +407,10 @@ Text {
}
\endcode
-Grouped property types are basic types which have subproperties. Some of these
-basic types are provided by the QML language, while others may only be used if
-the Qt Quick module is imported. See the documentation about
-\l{QML Basic Types} for more information.
-
+Grouped property types are types which have subproperties. If a grouped property
+type is an object type (as opposed to a value type), the property that holds it
+must be read-only. This is to prevent you from replacing the object the
+subproperties belong to.
\section3 Property Aliases
@@ -464,22 +443,24 @@ Unlike an ordinary property, an alias has the following restrictions:
must be provided when the alias is first declared.
\li It cannot refer to \l {Attached Properties and Attached Signal Handlers}
{attached properties}.
-\li It cannot refer to grouped properties; the following code will not work:
+\li It cannot refer to properties inside a hierarchy with depth 3 or greater. The
+ following code will not work:
\code
- property alias color: rectangle.border.color
+ property alias color: myItem.myRect.border.color
- Rectangle {
- id: rectangle
+ Item {
+ id: myItem
+ property Rectangle myRect
}
\endcode
- However, aliases to \l {QML Basic Types}{value type} properties do work:
+ However, aliases to properties that are up to two levels deep will work.
+
\code
- property alias rectX: object.rectProperty.x
+ property alias color: rectangle.border.color
- Item {
- id: object
- property rect rectProperty
+ Rectangle {
+ id: rectangle
}
\endcode
\endlist
@@ -489,7 +470,7 @@ which is connected to the \c text object of the \l Text child:
\qml
// Button.qml
-import QtQuick 2.0
+import QtQuick
Rectangle {
property alias buttonText: textItem.text
@@ -517,16 +498,6 @@ the other way around.
\section4 Considerations for Property Aliases
-Aliases are only activated once a component has been fully initialized. An
-error is generated when an uninitialized alias is referenced. Likewise,
-aliasing an aliasing property will also result in an error.
-
-\snippet qml/properties.qml alias complete
-
-When importing a \l{QML Object Types}{QML object type} with a property alias in
-the root object, however, the property appear as a regular Qt property and
-consequently can be used in alias references.
-
It is possible for an aliasing property to have the same name as an existing
property, effectively overwriting the existing property. For example,
the following QML type has a \c color alias property, named the same as the
@@ -604,12 +575,12 @@ property \c someText:
\qml
// MyLabel.qml
-import QtQuick 2.0
+import QtQuick
Text {
default property var someText
- text: "Hello, " + someText.text
+ text: `Hello, ${someText.text}`
}
\endqml
@@ -640,10 +611,73 @@ This is because the default property of \l Item is its \c data property, and
any items added to this list for an \l Item are automatically added to its
list of \l {Item::children}{children}.
-Default properties can be useful for reassigning the children of an item. See
-the \l{TabWidget Example}, which uses a default property to
-automatically reassign children of the TabWidget as children of an inner
-ListView. See also \l {Extending QML}.
+Default properties can be useful for reassigning the children of an item.
+For example:
+
+\qml
+Item {
+ default property alias content: inner.children
+
+ Item {
+ id: inner
+ }
+}
+\endqml
+
+By setting the default property \e alias to \c {inner.children}, any object
+assigned as a child of the outer item is automatically reassigned as a child
+of the inner item.
+
+\warning Setting the values of a an element's default list property can be done implicitly or
+explicitly. Within a single element's definition, these two methods must not be mixed as that leads
+to undefined ordering of the elements in the list.
+
+\qml
+Item {
+ // Use either implicit or explicit assignement to the default list property but not both!
+ Rectangle { width: 40 } // implicit
+ data: [ Rectangle { width: 100 } ] // explicit
+}
+\endqml
+
+\section3 Required Properties
+
+An object declaration may define a property as required, using the \c required
+keyword. The syntax is
+\code
+ required property <propertyType> <propertyName>
+\endcode
+
+As the name suggests, required properties must be set when an instance of the object
+is created. Violation of this rule will result in QML applications not starting if it can be
+detected statically. In case of dynamically instantiated QML components (for instance via
+\l {QtQml::Qt::createComponent()}{Qt.createComponent()}), violating this rule results in a
+warning and a null return value.
+
+It's possible to make an existing property required with
+\code
+ required <propertyName>
+\endcode
+The following example shows how to create a custom Rectangle component, in which the color
+property always needs to be specified.
+\qml
+// ColorRectangle.qml
+Rectangle {
+ required color
+}
+\endqml
+
+\note You can't assign an initial value to a required property from QML, as that would go
+directly against the intended usage of required properties.
+
+Required properties play a special role in model-view-delegate code:
+If the delegate of a view has required properties whose names match with
+the role names of the view's model, then those properties will be initialized
+with the model's corresponding values.
+For more information, visit the \l{Models and Views in Qt Quick} page.
+
+See \l{QQmlComponent::createWithInitialProperties}, \l{QQmlApplicationEngine::setInitialProperties}
+and \l{QQuickView::setInitialProperties} for ways to initialize required properties from C++.
\section3 Read-Only Properties
@@ -651,12 +685,12 @@ An object declaration may define a read-only property using the \c readonly
keyword, with the following syntax:
\code
- readonly property <propertyType> <propertyName> : <initialValue>
+ readonly property <propertyType> <propertyName> : <value>
\endcode
-Read-only properties must be assigned a value on initialization. After a
-read-only property is initialized, it no longer possible to give it a value,
-whether from imperative code or otherwise.
+Read-only properties must be assigned a static value or a binding expression on
+initialization. After a read-only property is initialized, you cannot change
+its static value or binding expression anymore.
For example, the code in the \c Component.onCompleted block below is invalid:
@@ -664,7 +698,7 @@ For example, the code in the \c Component.onCompleted block below is invalid:
Item {
readonly property int someNumber: 10
- Component.onCompleted: someNumber = 20 // doesn't work, causes an error
+ Component.onCompleted: someNumber = 20 // TypeError: Cannot assign to read-only property
}
\endqml
@@ -686,6 +720,8 @@ with a particular property is as follows:
}
\endcode
+This is commonly referred to as "on" syntax.
+
It is important to note that the above syntax is in fact an
\l{qtqml-syntax-basics.html#object-declarations}{object declaration} which
will instantiate an object which acts on a pre-existing property.
@@ -721,7 +757,7 @@ For example, the \e onClicked signal handler below is declared within the
clicked, causing a console message to be printed:
\qml
-import QtQuick 2.0
+import QtQuick
Item {
width: 100; height: 100
@@ -743,7 +779,7 @@ signal for an object type may be defined in an object declaration in a QML
document with the following syntax:
\code
- signal <signalName>[([<type> <parameter name>[, ...]])]
+ signal <signalName>[([<parameterName>: <parameterType>[, ...]])]
\endcode
Attempting to declare two signals or methods with the same name in the same
@@ -754,17 +790,26 @@ may be hidden and become inaccessible.)
Here are three examples of signal declarations:
\qml
-import QtQuick 2.0
+import QtQuick
Item {
signal clicked
signal hovered()
- signal actionPerformed(string action, var actionResult)
+ signal actionPerformed(action: string, actionResult: int)
}
\endqml
+You can also specify signal parameters in property style syntax:
+
+\qml
+signal actionCanceled(string action)
+\endqml
+
+In order to be consistent with method declarations, you should prefer the
+type declarations using colons.
+
If the signal has no parameters, the "()" brackets are optional. If parameters
-are used, the parameter types must be declared, as for the \c string and \c var
+are used, the parameter types must be declared, as for the \c string and \c int
arguments for the \c actionPerformed signal above. The allowed parameter types
are the same as those listed under \l {Defining Property Attributes} on this page.
@@ -800,7 +845,7 @@ the \c SquareButton.qml file as shown below, with signals \c activated and
Rectangle {
id: root
- signal activated(real xPosition, real yPosition)
+ signal activated(xPosition: real, yPosition: real)
signal deactivated
property int side: 100
@@ -808,8 +853,8 @@ Rectangle {
MouseArea {
anchors.fill: parent
- onPressed: root.activated(mouse.x, mouse.y)
onReleased: root.deactivated()
+ onPressed: mouse => root.activated(mouse.x, mouse.y)
}
}
\endqml
@@ -821,11 +866,17 @@ provided by the client:
\qml
// myapplication.qml
SquareButton {
- onActivated: console.log("Activated at " + xPosition + "," + yPosition)
onDeactivated: console.log("Deactivated!")
+ onActivated: (xPosition, yPosition) => {
+ console.log(`Activated at ${xPosition}, ${yPosition}`)
+ }
}
\endqml
+Signal handlers don't have to declare their parameter types because the signal
+already specifies them. The arrow function syntax shown above does not support
+type annotations.
+
See the \l {Signal and Handler Event System} for more details on use of
signals.
@@ -840,12 +891,12 @@ implicitly available through the fact that \l TextInput has a
\c onTextChanged signal handler to be called whenever this property changes:
\qml
-import QtQuick 2.0
+import QtQuick
TextInput {
text: "Change this!"
- onTextChanged: console.log("Text has changed to:", text)
+ onTextChanged: console.log(`Text has changed to: ${text}`)
}
\endqml
@@ -865,7 +916,7 @@ registering it as a Q_SLOT of the class. Alternatively, a custom method can
be added to an object declaration in a QML document with the following syntax:
\code
- function <functionName>([<parameterName>[, ...]]) { <body> }
+ function <functionName>([<parameterName>[: <parameterType>][, ...]]) [: <returnType>] { <body> }
\endcode
Methods can be added to a QML type in order to define standalone, reusable
@@ -873,7 +924,8 @@ blocks of JavaScript code. These methods can be invoked either internally or
by external objects.
Unlike signals, method parameter types do not have to be declared as they
-default to the \c var type.
+default to the \c var type. You should, however, declare them in order to
+help qmlcachegen generate more performant code, and to improve maintainability.
Attempting to declare two methods or signals with the same name in the same
type block is an error. However, a new method may reuse the name of an existing
@@ -884,11 +936,11 @@ Below is a \l Rectangle with a \c calculateHeight() method that is called when
assigning the \c height value:
\qml
-import QtQuick 2.0
+import QtQuick
Rectangle {
id: rect
- function calculateHeight() {
+ function calculateHeight(): real {
return rect.width / 2;
}
@@ -903,20 +955,20 @@ can then refer to the received \c newX and \c newY parameters to reposition the
text:
\qml
-import QtQuick 2.0
+import QtQuick
Item {
width: 200; height: 200
MouseArea {
anchors.fill: parent
- onClicked: label.moveTo(mouse.x, mouse.y)
+ onClicked: mouse => label.moveTo(mouse.x, mouse.y)
}
Text {
id: label
- function moveTo(newX, newY) {
+ function moveTo(newX: real, newY: real) {
label.x = newX;
label.y = newY;
}
@@ -955,7 +1007,7 @@ ListView. This can be used by each individual delegate object to determine
whether it is the currently selected item in the view:
\qml
-import QtQuick 2.0
+import QtQuick
ListView {
width: 240; height: 320
@@ -979,15 +1031,16 @@ been fully created, its \c Component.onCompleted signal handler will
automatically be invoked to populate the model:
\qml
-import QtQuick 2.0
+import QtQuick
ListView {
width: 240; height: 320
model: ListModel {
id: listModel
Component.onCompleted: {
- for (var i = 0; i < 10; i++)
- listModel.append({"Name": "Item " + i})
+ for (let i = 0; i < 10; i++) {
+ append({ Name: `Item ${i}` })
+ }
}
}
delegate: Text { text: index }
@@ -1012,7 +1065,7 @@ attached properties. This time, the delegate is an \l Item and the colored
\l Rectangle is a child of that item:
\qml
-import QtQuick 2.0
+import QtQuick
ListView {
width: 240; height: 320
@@ -1022,7 +1075,7 @@ ListView {
Rectangle {
width: 100; height: 30
- color: ListView.isCurrentItem ? "red" : "yellow" // WRONG! This won't work.
+ color: ListView.isCurrentItem ? "red" : "yellow" // WRONG! This won't work.
}
}
}
@@ -1037,14 +1090,13 @@ it cannot access the \c isCurrentItem attached property as
\qml
ListView {
- //....
delegate: Item {
id: delegateItem
width: 100; height: 30
Rectangle {
width: 100; height: 30
- color: delegateItem.ListView.isCurrentItem ? "red" : "yellow" // correct
+ color: delegateItem.ListView.isCurrentItem ? "red" : "yellow" // correct
}
}
}
@@ -1081,12 +1133,12 @@ Text {
property int textType: MyText.TextType.Normal
- font.bold: textType == MyText.TextType.Heading
- font.pixelSize: textType == MyText.TextType.Heading ? 24 : 12
+ font.bold: textType === MyText.TextType.Heading
+ font.pixelSize: textType === MyText.TextType.Heading ? 24 : 12
}
\endqml
-More information on enumeration usage in QML can be found in the \l {QML Basic Types} \l enumeration documentation.
+More information on enumeration usage in QML can be found in the \l {QML Value Types} \l enumeration documentation.
The ability to declare enumerations in QML was introduced in Qt 5.10.
diff --git a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
index e607666886..65e3b95f8e 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-syntax-propertybinding.html
diff --git a/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc b/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc
index cd73ccc025..b40181b49c 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/signals.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-syntax-signals.html
@@ -59,9 +35,9 @@ receiving this signal should be \c onClicked. In the example below, whenever
the button is clicked, the \c onClicked handler is invoked, applying a random
color to the parent \l Rectangle:
-\qml \QtMinorVersion
-import QtQuick 2.\1
-import QtQuick.Controls 2.\1
+\qml
+import QtQuick
+import QtQuick.Controls
Rectangle {
id: rect
@@ -78,6 +54,13 @@ Rectangle {
}
\endqml
+\note Even though signal handlers look a bit like JavaScript functions, you
+ should not call them directly. If you need to share code between signal
+ handlers and other functionality, refactor it into a separate function.
+ Otherwise always emit the signal if you want the signal handler to be
+ called. There can be multiple handlers, in different scopes, for the
+ same signal.
+
\section2 Property change signal handlers
A signal is automatically emitted when the value of a QML property changes.
@@ -85,10 +68,12 @@ This type of signal is a \e {property change signal} and signal handlers for
these signals are written in the form \e on<Property>Changed, where
\e <Property> is the name of the property, with the first letter capitalized.
-For example, the \l MouseArea type has a \l {MouseArea::pressed}{pressed} property. To receive a notification whenever this property changes, write a signal handler named \c onPressedChanged:
+For example, the \l MouseArea type has a \l {MouseArea::pressed}{pressed} property.
+To receive a notification whenever this property changes, write a signal handler
+named \c onPressedChanged:
-\qml \QtMinorVersion
-import QtQuick 2.\1
+\qml
+import QtQuick
Rectangle {
id: rect
@@ -104,6 +89,56 @@ Even though the \l TapHandler documentation does not document a signal handler
named \c onPressedChanged, the signal is implicitly provided by the fact that
the \c pressed property exists.
+\section2 Signal parameters
+
+Signals might have parameters. To access those, you should assign a function to the handler. Both
+arrow functions and anonymous functions work.
+
+For the following examples, consider a Status component with an errorOccurred signal (see
+\l{Adding signals to custom QML types} for more information about how signals can be added to
+QML components).
+
+\qml
+// Status.qml
+import QtQuick
+
+Item {
+ id: myitem
+
+ signal errorOccurred(message: string, line: int, column: int)
+}
+\endqml
+
+\qml
+Status {
+ onErrorOccurred: (mgs, line, col) => console.log(`${line}:${col}: ${msg}`)
+}
+\endqml
+
+\note The names of the formal parameters in the function do not have to match those in the
+signal.
+
+If you do not need to handle all parameters, it is possible to omit trailing ones:
+\qml
+Status {
+ onErrorOccurred: message => console.log(message)
+}
+\endqml
+
+It is not possible to leave out leading parameters you are interested in, however you can use some
+placeholder name to indicate to readers that they are not important:
+\qml
+Status {
+ onErrorOccurred: (_, _, col) => console.log(`Error happened at column ${col}`)
+}
+\endqml
+
+\note Instead of using a function, it is possible, but discouraged, to use a plain code block. In
+that case all signal parameters get injected into the scope of the block. However, this can make
+code difficult to read as it's unclear where the parameters come from, and results in slower
+lookups in the QML engine. Injecting parameters in this way is deprecated, and will cause runtime
+warnings if the parameter is actually used.
+
\section2 Using the Connections type
In some cases it may be desirable to access a signal outside of the object that
@@ -116,9 +151,9 @@ received by the root \l Rectangle instead, by placing the \c onClicked handler
in a \l Connections object that has its \l {Connections::target}{target} set to
the \c button:
-\qml \QtMinorVersion
-import QtQuick 2.\1
-import QtQuick.Controls 2.\1
+\qml
+import QtQuick
+import QtQuick.Controls
Rectangle {
id: rect
@@ -133,7 +168,7 @@ Rectangle {
Connections {
target: button
- onClicked: {
+ function onClicked() {
rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
}
}
@@ -151,8 +186,8 @@ For example, \l{Component::completed}{Component.onCompleted} is an attached
signal handler. It is often used to execute some JavaScript code when its
creation process is complete. Here is an example:
-\qml \QtMinorVersion
-import QtQuick 2.\1
+\qml
+import QtQuick
Rectangle {
width: 200; height: 200
@@ -195,9 +230,9 @@ root \l Rectangle object has an \c activated signal, which is emitted whenever t
child \l TapHandler is \c tapped. In this particular example the activated signal
is emitted with the x and y coordinates of the mouse click:
-\qml \QtMinorVersion
+\qml
// SquareButton.qml
-import QtQuick 2.\1
+import QtQuick
Rectangle {
id: root
@@ -209,8 +244,8 @@ Rectangle {
TapHandler {
id: handler
- onTapped: root.activated(mouseXY.x, mouseXY.y)
- onPressedChanged: mouseXY = handler.point.position
+ onTapped: root.activated(root.mouseXY.x, root.mouseXY.y)
+ onPressedChanged: root.mouseXY = handler.point.position
}
}
\endqml
@@ -220,7 +255,7 @@ Now any objects of the \c SquareButton can connect to the \c activated signal us
\qml
// myapplication.qml
SquareButton {
- onActivated: console.log("Activated at " + xPosition + "," + yPosition)
+ onActivated: (xPosition, yPosition) => console.log(`Activated at {xPosition}, ${yPosition}`)
}
\endqml
@@ -237,8 +272,8 @@ signal to be received by a method instead of a signal handler.
Below, the \c messageReceived signal is connected to three methods using the \c connect() method:
-\qml \QtMinorVersion
-import QtQuick 2.\1
+\qml
+import QtQuick
Rectangle {
id: relay
@@ -252,14 +287,14 @@ Rectangle {
relay.messageReceived("Tom", "Happy Birthday")
}
- function sendToPost(person, notice) {
- console.log("Sending to post: " + person + ", " + notice)
+ function sendToPost(person: string, notice: string) {
+ console.log(`Sending to post: ${person}, ${notice}`)
}
- function sendToTelegraph(person, notice) {
- console.log("Sending to telegraph: " + person + ", " + notice)
+ function sendToTelegraph(person: string, notice: string) {
+ console.log(`Sending to telegraph: ${person}, ${notice}`)
}
- function sendToEmail(person, notice) {
- console.log("Sending to email: " + person + ", " + notice)
+ function sendToEmail(person: string, notice: string) {
+ console.log(`Sending to email: ${person}, ${notice}`)
}
}
\endqml
@@ -289,8 +324,8 @@ Rectangle {
By connecting signals to other signals, the \c connect() method can form different
signal chains.
-\qml \QtMinorVersion
-import QtQuick 2.\1
+\qml
+import QtQuick
Rectangle {
id: forwarder
@@ -320,4 +355,65 @@ output:
MouseArea clicked
Send clicked
\endcode
-*/
+
+\note Connections to function objects will stay alive as long as the sender of the signal is alive.
+This behavior is analogous to the 3-argument version of QObject::connect() in C++.
+
+\qml
+Window {
+ visible: true
+ width: 400
+ height: 400
+
+ Item {
+ id: item
+ property color globalColor: "red"
+
+ Button {
+ text: "Change global color"
+ onPressed: {
+ item.globalColor = item.globalColor === Qt.color("red") ? "green" : "red"
+ }
+ }
+
+ Button {
+ x: 150
+ text: "Clear rectangles"
+ onPressed: repeater.model = 0
+ }
+
+ Repeater {
+ id: repeater
+ model: 5
+ Rectangle {
+ id: rect
+ color: "red"
+ width: 50
+ height: 50
+ x: (width + 2) * index + 2
+ y: 100
+ Component.onCompleted: {
+ if (index % 2 === 0) {
+ item.globalColorChanged.connect(() => {
+ color = item.globalColor
+ })
+ }
+ }
+ }
+ }
+ }
+}
+\endqml
+
+In the contrived example above, the goal is to flip the color of every even rectangle to follow
+some global color. To achieve this, for every even rectangle, a connection is made between the
+globalColorChanged signal and a function to set the rectangle's color. This works as expected while
+the rectangles are alive. However, once the clear button is pressed, the rectangles are gone but
+the function handling the signal is still called every time the signal is emitted. This can be
+seen by the error messages thrown by the function trying to run in the background when changing
+the global color.
+
+In the current setup, the connections would only be destroyed once the item holding
+globalColor is destroyed. To prevent the connections from lingering on, they can be explicitly
+disconnected when the rectangles are being destroyed.
+ */
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
index 5144fe219e..e0929f2879 100644
--- a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
@@ -1,681 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-typesystem-basictypes.html
\title QML Basic Types
-\brief Description of basic types provided by the Qt QML module
+\keyword QML Basic Types
+\brief QML Value Types used to be called "Basic Types"
-QML supports a number of basic types.
-
-A \e{basic type} is one that refers to a simple value, such as an \c int
-or a \c string. This contrasts with a \l{qtqml-typesystem-topic.html#qml-object-types}{QML Object Types},
-which refers to an object with properties, signals, methods and so on. Unlike an object type,
-a basic type cannot be used to declare QML objects: it is not possible, for example, to declare an
-\c int{} object or a \c size{} object.
-
-Basic types can be used to refer to:
-
-\list
-\li A single value (e.g. \l int refers to a single number, \l var can refer to a single list of items)
-\li A value that contains a simple set of property-value pairs (e.g. \l size refers to a value with \c width and \c height attributes)
-\endlist
-
-When a variable or property holds a basic type and it is assigned to another
-variable or property, then a copy of the value is made. In JavaScript, this
-value is called a primitive value.
-
-\sa {qtqml-typesystem-topic.html}{The QML Type System}
-
-
-\section1 Supported Basic Types
-
-Some basic types are supported by the engine by default and do not require an
-\l {Import Statements}{import statement} to be used, while others do require
-the client to import the module which provides them.
-All of the basic types listed below may be used as a \c property type in a QML
-document, with the following exceptions:
-\list
- \li \c list must be used in conjunction with a QML object type
- \li \c enumeration cannot be used directly as the enumeration must be defined by a registered QML object type
-\endlist
-
-\section2 Basic Types Provided By The QML Language
-
-The basic types supported natively in the QML language are listed below:
-\annotatedlist qmlbasictypes
-
-\section2 Basic Types Provided By QML Modules
-
-QML modules may extend the QML language with more basic types.
-For example, the basic types provided by the \c QtQuick module are listed below:
-\annotatedlist qtquickbasictypes
-
-The \l{QtQml::Qt}{Qt} global object provides useful functions for manipulating values of basic types.
-
-Currently only QML modules which are provided by Qt may provide their
-own basic types, however this may change in future releases of Qt QML.
-In order to use types provided by a particular QML module, clients
-must import that module in their QML documents.
-
-\section1 Property Change Behavior for Basic Types
-
-Some basic types have properties: for example, the \l font type has
-\c pixelSize, \c family and \c bold properties. Unlike properties of
-\l{qtqml-typesystem-topic.html#qml-object-types}{object types}, properties of
-basic types do not provide their own property change signals. It is only possible
-to create a property change signal handler for the basic type property itself:
-
-\code
-Text {
- // invalid!
- onFont.pixelSizeChanged: doSomething()
-
- // also invalid!
- font {
- onPixelSizeChanged: doSomething()
- }
-
- // but this is ok
- onFontChanged: doSomething()
-}
-\endcode
-
-Be aware, however, that a property change signal for a basic type is emitted
-whenever \e any of its attributes have changed, as well as when the property itself
-changes. Take the following code, for example:
-
-\qml
-Text {
- onFontChanged: console.log("font changed")
-
- Text { id: otherText }
-
- focus: true
-
- // changing any of the font attributes, or reassigning the property
- // to a different font value, will invoke the onFontChanged handler
- Keys.onDigit1Pressed: font.pixelSize += 1
- Keys.onDigit2Pressed: font.b = !font.b
- Keys.onDigit3Pressed: font = otherText.font
-}
-\endqml
-
-In contrast, properties of an \l{qtqml-typesystem-topic.html#qml-object-types}{object type}
-emit their own property change signals, and a property change signal handler for an object-type
-property is only invoked when the property is reassigned to a different object value.
-
-*/
-
-/*!
- \qmlbasictype int
- \ingroup qmlbasictypes
- \brief a whole number, e.g. 0, 10, or -20.
-
- The \c int type refers to a whole number, e.g. 0, 10, or -20.
-
- The possible \c int values range from around -2000000000 to around 2000000000,
- although most types will only accept a reduced range (which they
- mention in their documentation).
-
- Example:
- \qml
- Item { width: 100; height: 200 }
- \endqml
-
- This basic type is provided by the QML language.
-
- \sa {QML Basic Types}
-*/
-
-/*!
- \qmlbasictype bool
- \ingroup qmlbasictypes
- \brief a binary true/false value.
-
- The \c bool type refers to a binary true/false value.
-
- Example:
- \qml
- Item {
- focus: true
- clip: false
- }
- \endqml
-
- This basic type is provided by the QML language.
-
- \sa {QML Basic Types}
-*/
-
-/*!
- \qmlbasictype real
- \ingroup qmlbasictypes
-
- \brief a number with a decimal point.
-
- The \c real type refers to a number with decimal point, e.g. 1.2 or -29.8.
-
- Example:
- \qml
- Item { width: 100.45; height: 150.82 }
- \endqml
-
- \b{Note:} In QML all reals are stored in double precision, \l
- {http://en.wikipedia.org/wiki/IEEE_754} {IEEE floating point}
- format.
-
- This basic type is provided by the QML language.
-
- \sa {QML Basic Types}
-*/
-
-/*!
- \qmlbasictype double
- \ingroup qmlbasictypes
-
- \brief a number with a decimal point, stored in double precision.
-
- The \c double type refers to a number with a decimal point and is stored in double precision, \l
- {http://en.wikipedia.org/wiki/IEEE_754} {IEEE floating point} format.
-
- Example:
- \qml
- Item {
- property double number: 32155.2355
- }
- \endqml
-
- This basic type is provided by the QML language.
-
- \sa {QML Basic Types}
-*/
-
-/*!
- \qmlbasictype string
- \ingroup qmlbasictypes
- \brief a free form text string.
-
- The \c string type refers to a free form text string in quotes, e.g. "Hello world!".
-
- Example:
- \qml
- Text { text: "Hello world!" }
- \endqml
-
- Strings have a \c length attribute that holds the number of
- characters in the string.
-
- QML extends the JavaScript String type with a \l {String::arg}{arg()} function
- to support value substitution.
-
- When integrating with C++, note that any QString value
- \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
- converted into a \c string value, and vice-versa.
-
- This basic type is provided by the QML language.
-
- \sa {QML Basic Types}
-*/
-
-/*!
- \qmlbasictype url
- \ingroup qmlbasictypes
- \brief a resource locator.
-
- The \c url type refers to a resource locator (like a file name, for example). It can be either
- absolute, e.g. "http://qt-project.org", or relative, e.g. "pics/logo.png". A relative URL is
- resolved relative to the URL of the containing component.
-
- For example, the following assigns a valid URL to the \l {Image::source}
- property, which is of type \c url:
-
- \qml
- Image { source: "pics/logo.png" }
- \endqml
-
- When integrating with C++, note that any QUrl value
- \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
- converted into a \c url value, and vice-versa.
-
-
- \section1 Using the url Type
-
- When a relative URL is written to a \c url type property, it is converted
- into a URL object, so \b {matching the URL value against the input string
- value will fail}. Instead, convert the string to a URL using Qt.resolvedUrl()
- for means of comparison, and use \c toString() to get the contents of the URL:
-
- \qml
- Image {
- source: "pics/logo.png"
-
- Component.onCompleted: {
- // This prints 'false'. Although "pics/logo.png" was the input string,
- // it's been converted from a string to a URL, so these two are not the same.
- console.log(source == "pics/logo.png")
-
- // This prints 'true' as Qt.resovledUrl() converts the string into a
- // URL with the correctly resolved path
- console.log(source == Qt.resolvedUrl("pics/logo.png"))
-
- // This prints the absolute path, e.g. "file:///path/to/pics/logo.png"
- console.log(source.toString())
- }
- }
- \endqml
-
- \note When referring to files stored with the \l{resources.html}{Qt Resource System}
- from within QML, you should use "qrc:///" instead of ":/" as QML requires URL paths.
- Relative URLs resolved from within that file will use the same protocol.
-
- Additionally, URLs may contain encoded characters using the 'percent-encoding' scheme
- specified by \l {http://tools.ietf.org/html/rfc3986}{RFC 3986}. These characters
- will be preserved within properties of type \c url, to allow QML code to
- construct precise URL values. An exception to this rule is the preemptive
- decoding of directory-separator characters (\c '/') - these characters are decoded
- to allow the URL to be correctly classified.
-
- For example, a local file containing a '#' character, which would normally be
- interpreted as the beginning of the URL 'fragment' element, can be accessed by
- encoding the characters of the file name:
-
- \qml
- Image { source: encodeURIComponent("/tmp/test#1.png") }
- \endqml
-
- This basic type is provided by the QML language.
-
- \sa {QML Basic Types}
-*/
-
-
-/*!
- \qmlbasictype list
- \ingroup qmlbasictypes
- \brief a list of QML objects.
-
- The \c list type refers to a list of QML objects.
-
- A list value can be accessed in a similar way to a JavaScript array:
-
- \list
- \li Values are assigned using the \c[] square bracket syntax with comma-separated values
- \li The \c length property provides the number of items in the list
- \li Values in the list are accessed using the \c [index] syntax
- \endlist
-
- Values can be dynamically added to the list by using the \c push method,
- as if it were a JavaScript Array
-
- A \c list can only store QML objects, and cannot contain any
- \l {QML Basic Types}{basic type} values. (To store basic types within a
- list, use the \l var type instead.)
-
- When integrating with C++, note that any QQmlListProperty value
- \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
- converted into a \c list value, and vice-versa.
-
-
- \section1 Using the list Type
-
- For example, the \l Item type has a \l {Item::}{states} list-type property that
- can be assigned to and used as follows:
-
- \qml
- import QtQuick 2.0
-
- Item {
- width: 100; height: 100
-
- states: [
- State { name: "activated" },
- State { name: "deactivated" }
- ]
-
- Component.onCompleted: {
- console.log("Name of first state:", states[0].name)
- for (var i = 0; i < states.length; i++)
- console.log("state", i, states[i].name)
- }
- }
- \endqml
-
- The defined \l State objects will be added to the \c states list
- in the order in which they are defined.
-
- If the list only contains one object, the square brackets may be omitted:
-
- \qml
- import QtQuick 2.0
-
- Item {
- width: 100; height: 100
- states: State { name: "activated" }
- }
- \endqml
-
- Note that objects cannot be individually added to or removed from
- the list once created; to modify the contents of a list, it must be
- reassigned to a new list.
-
- \note The \c list type is not recommended as a type for custom properties.
- The \c var type should be used instead for this purpose as
- lists stored by the \c var type can be manipulated with greater
- flexibility from within QML.
-
- This basic type is provided by the QML language.
-
- \sa {QML Basic Types}
-*/
-
- /*!
- \qmlbasictype var
- \ingroup qmlbasictypes
- \brief a generic property type.
-
- The \c var type is a generic property type that can refer to any data type.
-
- It is equivalent to a regular JavaScript variable.
- For example, var properties can store numbers, strings, objects,
- arrays and functions:
-
- \qml
- Item {
- property var aNumber: 100
- property var aBool: false
- property var aString: "Hello world!"
- property var anotherString: String("#FF008800")
- property var aColor: Qt.rgba(0.2, 0.3, 0.4, 0.5)
- property var aRect: Qt.rect(10, 10, 10, 10)
- property var aPoint: Qt.point(10, 10)
- property var aSize: Qt.size(10, 10)
- property var aVector3d: Qt.vector3d(100, 100, 100)
- property var anArray: [1, 2, 3, "four", "five", (function() { return "six"; })]
- property var anObject: { "foo": 10, "bar": 20 }
- property var aFunction: (function() { return "one"; })
- }
- \endqml
-
- \section1 Change Notification Semantics
-
- It is important to note that changes in regular properties of JavaScript
- objects assigned to a var property will \b{not} trigger updates of bindings
- that access them. The example below will display "The car has 4 wheels" as
- the change to the wheels property will not cause the reevaluation of the
- binding assigned to the "text" property:
-
- \qml
- Item {
- property var car: new Object({wheels: 4})
-
- Text {
- text: "The car has " + car.wheels + " wheels";
- }
-
- Component.onCompleted: {
- car.wheels = 6;
- }
- }
- \endqml
-
- If the onCompleted handler instead had \tt{"car = new Object({wheels: 6})"}
- then the text would be updated to say "The car has 6 wheels", since the
- car property itself would be changed, which causes a change notification
- to be emitted.
-
- \section1 Property Value Initialization Semantics
-
- The QML syntax defines that curly braces on the right-hand-side of a
- property value initialization assignment denote a binding assignment.
- This can be confusing when initializing a \c var property, as empty curly
- braces in JavaScript can denote either an expression block or an empty
- object declaration. If you wish to initialize a \c var property to an
- empty object value, you should wrap the curly braces in parentheses.
-
- For example:
- \qml
- Item {
- property var first: {} // nothing = undefined
- property var second: {{}} // empty expression block = undefined
- property var third: ({}) // empty object
- }
- \endqml
-
- In the previous example, the \c first property is bound to an empty
- expression, whose result is undefined. The \c second property is bound to
- an expression which contains a single, empty expression block ("{}"), which
- similarly has an undefined result. The \c third property is bound to an
- expression which is evaluated as an empty object declaration, and thus the
- property will be initialized with that empty object value.
-
- Similarly, a colon in JavaScript can be either an object property value
- assignment, or a code label. Thus, initializing a var property with an
- object declaration can also require parentheses:
-
- \qml
- Item {
- property var first: { example: 'true' } // example is interpreted as a label
- property var second: ({ example: 'true' }) // example is interpreted as a property
- property var third: { 'example': 'true' } // example is interpreted as a property
- Component.onCompleted: {
- console.log(first.example) // prints 'undefined', as "first" was assigned a string
- console.log(second.example) // prints 'true'
- console.log(third.example) // prints 'true'
- }
- }
- \endqml
-
- \sa {QML Basic Types}
-*/
-/*
- TODO Qt 5.1: see explanation in expressions.qdoc
- \section1 Using Scarce Resources with the var Type
-
- A \c var type property can also hold an image or pixmap.
- A \c var which contains a QPixmap or QImage is known as a
- "scarce resource" and the declarative engine will attempt to
- automatically release such resources after evaluation of any JavaScript
- expression which requires one to be copied has completed.
-
- Clients may explicitly release such a scarce resource by calling the
- "destroy" method on the \c var property from within JavaScript. They
- may also explicitly preserve the scarce resource by calling the
- "preserve" method on the \c var property from within JavaScript.
-
- This basic type is provided by the QML language.
-*/
-
-/*!
- \obsolete
- \qmlbasictype variant
- \ingroup qmlbasictypes
- \brief a generic property type.
-
- The \c variant type is a generic property type. It is obsolete and exists only to
- support old applications; new applications should use \l var type
- properties instead.
-
- A variant type property can hold any of the \l {QML Basic Types}{basic type}
- values:
-
- \qml
- Item {
- property variant aNumber: 100
- property variant aString: "Hello world!"
- property variant aBool: false
- }
- \endqml
-
- When integrating with C++, note that any QVariant value
- \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
- converted into a \c variant value, and vice-versa.
-
-
- \section1 Using Scarce Resources with the variant Type
-
- A \c variant type property can also hold an image or pixmap.
- A \c variant which contains a QPixmap or QImage is known as a
- "scarce resource" and the declarative engine will attempt to
- automatically release such resources after evaluation of any JavaScript
- expression which requires one to be copied has completed.
-
- Clients may explicitly release such a scarce resource by calling the
- "destroy" method on the \c variant property from within JavaScript. They
- may also explicitly preserve the scarce resource by calling the
- "preserve" method on the \c variant property from within JavaScript.
-
- \section1 Storing Arrays and Objects
-
- The \c variant type can also hold:
-
- \list
- \li An array of \l {QML Basic Types}{basic type} values
- \li A map of key-value pairs with \l {QML Basic Types}{basic-type} values
- \endlist
-
- For example, below is an \c items array and an \c attributes map. Their
- contents can be examined using JavaScript \c for loops. Individual array
- values are accessible by index, and individual map values are accessible
- by key:
-
- \qml
- Item {
- property variant items: [1, 2, 3, "four", "five"]
- property variant attributes: { 'color': 'red', 'width': 100 }
-
- Component.onCompleted: {
- for (var i = 0; i < items.length; i++)
- console.log(items[i])
-
- for (var prop in attributes)
- console.log(prop, "=", attributes[prop])
- }
- }
- \endqml
-
- While this is a convenient way to store array and map-type values, you
- must be aware that the \c items and \c attributes properties above are \e not
- QML objects (and certainly not JavaScript object either) and the key-value
- pairs in \c attributes are \e not QML properties. Rather, the \c items
- property holds an array of values, and \c attributes holds a set of key-value
- pairs. Since they are stored as a set of values, instead of as an object,
- their contents \e cannot be modified individually:
-
- \qml
- Item {
- property variant items: [1, 2, 3, "four", "five"]
- property variant attributes: { 'color': 'red', 'width': 100 }
-
- Component.onCompleted: {
- items[0] = 10
- console.log(items[0]) // This will still be '1'!
- attributes.color = 'blue'
- console.log(attributes.color) // This will still be 'red'!
- }
- }
- \endqml
-
- Since it is not possible to individually add or remove items from a list or
- object stored in a \c variant, the only way to modify its contents is to
- reassign a new value. However, this is not efficient, as it causes the value
- to be serialized and deserialized.
-
- Additionally, since \c items and \c attributes are not QML objects, changing
- their individual values do not trigger property change notifications. If
- the above example had \c onNumberChanged or \c onAnimalChanged signal
- handlers, they would not have been called. If, however, the \c items or
- \c attributes properties themselves were reassigned to different values, then
- such handlers would be called.
-
- JavaScript programmers should also note that when a JavaScript object is
- copied to an array or map property, the \e contents of the object (that is,
- its key-value properties) are copied, rather than the object itself. The
- property does not hold a reference to the original JavaScript object, and
- extra data such as the object's JavaScript prototype chain is also lost in
- the process.
-
- This basic type is provided by the QML language.
-
- \sa {QML Basic Types}
-*/
-
-/*!
- \qmlbasictype enumeration
- \ingroup qmlbasictypes
- \brief a named enumeration value.
-
- The \c enumeration type refers to a named enumeration value.
-
- Each named value can be referred to as \c {<Type>.<value>}. For
- example, the \l Text type has an \c AlignRight enumeration value:
-
- \qml
- Text { horizontalAlignment: Text.AlignRight }
- \endqml
-
- (For backwards compatibility, the enumeration value may also be
- specified as a string, e.g. "AlignRight". This form is not
- recommended for new code.)
-
- When integrating with C++, note that any \c enum value
- \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
- converted into an \c enumeration value, and vice-versa.
-
- This basic type is provided by the QML language. Some enumeration values
- are provided by the QtQuick import.
-
- \section1 Using the enumeration Type in QML
-
- The \c enumeration type is a representation of a C++ \c enum type. It is
- not possible to refer to the \c enumeration type in QML itself; instead, the
- \l int or \l var types can be used when referring to \c enumeration values
- from QML code.
-
- For example:
-
- \qml
- import QtQuick 2.0
-
- Item {
- // refer to Text.AlignRight using an int type
- property int enumValue: textItem.horizontalAlignment
-
- signal valueEmitted(int someValue)
-
- Text {
- id: textItem
- horizontalAlignment: Text.AlignRight
- }
-
- // emit valueEmitted() signal, which expects an int, with Text.AlignRight
- Component.onCompleted: valueEmitted(Text.AlignRight)
- }
- \endqml
-
- \sa {QML Basic Types}
- \sa {qtqml-syntax-objectattributes.html#enumeration-attributes}{Enumeration Attributes}
+See \l{qtqml-typesystem-valuetypes.html} for the documentation of QML value types.
*/
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/namespaces.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/namespaces.qdoc
new file mode 100644
index 0000000000..0635dbd026
--- /dev/null
+++ b/src/qml/doc/src/qmllanguageref/typesystem/namespaces.qdoc
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+/*!
+\page qtqml-typesystem-namespaces.html
+\title QML Namespaces
+\brief Description of QML Namespaces
+
+A QML Namespace is a special kind of type that only exposes enumerations and cannot
+be instantiated. A namespace can only be declared in C++, using the \l QML_ELEMENT or
+\l QML_NAMED_ELEMENT macro inside a C++ namespace marked with \l{Q_NAMESPACE}.
+
+QML namespaces can be used to
+\l{qtqml-cppintegration-definetypes.html#value-types-with-enumerations}{extract enumerations}
+from other types.
+
+*/
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc
index 5f089b5ebc..d332617b16 100644
--- a/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-typesystem-objecttypes.html
\title QML Object Types
@@ -34,7 +10,7 @@ A QML object type is a type from which a QML object can be instantiated.
In syntactic terms, a QML object type is one which can be used to declare an
object by specifying the \e{type name} followed by a set of curly braces that
-encompasses the attributes of that object. This differs from \e {basic types},
+encompasses the attributes of that object. This differs from \e {value types},
which cannot be used in the same way. For example, \l Rectangle is a QML object
type: it can be used to create \c Rectangle type objects. This cannot be done
with primitive types such as \c int and \c bool, which are used to hold simple
@@ -48,6 +24,9 @@ and registering the type with the QML engine, as discussed in
Note that in both cases, the type name must begin with an uppercase letter in
order to be declared as a QML object type in a QML file.
+For more information about C++ and the different QML integration methods,
+see the
+\l {Overview - QML and C++ Integration} {C++ and QML integration overview} page.
\section1 Defining Object Types from QML
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/references.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/references.qdoc
new file mode 100644
index 0000000000..5326759638
--- /dev/null
+++ b/src/qml/doc/src/qmllanguageref/typesystem/references.qdoc
@@ -0,0 +1,53 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+/*!
+\page qtqml-typesystem-references.html
+\title QML Value Type and Sequence References
+\brief Description of QML value type and sequence references
+
+\l{QML Value Types} and \l{QML Sequence Types} are necessarily passed by value.
+In contrast to \l{QML Object Types} they have no identity of themselves, but can
+only be accessed as properties of other objects or values, or as values returned
+from methods. Each such access implicitly creates a copy. Yet, in JavaScript
+everything is an object. There is no such concept as a value type in JavaScript.
+For example, if you execute \c{font.bold = true} in JavaScript, we expect the \c bold
+property of \c font to be set, no matter what \c font is. But consider the following
+code snippet:
+
+\qml
+import QtQuick
+Text {
+ onSomethingHappened: font.bold = true
+}
+\endqml
+
+In this case we know that \c font is a value type. Accessing it creates a local copy
+by calling the getter of a \l{Q_PROPERTY}. We can then set the \c bold property on it,
+but that would usually only affect the copy, not the original \l{Q_PROPERTY}.
+
+To overcome this problem, QML offers the concept of references. When you retrieve
+an instance of a value or sequence type from a property, the QML engine remembers
+the property along with the value itself. If the value is modified, it is written
+back to the property. This produces the illusion of an object with separate identity
+and makes the above case, along with many others, just work.
+
+This can be rather expensive, though. If a sequence is exposed as a Q_PROPERTY,
+accessing any value in the sequence by index will cause the whole sequence data
+to be read from the property. From this sequence data, a single element is then
+retrieved. Similarly, modifying any value in the sequence causes the
+sequence data to be read. Then the modification is performed and the modified
+sequence is be written back to the property. A read operation can be relatively
+cheap if the type in question is implicitly shared. A modification always incurs
+at least one deep copy.
+
+If you return an instance of a sequence or value type from a \l Q_INVOKABLE function
+you avoid such overhead. Return values are not attached to any property and won't be
+written back.
+
+Sequences of object types are passed as \l{QQmlListProperty} by default.
+\l{QQmlListProperty} is not an actual container, but only a view, or reference, to
+some sequential storage. Therefore, \{QQmlListProperty} is not affected by this
+effect. You can, however, register other sequence types for objects using
+\l{QML_SEQUENTIAL_CONTAINER}. Those will be affected.
+
+*/
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/sequencetypes.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/sequencetypes.qdoc
new file mode 100644
index 0000000000..ca10f8c23b
--- /dev/null
+++ b/src/qml/doc/src/qmllanguageref/typesystem/sequencetypes.qdoc
@@ -0,0 +1,76 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+/*!
+\page qtqml-typesystem-sequencetypes.html
+\title QML Sequence Types
+\brief Description of QML sequence types
+
+For every \l{qtqml-typesystem-objecttypes.html}{object type} and
+\l{qtqml-typesystem-valuetypes.html}{value type} a sequence type for storing
+multiple instances of the type is automatically made available. You can use
+the \c list keyword to create properties of sequence types:
+
+\qml
+import QtQml
+
+QtObject {
+ property list<int> ints: [1, 2, 3, 4]
+ property list<Connection> connections: [
+ Connection {
+ // ...
+ },
+ Connection {
+ // ...
+ }
+ ]
+}
+\endqml
+
+Sequences of value types are implemented as \l{QList} and sequences of object
+types are implemented as \l{QQmlListProperty}.
+
+Sequences in QML generally behave like the JavaScript \c Array type, with some
+important differences which result from the use of a C++ storage type in the
+implementation:
+
+\list 1
+\li Deleting an element from a sequence will result in a default-constructed
+ value replacing that element, rather than an \c undefined value.
+\li Setting the \c length property of a sequence to a value larger
+ than its current value will result in the sequence being padded out to the
+ specified length with default-constructed elements rather than \c undefined
+ elements.
+\li The Qt container classes support signed (rather than
+ unsigned) integer indexes; thus, attempting to access any index greater
+ than the maximum number \l qsizetype can hold will fail.
+\endlist
+
+If you wish to remove elements from a sequence rather than simply replace
+them with default constructed values, do not use the indexed delete operator
+(\c{delete sequence[i]}) but instead use the \c {splice} function
+(\c{sequence.splice(startIndex, deleteCount)}).
+
+In general any container recognizable by \l QMetaSequence can be passed from
+C++ to QML via \l Q_PROPERTY or \l Q_INVOKABLE methods. This includes, but is
+not limited to, all registered QList, QQueue, QStack, QSet, std::list,
+std::vector that contain a type marked with \l Q_DECLARE_METATYPE.
+
+Using a sequence via \l QMetaSequence results in expensive data conversions.
+To avoid the conversions you can register your own anonymous sequence types
+using \l{QML_SEQUENTIAL_CONTAINER} from C++. Types registered this way behave
+like the pre-defined sequence types and are stored as-is. However, they have
+no QML names.
+
+\warning Sequences stored as a C++ container like \l QList or \c std::vector are
+subject to the effects caused by \l{QML Value Type and Sequence References} and
+should thus be handled with care. \l QQmlListProperty is not affected since
+it is only a view for an underlying container. C++ standard containers such as
+\c std::vector are not implicitly shared. Therefore, copying them always
+produces a deep copy. Since a sequence read from a property always has to be
+copied at least once, using such containers as QML sequences is rather
+expensive, even if you don't modify them from QML.
+
+The QtQml module contains a few \l [QML] {QtQml#Sequence Types}{sequence types}
+you may want to use.
+
+*/
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/topic.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/topic.qdoc
index a5f730e8d4..b1c5bce891 100644
--- a/src/qml/doc/src/qmllanguageref/typesystem/topic.qdoc
+++ b/src/qml/doc/src/qmllanguageref/typesystem/topic.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-typesystem-topic.html
\title The QML Type System
@@ -46,15 +22,44 @@ Wherever the type definitions come from, the engine will enforce type-safety
for properties and instances of those types.
-\section1 Basic Types
+\section1 QML Value Types
The QML language has built-in support for various primitive types including
integers, double-precision floating point numbers, strings, and boolean values.
Objects may have properties of these types, and values of these types may be
passed as arguments to methods of objects.
-See the \l{qtqml-typesystem-basictypes.html}{QML Basic Types} documentation for
-more information about basic types.
+See the \l{qtqml-typesystem-valuetypes.html}{QML Value Types} documentation for
+more information about value types.
+
+\section1 QML Object Types
+
+A QML object type is a type from which a QML object can be instantiated. QML
+object types are derived from \l QtObject, and are provided by QML modules.
+Applications can import these modules to use the object types they provide.
+The \c QtQuick module provides the most common object types needed to create
+user interfaces in QML.
+
+Finally, every QML document implicitly defines a QML object type, which can be
+re-used in other QML documents. See the documentation about
+\l{qtqml-typesystem-objecttypes.html}{object types in the QML type system} for
+in-depth information about object types.
+
+\section1 QML Sequence Types
+
+Sequence types can be used to store sequences of values or objects.
+
+See the documentation about
+\l{qtqml-typesystem-sequencetypes.html}{sequence types in the QML type system}
+for in-depth information about sequence types.
+
+\section1 QML Namespaces
+
+QML Namespaces can be used to expose enumerations from C++ namespaces.
+
+See the documentation about
+\l{qtqml-typesystem-namespaces.html}{namespaces in the QML type system}
+for in-depth information about namespaces.
\section1 JavaScript Types
@@ -64,7 +69,7 @@ JavaScript type can be created and stored using the generic \l var type.
For example, the standard \c Date and \c Array types are available, as below:
\qml
-import QtQuick 2.0
+import QtQuick
Item {
property var theArray: []
@@ -82,17 +87,4 @@ Item {
See \l {qtqml-javascript-expressions.html}{JavaScript Expressions in QML Documents} for more details.
-\section1 QML Object Types
-
-A QML object type is a type from which a QML object can be instantiated. QML
-object types are derived from \l QtObject, and are provided by QML modules.
-Applications can import these modules to use the object types they provide.
-The \c QtQuick module provides the most common object types needed to create
-user interfaces in QML.
-
-Finally, every QML document implicitly defines a QML object type, which can be
-re-used in other QML documents. See the documentation about
-\l{qtqml-typesystem-objecttypes.html}{object types in the QML type system} for
-in-depth information about object types.
-
*/
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/valuetypes.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/valuetypes.qdoc
new file mode 100644
index 0000000000..0bf849b155
--- /dev/null
+++ b/src/qml/doc/src/qmllanguageref/typesystem/valuetypes.qdoc
@@ -0,0 +1,606 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+/*!
+\page qtqml-typesystem-valuetypes.html
+\title QML Value Types
+\brief Description of QML value types
+
+QML supports built-in and custom value types.
+
+A \e{value type} is one that is conceptually passed by value rather than by
+reference, such as an \c int or a \c string. This contrasts with
+\l{qtqml-typesystem-topic.html#qml-object-types}{QML Object Types}. Object types
+are passed by reference. If you assign an instance of an object type to two
+different properties, both properties carry the same value. Modifying the object
+is reflected in both properties. If you assign an instance of a value type to
+two different properties, the properties carry separate values. If you modify
+one of them, the other one stays the same. Value types are only conceptually
+passed by value since it must still be possible to interact with them as if they
+were JavaScript objects. To facilitate this, in reality they are passed as
+\l{QML Value Type and Sequence References}{Value Type References} when you access
+them from JavaScript code.
+
+Unlike an object type, a value type cannot be used to declare QML objects:
+it is not possible, for example, to declare an \c int{} object or a \c size{} object.
+
+Value types can be used to refer to:
+
+\list
+\li A single value (e.g. \l int refers to a single number)
+\li A value that contains properties and methods (e.g. \l size refers to a value with \c width and \c height properties)
+\li The generic type \l{var}. It can hold values of any other type but is itself a value type.
+\endlist
+
+When a variable or property holds a value type and it is assigned to another
+variable or property, then a copy of the value is made.
+
+\sa {qtqml-typesystem-topic.html}{The QML Type System}
+
+
+\section1 Available Value Types
+
+Some value types are supported by the engine by default and do not require an
+\l {Import Statements}{import statement} to be used, while others do require
+the client to import the module which provides them.
+All of the value types listed below may be used as a \c property type in a QML
+document, with the following exceptions:
+\list
+ \li \c void, which marks the absence of a value
+ \li \c list must be used in conjunction with an object or value type as element
+ \li \c enumeration cannot be used directly as the enumeration must be defined by a registered QML object type
+\endlist
+
+\section2 Built-in Value Types Provided By The QML Language
+
+The built-in value types supported natively in the \l{The QML Reference}{QML language} are listed below:
+\annotatedlist qmlvaluetypes
+
+\section2 Value Types Provided By QML Modules
+
+QML modules may extend the QML language with more value types.
+
+For instance, the value types provided by the \c QtQml module are:
+\annotatedlist qtqmlvaluetypes
+
+The value types provided by the \c QtQuick module are:
+\annotatedlist qtquickvaluetypes
+
+The \l{QtQml::Qt}{Qt} global object provides \l{globalqtobjecttypes}{useful functions} for manipulating values of value
+types for the \l{Qt Qml} and \l{Qt Quick} modules.
+
+Other Qt modules will document their value types on their respective module pages.
+
+You may define your own value types as described in
+\l{qtqml-cppintegration-definetypes.html}{Defining QML Types from C++}.
+In order to use types provided by a particular QML module, clients
+must import that module in their QML documents.
+
+\section1 Property Change Behavior for Value Types
+
+Some value types have properties: for example, the \l font type has
+\c pixelSize, \c family and \c bold properties. Unlike properties of
+\l{qtqml-typesystem-topic.html#qml-object-types}{object types}, properties of
+value types do not provide their own property change signals. It is only possible
+to create a property change signal handler for the value type property itself:
+
+\code
+Text {
+ // invalid!
+ onFont.pixelSizeChanged: doSomething()
+
+ // also invalid!
+ font {
+ onPixelSizeChanged: doSomething()
+ }
+
+ // but this is ok
+ onFontChanged: doSomething()
+}
+\endcode
+
+Be aware, however, that a property change signal for a value type is emitted
+whenever \e any of its attributes have changed, as well as when the property itself
+changes. Take the following code, for example:
+
+\qml
+Text {
+ onFontChanged: console.log("font changed")
+
+ Text { id: otherText }
+
+ focus: true
+
+ // changing any of the font attributes, or reassigning the property
+ // to a different font value, will invoke the onFontChanged handler
+ Keys.onDigit1Pressed: font.pixelSize += 1
+ Keys.onDigit2Pressed: font.b = !font.b
+ Keys.onDigit3Pressed: font = otherText.font
+}
+\endqml
+
+In contrast, properties of an \l{qtqml-typesystem-topic.html#qml-object-types}{object type}
+emit their own property change signals, and a property change signal handler for an object-type
+property is only invoked when the property is reassigned to a different object value.
+
+*/
+
+/*!
+ \qmlvaluetype int
+ \ingroup qmlvaluetypes
+ \brief a whole number, e.g. 0, 10, or -20.
+
+ The \c int type refers to a whole number, e.g. 0, 10, or -20.
+
+ The possible \c int values range from -2147483648 to 2147483647,
+ although most types will only accept a reduced range (which they
+ mention in their documentation).
+
+ Example:
+ \qml
+ NumberAnimation { loops: 5 }
+ \endqml
+
+ This value type is provided by the QML language.
+
+ \sa {QML Value Types}
+*/
+
+/*!
+ \qmlvaluetype bool
+ \ingroup qmlvaluetypes
+ \brief a binary true/false value.
+
+ The \c bool type refers to a binary true/false value.
+
+ Properties of type \c bool have \c false as their default value.
+
+ Example:
+ \qml
+ Item {
+ focus: true
+ clip: false
+ }
+ \endqml
+
+ This value type is provided by the QML language.
+
+ \sa {QML Value Types}
+*/
+
+/*!
+ \qmlvaluetype real
+ \ingroup qmlvaluetypes
+
+ \brief a number with a decimal point.
+
+ The \c real type refers to a number with decimal point, e.g. 1.2 or -29.8.
+
+ Example:
+ \qml
+ Item { width: 100.45; height: 150.82 }
+ \endqml
+
+ \note In QML all reals are stored in double precision, \l
+ {http://en.wikipedia.org/wiki/IEEE_754} {IEEE floating point}
+ format.
+
+ This value type is provided by the QML language.
+
+ \sa {QML Value Types}
+*/
+
+/*!
+ \qmlvaluetype double
+ \ingroup qmlvaluetypes
+
+ \brief a number with a decimal point, stored in double precision.
+
+ The \c double type refers to a number with a decimal point and is stored in double precision, \l
+ {http://en.wikipedia.org/wiki/IEEE_754} {IEEE floating point} format. It's the same as \c real.
+
+ Properties of type \c double have \e {0.0} as their default value.
+
+ Example:
+ \qml
+ Item {
+ property double number: 32155.2355
+ }
+ \endqml
+
+ This value type is provided by the QML language.
+
+ \sa {QML Value Types}
+*/
+
+/*!
+ \qmlvaluetype string
+ \ingroup qmlvaluetypes
+ \brief A free form text string.
+
+ The \c string type refers to a free form text string in quotes, for example
+ "Hello world!". The QML language provides this value type by default.
+
+ Example:
+ \qml
+ Text { text: "Hello world!" }
+ \endqml
+
+ Properties of type \c string are empty by default.
+
+ Strings have a \c length attribute that holds the number of characters in
+ the string.
+
+ The string value type is backed by the C++ type QString. It extends the
+ JavaScript String primitive type in that it provides much of the same API,
+ plus some extra methods. For example, the QML string value type method
+ \c {arg()} supports value substitution:
+
+ \qml
+ var message = "There are %1 items"
+ var count = 20
+ console.log(message.arg(count))
+ \endqml
+
+ The example above prints "There are 20 items".
+
+ The QML string value type supports most of the ECMAScript string features,
+ such as template (string) literals, string interpolation, multi-line
+ strings, and looping over strings.
+
+ In general, QML string supports most JavaScript String methods, including
+ checking for inclusion using \c string.includes(), \c string.startsWith(),
+ and \c string.endsWith(); repeating a string using \c string.repeats(), and
+ slicing and splitting using \c string.slice() and \c string.split().
+
+ For more information about which version of ECMAScript QML supports, see
+ \l {JavaScript Host Environment}
+
+ For more information about JavaScript String methods, see
+ \l {https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String}
+ {mdn JavaScript String}
+
+ When integrating with C++, note that any QString value
+ \l{qtqml-cppintegration-data.html}{passed into QML from C++} is
+ automatically converted into a \c string value, and vice-versa.
+
+ \sa {QML Value Types}, {ECMA-262}{ECMAScript Language Specification}
+*/
+
+/*!
+ \qmlvaluetype url
+ \ingroup qmlvaluetypes
+ \brief a resource locator.
+
+ The \c url type refers to a resource locator (like a file name, for example). It can be either
+ absolute, e.g. "http://qt-project.org", or relative, e.g. "pics/logo.png". A relative URL is
+ resolved relative to the URL of the containing component.
+
+ For example, the following assigns a valid URL to the \l {Image::source}
+ property, which is of type \c url:
+
+ \qml
+ Image { source: "pics/logo.png" }
+ \endqml
+
+ When integrating with C++, note that any QUrl value
+ \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
+ converted into a \c url value, and vice-versa.
+
+ Alternatively you may convert your \c url to a \l{https://developer.mozilla.org/en-US/docs/Web/API/URL}{URL} object
+ in order to access and modify its components:
+ \qml
+ var urlObject = new URL(url);
+ \endqml
+
+ \note In Qt 5, URLs were automatically resolved based on the current context
+ when assigning them to any \c url property. This made it impossible to
+ work with relative URLs and it created inconsistent behavior when reading
+ back a URL previously written to a property. Therefore, the behavior was
+ changed in Qt 6: URLs are not automatically resolved on assignment anymore.
+ The individual elements that use URLs have to resolve them themselves.
+
+ \note When referring to files stored with the \l{resources.html}{Qt Resource System}
+ from within QML, you should use "qrc:///" instead of ":/" as QML requires URL paths.
+ Relative URLs resolved from within that file will use the same protocol.
+
+ Additionally, URLs may contain encoded characters using the 'percent-encoding' scheme
+ specified by \l {https://datatracker.ietf.org/doc/html/rfc3986}{RFC 3986}. These characters
+ will be preserved within properties of type \c url, to allow QML code to
+ construct precise URL values.
+
+ For example, a local file containing a '#' character, which would normally be
+ interpreted as the beginning of the URL 'fragment' element, can be accessed by
+ encoding the characters of the file name:
+
+ \qml
+ Image { source: encodeURIComponent("/tmp/test#1.png") }
+ \endqml
+
+ This value type is provided by the QML language.
+
+ \sa {QML Value Types}
+*/
+
+
+/*!
+ \qmlvaluetype list
+ \ingroup qmlvaluetypes
+ \brief a list of QML objects.
+
+ The \c list type refers to a list of QML objects or values.
+
+ Properties of type \c list are empty by default.
+
+ A \c list can store QML objects or \l{QML Value Types}{value type} values.
+
+ When integrating with C++, note that any QQmlListProperty value
+ \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
+ converted into a \c list value, and vice-versa.
+
+ Similarly any \c{QList<T>} of a registered value type \c{T} is automatically
+ converted into a \c list value, and vice-versa.
+
+ \section1 Using the list Type
+
+ For example, the \l Item type has a \l {Item::}{states} list-type property that
+ can be assigned to and used as follows:
+
+ \qml
+ import QtQuick
+
+ Item {
+ width: 100; height: 100
+
+ states: [
+ State { name: "activated" },
+ State { name: "deactivated" }
+ ]
+
+ Component.onCompleted: {
+ console.log("Name of first state:", states[0].name)
+ for (var i = 0; i < states.length; i++)
+ console.log("state", i, states[i].name)
+ }
+ }
+ \endqml
+
+ The defined \l State objects will be added to the \c states list
+ in the order in which they are defined.
+
+ If the list only contains one object, the square brackets may be omitted:
+
+ \qml
+ import QtQuick
+
+ Item {
+ width: 100; height: 100
+ states: State { name: "activated" }
+ }
+ \endqml
+
+ You can also declare your own list properties in QML:
+
+ \qml
+ import QtQml
+
+ QtObject {
+ property list<int> intList: [1, 2, 3, 4]
+ property list<QtObject> objectList
+ }
+ \endqml
+
+ Lists can be used much like JavaScript arrays. For example:
+
+ \list
+ \li Values are assigned using the \c[] square bracket syntax with comma-separated values
+ \li The \c length property provides the number of items in the list
+ \li Values in the list are accessed using the \c [index] syntax
+ \li You can use \c{push()} to append entries
+ \li You can set the \c length property of the list to truncate or extend it.
+ \endlist
+
+ However, you can \e{not} automatically extend the list by assigning to an
+ index currently out of range. Furthermore, if you insert \c null values
+ into a list of objects, those are converted to \c nullptr entries in
+ the underlying QQmlListProperty.
+
+ A list of value types is different from a JavaScript array in one further
+ important aspect: Growing it by setting its length does not produce undefined
+ entries, but rather default-constructed instances of the value type.
+
+ Similarly, growing a list of object types this way produces null entries,
+ rather than undefined entries.
+
+ This value type is provided by the QML language.
+
+ \sa {QML Value Types}
+*/
+
+ /*!
+ \qmlvaluetype var
+ \ingroup qmlvaluetypes
+ \brief a generic property type.
+
+ The \c var type is a generic property type that can refer to any data type.
+
+ It is equivalent to a regular JavaScript variable.
+ For example, var properties can store numbers, strings, objects,
+ arrays and functions:
+
+ \qml
+ Item {
+ property var aNumber: 100
+ property var aBool: false
+ property var aString: "Hello world!"
+ property var anotherString: String("#FF008800")
+ property var aColor: Qt.rgba(0.2, 0.3, 0.4, 0.5)
+ property var aRect: Qt.rect(10, 10, 10, 10)
+ property var aPoint: Qt.point(10, 10)
+ property var aSize: Qt.size(10, 10)
+ property var aVector3d: Qt.vector3d(100, 100, 100)
+ property var anArray: [1, 2, 3, "four", "five", (function() { return "six"; })]
+ property var anObject: { "foo": 10, "bar": 20 }
+ property var aFunction: (function() { return "one"; })
+ }
+ \endqml
+
+ \section1 Change Notification Semantics
+
+ It is important to note that changes in regular properties of JavaScript
+ objects assigned to a var property will \b{not} trigger updates of bindings
+ that access them. The example below will display "The car has 4 wheels" as
+ the change to the wheels property will not cause the reevaluation of the
+ binding assigned to the "text" property:
+
+ \qml
+ Item {
+ property var car: new Object({wheels: 4})
+
+ Text {
+ text: "The car has " + car.wheels + " wheels";
+ }
+
+ Component.onCompleted: {
+ car.wheels = 6;
+ }
+ }
+ \endqml
+
+ If the onCompleted handler instead had \tt{"car = new Object({wheels: 6})"}
+ then the text would be updated to say "The car has 6 wheels", since the
+ car property itself would be changed, which causes a change notification
+ to be emitted.
+
+ \section1 Property Value Initialization Semantics
+
+ The QML syntax defines that curly braces on the right-hand-side of a
+ property value initialization assignment denote a binding assignment.
+ This can be confusing when initializing a \c var property, as empty curly
+ braces in JavaScript can denote either an expression block or an empty
+ object declaration. If you wish to initialize a \c var property to an
+ empty object value, you should wrap the curly braces in parentheses.
+
+ Properties of type \c var are \c {undefined} by default.
+
+ For example:
+ \qml
+ Item {
+ property var first: {} // nothing = undefined
+ property var second: {{}} // empty expression block = undefined
+ property var third: ({}) // empty object
+ }
+ \endqml
+
+ In the previous example, the \c first property is bound to an empty
+ expression, whose result is undefined. The \c second property is bound to
+ an expression which contains a single, empty expression block ("{}"), which
+ similarly has an undefined result. The \c third property is bound to an
+ expression which is evaluated as an empty object declaration, and thus the
+ property will be initialized with that empty object value.
+
+ Similarly, a colon in JavaScript can be either an object property value
+ assignment, or a code label. Thus, initializing a var property with an
+ object declaration can also require parentheses:
+
+ \qml
+ Item {
+ property var first: { example: 'true' } // example is interpreted as a label
+ property var second: ({ example: 'true' }) // example is interpreted as a property
+ property var third: { 'example': 'true' } // example is interpreted as a property
+ Component.onCompleted: {
+ console.log(first.example) // prints 'undefined', as "first" was assigned a string
+ console.log(second.example) // prints 'true'
+ console.log(third.example) // prints 'true'
+ }
+ }
+ \endqml
+
+ \sa {QML Value Types}
+*/
+
+/*!
+ \qmlvaluetype variant
+ \ingroup qmlvaluetypes
+ \brief a generic property type.
+
+ The \c variant type is the same as the \c var type. Use \c var instead.
+
+ \sa {QML Value Types}
+*/
+
+/*!
+ \qmlvaluetype void
+ \ingroup qmlvaluetypes
+ \brief The empty value type.
+
+ The \c void type is exclusively used to type-annotate JavaScript functions
+ returning \c undefined. For example:
+
+ \qml
+ function doThings() : void { console.log("hello") }
+ \endqml
+
+ This is to help tooling analyze calls to such functions and compile them and
+ their callers to C++.
+
+ You cannot declare \c void properties in QML.
+
+ \sa {QML Value Types}
+*/
+
+/*!
+ \qmlvaluetype enumeration
+ \ingroup qmlvaluetypes
+ \brief a named enumeration value.
+
+ The \c enumeration type refers to a named enumeration value.
+
+ Each named value can be referred to as \c {<Type>.<value>}. For
+ example, the \l Text type has an \c AlignRight enumeration value:
+
+ \qml
+ Text { horizontalAlignment: Text.AlignRight }
+ \endqml
+
+ (For backwards compatibility, the enumeration value may also be
+ specified as a string, e.g. "AlignRight". This form is not
+ recommended for new code.)
+
+ When integrating with C++, note that any \c enum value
+ \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
+ converted into an \c enumeration value, and vice-versa.
+
+ This value type is provided by the QML language. Some enumeration values
+ are provided by the QtQuick import.
+
+ \section1 Using the enumeration Type in QML
+
+ The \c enumeration type is a representation of a C++ \c enum type. It is
+ not possible to refer to the \c enumeration type in QML itself; instead, the
+ \l int or \l var types can be used when referring to \c enumeration values
+ from QML code.
+
+ For example:
+
+ \qml
+ import QtQuick 2.0
+
+ Item {
+ // refer to Text.AlignRight using an int type
+ property int enumValue: textItem.horizontalAlignment
+
+ signal valueEmitted(int someValue)
+
+ Text {
+ id: textItem
+ horizontalAlignment: Text.AlignRight
+ }
+
+ // emit valueEmitted() signal, which expects an int, with Text.AlignRight
+ Component.onCompleted: valueEmitted(Text.AlignRight)
+ }
+ \endqml
+
+ \sa {QML Value Types}
+ \sa {qtqml-syntax-objectattributes.html#enumeration-attributes}{Enumeration Attributes}
+*/
diff --git a/src/qml/doc/src/qmllint/access-singleton-via-object.qdoc b/src/qml/doc/src/qmllint/access-singleton-via-object.qdoc
new file mode 100644
index 0000000000..66a2f86b7c
--- /dev/null
+++ b/src/qml/doc/src/qmllint/access-singleton-via-object.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-access-singleton-via-object.html
+\ingroup qmllint-warnings-and-errors
+
+\title access-singleton-via-object
+\brief BRIEF
+
+\section1 access-singleton-via-object
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/alias-cycle.qdoc b/src/qml/doc/src/qmllint/alias-cycle.qdoc
new file mode 100644
index 0000000000..561cedf416
--- /dev/null
+++ b/src/qml/doc/src/qmllint/alias-cycle.qdoc
@@ -0,0 +1,60 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-alias-cycle.html
+\ingroup qmllint-warnings-and-errors
+
+\title Alias Cycle
+\brief Alias property is part of an alias cycle.
+
+\section1 Alias Property Is Part Of An Alias Cycle
+
+\section2 What happened?
+A \l{QML Object Attributes#property-aliases}{property alias} resolves to itself or to another
+alias resolving to itself.
+
+Usually, \l{QML Object Attributes#property-aliases}{a property alias} should reference another
+property either directly, or indirectly by passing through another alias property.
+
+If a property alias directly or indirectly references itself, then it forms an alias cycle.
+The warning indicates that the current alias property is inside or references
+an alias cycle, see \l{#example}{Example}.
+
+\section2 Why is this bad?
+Instances of components with alias cycles will not be created at runtime: they will be null instead.
+
+\section2 Example
+\qml
+import QtQuick
+
+Item {
+ id: someId
+ property alias myself: someId.myself // not ok: referring to itself
+
+ property alias cycle: someId.cycle2 // not ok: indirectly referring to itself
+ property alias cycle2: someId.cycle
+
+ property alias indirect: someId.cycle // not ok: referring to alias indirectly referring to itself
+}
+\endqml
+You can fix this warning by breaking up the alias cycles:
+\qml
+import QtQuick
+
+Item {
+ id: someId
+ Item {
+ id: anotherId
+ property string myself
+ property int cycle
+ }
+ property alias myself: anotherId.myself // ok: referring to a property
+
+ property alias cycle: someId.cycle2 // ok: does not refer to itself anymore
+ property alias cycle2: anotherId.cycle // ok: not a cycle anymore
+
+ property alias indirect: someId.cycle // ok: cycle does not form an alias cycle anymore
+}
+\endqml
+*/
diff --git a/src/qml/doc/src/qmllint/attached-property-reuse.qdoc b/src/qml/doc/src/qmllint/attached-property-reuse.qdoc
new file mode 100644
index 0000000000..15d81f6b94
--- /dev/null
+++ b/src/qml/doc/src/qmllint/attached-property-reuse.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-attached-property-reuse.html
+\ingroup qmllint-warnings-and-errors
+
+\title attached-property-reuse
+\brief BRIEF
+
+\section1 attached-property-reuse
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/compiler.qdoc b/src/qml/doc/src/qmllint/compiler.qdoc
new file mode 100644
index 0000000000..7b2eb22f41
--- /dev/null
+++ b/src/qml/doc/src/qmllint/compiler.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-compiler.html
+\ingroup qmllint-warnings-and-errors
+
+\title compiler
+\brief BRIEF
+
+\section1 compiler
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/deferred-property-id.qdoc b/src/qml/doc/src/qmllint/deferred-property-id.qdoc
new file mode 100644
index 0000000000..990322a88e
--- /dev/null
+++ b/src/qml/doc/src/qmllint/deferred-property-id.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-deferred-property-id.html
+\ingroup qmllint-warnings-and-errors
+
+\title deferred-property-id
+\brief BRIEF
+
+\section1 deferred-property-id
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/deprecated.qdoc b/src/qml/doc/src/qmllint/deprecated.qdoc
new file mode 100644
index 0000000000..311796871a
--- /dev/null
+++ b/src/qml/doc/src/qmllint/deprecated.qdoc
@@ -0,0 +1,23 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-deprecated.html
+\ingroup qmllint-warnings-and-errors
+
+\title Deprecated
+\brief A deprecated property or type was used.
+
+\section1 Deprecated Binding or Type
+
+\section2 What happened?
+A deprecated type was instantiated, a deprecated property was used or a deprecated method was
+called.
+
+\section2 Why is this bad?
+Types, properties and methods can be deprecated for different reasons, please refer to the
+documentation of the deprecated item to find out why they were deprecated.
+
+You can fix the deprecation warning by following the advice on the deprecation notice in the
+documentation of the deprecated item.
+*/
diff --git a/src/qml/doc/src/qmllint/duplicate-property-binding.qdoc b/src/qml/doc/src/qmllint/duplicate-property-binding.qdoc
new file mode 100644
index 0000000000..4826a552ea
--- /dev/null
+++ b/src/qml/doc/src/qmllint/duplicate-property-binding.qdoc
@@ -0,0 +1,122 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-duplicate-property-binding.html
+\ingroup qmllint-warnings-and-errors
+
+\title Duplicate Bindings
+\brief A property was bound multiple times.
+
+This warning category has multiple warnings:
+\list
+ \li \l{Duplicate Interceptor On Property}
+ \li \l{Cannot Combine Value Source And Binding}
+ \li \l{Duplicate Value Source On Property}
+\endlist
+
+\section1 Duplicate Interceptor On Property
+
+\section2 What happened?
+One property has multiple \l{Property Modifier Types}{interceptors}.
+
+\section2 Why is this bad?
+Setting multiple interceptors on the same property is unsupported by the QML engine.
+
+\section2 Example
+
+Lets use \l{Behavior} as interceptor twice on the same property:
+\qml
+import QtQuick
+
+Rectangle {
+ Behavior on width {
+ NumberAnimation { duration: 1000 }
+ }
+ Behavior on width { // not ok: Duplicate interceptor on property "width" [duplicate-property-binding]
+ NumberAnimation { duration: 2000 }
+ }
+}
+\endqml
+You can fix this warning by removing all but one \l{Behavior}:
+\qml
+import QtQuick
+
+Rectangle {
+ Behavior on width {
+ NumberAnimation { duration: 2000 }
+ }
+}
+\endqml
+
+\b {See also} \l {Property Modifier Types}.
+
+\section1 Duplicate Value Source On Property
+
+\section2 What happened?
+One property has multiple \l{Property Value Sources}{value sources}.
+
+\section2 Why is this bad?
+The value sources will show unexpected behavior when combined. See \l{Example}{example} below.
+
+\section2 Example
+
+Lets use \l{NumberAnimation} as value source twice on the same property:
+\qml
+import QtQuick
+
+Rectangle {
+ NumberAnimation on x { to: 50; duration: 1000 }
+ NumberAnimation on x { to: 10; duration: 100 } // not ok: Duplicate value source on property "x" [duplicate-property-binding]
+
+ onXChanged: console.log(x)
+}
+\endqml
+
+If you check the output of that program, you will see that the two NumberAnimation will interleave
+each other, which is probably not the effect that was intended.
+You can fix this warning by removing all but one \l{NumberAnimation}:
+\qml
+import QtQuick
+
+Rectangle {
+ NumberAnimation on x { to: 50; duration: 1000 }
+}
+\endqml
+
+
+\section1 Cannot Combine Value Source And Binding
+
+\section2 What happened?
+One property has a \l{Property Value Sources}{value source} and a binding on the same property.
+
+\section2 Why is this bad?
+The binding will updated the property value before the value source starts updating this property.
+This may lead to unexpected behavior, and is also harder to read.
+
+\section2 Example
+
+Lets use \l{NumberAnimation} as value source on the same property:
+\qml
+import QtQuick
+
+Rectangle {
+ NumberAnimation on x { to: 50; duration: 1000 } // not ok: Cannot combine value source and binding on property "x" [duplicate-property-binding]
+ x: 55
+
+ onXChanged: console.log(x)
+}
+\endqml
+
+If you check the output of that program, you will see that the \l{NumberAnimation} will animate
+from 55 to 50, which would be easier to read with following code:
+\qml
+import QtQuick
+
+Rectangle {
+ NumberAnimation on x { from: 55; to: 50; duration: 1000 } // ok: intentions are clearer now!
+}
+\endqml
+
+*/
+
diff --git a/src/qml/doc/src/qmllint/duplicated-name.qdoc b/src/qml/doc/src/qmllint/duplicated-name.qdoc
new file mode 100644
index 0000000000..0cc4583cb4
--- /dev/null
+++ b/src/qml/doc/src/qmllint/duplicated-name.qdoc
@@ -0,0 +1,70 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-duplicated-name.html
+\ingroup qmllint-warnings-and-errors
+
+\title Duplicated Name
+\brief Multiple signals or properties share the same name in the same Component.
+
+This warning category has multiple warnings:
+\list
+ \li \l{Duplicated Property Name}
+ \li \l{Duplicated Signal Name}
+\endlist
+
+\section1 Duplicated Property Name
+
+\section2 What happened?
+Multiple properties in the same QML component scope have the same name.
+
+\section2 Why is this bad?
+Components with duplicate property names will not be created at runtime: they will be null instead.
+
+\section2 Example
+\qml
+import QtQuick
+
+Item {
+ property int helloWorld
+ property int helloWorld
+}
+\endqml
+You can fix this warning by removing the duplicate property or renaming it:
+\qml
+import QtQuick
+
+Item {
+ property int helloWorld
+}
+\endqml
+
+\section1 Duplicated Signal Name
+
+\section2 What happened?
+Multiple signals in the same QML component scope have the same name.
+
+\section2 Why is this bad?
+Components with duplicate signal names will not be created at runtime: they will be null instead.
+
+\section2 Example
+\qml
+import QtQuick
+
+Rectangle {
+ signal helloWorld
+ signal helloWorld
+}
+\endqml
+You can fix this warning by removing the duplicate signal or renaming it:
+\qml
+import QtQuick
+
+Rectangle {
+ signal helloWorld
+}
+
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/import.qdoc b/src/qml/doc/src/qmllint/import.qdoc
new file mode 100644
index 0000000000..c5adababc4
--- /dev/null
+++ b/src/qml/doc/src/qmllint/import.qdoc
@@ -0,0 +1,174 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-import.html
+\ingroup qmllint-warnings-and-errors
+
+\title Warnings Occurred While Importing
+\brief The imported module was not found.
+
+This warning category contains multiple warnings:
+\list
+\li \l{Failed To Import Module}
+\li \l{Component Was Not Found}
+\li \l{Import Qualifier Must Start With A Capital Letter}
+\li \l{Unknown Import Syntax}
+\endlist
+
+\section1 Failed To Import Module
+
+\section2 What happened?
+The module imported via \l{Import Statements}{import statement} was not found.
+
+This can be caused, for example, by
+\list
+ \li a typo in the import statement, or
+ \li a user-defined module that was not built, or
+ \li a wrong \l{Import Statements#qml-import-path}{import path}, or
+ \li a missing module
+\endlist
+
+\section2 Why is this bad?
+The application can't run because it can't find a module it relies on.
+
+\section2 Examples
+
+\section3 Typo In The Import Statement
+\qml
+import QtQuicky // not ok: typo in module name
+
+Item {
+}
+\endqml
+You can fix this warning by correcting the typo:
+\qml
+import QtQuick // ok: no typo in module name
+
+Item {
+}
+\endqml
+
+\section3 User-Defined Module That Was Not Built
+
+Some tooling like \l{\QMLLS Reference}{\QMLLS} or \l{qmllint Reference}{qmllint}
+can't find user-defined modules when they
+are not built. If your project defines the QML Module you are trying to import, then
+the QML tooling will not find it until you build it.
+
+\note If building the module does not help when using \l{\QMLLS Reference}{\QMLLS}, follow the
+instructions in
+\l{Setting up the \QMLLS in Your Editor}{\QMLLS setup instructions}
+and make sure that you communicate the correct build folder to \QMLLS.
+
+\section3 Wrong Import Path
+
+Please refer to \l{Import Statements#qml-import-path}{the QML import path documentation} and to
+\l{Debugging QML Applications#debugging-module-imports}{the debugging module import documentation}
+for more information about import paths.
+
+\section3 Missing Module
+
+If the previous sections did not help to find the imported module, it might be missing.
+This might be caused by a missing dependency. When using external libraries, verify that they are
+actually installed, and that their modules end up in an
+\l{Import Statements#qml-import-path}{import path}.
+
+\section1 Component Was Not Found
+
+\section2 What happened?
+Some component was not found.
+
+\section2 Why is this bad?
+The application can't run because it can't instantiate the non-found component.
+
+\section2 Examples
+
+\section3 Typo In The Component Name
+\qml
+import QtQuick
+
+Item {
+ Itemy {} // not ok: typo in name
+}
+\endqml
+You can fix this warning by correcting the typo:
+\qml
+import QtQuick
+
+Item {
+ Item {} // ok: no typo in name
+}
+\endqml
+
+\section3 Missing Import Statement
+
+\qml
+
+Item { // not ok: must be imported from QtQuick first
+}
+\endqml
+You can fix this warning by adding the missing module import:
+\qml
+import QtQuick
+
+Item { // ok: was imported from QtQuick
+}
+\endqml
+
+\section1 Import Qualifier must start with a capital letter
+
+\section2 What happened?
+Some imported module has an invalid qualifier.
+
+\section2 Why is this bad?
+The module imported with this invalid qualifier can't be used.
+
+\section2 Examples
+
+\qml
+import QtQuick as qq
+
+qq.Item {
+}
+\endqml
+You can fix this warning by making the import qualifier start with an upper case letter:
+\qml
+import QtQuick as Qq
+
+Qq.Item {
+}
+\endqml
+
+\section1 Unknown Import Syntax
+
+\section2 What happened?
+An import statement is using an invalid \l{Import Statements}{import syntax}.
+
+\section2 Why is this bad?
+The application can't run because it can't import a module it relies on.
+
+\section2 Examples
+
+\qml
+import "¯\(ツ)/¯:/path/to/Module"
+import QtQuick
+
+Item {
+}
+\endqml
+You can fix this warning by using URLs that have an allowed scheme:
+\qml
+import "qrc:/path/to/Module"
+import QtQuick
+
+Item {
+}
+\endqml
+
+\note This example assumes that you are not using \l{QQmlAbstractUrlInterceptor}{URL handlers}.
+
+\sa{Import Statements}
+
+*/
+
diff --git a/src/qml/doc/src/qmllint/incompatible-type.qdoc b/src/qml/doc/src/qmllint/incompatible-type.qdoc
new file mode 100644
index 0000000000..6946740b66
--- /dev/null
+++ b/src/qml/doc/src/qmllint/incompatible-type.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-incompatible-type.html
+\ingroup qmllint-warnings-and-errors
+
+\title incompatible-type
+\brief BRIEF
+
+\section1 incompatible-type
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/inheritance-cycle.qdoc b/src/qml/doc/src/qmllint/inheritance-cycle.qdoc
new file mode 100644
index 0000000000..c1be63ae78
--- /dev/null
+++ b/src/qml/doc/src/qmllint/inheritance-cycle.qdoc
@@ -0,0 +1,46 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-inheritance-cycle.html
+\ingroup qmllint-warnings-and-errors
+
+\title Inheritance Cycle
+\brief A component inherits from itself.
+
+\section1 Component Is Part Of An Inheritance Cycle
+
+\section2 What happened?
+A component inherited directly or indirectly from itself.
+
+Usually, Components can inherit properties, methods, signals and enums from other components.
+
+If a component inherits itself directly or indirectly through another base component, then
+it forms an inheritance cycle. The warning indicates that the current component is inside an
+inheritance cycle, see \l{#example}{Example}.
+
+\section2 Why is this bad?
+Components with inheritance cycles will not be created at runtime: they will be null instead.
+
+\section2 Example
+\qml
+import QtQuick
+
+Item {
+ component Cycle: Cycle {} // not ok: directly inherits from itself
+ component C: C2 {} // not ok: indirectly inherits from itself
+ component C2: C{}
+}
+\endqml
+You can fix this warning by breaking up the inheritance cycle
+\qml
+import QtQuick
+
+Item {
+ component Cycle: Item {} // ok: does not inherit from itself
+ component C: C2 {} // ok: does not indirectly inherits from itself anymore
+ component C2: Cycle{}
+}
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/invalid-lint-directive.qdoc b/src/qml/doc/src/qmllint/invalid-lint-directive.qdoc
new file mode 100644
index 0000000000..39488f291f
--- /dev/null
+++ b/src/qml/doc/src/qmllint/invalid-lint-directive.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-invalid-lint-directive.html
+\ingroup qmllint-warnings-and-errors
+
+\title invalid-lint-directive
+\brief BRIEF
+
+\section1 invalid-lint-directive
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/missing-enum-entry.qdoc b/src/qml/doc/src/qmllint/missing-enum-entry.qdoc
new file mode 100644
index 0000000000..433562f638
--- /dev/null
+++ b/src/qml/doc/src/qmllint/missing-enum-entry.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-missing-enum-entry.html
+\ingroup qmllint-warnings-and-errors
+
+\title missing-enum-entry
+\brief BRIEF
+
+\section1 missing-enum-entry
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/missing-property.qdoc b/src/qml/doc/src/qmllint/missing-property.qdoc
new file mode 100644
index 0000000000..4d1b9a02c3
--- /dev/null
+++ b/src/qml/doc/src/qmllint/missing-property.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-missing-property.html
+\ingroup qmllint-warnings-and-errors
+
+\title missing-property
+\brief BRIEF
+
+\section1 missing-property
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/missing-type.qdoc b/src/qml/doc/src/qmllint/missing-type.qdoc
new file mode 100644
index 0000000000..466370ef39
--- /dev/null
+++ b/src/qml/doc/src/qmllint/missing-type.qdoc
@@ -0,0 +1,240 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-missing-type.html
+\ingroup qmllint-warnings-and-errors
+
+\title Missing Type
+\brief A type used in a binding or alias was not found.
+
+This warning category has multiple warnings:
+\list
+ \li \l{Cannot Deduce Type of Alias}
+ \li \l{No Type Found For Property}
+\endlist
+
+\section1 Cannot Deduce Type of Alias
+
+\section2 What happened?
+An alias property points to a property with a C++ type whose QML counterpart was not found. This can
+be caused by importing a QML module which do not declare its QML dependencies on other modules.
+
+\note If you are importing QML modules with external dependencies, verify that they are
+actually installed, and that their modules end up in an
+\l{Import Statements#qml-import-path}{import path}.
+
+The warning might also indicate that the type of the property referenced by the alias does not have
+a QML counterpart. The referenced property type might be missing the
+\l{QQmlEngine::}{QML_ELEMENT} macro, for example. Refer to
+\l{Defining QML Types from C++} or \l{Overview - QML and C++ Integration} in this case.
+
+\section2 Why is this bad?
+QML tooling is not able to find the QML counterpart of the C++ type: the
+\l{Qt Quick Compiler}{compiler} can't compile this property alias to
+C++ and \l{qmllint Reference}{qmllint} as well as \l{\QMLLS Reference}{\QMLLS}
+can't analyze this property alias.
+
+\section2 Example
+Let our QML module have one C++ class with a property \c{myProperty}:
+
+\code
+#include <QQuickItem>
+#include <QtQml/qqmlregistration.h>
+#include <QObject>
+
+class MyCppObject : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+public:
+ MyCppObject(QObject *parent = nullptr)
+ : QObject(parent)
+ {}
+
+ Q_PROPERTY(QQuickItem *myProperty READ myProperty WRITE setMyProperty NOTIFY notifyMyProperty)
+ QQuickItem *myProperty() { return m_myProperty; }
+ void setMyProperty(QQuickItem *item) { emit notifyMyProperty(); m_myProperty = item; }
+
+private:
+ QQuickItem *m_myProperty;
+
+signals:
+ void notifyMyProperty();
+};
+\endcode
+
+with following \c{CMakeLists.txt}:
+\badcode
+project(mymodule VERSION 0.1 LANGUAGES CXX)
+
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+find_package(Qt6 6.5 REQUIRED COMPONENTS Quick)
+qt_standard_project_setup(REQUIRES 6.5)
+
+qt_add_executable(appmymodule
+ main.cpp
+)
+
+qt_add_qml_module(appmymodule
+ URI mymodule
+ VERSION 1.0
+ QML_FILES Main.qml HelloWorld.qml
+ SOURCES mycppobject.cpp mycppobject.h
+)
+
+target_link_libraries(appmymodule
+ PRIVATE Qt6::Quick
+)
+\endcode
+
+The C++ dependency \c{Quick} was declared, such that this class can compile and the QQuickItem
+include can be found. Also, \c{mymodule} does not have any dependency on QtQuick.
+
+Now, let's try to use \c{myProperty} in an alias in QML. The program will run but QML tooling like
+the \l{Qt Quick Compiler}{compiler}, for example, will complain about the usage of \c{myProperty}:
+\qml
+import mymodule
+
+MyCppObject {
+ id: root
+
+ property alias myAlias: root.myProperty // not ok: Cannot deduce type of alias [missing-type]
+}
+\endqml
+The reason for the warning message is that in the QML code, the type \c{QQuickItem} of
+\c{myProperty} and its QML counterpart \c{Item} are not known, even if you have \c{import QtQuick}
+in your QML file. This is because the same type can be exposed multiple times with different
+attributes in different modules: \c{mymodule} actually has to be precise about the QML type of
+\c{myProperty}.
+
+You can fix this warning by adding the dependency in the \c{CMakeLists.txt}:
+\badcode
+qt_add_qml_module(mymodule
+ URI mymodule
+ ...
+ # declarare QML dependency to QtQuick module
+ DEPENDENCIES QtQuick
+ ...
+)
+\endcode
+
+Now, the warning should be gone!
+
+\b {See also} \l {Declaring module dependencies}.
+
+\section1 No Type Found For Property
+
+\section2 What happened?
+A binding was set on a property whose QML type was not found. This can be caused by a QML module
+which does not declare its QML dependencies on other modules.
+
+\note If you are importing QML modules with external dependencies, verify that they are
+actually installed, and that their modules end up in an
+\l{Import Statements#qml-import-path}{import path}.
+
+The warning might also indicate that the type of the property does not have
+a QML counterpart. The property type might be missing the
+\l{QQmlEngine::}{QML_ELEMENT} macro, for example. Refer to
+\l{Defining QML Types from C++} or \l{Overview - QML and C++ Integration} in this case.
+
+\section2 Why is this bad?
+QML tooling is not able to find the QML counterpart of the C++ type: the
+\l{Qt Quick Compiler}{compiler} can't compile this property binding to
+C++ and \l{qmllint Reference}{qmllint} as well as \l{\QMLLS Reference}{\QMLLS} can't analyze this property binding.
+
+\section2 Example
+Let our QML module have a C++ class with two properties, \c{myProperty} and \c{myProperty2}:
+
+\code
+#include <QQuickItem>
+#include <QtQml/qqmlregistration.h>
+#include <QObject>
+
+class MyCppObject : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+public:
+ MyCppObject(QObject *parent = nullptr)
+ : QObject(parent)
+ {}
+
+ Q_PROPERTY(QQuickItem *myProperty READ myProperty WRITE setMyProperty NOTIFY notifyMyProperty)
+ QQuickItem *myProperty() { return m_myProperty; }
+ void setMyProperty(QQuickItem *item) { emit notifyMyProperty(); m_myProperty = item; }
+
+ Q_PROPERTY(QQuickItem *myProperty2 READ myProperty2 WRITE setMyProperty2 NOTIFY notifyMyProperty2)
+ QQuickItem *myProperty2() { return m_myProperty2; }
+ void setMyProperty2(QQuickItem *item) { emit notifyMyProperty2(); m_myProperty2 = item; }
+
+private:
+ QQuickItem *m_myProperty;
+ QQuickItem *m_myProperty2;
+
+signals:
+ void notifyMyProperty();
+ void notifyMyProperty2();
+};
+\endcode
+
+with following \c{CMakeLists.txt}:
+\badcode
+project(mymodule VERSION 0.1 LANGUAGES CXX)
+
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+find_package(Qt6 6.5 REQUIRED COMPONENTS Quick)
+qt_standard_project_setup(REQUIRES 6.5)
+
+qt_add_executable(appmymodule
+ main.cpp
+)
+
+qt_add_qml_module(appmymodule
+ URI mymodule
+ VERSION 1.0
+ QML_FILES Main.qml HelloWorld.qml
+ SOURCES mycppobject.cpp mycppobject.h
+)
+
+target_link_libraries(appmymodule
+ PRIVATE Qt6::Quick
+)
+\endcode
+
+The C++ dependency \c{Quick} was declared, such that this class can compile and the QQuickItem
+include can be found. Also, \c{mymodule} does not have any dependency on QtQuick.
+
+Now, let's try to bind \c{myProperty2} to \c{myProperty} in an alias in QML. The program will run
+but QML tooling like the \l{Qt Quick Compiler}{compiler}, for example, will complain about the
+usage of \c{myProperty}:
+
+\qml
+import mymodule
+
+MyCppObject {
+ id: root
+
+ myProperty: myProperty2 // not ok: No type found for property "myProperty". [missing-type]
+}
+\endqml
+The reason for the warning message is that in the QML code, the type \c{QQuickItem} of \c{myProperty}
+and its QML counterpart \c{Item} are not known: the dependency 'QtQuick' of mymodule was not
+declared in the \c{CMakeLists.txt}.
+
+You can fix this warning by adding the dependency in the \c{CMakeLists.txt}:
+\badcode
+qt_add_qml_module(mymodule
+ URI mymodule
+ ...
+ # declarare QML dependency to QtQuick module
+ DEPENDENCIES QtQuick
+ ...
+)
+\endcode
+
+Now, the warning should be gone!
+
+\b {See also} \l {Declaring module dependencies}.
+*/
+
diff --git a/src/qml/doc/src/qmllint/multiline-strings.qdoc b/src/qml/doc/src/qmllint/multiline-strings.qdoc
new file mode 100644
index 0000000000..4c1aef4e85
--- /dev/null
+++ b/src/qml/doc/src/qmllint/multiline-strings.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-multiline-strings.html
+\ingroup qmllint-warnings-and-errors
+
+\title multiline-strings
+\brief BRIEF
+
+\section1 multiline-strings
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/non-list-property.qdoc b/src/qml/doc/src/qmllint/non-list-property.qdoc
new file mode 100644
index 0000000000..2d778d87bc
--- /dev/null
+++ b/src/qml/doc/src/qmllint/non-list-property.qdoc
@@ -0,0 +1,85 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-non-list-property.html
+\ingroup qmllint-warnings-and-errors
+
+\title Non-List Property
+\brief Multiple values were assigned to a non-list property.
+
+\section1 Cannot Assign Multiple Objects To A Default Non-List Property
+
+\section2 What happened?
+A \l{Default Properties}{default property} has multiple bindings but the default
+property type is not a list type and only expects one binding.
+
+\section2 Why is this bad?
+All the bindings to the default property, except the last one, will be ignored. This most likely
+hints that the default property should instead be a list, or that there are too many bindings to
+the same property.
+
+\section2 Example
+
+Let's declare a component \c{MyComponent} that has one default non-list property, and then lets
+bind three items to that default property:
+\qml
+import QtQuick
+
+Item {
+ component MyComponent: QtObject {
+ default property Item helloWorld
+ }
+ MyComponent {
+ // first item bound to default property:
+ Item { objectName: "first" } // will warn: Cannot assign multiple objects to a default non-list property [non-list-property]
+ // second item bound to default property:
+ Item { objectName: "second" } // not ok: default property was bound already
+ // third item bound to default property:
+ Item { objectName: "third" } // not ok: default property was bound already
+
+ Component.onCompleted: console.log(helloWorld.objectName) // prints "third"
+ }
+}
+
+\endqml
+You can fix this warning by replacing the default property by a list:
+\qml
+import QtQuick
+
+Item {
+ component MyComponent: QtObject {
+ default property list<Item> helloWorld
+ }
+ MyComponent {
+ // first item bound to default property:
+ Item { objectName: "first" } // ok: binding a first item to the list
+ // second item bound to default property:
+ Item { objectName: "second" } // ok: binding a second item to the list
+ // third item bound to default property:
+ Item { objectName: "third" } // ok: binding a third item to the list
+ }
+}
+\endqml
+You can also fix this warning by removing all the unwanted bindings, in case the default property
+is not supposed to be a list:
+\qml
+import QtQuick
+
+Item {
+ component MyComponent: QtObject {
+ default property Item helloWorld
+ }
+ MyComponent {
+ Item { objectName: "first" } // ok: just one item bound to default property
+ }
+ MyComponent {
+ Item { objectName: "second" } // ok: just one item bound to default property
+ }
+ MyComponent {
+ Item { objectName: "third" } // ok: just one item bound to default property
+ }
+}
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/plugin.qdoc b/src/qml/doc/src/qmllint/plugin.qdoc
new file mode 100644
index 0000000000..b2b43ea5f3
--- /dev/null
+++ b/src/qml/doc/src/qmllint/plugin.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-plugin.html
+\ingroup qmllint-warnings-and-errors
+
+\title plugin
+\brief BRIEF
+
+\section1 plugin
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/prefixed-import-type.qdoc b/src/qml/doc/src/qmllint/prefixed-import-type.qdoc
new file mode 100644
index 0000000000..f2f53bcffb
--- /dev/null
+++ b/src/qml/doc/src/qmllint/prefixed-import-type.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-prefixed-import-type.html
+\ingroup qmllint-warnings-and-errors
+
+\title prefixed-import-type
+\brief BRIEF
+
+\section1 prefixed-import-type
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/qtqml-qmllint-warnings-and-errors.qdoc b/src/qml/doc/src/qmllint/qtqml-qmllint-warnings-and-errors.qdoc
new file mode 100644
index 0000000000..894f5f4306
--- /dev/null
+++ b/src/qml/doc/src/qmllint/qtqml-qmllint-warnings-and-errors.qdoc
@@ -0,0 +1,9 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\group qmllint-warnings-and-errors
+\title QML Lint Warning and Errors
+
+Here is an overview over all QML Lint warning and error messages.
+*/
diff --git a/src/qml/doc/src/qmllint/read-only-property.qdoc b/src/qml/doc/src/qmllint/read-only-property.qdoc
new file mode 100644
index 0000000000..7bc6b5fcc2
--- /dev/null
+++ b/src/qml/doc/src/qmllint/read-only-property.qdoc
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-read-only-property.html
+\ingroup qmllint-warnings-and-errors
+
+\title Readonly Property
+\brief A readonly property was written.
+
+\section1 Cannot Assign To Read-Only Property
+
+\section2 What happened?
+A \l{Read-Only Properties}{read-only property} was written.
+
+\section2 Why is this bad?
+The QML engine will throw a Type Error when it sees the write to a read-only property.
+
+\section2 Example
+\qml
+import QtQuick
+
+Item {
+ id: root
+ readonly property int someNumber: 10
+
+ Component.onCompleted: {
+ someNumber = 20 // not ok: TypeError: Cannot assign to read-only property
+ }
+}
+\endqml
+You can fix this warning by removing the write to the read-only property, by writing to another
+non-read-only property, or by removing the readonly modifier if the property should no longer be
+considered constant.
+
+\sa{Read-Only Properties}
+*/
+
diff --git a/src/qml/doc/src/qmllint/recursion-depth-errors.qdoc b/src/qml/doc/src/qmllint/recursion-depth-errors.qdoc
new file mode 100644
index 0000000000..ed0d2c09b2
--- /dev/null
+++ b/src/qml/doc/src/qmllint/recursion-depth-errors.qdoc
@@ -0,0 +1,53 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-recursion-depth-errors.html
+\ingroup qmllint-warnings-and-errors
+
+\title Recursion Depths Errors
+\brief Qml statement or expression is too deeply nested.
+
+\section1 Maximum Statement Or Expression Depth Exceeded
+\section2 What happened?
+A QML statement or expression was too deeply nested for the compiler. This usually only happens for
+generated code where statements or expressions can be very long, as the recursion limit is usually
+large enough for any sensible QML document.
+
+\section2 Why is this bad?
+The QML engine will not be able to run this code.
+
+\section2 Example
+\qml
+import QtQuick
+
+Item {
+ function f() {
+ let x = 1 + 1 + .... + 1 // maximum depth exceeded: add too many ones together
+ return x
+ }
+
+ Item { Item { .... } } // maximum depth exceeded: too many nested Item's
+}
+\endqml
+
+You can fix this warning by auto-generating smaller code pieces. You could split deeply nested
+Components in multiple files or inline components, or split deeply nested expressions into multiple
+expressions:
+\qml
+import QtQuick
+
+Item {
+ function f() {
+ let x = 1 + 1 + .... + 1 // first half of the split
+ x += 1 + 1 + .... + 1 // second half of the split
+ return x
+ }
+
+ component NestedItem : Item { Item {... }} // first half of the nested Item
+ component DeeplyNestedItem: Item { ... NestedItem{} ... } // second half of the nested Items + NestedItem
+ DeeplyNestedItem {}
+}
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/required.qdoc b/src/qml/doc/src/qmllint/required.qdoc
new file mode 100644
index 0000000000..6252ddef2d
--- /dev/null
+++ b/src/qml/doc/src/qmllint/required.qdoc
@@ -0,0 +1,65 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-required.html
+\ingroup qmllint-warnings-and-errors
+
+\title Component is Missing a Required Property
+\brief A component's required property was not bound.
+
+\section1 Component is Missing a Required Property
+
+\section2 What happened?
+The \l{QML Object Attributes#required-properties}{required property} of a component was not set.
+
+
+\section2 Why is this bad?
+QML applications where components miss required properties will misbehave: they will not
+start at all if a missing required property is detected statically. Dynamically created components
+with missing required properties will not be created at runtime: they will be null instead.
+
+\section2 Example
+\qml
+import QtQuick
+
+Item {
+ component RepeatMe: Item {
+ required property int index;
+ required property int helloWorld;
+ }
+
+ RepeatMe {} // not ok: required properties index and helloWorld not set
+
+ Repeater {
+ model: 10
+ RepeatMe {} // not ok: required property index set by Repeater, but not helloWorld
+ }
+}
+\endqml
+You can fix this warning by setting the required properties
+\qml
+import QtQuick
+
+Item {
+ component RepeatMe: Item {
+ required property int index;
+ required property int helloWorld;
+ }
+
+ RepeatMe {
+ index: 0
+ helloWorld: 42
+ } // ok: all required properties were set
+
+ Repeater {
+ model: 10
+ RepeatMe {
+ helloWorld: index * 2 + 1
+ } // ok: all required properties were set: index by the Repeater and helloWorld by the user
+ }
+}
+\endqml
+
+\sa {QML Coding Conventions#required-properties}{QML Coding Conventions - Required Properties}
+*/
diff --git a/src/qml/doc/src/qmllint/restricted-type.qdoc b/src/qml/doc/src/qmllint/restricted-type.qdoc
new file mode 100644
index 0000000000..d240f55e4a
--- /dev/null
+++ b/src/qml/doc/src/qmllint/restricted-type.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-restricted-type.html
+\ingroup qmllint-warnings-and-errors
+
+\title restricted-type
+\brief BRIEF
+
+\section1 restricted-type
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/signal-handler-parameters.qdoc b/src/qml/doc/src/qmllint/signal-handler-parameters.qdoc
new file mode 100644
index 0000000000..a6510b566b
--- /dev/null
+++ b/src/qml/doc/src/qmllint/signal-handler-parameters.qdoc
@@ -0,0 +1,261 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-signal-handler-parameters.html
+\ingroup qmllint-warnings-and-errors
+
+\title Signal Handler Parameters
+\brief The signal handler does not satisfy the signal types.
+
+This warning category has multiple warnings:
+\list
+ \li \l{Type Of Parameter In Signal Was Not Found}
+ \li \l{Type Of Parameter In Signal Cannot Be Used}
+ \li \l{The Signal Has A Parameter Of The Same Name}
+\endlist
+
+
+\section1 Type Of Parameter In Signal Was Not Found
+
+\section2 What happened?
+A signal handler tried to handle a signal with parameters of unknown QML types.
+
+Usually, this happens when handling C++ defined signals in QML when the module with the C++ defined
+signal does not properly declare its QML dependency to another QML module. If the module with the
+C++ defined signal compiles, then this is a sign that a dependency was only declared on the C++
+level and not on \l{qt_add_qml_module#declaring-module-dependencies}{the QML module level}.
+
+\note If you are importing QML modules with external dependencies, verify that they are
+actually installed, and that their modules end up in an
+\l{Import Statements#qml-import-path}{import path}.
+
+The warning might also indicate that the parameter type of the C++ defined signal does not have
+a QML counterpart. The parameter type might be missing the
+\l{QQmlEngine Class#QML_ELEMENT}{QML_ELEMENT} macro, for example. Refer to
+\l{Defining QML Types from C++} or \l{Overview - QML and C++ Integration} in this case.
+
+\section2 Why is this bad?
+In the first case, the module with the C++ signal has an undeclared dependency on the QML module
+level, which makes it hard to use the module, as users of the module need to guess the module's
+hidden dependencies.
+
+In both cases, QML tooling is not able to find the QML counterpart of the
+C++ type: the \l{Qt Quick Compiler}{compiler} can't compile this signal handler to
+C++ and \l{qmllint Reference}{qmllint} as well as \l{\QMLLS Reference}{\QMLLS}
+can't analyze this handler.
+
+\section2 Example
+
+Let our module have a C++ class with one \c{helloWorld} signal:
+\code
+#include <QQuickItem>
+#include <QtQml/qqmlregistration.h>
+#include <QObject>
+
+class MyCppObject : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+public:
+ MyCppObject(QObject *parent = nullptr)
+ : QObject(parent)
+ {}
+
+signals:
+ void helloWorld(QQuickItem *i);
+
+};
+\endcode
+with following CMakeLists.txt:
+\badcode
+find_package(Qt6 6.5 REQUIRED COMPONENTS Quick QuickControls2)
+
+qt_standard_project_setup(REQUIRES 6.5)
+
+qt_add_executable(mymodule
+ main.cpp
+)
+
+qt_add_qml_module(mymodule
+ URI MyModule
+ VERSION 1.0
+ QML_FILES Main.qml
+ SOURCES mycppobject.cpp mycppobject.h
+)
+
+# declare C++ dependency to Quick
+target_link_libraries(appuntitled27
+ PRIVATE Qt6::Quick
+)
+\endcode
+The C++ dependency \c{Quick} was declared, such that this class can compile and the QQuickItem
+include can be found. Also, mymodule does not have any dependency on QtQuick.
+
+Now, lets try to handle this \c{helloWorld} signal in QML:
+\qml
+import MyModule // name of the module with MyCppObject
+
+MyCppObject {
+ onHelloWorld: function (x) { console.log(x); } // not ok: Type QQuickItem was not found!
+}
+\endqml
+
+The reason of the warning message is that in the QML code, \c{QQuickItem} and its QML counterpart
+\c{Item} are not known: the dependency 'QtQuick' of MyModule was not declared in the CMakeLists.txt!
+
+You can add it as following in the qt_add_qml_module() call:
+\badcode
+qt_add_qml_module(mymodule
+ URI MyModule
+ ...
+ # declare QML dependencies to QtQuick:
+ DEPENDENCIES QtQuick
+ ...
+)
+\endcode
+
+Now, the QML code should be fine again!
+
+\sa {qt_add_qml_module#declaring-module-dependencies}
+
+\omit
+TODO: QML Lint cannot detect if you pass signal parameters by value, reference or pointer!
+Therefore, it will never print that warning.
+\section1 Type Of Parameter In Signal Should Be Passed By Pointer
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+
+TODO: QML Lint cannot detect if you pass signal parameters by value, reference or pointer!
+Therefore, it will never print that warning.
+that warning
+\section1 Type Of Parameter In Signal Should Be Passed By Value Or Const Reference
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+
+\endomit
+
+\section1 Signal Handler Has More Formal Parameters Than The Signal It Handles
+\section2 What happened?
+A signal handler expects more parameters than what the signal will actually provide.
+
+\section2 Why is this bad?
+The extra parameters will be undefined.
+
+\section2 Example
+\qml
+import QtQuick
+
+Item {
+ signal helloWorld(x: QtObject) // signal expects only one parameter
+
+ onHelloWorld: function (x,y,z) {} // not ok: signal handler handles three parameters
+}
+\endqml
+You can fix this warning by removing the extra parameters of the signal handler:
+\qml
+import QtQuick
+
+Item {
+ signal helloWorld(x: QtObject) // signal expects only one parameter
+
+ onHelloWorld: function (x) {} // ok: signal handler handles one parameter
+}
+\endqml
+
+It can also be fixed by adding the missing parameters to the signal's declaration:
+\qml
+import QtQuick
+
+Item {
+ signal helloWorld(x: QtObject, y: int, y: int) // signal expects three parameters
+
+ onHelloWorld: function (x,y,z) {} // ok: signal handler handles three parameters
+}
+\endqml
+
+\section1 The Signal Has A Parameter Of The Same Name
+\section2 What happened?
+The signal or signal handler might have swapped some of its arguments, or some arguments might be
+missing.
+
+\section2 Why is this bad?
+This is very probably a typo and not intended by the user.
+
+\section2 Example
+\section3 Missing Arguments
+\qml
+import QtQuick
+
+Item {
+ signal helloWorld(x: QtObject, y: int)
+
+ onHelloWorld: function (y) {} // not ok: it seems that x was forgotten
+}
+
+\endqml
+You can fix this warning by adding the missing parameters:
+\qml
+import QtQuick
+
+Item {
+ signal helloWorld(x: QtObject, y: int)
+
+ onHelloWorld: function (x, y) {} // ok: parameters have the same order as in helloWorld
+}
+\endqml
+or by renaming the first parameter:
+\qml
+import QtQuick
+
+Item {
+ signal helloWorld(x: QtObject, y: int)
+
+ onHelloWorld: function (x) {} // ok: parameters have the same order as in helloWorld, even if y is missing
+}
+\endqml
+
+\section3 Swapped Arguments
+\qml
+import QtQuick
+
+Item {
+ signal helloWorld(x: QtObject, y: int)
+
+ onHelloWorld: function (y, x) {} // not ok: helloWorld expects first 'x' then 'y'
+}
+
+\endqml
+You can fix this warning by reordering the parameters in the correct order
+\qml
+import QtQuick
+
+Item {
+ signal helloWorld(x: QtObject, y: int)
+
+ onHelloWorld: function (x, y) {} // ok: parameters have the same order as in helloWorld
+}
+
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/syntax.duplicate-ids.qdoc b/src/qml/doc/src/qmllint/syntax.duplicate-ids.qdoc
new file mode 100644
index 0000000000..e1f796c8fd
--- /dev/null
+++ b/src/qml/doc/src/qmllint/syntax.duplicate-ids.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-syntax.duplicate-ids.html
+\ingroup qmllint-warnings-and-errors
+
+\title syntax.duplicate-ids
+\brief BRIEF
+
+\section1 syntax.duplicate-ids
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/syntax.id-quotation.qdoc b/src/qml/doc/src/qmllint/syntax.id-quotation.qdoc
new file mode 100644
index 0000000000..b335bbc962
--- /dev/null
+++ b/src/qml/doc/src/qmllint/syntax.id-quotation.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-syntax.id-quotation.html
+\ingroup qmllint-warnings-and-errors
+
+\title syntax.id-quotation
+\brief BRIEF
+
+\section1 syntax.id-quotation
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/syntax.qdoc b/src/qml/doc/src/qmllint/syntax.qdoc
new file mode 100644
index 0000000000..e2e59e8dce
--- /dev/null
+++ b/src/qml/doc/src/qmllint/syntax.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-syntax.html
+\ingroup qmllint-warnings-and-errors
+
+\title syntax
+\brief BRIEF
+
+\section1 syntax
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/top-level-component.qdoc b/src/qml/doc/src/qmllint/top-level-component.qdoc
new file mode 100644
index 0000000000..111a1e4bf6
--- /dev/null
+++ b/src/qml/doc/src/qmllint/top-level-component.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-top-level-component.html
+\ingroup qmllint-warnings-and-errors
+
+\title top-level-component
+\brief BRIEF
+
+\section1 top-level-component
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/uncreatable-type.qdoc b/src/qml/doc/src/qmllint/uncreatable-type.qdoc
new file mode 100644
index 0000000000..05dcb53edc
--- /dev/null
+++ b/src/qml/doc/src/qmllint/uncreatable-type.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-uncreatable-type.html
+\ingroup qmllint-warnings-and-errors
+
+\title uncreatable-type
+\brief BRIEF
+
+\section1 uncreatable-type
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/unqualified.qdoc b/src/qml/doc/src/qmllint/unqualified.qdoc
new file mode 100644
index 0000000000..7f2e315efe
--- /dev/null
+++ b/src/qml/doc/src/qmllint/unqualified.qdoc
@@ -0,0 +1,52 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-unqualified.html
+\ingroup qmllint-warnings-and-errors
+
+\title Unqualified Access
+\brief Accessing an outer scope without its id.
+
+\section1 Unqualified Access
+
+\section2 What happened?
+
+A parent element was accessed without its \l{QML Object Attributes#the-id-attribute}{id}.
+
+\section2 Why is this bad?
+
+This makes the code harder to read and impedes performance.
+
+\section2 Example
+
+\qml
+import QtQuick
+
+Item {
+ property int helloWorld
+ Item {
+ property int unqualifiedAccess: helloWorld + 1 // not ok: Unqualified access here.
+ }
+}
+\endqml
+
+You can fix this warning by referring to the parent object by
+\l{QML Object Attributes#the-id-attribute}{id}.
+If the object currently has no \l{QML Object Attributes#the-id-attribute}{id}, you will need to add
+one first.
+
+\qml
+import QtQuick
+
+Item {
+ id: root
+ property int helloWorld
+ Item {
+ property int unqualifiedAccess: root.helloWorld + 1 // ok: this access is qualified now!
+ }
+}
+\endqml
+
+\sa {QML Coding Conventions#unqualified-access}{QML Coding Conventions - Unqualified Access}
+*/
diff --git a/src/qml/doc/src/qmllint/unresolved-alias.qdoc b/src/qml/doc/src/qmllint/unresolved-alias.qdoc
new file mode 100644
index 0000000000..63b02613dd
--- /dev/null
+++ b/src/qml/doc/src/qmllint/unresolved-alias.qdoc
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-unresolved-alias.html
+\ingroup qmllint-warnings-and-errors
+
+\title Unresolved Alias
+\brief Property of property alias was not found.
+
+\section1 Unresolved Alias
+
+\section2 What happened?
+A property alias should hold a reference to another property, see also
+\l{QML Object Attributes#property-aliases}{QML Object Attributes - Property Aliases}.
+In this case, it holds a reference to a property that was not found.
+
+\section2 Why is this bad?
+Instances of components with unresolved alias will not be created at runtime:
+they will be null instead.
+
+\section2 Example
+\qml
+import QtQuick
+
+Item {
+ id: someId
+ property int helloWorld
+
+ property alias helloWorldAlias: helloWorld // not ok: aliases have to refer by id
+ property alias helloWorldAlias2: someId.helloWorlddd // not ok: no helloWorlddd in someId
+ property alias helloWorldAlias3: someIddd.helloWorld // not ok: someIddd does not exist
+}
+
+\endqml
+You can fix this warning by making sure that the id and the properties of the alias property
+really do exist:
+\qml
+import QtQuick
+
+Item {
+ id: someId
+ property int helloWorld
+
+ property alias helloWorldAlias: someId.helloWorld // ok: alias refers by id
+ property alias helloWorldAlias2: someId.helloWorld // ok: helloWorld does exist in someId
+ property alias helloWorldAlias3: someId.helloWorld // ok: someId does exist
+}
+\endqml
+*/
diff --git a/src/qml/doc/src/qmllint/unresolved-type.qdoc b/src/qml/doc/src/qmllint/unresolved-type.qdoc
new file mode 100644
index 0000000000..5b0a943fe8
--- /dev/null
+++ b/src/qml/doc/src/qmllint/unresolved-type.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-unresolved-type.html
+\ingroup qmllint-warnings-and-errors
+
+\title unresolved-type
+\brief BRIEF
+
+\section1 unresolved-type
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/unused-imports.qdoc b/src/qml/doc/src/qmllint/unused-imports.qdoc
new file mode 100644
index 0000000000..58821afb88
--- /dev/null
+++ b/src/qml/doc/src/qmllint/unused-imports.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-unused-imports.html
+\ingroup qmllint-warnings-and-errors
+
+\title unused-imports
+\brief BRIEF
+
+\section1 unused-imports
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/use-proper-function.qdoc b/src/qml/doc/src/qmllint/use-proper-function.qdoc
new file mode 100644
index 0000000000..d87667a6f9
--- /dev/null
+++ b/src/qml/doc/src/qmllint/use-proper-function.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-use-proper-function.html
+\ingroup qmllint-warnings-and-errors
+
+\title use-proper-function
+\brief BRIEF
+
+\section1 use-proper-function
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/var-used-before-declaration.qdoc b/src/qml/doc/src/qmllint/var-used-before-declaration.qdoc
new file mode 100644
index 0000000000..5089ecf276
--- /dev/null
+++ b/src/qml/doc/src/qmllint/var-used-before-declaration.qdoc
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-var-used-before-declaration.html
+\ingroup qmllint-warnings-and-errors
+
+\title var-used-before-declaration
+\brief BRIEF
+
+\section1 var-used-before-declaration
+
+\section2 What happened?
+TODO
+
+\section2 Why is this bad?
+TODO
+
+\section2 Example
+\qml
+\endqml
+You can fix this warning by TODO
+\qml
+\endqml
+*/
+
diff --git a/src/qml/doc/src/qmllint/with.qdoc b/src/qml/doc/src/qmllint/with.qdoc
new file mode 100644
index 0000000000..bfdde2e86b
--- /dev/null
+++ b/src/qml/doc/src/qmllint/with.qdoc
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qmllint-warnings-and-errors-with.html
+\ingroup qmllint-warnings-and-errors
+
+\title With Statements
+\brief With statements are strongly discouraged in QML.
+
+\section1 With Statements
+
+\section2 What happened?
+The JavaScript \c{with} statement was used.
+
+\section2 Why is this bad?
+With statements might cause false positives when analysing unqualified identifiers. Also, \c{with}
+statements are
+\l{https://262.ecma-international.org/#sec-with-statement}{marked as deprecated by the latest JavaScript standard}.
+
+\section2 Example
+\qml
+import QtQuick
+
+Item {
+ function f() {
+ with (Math) {
+ return PI
+ }
+ }
+}
+\endqml
+You can fix this warning by replacing the \c{with} statement with a destructuring property,
+for example:
+\qml
+import QtQuick
+
+Item {
+ function f() {
+ const { PI } = Math;
+ return PI
+ }
+}
+
+\endqml
+
+\note You can find more replacement ideas
+\l{https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with?retiredLocale=de#examples}{here}.
+*/
+
diff --git a/src/qml/doc/src/qmlsa-plugin-system.md b/src/qml/doc/src/qmlsa-plugin-system.md
new file mode 100644
index 0000000000..606bda9e55
--- /dev/null
+++ b/src/qml/doc/src/qmlsa-plugin-system.md
@@ -0,0 +1,124 @@
+# The qmllint plugin system (Qml Static Analysis / QmlSA)
+
+In order to allow for users to extend qmllint and for us to separate module specific linting warnings into separate modules so they don't pollute qmllint - we created a plugin system. We will refer to it as QmlSA for short in the rest of this document.
+
+It currently does not have a stable API and doesn't have any public headers.
+
+## Anatomy of a plugin
+
+A basic QQmlSA plugin header looks like this:
+
+```cpp
+#include <QtPlugin>
+#include <QtCore/qobject.h>
+#include <QtQmlCompiler/private/qqmlsa_p.h>
+
+class FooPlugin : public QObject, public QQmlSA::LintPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QmlLintPluginInterface_iid FILE "metadata.json")
+ Q_INTERFACES(QQmlSA::LintPlugin)
+
+public:
+ void registerPasses(QQmlSA::PassManager *manager, const QQmlSA::Element &rootElement) override;
+};
+```
+
+Note the reference to the metadata file. This is required in order for a QQmlSA plugin to work properly and must contain the following entries:
+
+```js
+{
+ /* The name of the plugin. Shouldn't contain any spaces, ideally with the first letter capitalized */
+ "name": "PluginName",
+ /* Plugin author. You may or may not provide a contact email in here as well */
+ "author": "John Doe",
+ /* A short description of the plugin - should not contain multiple lines */
+ "description": "A plugin for doing X",
+ /* A version string. There are no strict requirements in how you use this but it should be present */
+ "version": "1.0"
+}
+```
+
+The plugin implementation itself is rather simple:
+
+```cpp
+void FooPlugin::registerPasses(QQmlSA::PassManager *manager, const QQmlSA::Element &rootElement)
+{
+ // You can register either element or property passes
+ manager->registerElementPass(std::make_unique<SomeElementPass>(manager));
+ manager->registerPropertyPass(std::make_shared<PropertyTest>(manager), "SomeModule", "SomeElement",
+ "somePropertyName");
+ // ...or check whether a module has been imported in a certain file
+ manager->hasImportedModule("QtQuick.Controls")
+
+ // You may also inspect the root element
+ rootElement->filePath()
+}
+```
+
+As you can see there's calls to ``registerElementPass`` adn ``registerPropertyPass`` in the above example. We will explain both of these in more detail in the next section.
+
+## The passes
+
+The way QQmlSA plugins work is that they can register different kinds of passes which will run and iterate over the QML file being linted in different ways.
+
+Right now QmlSA has two types of passes:
+
+## Element passes (QQmlSA::ElementPass)
+
+These run for every QML element present in the QML scope being linted.
+
+### Methods
+
+The pass has a ``shouldRun`` and ``run`` method.
+
+``shouldRun`` checks whether the element is interesting to the pass at hand or not (i.e. by checking whether the element is derived from a certain type). It then returns either true or false.
+
+If it returns true, the ``run`` is executed. This will do the actual checking and emitting of warnings.
+
+**Do not do anything computationally expensive in shouldRun**. Either it has to be moved into the constructor (i.e. resolving a type that has to be checked against) or it should be done later in ``run``. This is because shouldRun will be run for every single element in the document and this can easily get too much.
+
+## Property passes (QQmlSA::PropertyPass)
+
+These run every time a property is written from, written to or has a binding created on.
+
+Because there are many more instances of this happening in a QML document then there are elements this pass works a bit differently than element passes.
+
+When registering a property pass you will need to specify what type and property the pass should work on. You may omit the type name if you're interested in all properties with a certain name (i.e. ``width``) or omit the property name if you're interested in all properties of a certain type.
+**In the interest of performance you should always prefer fully specifying what you're interested in if at all possible.**
+
+Note that unlike with Element passes you may register the same pass multiple times with different types and properties. This is so you can use one pass across different types and properties.
+
+### Methods
+
+(All of the following only apply if it happens in the scope of the document)
+
+* ``onBinding`` - Called when a binding on a property gets created.
+* ``onRead`` - Called when a property is read. Either as part of a binding or in a script block.
+* ``onWrite`` - Called when a property is written to. Usually as part of a script block.
+
+All of these bindings get the following parameters:
+* ``element`` - The QQmlSA::Element the property is a part of
+* ``propertyName`` - The name of the property that has been changed (mainly interesting when the pass runs on multiple property names)
+* ``bindingScope/readScope/writeScope`` - The actual scope the action took place. This can be different from the element in case a property is written/read to from another scope or we are talking about grouped properties.
+* ``location`` - A QQmlJS::SourceLocation indicating where this took place. This is useful for printing locations in warnings
+
+Then there are some specific parameters:
+* onBinding
+ * ``binding`` - A ``QQmlJSMetaPropertyBinding`` property that contains type information about the binding and what kind of binding is being dealt with
+ * ``value`` - A QQmlSA::Element mainly used in case it's an object binding (i.e. ``contentItem: Item {}``)
+* onWrite
+ * ``value`` - A QQmlSA::Element containing the value that is being written to the property. It may also only contain type information if it's not a proper object.
+
+## API available to all passes
+
+In these methods passes can use the following methods to interact with qmllint further:
+* ``void emitWarning(QAnyStringView message, QQmlJS::SourceLocation srcLocation = QQmlJS::SourceLocation())``
+ * (should only be used in ElementPass::run and PropertyPass:onRead/Write/Binding) emits a warning highlighting the piece of code given in source location.
+* ``QQmlSA::Element resolveType(QAnyStringView moduleName, QAnyStringView typeName)`` - Allows you to obtain any type from any module i.e. for later comparisons in ``shouldRun``. Use this in the constructor of your pass as doing this every time in ``shouldRun`` would be very expensive.
+
+## TODOs
+- Stabilize the API
+- Make the API public
+ - Don't expose QQmlJSMeta* types or QQmlJSScopes (currently ``QQmlSA::Element == QQmlJSScope``)
+ - Instead: Create a wrapper around these types
diff --git a/src/qml/doc/src/qmlsingletons.qdoc b/src/qml/doc/src/qmlsingletons.qdoc
new file mode 100644
index 0000000000..ad441eca85
--- /dev/null
+++ b/src/qml/doc/src/qmlsingletons.qdoc
@@ -0,0 +1,339 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qml-singleton.html
+\title Singletons in QML
+\brief A guide for using singletons in QML
+
+In QML, a singleton is an object which is created at most once per
+\l{QQmlEngine}{engine}. In this guide, we'll
+\l{How can singletons be created in QML}{explain how to create} singletons
+and \l{Accessing singletons}{how to use them}. We'll also provide some
+best practices for working with singletons.
+
+\section1 How can singletons be created in QML?
+
+There are two separate ways of creating singletons in QML. You can either define
+the singleton in a QML file, or register it from C++.
+
+\section2 Defining singletons in QML
+To define a singleton in QML, you first have to add
+\code
+pragma singleton
+\endcode
+to the top of your file.
+There's one more step: You will need to add an entry to the QML module's
+\l{Module Definition qmldir Files}{qmldir file}.
+
+\section3 Using qt_add_qml_module (CMake)
+When using CMake, the qmldir is automatically created by \l{qt_add_qml_module}.
+To indicate that the QML file should be turned into a singleton, you need to set
+the \c{QT_QML_SINGLETON_TYPE}
+file property on it:
+\code
+set_source_files_properties(MySingleton.qml
+ PROPERTIES QT_QML_SINGLETON_TYPE TRUE)
+\endcode
+
+You can pass multiple files at once to \c{set_source_files_properties}:
+\code
+set(plain_qml_files
+ MyItem1.qml
+ MyItem2.qml
+ FancyButton.qml
+)
+set(qml_singletons
+ MySingleton.qml
+ MyOtherSingleton.qml
+)
+set_source_files_properties(${qml_singletons}
+ PROPERTIES QT_QML_SINGLETON_TYPE TRUE)
+qt_add_qml_module(myapp
+ URI MyModule
+ QML_FILES ${plain_qml_files} ${qml_singletons}
+)
+\endcode
+
+\note set_source_files_properties needs to be called before \c{qt_add_qml_module}
+
+\section3 Without qt_add_qml_module
+If you aren't using \c{qt_add_qml_module}, you'll need to manually create a
+\l{Module Definition qmldir Files}{qmldir file}.
+There, you'll need to mark your singletons accordingly:
+\code
+module MyModule
+singleton MySingleton 1.0 MySingleton.qml
+singleton MyOtherSingleton 1.0 MyOtherSingleton.qml
+\endcode
+See also \l{Object Type Declaration} for more details.
+
+
+\section2 Defining singletons in C++
+
+There are multiple ways of exposing singletons to QML from C++. The main
+difference depends on whether a new instance of a class should be created when
+needed by the QML engine; or if some existing object needs to be exposed to a
+QML program.
+
+\section3 Registering a class to provide singletons
+
+The simplest way of defining a singleton is to have a default-constructible
+class, which derives from QObject and mark it with the \l{QML_SINGLETON} and
+\l{QML_ELEMENT} macros.
+\code
+class MySingleton : public QObject
+{
+ Q_OBJECT
+ QML_SINGLETON
+ QML_ELEMENT
+public:
+ MySingleton(QObject *parent = nullptr) : QObject(parent) {
+ // ...
+ }
+};
+\endcode
+This will register the \c{MySingleton} class under the name \c{MySingleton} in
+the QML module to which the file belongs.
+If you want to expose it under a different name, you can use \l{QML_NAMED_ELEMENT}
+instead.
+
+If the class can't be made default-constructible, or if you need access to
+the \l{QQmlEngine} in which the singleton is instantiated, it is possible to
+use a static create function instead. It must have the signature
+\c{MySingleton *create(QQmlEngine *, QJSEngine *)}, where \c{MySingleton} is
+the type of the class that gets registered.
+\code
+class MyNonDefaultConstructibleSingleton : public QObject
+{
+ Q_OBJECT
+ QML_SINGLETON
+ QML_NAMED_ELEMENT(MySingleton)
+public:
+ MyNonDefaultConstructibleSingleton(QJSValue id, QObject *parent = nullptr)
+ : QObject(parent)
+ , m_symbol(std::move(id))
+ {}
+
+ static MyNonDefaultConstructibleSingleton *create(QQmlEngine *qmlEngine, QJSEngine *)
+ {
+ return new MyNonDefaultConstructibleSingleton(qmlEngine->newSymbol(u"MySingleton"_s));
+ }
+
+private:
+ QJSValue m_symbol;
+};
+\endcode
+
+\note The create function takes both a \l{QJSEngine} and a \l{QQmlEngine} parameter. That is
+for historical reasons. They both point to the same object which is in fact a QQmlEngine.
+
+\section3 Exposing an existing object as a singleton
+
+Sometimes, you have an existing object that might have been created via
+some third-party API. Often, the right choice in this case is to have one
+singleton, which exposes those objects as its properties (see
+\l{Grouping together related data}).
+But if that is not the case, for example because there is only a single object that needs
+to be exposed, use the following approach to expose an instance of type
+\c{MySingleton} to the engine.
+We first expose the Singleton as a \l{QML_FOREIGN}{foreign type}:
+\code
+struct SingletonForeign
+{
+ Q_GADGET
+ QML_FOREIGN(MySingleton)
+ QML_SINGLETON
+ QML_NAMED_ELEMENT(MySingleton)
+public:
+
+ inline static MySingleton *s_singletonInstance = nullptr;
+
+ static MySingleton *create(QQmlEngine *, QJSEngine *engine)
+ {
+ // The instance has to exist before it is used. We cannot replace it.
+ Q_ASSERT(s_singletonInstance);
+
+ // The engine has to have the same thread affinity as the singleton.
+ Q_ASSERT(engine->thread() == s_singletonInstance->thread());
+
+ // There can only be one engine accessing the singleton.
+ if (s_engine)
+ Q_ASSERT(engine == s_engine);
+ else
+ s_engine = engine;
+
+ // Explicitly specify C++ ownership so that the engine doesn't delete
+ // the instance.
+ QJSEngine::setObjectOwnership(s_singletonInstance,
+ QJSEngine::CppOwnership);
+ return s_singletonInstance;
+ }
+
+private:
+ inline static QJSEngine *s_engine = nullptr;
+};
+\endcode
+Then we set \c{SingletonForeign::s_singletonInstance} before we start
+the first engine
+\code
+SingletonForeign::s_singletonInstance = getSingletonInstance();
+QQmlApplicationEngine engine;
+engine.loadFromModule("MyModule", "Main");
+\endcode
+
+\note It can be very tempting to simply use \l{qmlRegisterSingletonInstance} in
+this case. However, be wary of the pitfalls of imperative type registration
+listed in the next section.
+
+\section3 Imperative type registration
+Before Qt 5.15, all types, including singletons were registered via the
+\c{qmlRegisterType} API. Singletons specifically were registered via either
+\l{qmlRegisterSingletonType} or \l{qmlRegisterSingletonInstance}. Besides the
+minor annoyance of having to repeat the module name for each type and the forced
+decoupling of the class declaration and its registration, the major problem with
+that approach was that it is tooling unfriendly: It was not statically possible
+to extract all the necessary information about the types of a module at compile
+time. The declarative registration solved this issue.
+
+\note There is one remaining use case for the imperative \c{qmlRegisterType} API:
+It is a way to expose a singleton of non-QObject type as a \c{var} property via
+\l{qmlRegisterSingletonType}{the QJSValue based \c{qmlRegisterSingletonType} overload}
+. Prefer the alternative: Expose that value as the property of a (\c{QObject}) based
+singleton, so that type information will be available.
+
+\section2 Accessing singletons
+Singletons can be accessed both from QML as well as from C++. In QML, you need
+to import the containing module. Afterwards, you can access the singleton via its
+name. Reading its properties and writing to them inside JavaScript contexts is
+done in the same way as with normal objects:
+
+\code
+import QtQuick
+import MyModule
+
+Item {
+ x: MySingleton.posX
+ Component.onCompleted: MySingleton.ready = true;
+}
+\endcode
+
+Setting up bindings on a singletons properties is not possible; however, if it
+is needed, a \l{Binding} element can be used to achieve the same result:
+\code
+import QtQuick
+import MyModule
+
+Item {
+ id: root
+ Binding {
+ target: MySingleton
+ property: "posX"
+ value: root.x
+ }
+}
+\endcode
+
+\note Care must be taken when installing a binding on a singleton property: If
+done by more than one file, the results are not defined.
+
+\section1 Guidelines for (not) using singletons
+
+Singletons allow you to expose data which needs to be accessed in multiple places
+to the engine. That can be globally shared settings, like the spacing between
+elements, or data models which need to be displayed in multiple places.
+Compared to context properties which can solve a similar use case,
+they have the benefit of being typed, being supported by tooling like the
+\l{\QMLLS Reference}{\QMLLS}, and they are also generally faster at runtime.
+
+It is recommended not to register too many singletons in a module: Singletons,
+once created, stay alive until the engine itself gets destroyed
+and come with the drawbacks of shared state as they are part of the global state.
+Thus consider using the following techniques to reduce the amount of singletons
+in your application:
+
+\section2 Grouping together related data
+Adding one singleton for each object which you want to expose adds quite some boiler plate.
+Most of the time, it makes more sense to group data you want to expose together as properties
+of a single singleton. Assume for instance that you want to create an ebook reader
+where you need to expose three \l{QAbstractItemModel}{abstract item models}, one
+for local books, and two for remote sources. Instead of repeating the process
+for \l{Exposing an existing object as a singleton}{exposing existing objects}
+three times, you can instead create one singleton and set it up before starting
+the main application:
+\code
+class GlobalState : QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+ Q_PROPERTY(QAbstractItemModel* localBooks MEMBER localBooks)
+ Q_PROPERTY(QAbstractItemModel* digitalStoreFront MEMBER digitalStoreFront)
+ Q_PROPERTY(QAbstractItemModel* publicLibrary MEMBER publicLibrary)
+public:
+ QAbstractItemModel* localBooks;
+ QAbstractItemModel* digitalStoreFront;
+ QAbstractItemModel* publicLibrary
+};
+
+int main() {
+ QQmlApplicationEngine engine;
+ auto globalState = engine.singletonInstance<GlobalState *>("MyModule", "GlobalState");
+ globalState->localBooks = getLocalBooks();
+ globalState->digitalStoreFront = setupLoalStoreFront();
+ globalState->publicLibrary = accessPublicLibrary();
+ engine.loadFromModule("MyModule", "Main");
+}
+\endcode
+
+\section2 Use object instances
+In the last section, we had the example of exposing three models as members of a
+singleton. That can be useful when either the models need to be used in multiple
+places, or when they are provided by some external API over which we have no
+control. However, if we need the models only in a single place it might make
+more sense have them as an instantiable type. Coming back to the previous example,
+we can add an instantiable RemoteBookModel class, and then instantiate it inside
+the book browser QML file:
+
+
+\code
+// remotebookmodel.h
+class RemoteBookModel : public QAbstractItemModel
+{
+ Q_OBJECT
+ QML_ELEMENT
+ Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged)
+ // ...
+};
+
+// bookbrowser.qml
+Row {
+ ListView {
+ model: RemoteBookModel { url: "www.public-lib.example"}
+ }
+ ListView {
+ model: RemoteBookModel { url: "www.store-front.example"}
+ }
+}
+
+\endcode
+
+\section2 Passing initial state
+
+While singletons can be used to pass state to QML, they are wasteful when the
+state is only needed for the initial setup of the application. In that case, it
+is often possible to use \l{QQmlApplicationEngine::setInitialProperties}.
+You might for instance want to set \l{Window::visibility} to fullscreen if
+a corresponding command line flag has been set:
+\code
+QQmlApplicationEngine engine;
+if (parser.isSet(fullScreenOption)) {
+ // assumes root item is ApplicationWindow
+ engine.setInitialProperties(
+ { "visibility", QVariant::fromValue(QWindow::FullScreen)}
+ );
+}
+engine.loadFromModule("MyModule, "Main");
+\endcode
+
+*/
diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc
index ae36ebbcc9..e6896addf6 100644
--- a/src/qml/doc/src/qmltypereference.qdoc
+++ b/src/qml/doc/src/qmltypereference.qdoc
@@ -1,39 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
-\qmlmodule QtQml 2.\QtMinorVersion
+\qmlmodule QtQml
\title Qt QML QML Types
\ingroup qmlmodules
\brief List of QML types provided by the Qt QML module
-The \l{Qt QML} module provides the definition and implementation of various
-convenience types which can be used with the QML language, including some
-elementary QML types which can provide the basis for further extensions to the
+The \l{Qt Qml} module provides the definition and implementation of various
+convenience types that can be used with the QML language. This includes
+elementary QML types, which can provide the basis for further extensions to the
QML language. The \l QtObject and \l Component object types are non-visual and
provide building-blocks for extensions to QML.
@@ -43,38 +19,57 @@ The types provided by the \c QtQml module are only available in a QML document
if that document imports the \c QtQml namespace (or if the document imports the
\c QtQuick namespace, as noted below).
-The current version of the \c QtQml module is version 2.\QtMinorVersion, and
-thus it may be imported via the following statement:
+To use the module, import the \c QtQml module with the following statement:
-\qml \QtMinorVersion
-import QtQml 2.\1
+\qml
+import QtQml
\endqml
-Most clients will never need to use the \c QtQml import, as all of the types
-are also provided by the \c QtQuick namespace which may be imported as
-follows:
+Many clients will never need to use the \c QtQml module directly, but will rather
+import it indirectly via the \c QtQuick module as follows:
-\qml \QtMinorVersion
-import QtQuick 2.\1
+\qml
+import QtQuick
\endqml
-See the \l{Qt Quick} module documentation for more information about the \c
-QtQuick namespace and what it provides to QML application developers.
+See the \l{Qt Quick} module documentation for more information about its types.
+
+The QML types for creating lists and models, such as \l ListModel and
+\l ListElement, belong to a submodule, \l{Qt QML Models QML Types}{QtQml.Models}.
-The QML types for creating lists and models, such as \l ListModel and \l
-ListElement, are moved to a submodule, \c QtQml.Models. The \l{Qt QML Models QML
-Types}{Qt QML Models} page has more information.
+The \l WorkerScript QML type belongs to the submodule
+\l{Qt QML WorkerScript QML Types}{QtQml.WorkerScript}.
+Both, \l{Qt QML Models QML Types}{QtQml.Models} and
+\l{Qt QML WorkerScript QML Types}{QtQml.WorkerScript} are automatically imported
+whenever you import \c QtQml. All their types are then available, too.
-The documentation for the types below applies equally to the types of the same
-name provided by the \l{Qt Quick} module, as they are in fact identical.
+The \l{Qt Quick} module automatically imports \c QtQml and, transitively,
+\l{Qt QML Models QML Types}{QtQml.Models} and
+\l{Qt QML WorkerScript QML Types}{QtQml.WorkerScript}, making all their types
+available whenever you import \c QtQuick.
-\section1 Basic Types
+\section1 Value Types
-The following \l{qtqml-typesystem-basictypes.html}{QML basic types} are
+The following \l{qtqml-typesystem-valuetypes.html}{QML Value Types} are
provided:
-\annotatedlist qtqmlbasictypes
+\annotatedlist qtqmlvaluetypes
+
+\section1 Sequence Types
+
+The following \l{QML Sequence Types}{QML sequence types} are provided by the Qt
+QML module in addition to the ones registered with each value type and object
+type:
+
+\list
+ \li \c {std::vector<QString>}
+ \li \c {std::vector<QUrl>}
+ \li \c {std::vector<bool>}
+ \li \c {std::vector<int>}
+ \li \c {std::vector<float>}
+ \li \c {std::vector<double>}
+\endlist
\section1 Object Types
@@ -84,13 +79,14 @@ provided:
*/
/*!
-\qmlbasictype date
-\ingroup qtqmlbasictypes
-\ingroup qtquickbasictypes
+\qmlvaluetype date
+\ingroup qmlvaluetypes
\brief a date value.
The \c date type refers to a date value, including the time of the day.
+Properties of type \c date default to an invalid value.
+
To create a \c date value, specify it as a "YYYY-MM-DDThh:mm:ss.zzzZ" string.
(The T is literal, YYYY is a full year number, MM and DD are month and day
numbers, hh, mm and ss are hours, minutes and seconds, with .zzz as
@@ -98,7 +94,7 @@ milliseconds and Z as time-zone offset. The T and following time are optional.
If they are omitted, the date is handled as the start of UTC's day, which
falls on other dates in some time-zones. When T is included, the :ss.zzz or
just .zzz part can be omitted. With or without those, the zone offset can be
-omitted, in which case local time is used.) For example:
+omitted, in which case local time is used.) For example:
\qml
MyDatePicker { minDate: "2000-01-01 0:0"; maxDate: "2020-12-31 23:59" }
@@ -117,16 +113,15 @@ or a relevant time-zone and selecting a time of day (such as noon)
that reliably exists (daylight-savings transitions skip an hour, near
one end or the other of a day).
-This basic type is provided by the QML language. It can be implicitly converted
+This value type is provided by the QML language. It can be implicitly converted
to a \l{QtQml::Date}{Date} object.
-\sa {QtQml::Date}{QML Date object}, {QML Basic Types}
+\sa {QtQml::Date}{QML Date object}, {QML Value Types}
*/
/*!
-\qmlbasictype point
-\ingroup qtqmlbasictypes
-\ingroup qtquickbasictypes
+\qmlvaluetype point
+\ingroup qtqmlvaluetypes
\brief a value with x and y attributes.
The \c point type refers to a value with \c x and \c y attributes.
@@ -148,17 +143,20 @@ When integrating with C++, note that any QPoint or QPointF value
converted into a \c point value. When a \c point value is passed to C++, it
is automatically converted into a QPointF value.
-\sa{QML Basic Types}
+Properties of type \c point are \c {Qt.point(0, 0)} by default.
+
+\sa{QML Value Types}
*/
/*!
-\qmlbasictype size
-\ingroup qtqmlbasictypes
-\ingroup qtquickbasictypes
-\brief a value with width and height attributes
+\qmlvaluetype size
+\ingroup qtqmlvaluetypes
+\brief a value with width and height attributes.
The \c size type refers to a value with has \c width and \c height attributes.
+Properties of type \c size have \c {Qt.size(-1, -1)} as default value.
+
For example, to read the \c width and \c height values of the
\l {Image::sourceSize} size-type property:
@@ -186,17 +184,19 @@ When integrating with C++, note that any QSize or QSizeF value
converted into a \c size value, and vice-versa. When a \c size value is passed to C++, it
is automatically converted into a QSizeF value.
-\sa{QML Basic Types}
+\sa{QML Value Types}
*/
/*!
-\qmlbasictype rect
-\ingroup qtqmlbasictypes
-\ingroup qtquickbasictypes
+\qmlvaluetype rect
+\ingroup qtqmlvaluetypes
\brief a value with x, y, width and height attributes.
The \c rect type refers to a value with \c x, \c y, \c width and \c height attributes.
+Properties of type \c rect are \c {Qt.rect(0, 0, 0, 0)} by default. This is an
+empty rectangle at the coordinate origin.
+
For example, to read the \c width and \c height values of the \l Item
\l {Item::childrenRect.x}{childrenRect} rect-type property:
@@ -229,5 +229,5 @@ When integrating with C++, note that any QRect or QRectF value
converted into a \c rect value, and vice-versa. When a \c rect value is passed to C++, it
is automatically converted into a QRectF value.
-\sa{QML Basic Types}
+\sa{QML Value Types}
*/
diff --git a/src/qml/doc/src/qt6-changes.qdoc b/src/qml/doc/src/qt6-changes.qdoc
new file mode 100644
index 0000000000..4f95103a4f
--- /dev/null
+++ b/src/qml/doc/src/qt6-changes.qdoc
@@ -0,0 +1,257 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qml-changes-qt6.html
+ \title Changes to Qt QML
+ \ingroup changes-qt-5-to-6
+ \brief Migrate Qt QML to Qt 6.
+
+ Qt 6 is a result of the conscious effort to make the framework more
+ efficient and easy to use.
+
+ We try to maintain binary and source compatibility for all the public
+ APIs in each release. But some changes were inevitable in an effort to
+ make Qt a better framework.
+
+ In this topic we summarize those changes in Qt QML, and provide
+ guidance to handle them.
+
+ \section1 QML language
+
+ \section2 URL resolution
+
+ In Qt 5, relative urls were often, albeit inconsistently, directly resolved, especially when
+ assigned to an url property. In Qt 6 this is no longer the case.
+
+ If you had a QML file stored under "/home/qml/example.qml", and "example.qml" contained
+ \code
+ property url imageFolder: "./images"
+ \endcode
+ then the url property would store the URL "/home/qml/images". This made it impossible to use
+ relative URLs in QML in this way, so in Qt 6, the URL stays relative, and only gets resolved
+ when this is required (e.g. when it is used as the source of an Image component).
+ If you depend on the old behavior, you can use \c Qt.resolvedUrl
+
+ For example, if you have code like
+
+ \code
+ property url imageFolder: "./images"
+ \endcode
+
+ you can rewrite it as
+
+ \code
+ property url imageFolder: Qt.resolvedUrl("./images")
+ \endcode
+
+ Qt.resolvedUrl can be used in both Qt 5 and 6.
+
+ \section2 Variant Properties
+
+ \c variant properties, which have been marked as obsolete since Qt 5, are now treated in exactly
+ the same way as \c var properties.
+ Code that relied on implicit string conversion triggered on assignment to variant properties
+ should be updated to explicitly create an object of the correct type.
+
+ For example, if you have code like
+
+ \code
+ property variant myColor: "red"
+ \endcode
+
+ you can rewrite it as
+
+ \code
+ property variant myColor: Qt.color("red")
+ \endcode
+
+ Implicit conversions were done for strings that could be parsed as
+ \list
+ \li color (use Qt.color instead),
+ \li date (use the Date object instead),
+ \li rect (use Qt.rect instead) and
+ \li size (use Qt.size instead)
+ \endlist
+
+ \c variant still remains a deprecated keyword in Qt 6, though new code is strongly encouraged to
+ use \c var properties instead.
+
+ \note If the type of the property is known not to change, use a property of the concrete type,
+ instead of a \c var property.
+
+ \note These conversions were also applied to \c QVariant properties of classes registered with
+ the engine. As with \c variant properties, code that relied on implicit string conversions need
+ to use the corresponding functions of the Qt object.
+
+ \section1 Source Incompatible API Changes
+
+ \section2 Changed API
+
+ \c QQmlListProperty's \c CountFunction and \c AtFunction have been changed to use \c qsizetype
+ instead of \c int to align with the corresponding changes in Qt's containers.
+
+ For example, if you have code like
+
+ \code
+ int myCountFunction(QQmlListProperty<MyType> *);
+ MyType *myAtFunction(QQmlListProperty<MyType> *, int);
+
+ QQmlListProperty<MyType> myReadOnlyList(containingObject, container, &myCountFunction,
+ &myAtFunction);
+ \endcode
+
+ you can rewrite it as
+
+ \code
+ qsizetype myCountFunction(QQmlListProperty<MyType> *);
+ MyType *myAtFunction(QQmlListProperty<MyType> *, qsizetype);
+
+ QQmlListProperty<MyType> myReadOnlyList(containingObject, container, &myCountFunction,
+ &myAtFunction);
+ \endcode
+
+ Code which needs to supports both Qt 5 and Qt 6 can either use a typedef which is \c int in Qt 5
+ and \c qsizetype in Qt 6, or use \c QList::size_type, which already is such a type alias.
+
+ \section2 Removed API
+
+ Various deprecated functions have been removed.
+
+ \list
+ \li The QQmlListProperty constructor taking a reference has been removed.
+
+ For example, if you have code like
+
+ \code
+ QQmlListProperty<QObject>(owner, owner->objectList);
+ \endcode
+
+ you can rewrite it as
+
+ \code
+ QQmlListProperty<QObject>(owner, &owner->objectList);
+ \endcode
+
+ \li The functions \c qmlDebug, \c qmlInfo, \c qmlWarning, \c qmlContext and \c qmlEngine used
+ to exist both in the global namespace (or Qt namespace in namespaced builds), and in the \c
+ QtQml namespace. These functions now exist only in the global namespace.
+
+ For example, if you have code like
+
+ \code
+ QQmlEngine *engine = QtQml::qmlEngine(qmlObject);
+ \endcode
+
+ you can rewrite it as
+
+ \code
+ QQmlEngine *engine = qmlEngine(qmlObject);
+ \endcode
+
+ \li The \c qmlRegisterType overload taking no arguments has been removed. Use
+ \c qmlRegisterAnonymousType instead, or switch to declarative type registration with
+ \c QML_ANONYMOUS.
+
+ For example, if you have code like
+
+ \code
+ class AnonymousType : public QObject {
+ // ...
+ };
+
+ qmlRegisterType<AnonymousType>();
+ \endcode
+
+ you can rewrite it as
+
+ \code
+ class AnonymousType : public QObject {
+ // ...
+ };
+
+ qmlRegisterAnonymousType<AnonymousType>("MyModule", 1);
+ \endcode
+
+ Or alternatively
+ \code
+ class AnonymousType : public QObject {
+ QML_ANONYMOUS
+ // ...
+ };
+ \endcode
+
+ \li The overloads of \c qmlRegisterExtendedType and \c qmlRegisterInterface
+ which take no version argument have been removed. Use the overloads providing a
+ version, or switch to declarative type registration with QML_EXTENDED
+ and QML_INTERFACE.
+
+ For example, if you have code like
+
+ \code
+ struct GreetInterface
+ {
+ virtual ~GreetInterface();
+ virtual void greet();
+ };
+ Q_DECLARE_INTERFACE(GreetInterface, "org.hi.GreetInterface")
+
+ qmlRegisterInterface<GreetInterface>("Greeter");
+ \endcode
+
+ you can rewrite it as
+
+ \code
+ struct GreetInterface
+ {
+ virtual ~GreetInterface();
+ virtual void greet();
+ };
+ Q_DECLARE_INTERFACE(GreetInterface, "org.hi.GreetInterface")
+
+ qmlRegisterInterface<GreetInterface>("Greeter", 1);
+ \endcode
+
+ Alternatively
+
+ \code
+ struct GreetInterface
+ {
+ QML_INTERFACE(Greeter)
+ virtual ~GreetInterface();
+ virtual void greet();
+ };
+ Q_DECLARE_INTERFACE(GreetInterface, "org.hi.GreetInterface")
+ \endcode
+
+ \note In new code, declarative type registration should be preferred.
+
+ \li The function \c QJSValue::engine has been removed. If access to the engine is required, a
+ reference to it must be stored instead.
+
+ \li \c qmlAttachedPropertiesObjectById and \c qmlAttachedPropertiesObject(int *, const QObject *,
+ const QMetaObject *, bool) have been removed. Use the
+ \c qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc, bool) overload of
+ \c qmlAttachedPropertiesObject instead.
+
+ \li \c QJSEngine::installTranslatorFunctions has been removed. \c QJSEngine::installExtensions
+ is available as a replacement.
+
+ For example, if you have code like
+
+ \code
+ QJSEngine engine;
+ engine.installTranslatorFunctions();
+ \endcode
+
+ you can rewrite it as
+
+ \code
+ QJSEngine engine;
+ engine.installExtensions(QJSEngine::TranslationExtension);
+ \endcode
+
+ \endlist
+
+
+*/
diff --git a/src/qml/doc/src/qtqml-cpp.qdoc b/src/qml/doc/src/qtqml-cpp.qdoc
index 2c4d2a5ade..e337364489 100644
--- a/src/qml/doc/src/qtqml-cpp.qdoc
+++ b/src/qml/doc/src/qtqml-cpp.qdoc
@@ -1,48 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\module QtQml
\title Qt QML C++ Classes
\ingroup modules
+\qtcmakepackage Qml
\qtvariable qml
\brief The C++ API provided by the Qt QML module.
-To include the definitions of the module's classes, use the
-following directive:
-
-\snippet code/doc_src_qtqml.cpp 0
-
-\if !defined(qtforpython)
-To link against the module, add this line to your \l qmake \c
-.pro file:
-
-\snippet code/doc_src_qtqml.pro 0
-\endif
-
For more information on the Qt QML module, see the
-\l{Qt QML} module documentation.
+\l{Qt Qml} module documentation.
*/
diff --git a/src/qml/doc/src/qtqml-qtquick-compiler-tech.qdoc b/src/qml/doc/src/qtqml-qtquick-compiler-tech.qdoc
new file mode 100644
index 0000000000..3631a85b5f
--- /dev/null
+++ b/src/qml/doc/src/qtqml-qtquick-compiler-tech.qdoc
@@ -0,0 +1,123 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-qtquick-compiler-tech.html
+\ingroup overviews
+\title Qt Quick Compiler
+\brief Overview of Qt Quick Compiler components
+
+Qt Quick Compiler lets you process QML and JavaScript code at compile
+time, rather than at run time. This allows for:
+
+\list
+ \li Faster application startup
+ \li Faster evaluation of bindings and functions
+\endlist
+
+The Qt Quick Compiler consist of two components:
+\list
+ \li \l {QML type compiler}
+ \li \l {QML script compiler}
+\endlist
+
+\note \e qmltc, \e qmlsc and \l qmlcachegen are internal build tools. If you
+need to care about their invocation, you are either writing a build system, or
+you are doing something wrong.
+
+\section1 The QML type compiler
+
+The \l{QML type compiler}, \e(qmltc) compiles QML types to C++ classes. These C++
+classes are then added to your application and can be instantiated from other
+C++ code. This way you can avoid much of the overhead of using \l{QQmlComponent}
+to create instances of your QML types. In order to benefit from \l qmltc, you
+need to adapt your C++ code and make use of the new classes.
+
+\l qmltc can only compile a QML document if it completely understands its
+structure. It will fail if an unsupported language feature is encountered.
+It does not have to understand the JavaScript code in bindings and functions,
+though.
+
+\section1 The QML script compiler
+
+The \l{QML script compiler}, (\e qmlsc and \e qmlcachegen) compiles bindings and
+functions to both, an efficient byte code and C++ functions. This process
+automatically happens behind the scenes if you are using \l{qt_add_qml_module}
+to specify your QML modules. For more information about available options to
+control different aspects of QML compilation, see
+\l {Caching compiled QML sources}.
+
+At compile time, for each QML or JavaScript
+document a corresponding C++ file is created and built into the application. The
+C++ file then contains a \e{QML compilation unit}, which consists of:
+
+\list
+ \li An efficient representation of the document structure
+ \li Byte code for all functions and bindings in the document
+ \li C++ code for functions and bindings the compiler fully understands
+\endlist
+
+The QML engine then refrains from compiling the QML or JavaScript source code
+at run time and instead uses the pre-built compilation unit to load the QML
+component and its functions and bindings more quickly. The functions and
+bindings that were compiled to C++ can also be executed faster. Other bindings
+and functions are either interpreted directly from the byte code, or compiled
+to machine code via a JIT compilation step at run time. At compile time, more
+involved type analysis can be performed. Therefore, the generated C++ code
+is generally more efficient than the result of the JIT compilation.
+
+There are limitations on what JavaScript constructs can be compiled to C++.
+For more information, see \l {Limitations when compiling JavaScript to C++}.
+
+\e{qmlsc} will be used instead of \e{qmlcachegen} if the Qt Quick Compiler
+Extensions are installed. It has the following additional features over
+\e{qmlcachegen}:
+
+\list
+ \li It can compile documents in Direct Mode. In that case, the C++ headers
+ of the types underpinning other QML components are directly included
+ and the methods of those types are directly called. Conversely, in
+ Indirect Mode, \e qmlcachegen or \e qmlsc call methods through the
+ lookup mechanism which is also used in the interpreter and JIT.
+ \li It can compile documents in Static Mode. In that case, \e qmlsc assumes
+ that no properties of any types exposed to C++ can be shadowed by
+ derived types. This allows for more bindings and functions to be
+ compiled, but generates invalid code if any properties are shadowed.
+\endlist
+
+Instead of producing C++ as output, \l {qmlsc} and \l {qmlcachegen} can also
+generate .qmlc, .jsc and .mjsc "cache files". These still contain a QML
+compilation unit each, and can be loaded by the QML engine to avoid
+re-compilation. They can only contain document structure and byte code, though.
+Compilation of bindings and functions to C++ is omitted if cache files are
+produced. Neither the CMake nor the qmake build system offered by Qt expose this
+functionality.
+
+\section1 Summary
+
+The following table summarizes the differences between \l{qmltc},
+\l{qmlcachegen} and \l{qmlsc}:
+
+\table
+ \header
+ \li \e qmltc
+ \li \e qmlcachegen
+ \li \e qmlsc
+ \row
+ \li Compiles QML types to C++ classes
+ \li Compiles QML documents to QML compilation units
+ \li Compiles QML documents to QML compilation units
+ \row
+ \li Generated output acts as faster alternative to
+ \l{QQmlComponent}-based object creation.
+ \li Generated output is used internally by the QML engine to avoid
+ re-compilation, and to speed up execution.
+ \li Generated output is used internally by the QML engine to avoid
+ re-compilation, and to speed up execution. Direct Mode and Static
+ Mode can further accelerate your application.
+ \row
+ \li Available for all versions of Qt
+ \li Available for all versions of Qt
+ \li Available for commercial customers
+\endtable
+*/
diff --git a/src/qml/doc/src/qtqml-tooling.qdoc b/src/qml/doc/src/qtqml-tooling.qdoc
new file mode 100644
index 0000000000..45e4528a6b
--- /dev/null
+++ b/src/qml/doc/src/qtqml-tooling.qdoc
@@ -0,0 +1,48 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+/*!
+\group qtqml-tooling
+\title Qt Qml Tooling
+\brief List of Qt Qml Tools and Utilities
+
+The Qt Qml module provides a range of tools and utilities that enhance
+the developer and designer experience and includes some internal tools
+used by Qt. The following sections offer a concise overview of these tools
+and utilities, along with links to additional information about each of them.
+
+\section1 Developer Tools
+
+A set of tools provided by the Qt Qml module that aim to facilitate a QML developer's life
+during various phases of development. These tools are:
+
+\list
+ \li \l {qmllint Reference}{qmllint}
+ \li \l {qmlformat}
+ \li \l {\QMLLS Reference}{qmlls}
+ \li \l {qmlprofiler}
+\endlist
+
+\section1 Designer Tools
+
+The Qt Qml module also provides user facing tools which can increase the productivity
+of designers by helping them with fast prototyping. These tools are:
+
+\list
+ \li \l{qml}
+ \li \l{qmlpreview}
+\endlist
+
+\section1 Internal Tools
+
+Certain utility tools are not intended for direct user interaction.
+Instead, they are all meant to be invoked by the build system,
+augmenting its functionality and capabilities.
+
+\list
+ \li \l {QML type compiler}
+ \li \l {QML script compiler}
+ \li \l {qmltyperegistrar}
+ \li \l {qmlimportscanner}
+\endlist
+
+*/
diff --git a/src/qml/doc/src/qtqml-writing-a-module.qdoc b/src/qml/doc/src/qtqml-writing-a-module.qdoc
new file mode 100644
index 0000000000..c8a99f1a37
--- /dev/null
+++ b/src/qml/doc/src/qtqml-writing-a-module.qdoc
@@ -0,0 +1,461 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-writing-a-module.html
+\title Writing QML Modules
+\brief How to write a custom QML module.
+
+You should declare a QML module using the \l{qt_add_qml_module}
+{CMake QML Module API} to:
+
+\list
+\li Generate \l {Module Definition qmldir Files}{qmldir} and
+ \l {Type Description Files}{*.qmltypes files}.
+\li Register C++ types annotated with \l QML_ELEMENT.
+\li Combine QML files and C++-based types in the same module.
+\li Invoke \l {Ahead-of-Time-Compilation}{qmlcachegen} on all
+ QML files.
+\li Use the pre-compiled versions of QML files inside the module.
+\li Provide the module both in the physical and in the
+ \l{The Qt Resource System}{resource file system}.
+\li Create a backing library and an optional plugin. Link the backing library
+ into the application to avoid loading the plugin at run time.
+\endlist
+
+All the above actions can also be configured separately.
+For more information, see \l {qt_add_qml_module}{CMake QML Module API}.
+
+\section1 Multiple QML Modules in One Binary
+
+You can add multiple QML modules into the same binary. Define a CMake target for
+each module and then link the targets to the executable.
+If the extra targets are all static libraries, the result will be one binary,
+which contains multiple QML modules. In short you can create an application
+like this:
+
+\badcode
+myProject
+ | - CMakeLists.txt
+ | - main.cpp
+ | - main.qml
+ | - onething.h
+ | - onething.cpp
+ | - ExtraModule
+ | - CMakeLists.txt
+ | - Extra.qml
+ | - extrathing.h
+ | - extrathing.cpp
+\endcode
+
+To begin, let's assume main.qml contains an instantiation of Extra.qml:
+
+ \badcode
+ import ExtraModule
+ Extra { ... }
+ \endcode
+
+The extra module has to be a static library so that you can link it
+into the main program. Therefore, state as much in ExtraModule/CMakeLists.txt:
+
+\quotefromfile qml/CMakeLists.txt
+\printuntil extrathing.h
+\printuntil )
+
+This generates two targets: \c extra_module for the backing library, and
+\c extra_moduleplugin for the plugin. Being a static library too, the plugin cannot
+be loaded at runtime.
+
+In myProject/CMakeLists.txt you need to specify the QML module that main.qml
+and any types declared in onething.h are part of:
+
+\quotefromfile qml/myProject-CMakeLists.txt
+\printuntil onething.h
+\printuntil )
+
+
+From there, you add the subdirectory for the extra module:
+
+\quotefromfile qml/CMakeLists.txt
+\skipto add_subdirectory
+\printuntil )
+
+To ensure that linking the extra module works correctly, you need to:
+
+\list
+\li Define a symbol in the extra module.
+\li Create a reference to the symbol from the main program.
+\endlist
+
+QML plugins contain a symbol you can use for this purpose.
+You can use the \l Q_IMPORT_QML_PLUGIN macro to create a reference to this symbol.
+Add the following code to the main.cpp:
+
+\badcode
+#include <QtQml/QQmlExtensionPlugin>
+Q_IMPORT_QML_PLUGIN(ExtraModulePlugin)
+\endcode
+
+\c ExtraModulePlugin is the name of the generated plugin class. It's composed
+of the module URI with \c Plugin appended to it. Then, in the main program's
+CMakeLists.txt, link the plugin, not the backing library, into the main program:
+
+\quotefromfile qml/myProject-CMakeLists.txt
+\skipto target_link_libraries
+\printuntil )
+
+\section1 Versions
+
+QML has a complex system to assign versions to components and modules. In most
+cases you should ignore all of it by:
+
+\list 1
+ \li Never adding a version to your import statements
+ \li Never specifying any versions in \l{qt_add_qml_module}
+ \li Never using \l{QML_ADDED_IN_VERSION} or \l{QT_QML_SOURCE_VERSIONS}
+ \li Never using \l{Q_REVISION} or the \c{REVISION()} attribute in \l{Q_PROPERTY}
+ \li Avoiding unqualified access
+ \li Generously using import namespaces
+\endlist
+
+Versioning is ideally handled outside the language itself. You may, for example,
+keep separate \l{QML Import Path}{import paths} for different sets of QML modules.
+Or you may use a versioning mechanism provided by your operating system to install
+or uninstall packages with QML modules.
+
+In some cases, Qt's own QML modules may show different behavior, depending on what
+version is imported. In particular, if a property is added to a QML component, and
+your code contains unqualified access to another property of the same name, your
+code will break. In the following example, the code will behave differently
+depending on the version of Qt, because the \l [QML] {Rectangle::}{topLeftRadius}
+property was added in Qt 6.7:
+
+\qml
+import QtQuick
+
+Item {
+ // property you want to use
+ property real topLeftRadius: 24
+
+ Rectangle {
+
+ // correct for Qt version < 6.7 but uses Rectangle's topLeftRadius in 6.7
+ objectName: "top left radius:" + topLeftRadius
+ }
+}
+\endqml
+
+The solution here is to avoid the unqualified access. \l{qmllint Reference}{qmllint} can be used to
+find such problems. The following example accesses the property you actually mean
+in a safe, qualified way:
+
+\qml
+import QtQuick
+
+Item {
+ id: root
+
+ // property you want to use
+ property real topLeftRadius: 24
+
+ Rectangle {
+
+ // never mixes up topLeftRadius with unrelated Rectangle's topLeftRadius
+ objectName: "top left radius:" + root.topLeftRadius
+ }
+}
+\endqml
+
+You can also avoid the incompatibility by importing a specific version of QtQuick:
+
+\qml
+// make sure Rectangle has no topLeftRadius property
+import QtQuick 6.6
+
+Item {
+ property real topLeftRadius: 24
+ Rectangle {
+ objectName: "top left radius:" + topLeftRadius
+ }
+}
+\endqml
+
+Another problem solved by versioning is the fact that QML components imported by
+different modules may shadow each other. In the following example, if \c{MyModule} were
+to introduce a component named \c{Rectangle} in a newer version, the \c{Rectangle}
+created by this document would not be a \c {QQuickRectangle} anymore, but rather the
+new \c{Rectangle} introduced by \c{MyModule}.
+
+\qml
+import QtQuick
+import MyModule
+
+Rectangle {
+ // MyModule's Rectangle, not QtQuick's
+}
+\endqml
+
+A good way to avoid the shadowing would be to import \c{QtQuick} and/or \c{MyModule}
+into type namespaces as follows:
+
+\qml
+import QtQuick as QQ
+import MyModule as MM
+
+QQ.Rectangle {
+ // QtQuick's Rectangle
+}
+\endqml
+
+Alternatively, if you import \c{MyModule} with a fixed version, and the new component
+receives a correct version tag via \l{QML_ADDED_IN_VERSION} or \l{QT_QML_SOURCE_VERSIONS},
+the shadowing is also avoided:
+
+\qml
+import QtQuick 6.6
+
+// Types introduced after 1.0 are not available, like Rectangle for example
+import MyModule 1.0
+
+Rectangle {
+ // QtQuick's Rectangle
+}
+\endqml
+
+For this to work, you need to use versions in \c{MyModule}. There are a few things
+to be aware of.
+
+\section2 If you add versions, add them everywhere
+
+You need to add a \c{VERSION} attribute to \l{qt_add_qml_module}. The version should
+be the most recent version provided by your module. Older minor versions of the same
+major version will automatically be registered. For older major versions, see
+\l{#Exporting Multiple Major Versions from The Same Module}{below}.
+
+You should add \l{QML_ADDED_IN_VERSION} or \l{QT_QML_SOURCE_VERSIONS} to every type
+that was \e not introduced in version \c{x.0} of your module, where \c{x} is the current
+major version.
+
+If you forget to add a version tag, the component will be available in all versions,
+making the versioning ineffective.
+
+However, there is no way to add versions to properties, methods, and signals defined
+in QML. The only way to version QML documents is to add a new document with separate
+\l{QT_QML_SOURCE_VERSIONS} for each change.
+
+\section2 Versions are not transitive
+
+If a component from your module \c{A} imports another module \c{B} and instantiates a type
+from that module as the root element, then the import version of \c{B} is relevant for the
+properties available from the resulting component, no matter what version of \c{A} is
+imported by a user.
+
+Consider a file \c{TypeFromA.qml} with version \c{2.6} in module \c{A}:
+
+\qml
+import B 2.7
+
+// Exposes TypeFromB 2.7, no matter what version of A is imported
+TypeFromB { }
+\endqml
+
+Now consider a user of \c{TypeFromA}:
+
+\qml
+import A 2.6
+
+// This is TypeFromB 2.7.
+TypeFromA { }
+\endqml
+
+The user hopes to see version \c{2.6} but actually gets version
+\c{2.7} of the base class \c{TypeFromB}.
+
+Therefore, in order to be safe, you not only have to duplicate your QML files and
+give them new versions when you add properties yourself, but also when you bump
+versions of modules you import.
+
+\section2 Qualified access does not honor versioning
+
+Versioning only affects unqualified access to members of a type or the type itself.
+In the example with \c{topLeftRadius}, if you write \c{this.topLeftRadius}, the
+property will be resolved if you're using Qt 6.7, even if you \c{import QtQuick 6.6}.
+
+\section2 Versions and revisions
+
+With \l{QML_ADDED_IN_VERSION}, and the two-argument variants of \l{Q_REVISION} and
+\l{Q_PROPERTY}'s \c{REVISION()}, you can only declare versions that are tightly coupled
+to the \l{QMetaObject}{metaobject's} revision as exposed in \l{QMetaMethod::revision}
+and \l{QMetaProperty::revision}. This means all the types in your type hierarchy have
+to follow the same versioning scheme. This includes any types provided by Qt itself
+that you inherit from.
+
+With \l{QQmlEngine::}{qmlRegisterType} and related functions you can register any mapping
+between metaobject revisions and type versions. You then need to use the one-argument forms
+of \l{Q_REVISION} and the \c{REVISION} attribute of \l{Q_PROPERTY}. However, this
+can become rather complex and confusing and is not recommended.
+
+\section2 Exporting multiple major versions from the same module
+
+\l qt_add_qml_module by default considers the major version given in its
+VERSION argument, even if the individual types declare other versions in their
+added specific version via \l QT_QML_SOURCE_VERSIONS or \l Q_REVISION.
+If a module is available under more than one version, you also need to decide
+what versions the individual QML files are available under. To declare further
+major versions, you can use the \c PAST_MAJOR_VERSIONS option to
+\c qt_add_qml_module as well as the \c {QT_QML_SOURCE_VERSIONS} property on
+individual QML files.
+
+\quotefile qml/MajorProject-CMakeLists.txt
+
+\c MyModule is available in major versions 1, 2, and 3. The maximum version
+available is 3.2. You can import any version 1.x or 2.x with a positive x. For
+Thing.qml and OtherThing.qml we have added explicit version information.
+Thing.qml is available from version 1.4, and OtherThing.qml is available from
+version 2.2. You have to specify the later versions, too, in each
+\c set_source_files_properties() because you may remove QML files
+from a module when bumping the major version. There is no explicit version
+information for OneMoreThing.qml. This means that OneMoreThing.qml is available
+in all major versions, from minor version 0.
+
+With this setup, the generated registration code will register the module
+\c versions using \l qmlRegisterModule() for each of the major versions. This
+way, all versions can be imported.
+
+
+\section1 Custom Directory Layouts
+
+The easiest way to structure QML modules is to keep them in directories named by
+their URIs. For example, a module My.Extra.Module would live in a directory
+My/Extra/Module relative to the application that uses it. This way, they can
+easily be found at run time and by any tools.
+
+In more complex projects, this convention can be too limiting. You might for
+instance want to group all QML modules in one place to avoid polluting the
+project's root directory. Or you want to reuse a single module in multiple
+applications. For those cases, \c QT_QML_OUTPUT_DIRECTORY in combination with
+\c RESOURCE_PREFIX and \l IMPORT_PATH can be used.
+
+To collect QML modules into a specific output directory, for example a
+subdirectory "qml" in the build directory \l QT_QML_OUTPUT_DIRECTORY, set the
+following in the top-level CMakeLists.txt:
+
+\badcode
+set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml)
+\endcode
+
+The output directories of QML modules move to the new location.
+Likewise, the \c qmllint and \c qmlcachegen invocations are automatically
+adapted to use the new output directory as an \l[QtQml]{QML Import Path}{import path}.
+Because the new output directory is not part of the default QML import path,
+you have to add it explicitly at run time, so that the QML modules can be found.
+
+
+Now that the physical file system is taken care of, you may still want to move
+the QML modules into a different place in the resource file system. This is what
+the RESOURCE_PREFIX option is for. You have to specify it separately in
+each \l qt_add_qml_module. The QML module will then be placed under the specified
+prefix, with a target path generated from the URI appended. For example,
+consider the following module:
+
+\code
+qt_add_qml_module(
+ URI My.Great.Module
+ VERSION 1.0
+ RESOURCE_PREFIX /example.com/qml
+ QML_FILES
+ A.qml
+ B.qml
+)
+\endcode
+
+This will add a directory \c example.com/qml/My/Great/Module to the resource file
+system and place the QML module defined above in it. You don't strictly need to
+add the resource prefix to the QML import path as the module can still be found
+in the physical file system. However, it generally is a good idea to add the
+resource prefix to the QML import path because loading from the resource file
+system is faster than loading from the physical file system for most modules.
+
+If the QML modules are meant to be used in a larger project with multiple import
+paths, you'll have to do an additional step: Even if you add the import paths at
+run time, tooling like \c qmllint does not have access to it, and might fail to
+find the correct dependencies. Use \c IMPORT_PATH to tell tooling about the
+additional paths it has to consider. For example:
+
+\badcode
+qt_add_qml_module(
+ URI My.Dependent.Module
+ VERSION 1.0
+ QML_FILES
+ C.qml
+ IMPORT_PATH "/some/where/else"
+)
+\endcode
+
+\section1 Eliminating Run Time File System Access
+
+If all QML modules are always loaded from the resource
+file system, you can deploy the application as a single binary.
+
+If \l{QTP0001} policy is set to \c NEW, the \c RESOURCE_PREFIX argument
+for \c{qt_add_qml_module()} defaults to \c{/qt/qml/}, therefore your
+modules are placed in \c{:/qt/qml/} in the resource file system.
+This is part of the default \l{QML Import Path}, but not used by Qt
+itself. For modules to be used within your application, this is the right place.
+
+If you have instead specified a custom \c RESOURCE_PREFIX, you have to add the
+custom resource prefix to the \l{QML Import Path}. You can also add multiple
+resource prefixes:
+
+\badcode
+QQmlEngine qmlEngine;
+qmlEngine.addImportPath(QStringLiteral(":/my/resource/prefix"));
+qmlEngine.addImportPath(QStringLiteral(":/other/resource/prefix"));
+// Use qmlEngine to load the main.qml file.
+\endcode
+
+This might be necessary when using third party libraries to avoid module name
+conflicts. Using a custom resource prefix is discouraged in all other cases.
+
+The path \c :/qt-project.org/imports/ is also part of the default \l{QML Import
+Path}. For modules that are heavily re-used across different projects or Qt
+versions, \c :/qt-project.org/imports/ is acceptable as resource prefix. Qt's
+own QML modules are placed there, though. You have to be careful not to
+overwrite them.
+
+Do not add any unnecessary import paths. The QML engine might find your modules
+in the wrong place then. This can trigger problems which can only be reproduced
+in specific environments.
+
+\section1 Integrating custom QML plugins
+
+If you bundle an \l {QQuickImageProvider}{image provider} in the QML module, you
+need to implement the \l {QQmlEngineExtensionPlugin::initializeEngine()}
+method. This, in turn, makes it necessary to write your own plugin. To support
+this use case, \l NO_GENERATE_PLUGIN_SOURCE can be used.
+
+Let's consider a module that provides its own plugin source:
+
+\quotefile qml/myimageprovider.txt
+
+You may declare an image provider in myimageprovider.h, like this:
+
+\badcode
+class MyImageProvider : public QQuickImageProvider
+{
+ [...]
+};
+\endcode
+
+In plugin.cpp you can then define the QQmlEngineExtensionPlugin:
+
+\quotefile qml/plugin.cpp.txt
+
+This will make the image provider available. The plugin and the backing library
+both are in the same CMake target imageproviderplugin. This is done so that the
+linker does not drop parts of the module in various scenarios.
+
+As the plugin creates an image provider, it no longer has a trivial
+\c initializeEngine function. Therefore, the plugin is no longer optional.
+
+*/
diff --git a/src/qml/doc/src/qtqml.qdoc b/src/qml/doc/src/qtqml.qdoc
index 68d2b66950..51a638bf4d 100644
--- a/src/qml/doc/src/qtqml.qdoc
+++ b/src/qml/doc/src/qtqml.qdoc
@@ -1,135 +1,90 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-index.html
-\title Qt QML
-\brief The Qt QML module defines and implements the QML language
+\title Qt Qml
+\brief The Qt Qml module implements the QML language and offers APIs to register
+ types for it.
-The Qt QML module provides a framework for developing applications and libraries
-with the \l{QML Applications}{QML language}. It defines and implements the
+The Qt Qml module provides a framework for developing applications and libraries
+with the \l{The QML Reference}{QML language}. It defines and implements the
language and engine infrastructure, and provides an API to enable application
-developers to extend the QML language with custom types and integrate QML code
-with JavaScript and C++. The Qt QML module provides both a \l{Qt QML QML Types}
-{QML API} and a \l{Qt QML C++ Classes}{C++ API}.
+developers to \l{Registering QML Types and QML Modules}{register} custom QML types
+and modules and integrate QML code with JavaScript and C++. The Qt Qml module
+provides both a \l{Qt QML QML Types}{QML API} and a
+\l{Qt Qml C++ Classes}{C++ API}.
-Note that while the Qt QML module provides the language and infrastructure
-for QML applications, the \l{Qt Quick} module provides many visual components,
-model-view support, an animation framework, and much more for building user
-interfaces.
+\section1 Using the Module
-For those new to QML and Qt Quick, please see
-\l{QML Applications}
-for an introduction to writing QML applications.
+\section2 QML API
-\section1 Getting Started
+\include {module-use.qdocinc} {using the qml api} {QtQml}
-To include the definitions of the module's classes, use the
-following directive:
+The Qt QML module contains the QML framework and important QML types used in
+applications. The constructs of QML are described in the \l{The QML Reference}.
-\code
-#include <QtQml>
-\endcode
+The \l{Qt QML QML Types}{QML API} of the Qt QML module provides a number of
+\l{qtqml-typesystem-objecttypes.html}{QML Object Types},
+\l{qtqml-typesystem-valuetypes.html}{QML Value Types} and namespaces.
-The QML types in Qt QML are available through the \c QtQml import. To use the
-types, add the following import statement to your .qml file:
+\section2 C++ API
-\qml \QtMinorVersion
-import QtQml 2.\1
-\endqml
+\include {module-use.qdocinc} {using the c++ api}
+The C++ API contains some
+\l{Important C++ Classes Provided By The Qt QML Module}{important classes}
+you should get familiar with. It also provides
+\l{Integrating with JavaScript values from C++}{types} to hold JavaScript
+values.
-To link against the module, add this line to your \l qmake \c
-.pro file:
+\section3 Building with CMake
-\code
-QT += qml
-\endcode
+\include {module-use.qdocinc} {building with cmake} {Qml}
-\section1 QML and QML Types
+To provide foreign QML type support for a non-QML library, locate
+the \c QmlIntegration module as follows:
-The Qt QML module contains the QML framework and important QML types used in
-applications. The constructs of QML are described in the \l{The QML Reference}.
+\snippet code/doc_src_qtqml.cmake 1
-In addition to the \l{QML Basic Types}, the module comes with
-the following QML object types:
-\list
-\li \l Component
-\li \l QtObject
-\li \l Binding
-\li \l Connections
-\li \l Timer
-\endlist
-
-The \l{QtQml::Qt}{Qt} global object provides useful enums and functions
-for various QML types.
+See \l{qt6_generate_foreign_qml_types} for details.
-\section2 Lists and Models
+\section3 Building with qmake
-New in Qt 5.1, the model types are moved to a submodule, \c QtQml.Models. The
-\l{Qt QML Models QML Types}{Qt QML Models} page has more information.
+\include {module-use.qdocinc} {building_with_qmake} {qml}
-\list
-\li \l DelegateModel
-\li \l DelegateModelGroup
-\li \l ListElement
-\li \l ListModel
-\li \l ObjectModel
-\endlist
+\section1 Registering QML Types and QML Modules
-\section1 JavaScript Environment for QML Applications
+In order to register types for usage with QML you first need to define a
+\l{Writing QML Modules}{QML module}, preferably using \l{qt_add_qml_module} in CMake.
+Then, you can add C++ headers to your new module, and
+\l{Defining QML Types from C++}{define types} to be
+\l{Exposing Attributes of C++ Types to QML}{exposed to QML} in them.
-JavaScript expressions allow QML code to contain application logic. Qt QML
-provides the framework for running JavaScript expressions in QML and from C++.
+\section1 Tweaking the engine
-These sections are from \l{The QML Reference}.
- \list
- \li \l{qtqml-javascript-topic.html}{Integrating QML and JavaScript}
- \li \l{qtqml-javascript-expressions.html}{Using JavaScript Expressions with QML}
- \li \l{qtqml-javascript-dynamicobjectcreation.html}{Dynamic QML Object Creation from JavaScript}
- \li \l{qtqml-javascript-resources.html}{Defining JavaScript Resources In QML}
- \li \l{qtqml-javascript-imports.html}{Importing JavaScript Resources In QML}
- \li \l{qtqml-javascript-hostenvironment.html}{JavaScript Host Environment}
- \endlist
+There are a number of knobs you can turn to customize the behavior of the QML engine.
+The page on \l{Configuring the JavaScript Engine}{configuring the JavaScript engine}
+lists the environment variables you may use to this effect. The description of the
+\l{The QML Disk Cache}{QML Disk Cache} describes the options related to how your QML
+components are compiled and loaded.
-\section1 Integrating QML with C++ Applications
+\section1 Articles and Guides
-The module also provides the framework for running QML applications.
-The QML framework allows QML code to contain JavaScript expressions and for
-the QML code to interact with C++ code.
+These articles contain information about Qt Qml.
\list
-\li \l{Important C++ Classes Provided By The Qt QML Module}
-\li \l{Integrating QML and C++}
+ \li \l{The QML Reference}
+ \li \l{Qt Qml Tooling}
+ \li \l{Writing QML Modules}
+ \li \l{Singletons in QML}
\endlist
-\section1 Additional Frameworks
+\section1 Reference
+
\list
-\li \l{The Declarative State Machine Framework}
+ \li \l {Qt QML C++ Classes} {C++ Classes}
+ \li \l {Qt QML QML Types} {QML Types}
\endlist
\section1 Licenses and Attributions
@@ -146,22 +101,4 @@ modules under following permissive licenses:
\generatelist{groupsbymodule attributions-qtqml}
-\section1 Guides and Other Information
-
-Further information for writing QML applications:
-\list
-\li \l{The QML Reference}
-\li \l{QML Applications}
- - essential information for application development with QML and Qt Quick
-\li \l{Qt Quick} - a module which provides a set of QML types and C++ classes
- for building user interfaces and applications with QML
-\endlist
-
-\section2 Reference
-\list
-\li \l{Qt QML C++ Classes}{C++ Classes}
-\li \l{Qt QML QML Types}{QML Types}
-\li \l{Qt QML Examples}{Examples}
-\endlist
-
*/
diff --git a/src/qml/doc/src/statemachine.qdoc b/src/qml/doc/src/statemachine.qdoc
deleted file mode 100644
index 231b85af76..0000000000
--- a/src/qml/doc/src/statemachine.qdoc
+++ /dev/null
@@ -1,328 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
- \qmlmodule QtQml.StateMachine 1.\QtMinorVersion
- \title Qt QML State Machine QML Types
- \brief Provides QML types to create and execute state graphs.
-
- The following is a list of QML types provided by the module:
-*/
-
-
-/*!
- \page qmlstatemachine.html
- \title The Declarative State Machine Framework
- \brief Overview of the Declarative State Machine Framework for constructing and executing state graphs.
-
- \ingroup frameworks-technologies
-
- \tableofcontents
-
- The Declarative State Machine Framework provides types for creating and
- executing state graphs in QML. It is similar to the C++ State Machine
- framework based on Harel's
- \l{Statecharts: A visual formalism for complex systems}, which
- is also the basis for UML state diagrams. Like its
- \l{The State Machine Framework}{C++ counterpart}, the framework provides an
- API and execution model based on \l{State Chart XML: State Machine Notation for
- Control Abstraction}{State Chart XML (SCXML)}
- to embed the elements and semantics of statecharts in QML applications.
-
- For user interfaces with multiple visual states, independent of the
- application's logical state, consider using QML States and Transitions.
-
- These following QML types are provided by framework to create event-driven
- state machines:
-
- \annotatedlist statemachine-qmltypes
-
- \section1 Using Both QtQuick and QtQml.StateMachine Imports
-
- \warning If you're attempting to import both \l{QtQuick} and
- \e{QtQml.StateMachine} in one single QML file, make sure to import
- \e{QtQml.StateMachine} \e{last}. This way, the \e{State} type is provided
- by the Declarative State Machine Framework and not by \l{QtQuick}:
-
- \qml \QtMinorVersion
- import QtQuick 2.\1
- import QtQml.StateMachine 1.\1
-
- StateMachine {
- State {
- // okay, is of type QtQml.StateMachine.State
- }
- }
- \endqml
-
- Alternatively, you can import \e{QtQml.StateMachine} into a separate
- namespace to avoid any ambiguity with QtQuick's \e{State} item:
-
- \qml \QtMinorVersion
- import QtQuick 2.\1
- import QtQml.StateMachine 1.\1 as DSM
-
- DSM.StateMachine {
- DSM.State {
- // ...
- }
- }
- \endqml
-
- \section1 A Simple State Machine
-
- To demonstrate the core functionality of the State Machine API, let's look
- at an example: A state machine with three states, \c s1, \c s2 and \c
- s3. The state machine is controlled by a single Button; when the button
- is clicked, the machine transitions to another state. Initially, the state
- machine is in state \c s1. The following is a state chart showing the
- different states in our example.
-
- \image statemachine-button.png
-
- The following snippet shows the code needed to create such a state machine.
-
- \snippet qml/statemachine/statemachine-button.qml 0
-
- The state machine runs asynchronously to become part of your application's
- event loop.
-
- \section1 State Machines That Finish
-
- The state machine defined in the previous section never finishes. In order
- for a state machine to be able to finish, it needs to have a top-level \e
- final state (FinalState object). When the state machine enters the top-level
- final state, the machine emits the \l{State::finished}{finished}
- signal and halts.
-
- All you need to do to introduce a final state in the graph is create a
- FinalState object and use it as the target of one or more transitions.
-
- \section1 Sharing Transitions
-
- Assume we wanted the user to be able to quit the application at any time by
- clicking a Quit button. In order to achieve this, we need to create a final
- state and make it the target of a transition associated with the Quit
- button's \e clicked() signal. We could add a transition for each state;
- however, this seems redundant and one would also have to
- remember to add such a transition from every new state that is added in the
- future.
-
- We can achieve the same behavior (namely that clicking the Quit button quits
- the state machine, regardless of which state the state machine is in) by
- grouping states \c s1, \c s2 and \c s3. This is done by creating a new
- top-level state and making the three original states children of the new
- state. The following diagram shows the new state machine.
-
- \image statemachine-button-nested.png
-
- The three original states have been renamed \c s11, \c s12 and \c s13 to
- reflect that they are now childrens of the new top-level state, \c s1. Child
- states implicitly inherit the transitions of their parent state. This means
- it is now sufficient to add a single transition from \c s1 to the final
- state, \c s2. New states added to \c s1 will automatically inherit this
- transition.
-
- All that's needed to group states is to specify the proper parent when the
- state is created. You also need to specify which of the child states is the
- initial one (the child state the state machine should enter when the
- parent state is the target of a transition).
-
- \snippet qml/statemachine/statemachine-button-nested.qml 0
-
- In this case we want the application to quit when the state machine is
- finished, so the machine's \e finished() signal is connected to the
- application's \e quit() slot.
-
- A child state can override an inherited transition. For example, the
- following code adds a transition that effectively causes the Quit button to
- be ignored when the state machine is in state, \c s12.
-
- \snippet qml/statemachine/statemachine-button-nested-ignore-quit.qml 0
-
- A transition can have any state as its target irrespective of where the
- target state is in the state hierarchy.
-
- \section1 Using History States
-
- Imagine that we wanted to add an "interrupt" mechanism to the example
- discussed in the previous section; the user should be able to click a button
- to have the state machine perform some non-related task, after which the
- state machine should resume whatever it was doing before (i.e. return to the
- old state, which is one of the three states in this case).
-
- Such behavior can easily be modeled using \e{history states}. A history
- state (HistoryState object) is a pseudo-state that represents the child
- state that the parent state was in before it exited last.
-
- A history state is created as a child of the state for which we wish to
- record the current child state; when the state machine detects the presence
- of such a state at runtime, it automatically records the current (real)
- child state when the parent state exits. A transition to the history
- state is in fact a transition to the child state that the state machine had
- previously saved; the state machine automatically "forwards" the transition
- to the real child state.
-
- The following diagram shows the state machine after the interrupt mechanism
- has been added.
-
- \image statemachine-button-history.png
-
- The following code shows how it can be implemented; in this example we
- simply display a message box when \c s3 is entered, then immediately return
- to the previous child state of \c s1 via the history state.
-
- \snippet qml/statemachine/statemachine-button-history.qml 0
-
- \section1 Using Parallel States
-
- Assume that you wanted to model a set of mutually exclusive properties of a
- car in a single state machine. Let's say the properties we are interested in
- are Clean vs Dirty, and Moving vs Not moving. It would take four mutually
- exclusive states and eight transitions to represent the states and freely
- move between all possible combinations as shown in the following state chart.
-
- \image statemachine-nonparallel.png
-
- If we added a third property (say, Red vs Blue), the total number of states
- would double, to eight; and if we added a fourth property (say, Enclosed vs
- Convertible), the total number of states would double again, to 16.
-
- This exponential increase can be reduced using parallel states, which enables
- linear growth in the number of states and transitions as we add more
- properties. Furthermore, states can be added to or removed from the parallel
- state without affecting any of their sibling states. The following state
- chart shows the different paralles states for the car example.
-
- \image statemachine-parallel.png
-
- To create a parallel state group, set childMode to QState.ParallelStates.
-
- \qml
- State {
- id: s1
- childMode: QState.ParallelStates
- State {
- id: s11
- }
- State {
- id: s12
- }
- }
- \endqml
-
- When a parallel state group is entered, all its child states will be
- simultaneously entered. Transitions within the individual child states
- operate normally. However, any of the child states may take a transition
- which exits the parent state. When this happens, the parent state and all of
- its child states are exited.
-
- The parallelism in the State Machine framework follows an interleaved
- semantics. All parallel operations will be executed in a single, atomic step
- of the event processing, so no event can interrupt the parallel operations.
- However, events will still be processed sequentially, as the machine itself
- is single threaded. For example, consider the situation where there are two
- transitions that exit the same parallel state group, and their conditions
- become true simultaneously. In this case, the event that is processed last
- of the two will not have any effect.
-
- \section1 Exiting a Composite State
-
- A child state can be final (a FinalState object); when a final child state
- is entered, the parent state emits the State::finished signal. The
- following diagram shows a composite state \c s1 which does some processing
- before entering a final state:
-
- \image statemachine-finished.png
-
- When \c s1 's final state is entered, \c s1 will automatically emit
- \l{State::finished}{finished}. We use a signal transition to cause this event to
- trigger a state change:
-
- \qml
- State {
- id: s1
- SignalTransition {
- targetState: s2
- signal: s1.finished
- }
- }
- \endqml
-
- Using final states in composite states is useful when you want to hide the
- internal details of a composite state. The outside world should be able to
- enter the state and get a notification when the state has completed its work,
- without the need to know the internal details. This is a very powerful
- abstraction and encapsulation mechanism when building complex (deeply nested)
- state machines. (In the above example, you could of course create a transition
- directly from \c s1 's \c done state rather than relying on \c s1 's
- finished() signal, but with the consequence that implementation details of
- \c s1 are exposed and depended on).
-
- For parallel state groups, the State::finished signal is emitted when \e
- all the child states have entered final states.
-
- \section1 Targetless Transitions
-
- A transition need not have a target state. A transition without a target can
- be triggered the same way as any other transition; the difference is that
- it doesn't cause any state changes. This allows you to react to a signal or
- event when your machine is in a certain state, without having to leave that
- state. For example:
-
- \qml
- Button {
- id: button
- text: "button"
- StateMachine {
- id: stateMachine
- initialState: s1
- running: true
- State {
- id: s1
- SignalTransition {
- signal: button.clicked
- onTriggered: console.log("button pressed")
- }
- }
- }
- }
- \endqml
-
- The "button pressed" message will be displayed each time the button is clicked, but the
- state machine will remain in its current state (s1). If the target state
- were explicitly set to s1, s1 would be exited and re-entered each
- time (the QAbstractState::entered and QAbstractState::exited
- signals would be emitted).
-
- \section1 Related Information
-
- \list
- \li \l{Qt QML State Machine QML Types}
- \li \l{The State Machine Framework}
- \endlist
-*/
diff --git a/src/qml/doc/src/tools/qtqml-tooling-qml.qdoc b/src/qml/doc/src/tools/qtqml-tooling-qml.qdoc
new file mode 100644
index 0000000000..6a0a335839
--- /dev/null
+++ b/src/qml/doc/src/tools/qtqml-tooling-qml.qdoc
@@ -0,0 +1,107 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-tooling-qml.html
+\title qml
+\brief Overview of the qml command line utility.
+\ingroup qtqml-tooling
+
+\section1 The qml utility
+\c The qml utility tool loads QML documents and creates a window to show the scene
+if your QML document includes a visual item. You can also evaluate non-visual QML
+documents with it.
+It is mainly meant for testing your QML applications or components quickly
+as described in \l {Prototyping with the QML Runtime Tool}{here}.
+
+\table
+\header
+ \li Usage:
+\row
+ \li qml [\l{options}] files... [-- args...]
+\endtable
+
+\section2 options
+
+\table
+\header
+ \li Option
+ \li Description
+\row
+ \li -h, --help
+ \li Displays help on commandline options.
+\row
+ \li --help-all
+ \li Displays help, including generic Qt options.
+\row
+ \li -v, --version
+ \li Displays version information.
+\row
+ \li -a, --apptype <core|gui|widget>
+ \li Select which application class to use. Default is gui.
+\row
+ \li -I <path>
+ \li Prepend the given path to the import paths.
+\row
+ \li -f <file>
+ \li Load the given file as a QML file.
+\row
+ \li -c, --config <file>
+ \li Load the given built-in configuration or configuration file.
+\row
+ \li --list-conf
+ \li List the built-in configurations.
+\row
+ \li --translation <file>
+ \li Load the given file as the translations file.
+\row
+ \li --dummy-data <file>
+ \li Load QML files from the given directory as context properties. (deprecated)
+\row
+ \li --desktop
+ \li Force use of desktop OpenGL (AA_UseDesktopOpenGL).
+\row
+ \li --gles
+ \li Force use of GLES (AA_UseOpenGLES).
+\row
+ \li --software
+ \li Force use of software rendering (AA_UseSoftwareOpenGL).
+\row
+ \li --core-profile
+ \li Force use of OpenGL Core Profile.
+\row
+ \li --disable-context-sharing
+ \li Disable the use of a shared GL context for QtQuick Windows
+\row
+ \li --enable-shader-cache
+ \li Enable persistent caching of generated shaders
+\row
+ \li --transparent
+ \li Requests an alpha channel in order to enable semi-transparent windows.
+\row
+ \li --multisample
+ \li Requests 4x multisample antialiasing.
+\row
+ \li --quiet
+ \li Suppress all output.
+\row
+ \li --verbose
+ \li Print information about what qml is doing, like specific file URLs being loaded.
+\row
+ \li --slow-animations
+ \li Run all animations in slow motion.
+\row
+ \li --fixed-animations
+ \li Run animations off animation tick rather than wall time.
+\row
+ \li -r, --rhi <backend>
+ \li Set the backend for the Qt graphics abstraction (RHI). Backend is one of:
+ default, vulkan, metal, d3d11, gl
+\row
+ \li -S <selector>
+ \li Add selector to the list of QQmlFileSelectors.
+
+\endtable
+
+
+*/
diff --git a/src/qml/doc/src/tools/qtqml-tooling-qmlformat.qdoc b/src/qml/doc/src/tools/qtqml-tooling-qmlformat.qdoc
new file mode 100644
index 0000000000..b516104f66
--- /dev/null
+++ b/src/qml/doc/src/tools/qtqml-tooling-qmlformat.qdoc
@@ -0,0 +1,146 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-tooling-qmlformat.html
+\title qmlformat
+\brief Overview of the qmlformat tool.
+\ingroup qtqml-tooling
+
+\section1 qmlformat
+\e qmlformat is a tool that automatically formats QML files in accordance
+with the \l{QML Coding Conventions}. \l{Details}{More...}
+
+\table
+\header
+ \li Usage:
+\row
+ \li qmlformat [\l{options}] \l{arguments}
+\endtable
+
+\section2 Options
+\target options
+The following options are available:
+
+\table
+\header
+ \li Option
+ \li Default Value
+ \li Description
+\row
+ \li -h, --help
+ \li
+ \li Displays help on commandline options.
+\row
+ \li --help-all
+ \li
+ \li Displays help, including generic Qt options.
+
+\row
+ \li -v, --version
+ \li
+ \li Displays version information.
+\row
+ \li -V, --verbose
+ \li
+ \li Verbose mode. Outputs more detailed information.
+\row
+ \li --write-defaults
+ \li
+ \li Writes defaults settings to .qmlformat.ini and exits
+ (Warning: This will overwrite any existing settings and comments!)
+\row
+ \li --ignore-settings
+ \li
+ \li Ignores all settings files and only takes command line options into consideration
+\row
+ \li -i, --inplace
+ \li
+ \li Edit file in-place instead of outputting to stdout.
+\row
+ \li -f, --force
+ \li
+ \li Continue even if an error has occurred.
+\row
+ \li -t, --tabs
+ \li
+ \li Use tabs instead of spaces.
+\row
+ \li -w, --indent-width <width>
+ \li 4
+ \li How many spaces are used when indenting.
+\row
+ \li -n, --normalize
+ \li
+ \li Reorders the attributes of the objects according to the QML Coding Guidelines.
+\row
+ \li -F, --files <file>
+ \li
+ \li Format all files listed in file, in-place
+\row
+ \li -l, --newline <newline>
+ \li
+ \li Override the new line format to use (native macos unix windows).
+\row
+ \li --objects-spacing
+ \li
+ \li Ensure spaces between objects (only works with normalize option).
+\row
+ \li --functions-spacing
+ \li
+ \li Ensure spaces between functions (only works with normalize option).
+
+\endtable
+
+\section2 Arguments
+\target arguments
+\table
+\header
+ \li Arguments:
+\row
+ \li filenames
+\endtable
+
+\section2 Details
+\e qmlformat is flexible and can be configured according to your needs.
+
+\section3 Output
+qmlformat writes the formatted version of the file to stdout.
+If you wish to have your file updated in-place specify the \c{-i} flag.
+
+\section3 Grouping Properties, Functions, and Signals Together
+With \c{-n} or \c{--normalize} flag, \e qmlformat groups all properties, functions,
+and signals together, instead of retaining the order you specified.
+
+\section3 Settings File
+You can configure \e qmlformat by including a settings file \c{.qmlformat.ini} in your
+project source or in the parent directories of your project source folder. A default
+settings file can be obtained by passing the \c{--write-defaults} flag. This generates the
+\c{.qmlformat.ini} file in the current working directory.
+
+\warning \c{--write-defaults} will overwrite any existing settings and comments!
+
+\section3 Formatting a List of Files
+While you can pass a list of files to be formatted as arguments, qmlformat provides
+\c {-F} option to format a set of files stored in a file. In this case, formatting will happen
+inplace.
+
+\code
+ // FileList.txt
+ main.qml
+ mycomponent.qml
+\endcode
+
+Then, use it like
+\code
+ qmlformat -F FileList.txt
+\endcode
+
+\note If the file contains an invalid entry, for example, a file path that
+doesn't exist or a valid file path but the content is an invalid qml document,
+then \c qmlformat will error out for that particular entry. It will still format
+the valid file entries in place.
+
+\warning If you provide -F option, qmlformat will ignore the positional arguments.
+
+*/
diff --git a/src/qml/doc/src/tools/qtqml-tooling-qmlimportscanner.qdoc b/src/qml/doc/src/tools/qtqml-tooling-qmlimportscanner.qdoc
new file mode 100644
index 0000000000..7a4047cf7d
--- /dev/null
+++ b/src/qml/doc/src/tools/qtqml-tooling-qmlimportscanner.qdoc
@@ -0,0 +1,15 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-tooling-qmlimportscanner.html
+\title qmlimportscanner
+\brief Overview of the qmlimportscanner utility.
+\ingroup qtqml-tooling
+
+\section1 qmlimportscanner
+\c qmlimportscanner is an internal tool shipped with Qt Qml to scan QML files
+inside the directory for QML import dependencies. It is meant to be invoked by
+the build system only, users shouldn't need to execute it directly.
+
+*/
diff --git a/src/qml/doc/src/tools/qtqml-tooling-qmllint.qdoc b/src/qml/doc/src/tools/qtqml-tooling-qmllint.qdoc
new file mode 100644
index 0000000000..b26fe1eff0
--- /dev/null
+++ b/src/qml/doc/src/tools/qtqml-tooling-qmllint.qdoc
@@ -0,0 +1,141 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-tooling-qmllint.html
+\title qmllint Reference
+\ingroup qtqml-tooling
+\brief A tool for verifying the syntax of QML files and warning about
+anti-patterns.
+
+\e qmllint is a tool shipped with Qt, that verifies the syntatic validity of
+QML files.
+It also warns about some QML anti-patterns. If you want to disable a specific
+warning type, you can find the appropriate flag for doing so by passing
+\c{--help} on the command line.
+
+By default, some issues will result in warnings that will be printed and result
+in a non-zero exit code.
+Minor issues however (such as unused imports) are just informational messages
+by default and will not affect the exit code.
+qmllint is very configurable and allows for disabling warnings or changing how
+they are treated.
+Users may freely turn any issue into a warning, informational message, or
+disable them outright.
+
+qmllint warns about:
+\list
+ \li Unqualified accesses of properties
+ \li Usage of signal handlers without a matching signal
+ \li Usage of with statements in QML
+ \li Issues related to compiling QML code
+ \li Unused imports
+ \li Deprecated components and properties
+ \li And many other things
+\endlist
+
+\note In order for qmllint to work properly, it requires type information.
+That information is provided by QML modules in the import paths.
+The current directory, as well as the import paths for Qt's built-in types,
+are used as import paths by default.
+To add more import paths not included in the default,
+add them via the \c{-I} flag.
+
+To get an overview and explanation of all available command line options, run \c{qmllint --help}.
+
+\section2 Compiler warnings
+
+qmllint can warn you about code that cannot be compiled by \l{qmlsc}.
+
+These warnings are not enabled by default. In order to enable them specify
+\c{--compiler warning} or adjust your settings file accordingly.
+
+\section2 Marking components and properties as deprecated
+
+qmllint allows you to mark both properties and components as deprecated:
+
+\code
+@Deprecated { reason: "Use NewCustomText instead" }
+Text {
+ @Deprecated { reason: "Use newProperty instead" }
+ property int oldProperty
+ property int newProperty
+ Component.onCompleted: console.log(oldProperty); // Warning: XY.qml:8:40: Property "oldProperty" is deprecated (Reason: Use newProperty instead)
+}
+\endcode
+
+Deprecation warnings for components will be shown every time the component is created.
+
+\section2 Disabling warnings inline
+
+You may at any point disable warnings temporarily in a file using \c{// qmllint
+disable}.
+
+You can do this at the end of a line when a single line produces warnings:
+
+\code
+Item {
+ property string foo
+ Item {
+ property string bar: foo // qmllint disable unqualified
+ }
+}
+\endcode
+
+Alternatively you can disable comments for a block of lines by putting the
+comment in a line only containing \c{// qmllint disable}, ending the block with
+\c{// qmllint enable}:
+
+\code
+Item {
+ property string foo
+ Item {
+ // qmllint disable unqualified
+ property string bar: foo
+ property string bar2: foo
+ // qmllint enable unqualified
+ }
+}
+\endcode
+
+qmllint interprets all single line comments starting with \c {qmllint} as
+directives. Thus you may not start a comment that way unless you wish to enable
+or disable warnings.
+
+\note As done in the examples above it is preferable to explicitly specify the
+warning or a list of warnings you want to disable instead of disabling all
+warnings. This can be done by simply listing warning categories after \c{qmllint disable} (the names are
+the same as the options listed in \c{--help}).
+
+\section2 Settings
+
+In addition to passing command-line options, you can also
+configure qmllint via a settings file.
+The command line \c{--write-defaults} will generate one for you.
+
+Setting files are named \c{.qmllint.ini} and look like this:
+
+\quotefile qmllint/config.ini
+
+Warning levels may be set to \c{info}, \c{warning} or \c{disable} just as with
+command line options.
+
+qmllint will automatically look for a settings file at the location of the qml
+file that is being linted.
+It also looks through all parent directories to find this file and
+automatically applies the settings therein. You can disable this behavior by
+using \c{--ignore-settings}.
+You may always override these defaults by specifying command line parameters
+that take precedence over the warning levels in settings.
+
+\section2 Scripting
+
+qmllint can write or output JSON via the \c{--json <file>} option which will return valid JSON
+with warning messages, file and line location of warnings, and their severity
+level. Use the special filename '-' to write to stdout instead of a file.
+This can be used to more easily integrate qmllint in your pre-commit hooks or
+CI testing.
+
+\sa {Type Description Files}
+\sa {Qt Quick Tools and Utilities}
+*/
diff --git a/src/qml/doc/src/tools/qtqml-tooling-qmlls.qdoc b/src/qml/doc/src/tools/qtqml-tooling-qmlls.qdoc
new file mode 100644
index 0000000000..e9c737c036
--- /dev/null
+++ b/src/qml/doc/src/tools/qtqml-tooling-qmlls.qdoc
@@ -0,0 +1,168 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-tooling-qmlls.html
+\title \QMLLS Reference
+\brief Overview of \QMLLS (qmlls).
+\ingroup qtqml-tooling
+
+\QMLLS is a tool shipped with Qt that helps you write code
+in your favorite (LSP-supporting) editor.
+See \l{https://microsoft.github.io/language-server-protocol/}{Language Server Protocol}
+for more information.
+
+Currently, it enables your editor to:
+\list
+ \li Autocomplete your code
+ \li Display qmllint warnings
+ \li Navigate to definitions in QML files
+ \li Find usages of JavaScript variables and QML objects
+ \li Rename JavaScript variables and QML objects
+ \li Format QML files
+\endlist
+
+\note qmlls is currently in development, see \l{Known Limitations} for
+more details.
+
+\section1 Supported Features
+
+\section2 Linting
+
+\QMLLS can automatically lint opened QML files
+and display warnings or errors straight in the editor. See
+\l{qmllint Reference}{qmllint} for more information about the linting process.
+
+\section2 Formatting
+
+\QMLLS can format entire files from inside
+the editor. See \l{qmlformat} for more information about the
+formatting process.
+
+
+\section2 Finding Definitions
+
+\QMLLS can find definitions of JavaScript variables,
+functions, QML object id's and QML properties from their usages.
+
+\QMLLS can also find the definition of types used in
+type annotations for JavaScript functions, QML object properties,
+and QML object instantiation.
+
+\section2 Finding Usages
+
+\QMLLS can find usages of JavaScript variables,
+QML object properties, JavaScript functions, QML object methods,
+and QML object id's.
+
+\section2 Renaming
+
+\QMLLS can rename JavaScript variables and functions,
+as well as QML object properties, methods, and id's, as long as
+they are defined in a QML file.
+
+\section2 Suggesting Autocompletion Items
+
+\QMLLS provides autocompletion suggestions for
+JavaScript variables, expressions, and statements, as well as
+QML object properties, methods, and id's.
+
+\section2 Tracking Changes in C++ Files
+
+\QMLLS can track changes in C++ files defining QML
+types. It automatically rebuilds CMake QML modules to provide
+accurate and up-to-date warnings and completion items for C++
+defined QML types.
+
+You can
+\l{Disabling automatic CMake builds}{disable this feature}.
+
+\section1 Setting up the \QMLLS in Your Editor
+
+\note You can find the \QMLLS binary under
+\c{<Qt installation folder>/bin/qmlls} in installations of Qt
+made with \QOI.
+
+\section2 Setting up the Build Directory
+
+\QMLLS needs to know the location of your build
+folder. You can pass it the following ways:
+\list
+ \li The \c{--build-dir} command line option. In this case
+your editor should invoke \c{qmlls} as following:
+\badcode
+<path/to/qmlls> --build-dir <path/to/build-directory>
+\endcode
+ \li The \c{QMLLS_BUILD_DIRS} environment variable.
+ \li The \c{.qmlls.ini} settings file, see \l {Configuration File}.
+\endlist
+
+\note When the build directory is specified in multiple ways, the
+command line option takes preference over the environment variable
+that takes precedence over the setting file.
+
+\section2 Disabling Automatic CMake Builds
+
+\c{qmlls} will try to trigger a CMake rebuild when it detects that the
+source code of a C++ defined QML type has been modified.
+
+To disable this feature, use the following ways:
+\list
+ \li The \c{--no-cmake-calls} command line option. In this case
+your editor should invoke \c{qmlls} as follows:
+\badcode
+<path/to/qmlls> --build-dir <path/to/build-directory> --no-cmake-calls
+\endcode
+ \li The \c{QMLLS_NO_CMAKE_CALLS} environment variable.
+ \li The \c{.qmlls.ini} settings file, see \l {Configuration File}.
+\endlist
+
+\section1 Configuration File
+
+\QMLLS can be configured via a configuration file \c{.qmlls.ini}.
+This file should be in the root source directory of the project.
+It should be a text file in the ini-format.
+
+\note \c{.qmlls.ini} files can be generated automatically via
+\l{QT_QML_GENERATE_QMLLS_INI}.
+
+The configuration file should look like this:
+\code
+// .qmlls.ini
+[General]
+buildDir=<path/to/build-directory>
+no-cmake-calls=<true-or-false>
+\endcode
+
+Currently, the configuration file can be used to set the build
+directory of the current project and optionally disable the automatic
+CMake rebuild functionality for C++ defined QML types.
+
+\note \QMLLS can create default configuration files
+using the \c{--write-defaults} option. This will overwrite an
+already existing .qmlls.ini file in the current directory.
+
+\section1 Known Limitations
+
+\QMLLS might emit false positive warnings on projects
+that were not built, as it needs the build information to find
+QML modules defined in the same project, for example.
+
+Despite covering many common QML features,
+the \QMLLS is still in development with some features
+yet to be supported:
+
+\list
+ \li Renaming QML types.
+ \li Suggesting autocompletions on invalid QML files.
+ \li Navigating to definitions of objects defined in C++.
+ \li Supporting all QML and JavaScript language constructs for all features.
+\endlist
+
+The QML code model in the \QMLLS does not yet
+support all of the JavaScript language constructs, which means that
+some features like navigating to definition and finding usages might not
+work on these language constructs.
+
+
+*/
diff --git a/src/qml/doc/src/tools/qtqml-tooling-qmlpreview.qdoc b/src/qml/doc/src/tools/qtqml-tooling-qmlpreview.qdoc
new file mode 100644
index 0000000000..5e9da3d2f4
--- /dev/null
+++ b/src/qml/doc/src/tools/qtqml-tooling-qmlpreview.qdoc
@@ -0,0 +1,74 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-tooling-qmlpreview.html
+\title qmlpreview
+\brief Overview of the qmlpreview utility.
+\ingroup qtqml-tooling
+
+\section1 The Qml Preview
+The QML Preview tool watches QML and JavaScript files on disk and updates
+the application live with any changes. The application to be previewed
+has to have QML debugging enabled. \l {details}{More...}
+
+\table
+\header
+ \li Usage
+\row
+ \li qmlpreview [\l{options}] executable [parameters...]
+\endtable
+
+\section2 options
+
+\table
+\header
+ \li Option
+ \li Description
+\row
+ \li --verbose
+ \li Print debugging output.
+\row
+ \li -h, --help
+ \li Displays help on commandline options.
+\row
+ \li --help-all
+ \li Displays help, including generic Qt options.
+\row
+ \li -v, --version
+ \li Displays version information.
+\endtable
+
+\section2 Arguments
+
+\table
+ \header
+ \li Argument
+ \li Description
+ \row
+ \li executable
+ \li The path of the executable file that loads a QML document.
+ \row
+ \li parameters
+ \li Arguments of the executable
+
+\endtable
+
+\section2 Details
+\target details
+
+\section3 Enable QML Debugging
+To enable QML debugging, make sure you build your application with appropriate
+configuration parameters. When using qmake, you should add \c {CONFIG+=qml_debug}
+in the \c {.pro} file. If you use another build system, then \c {QT_QML_DEBUG}
+variable should be defined.
+
+\badcode
+ qt_add_executable(MyApp
+ ...
+ )
+
+ target_compile_definitions(MyApp PRIVATE QT_QML_DEBUG)
+\endcode
+
+*/
diff --git a/src/qml/doc/src/tools/qtqml-tooling-qmlprofiler.qdoc b/src/qml/doc/src/tools/qtqml-tooling-qmlprofiler.qdoc
new file mode 100644
index 0000000000..6bce0417b7
--- /dev/null
+++ b/src/qml/doc/src/tools/qtqml-tooling-qmlprofiler.qdoc
@@ -0,0 +1,10 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-tooling-qmlprofiler.html
+\title qmlprofiler
+\brief Overview of the qml profiler tool.
+\ingroup qtqml-tooling
+
+*/
diff --git a/src/qml/doc/src/tools/qtqml-tooling-qmltyperegistrar.qdoc b/src/qml/doc/src/tools/qtqml-tooling-qmltyperegistrar.qdoc
new file mode 100644
index 0000000000..1f2103d1b1
--- /dev/null
+++ b/src/qml/doc/src/tools/qtqml-tooling-qmltyperegistrar.qdoc
@@ -0,0 +1,10 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-tooling-qmltyperegistrar.html
+\title qmltyperegistrar
+\brief Overview of the qmltyperegistrar utility.
+\ingroup qtqml-tooling
+
+*/
diff --git a/src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc b/src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc
new file mode 100644
index 0000000000..836acc3f6a
--- /dev/null
+++ b/src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc
@@ -0,0 +1,92 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-tooling-svgtoqml.html
+\title svgtoqml
+\brief The SVG to QML converter tool
+\ingroup qtqml-tooling
+
+\c svgtoqml is a command line tool shipped with Qt that converts an SVG document
+to a QML file. This QML file can then be used as a component in Qt Quick
+applications. The \l{Weather Forecast Example} includes multiple QML files that have been generated
+using this tool.
+
+\section1 Overview
+The \c svgtoqml will convert an SVG file to a QML file which uses Qt Quick primitives. Since
+Qt Quick supports scalable vector graphics, the resulting item will be smoothly transformable as far
+as this is possible. As a baseline, the tool supports most of the static features of the SVG Tiny 1.2
+profile. Certain additional features are supported, determined on a case-by-case basis. Interactive
+features and animations are not supported.
+
+\section1 Usage
+The basic usage of \c svgtoqml is to provide an input file and an output file:
+\c{svgtoqml input.svg output.qml}. This will read the \c{input.svg} file and convert it into the
+corresponding Qt Quick scene in \c{output.qml}, which can then be used as part of a Qt Quick
+application.
+
+In addition, it supports the following options:
+
+\table
+\header
+ \li Option
+ \li Description
+\row
+ \li --copyright-statement <string>
+ \li Adds <string> as a comment at the beginning of the generated file.
+\row
+ \li --curve-renderer
+ \li Enables the curve renderer backend for \l{Qt Quick Shapes}. This enables smooth, antialiased
+ shapes in the scene without multi-sampling, but at some extra cost.
+\row
+ \li --optimize-paths
+ \li Enables optimization of paths before committing them to the QML file, potentially making
+ them faster to load and render later.
+\row
+ \li --outline-stroke-mode
+ \li Stroke the outline (contour) of the filled shape instead of the original path.
+\row
+ \li -t, --type-name <string>
+ \li In place of \l{Shape}, the output will use the type name <string> instead. This is
+ enables using a custom item to override the default behavior of \l{Shape} items.
+\row
+ \li -v, --view
+ \li Display a preview of the Qt Quick item as it will be generated.
+\endtable
+
+\section1 Comparison to other options
+There are multiple options for including SVG content in Qt Quick. The following will give an
+overview of where \c svgtoqml fits into the story.
+
+\section2 Comparison to Qt Svg
+\l{Qt Svg} is a module which provides a parser and software renderer for SVG files. In addition, it
+includes an image loader plugin, so that SVG files can be loaded directly by the \l{Image} element
+in Qt Quick. The SVG will then be rasterized and cached at a specified size and redrawing it will
+be quite cheap. But zooming into the image without pixelation will involve reloading it at a
+different size, which in turn can be expensive.
+
+\c svgtoqml (and the \l{VectorImage} component) are alternative ways of rendering the same content.
+Once loaded into Qt Quick, transforms can be changed while retaining the geometry data needed to
+render the scene in GPU memory. Thus, the vector image can be redrawn at different scales with very
+little overhead.
+
+If the image size will not change during the life time of the application, however, loading the
+SVG as an \l{Image} will be more efficient. In this case, if the SVG is always rendered at a
+small subset of possible sizes, consider pre-rasterizing it to an image format which is more
+efficient to load, such as \c PNG.
+
+\section2 Comparison to VectorImage
+The \l{VectorImage} component provides the same basic functionality as \c svgtoqml, but instead of
+pregenerating the Qt Quick scene as a QML file, it creates the scene at runtime. This allows loading
+SVG files that are not provided at build time and thus allows for more flexibility. Pregenerating
+the scenes with \c svgtoqml allows optimizing the scene before it is loaded. Thus, for files that
+are available at build time, \c svgtoqml is the preferred option.
+
+\section2 Comparison to PathSvg
+The \l{PathSvg} component is part of the \l{Qt Quick Shapes} module. It provides a way to define
+paths with the syntax used by SVG, where the control points of a path are specified as a string. It
+does not support loading SVG files, so it is not a direct alternative to \c svgtoqml. If a complex
+SVG contains a specific shape needed by the application, then copying this path description into
+\l{PathSvg} may be more convenient than generating the full file.
+
+*/
diff --git a/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-script-compiler.qdoc b/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-script-compiler.qdoc
new file mode 100644
index 0000000000..302c71882a
--- /dev/null
+++ b/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-script-compiler.qdoc
@@ -0,0 +1,120 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-qml-script-compiler.html
+\title QML script compiler
+\brief A tool to compile functions and expressions in QML.
+\keyword qmlsc
+\ingroup qtqml-tooling
+
+The QML script compiler compiles functions and expressions in QML and JavaScript
+files to a byte code that can be interpreted or Just-in-time compiled by the
+QML engine.
+
+In addition, it compiles some functions and expressions in QML files into C++
+code, within limitations set by the nature of JavaScript. It generates C++ code
+for functions that can be exhaustively analyzed. The following flow chart
+explains the compilation workflow.
+
+\image qmlsc-compilation-scheme.png
+
+QML script compiler is available in two versions. One is \e qmlcachegen, which
+is a part of the \l{Qt Quick Compiler}. Another one is \e qmlsc, which is a part
+of the commercial-only add-on \e{Qt Quick Compiler Extensions}.
+
+\section1 qmlcachegen
+\e qmlcachegen uses the meta-object system and generates lookups and stores them in a
+central place, a compilation unit. The compilation unit contains a representation of
+document structure, compact byte code representation for each function and expression,
+and native code for functions and bindings that compiler fully understands.
+The byte code in a compilation unit can be used by the QML engine to avoid re-compilation
+and to speed up execution.
+
+\section1 qmlsc
+\e qmlsc, on the flip side, extends the base functionality of qmlcachegen by providing
+two extra modes.
+
+\list
+\li \l {static mode}
+\li \l {direct mode}
+\endlist
+
+\section2 static mode
+In static mode, qmlsc assumes that no properties of any types exposed to C++ can be
+shadowed by derived types. It eliminates the shadow checking mechanism and allows more
+JavaScript code to be compiled to C++ and eventually generates faster code.
+
+To enable static mode in qmlsc, you should pass \c{--static} via \c{QT_QMLCACHEGEN_ARGUMENTS} to \l{qt_add_qml_module}.
+\badcode
+ qt_add_qml_module(someTarget
+ ...
+ )
+
+ set_target_properties(someTarget PROPERTIES
+ QT_QMLCACHEGEN_ARGUMENTS "--static"
+ )
+\endcode
+
+\warning qmlsc static-mode generates invalid code if any properties are shadowed in
+the QML document.
+
+\section2 direct mode
+In direct mode, qmlsc assumes that all C++ types used in your QML code are available
+and can be included as C++ headers to the generated code. Then the generated code
+accesses or modifies properties by directly calling getters, setters and invokable
+functions in those headers which makes the execution even faster. This means you have to
+link to private Qt APIs in CMake.
+
+\warning Private Qt APIs change often. You will need to recompile Qt for each new version.
+
+\warning If a type is only defined in a plugin or has no header, you can’t use it in direct mode.
+
+To enable direct mode, you should consider the followings:
+
+\list
+ \li you should pass \c{--direct-calls} via \c{QT_QMLCACHEGEN_ARGUMENTS} to \l{qt_add_qml_module}.
+
+\badcode
+ qt_add_qml_module(someTarget
+ ...
+ )
+
+ set_target_properties(someTarget PROPERTIES
+ QT_QMLCACHEGEN_ARGUMENTS "--direct-calls"
+ )
+\endcode
+
+ \li Link all the relavant private Qt modules instead of their public counterparts.
+\badcode
+ qt_add_qml_module(someTarget
+ ...
+ )
+
+ target_link_libraries(someTarget PRIVATE
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ ...
+ )
+\endcode
+
+ \li Do not set the \c{PLUGIN_TARGET} to be the same as the backing library target.
+\badcode
+ # direct mode will not function in this setup.
+ qt_add_qml_module(someTarget
+ PLUGIN_TARGET someTarget
+ ...
+ )
+\endcode
+\endlist
+
+\section1 Limitations when compiling JavaScript to C++
+
+Many JavaScript constructs cannot be efficiently represented in C++. The QML
+script compiler skips the C++ code generation for functions that contain such
+constructs and only generates byte code to be interpreted or run through the
+Just-in-time compiler. Most common QML expressions are rather simple: value
+lookups on QObjects, arithmetics, simple if/else or loop constructs. Those can
+easily be expressed in C++, and doing so makes your application run faster.
+
+*/
diff --git a/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc b/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc
new file mode 100644
index 0000000000..38f8fe039b
--- /dev/null
+++ b/src/qml/doc/src/tools/qtquickcompiler/qtqml-qml-type-compiler.qdoc
@@ -0,0 +1,283 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-qml-type-compiler.html
+\title QML type compiler
+\brief A tool to compile QML types to C++ ahead of time.
+\keyword qmltc
+\ingroup qtqml-tooling
+
+The QML type compiler, \c qmltc, is a tool shipped with Qt to translate QML
+types into C++ types that are \e{ahead-of-time} compiled as part of the user
+code. Using qmltc can lead to better run-time performance due to more
+optimization opportunities available to the compiler compared to a
+QQmlComponent-based object creation. The qmltc is part of the \l{Qt Quick Compiler}
+toolchain.
+
+By design, qmltc outputs user-facing code. That code is supposed to be utilized
+by the C++ application directly, otherwise you won't see any benefit. This
+generated code essentially replaces QQmlComponent and its APIs to create objects
+from QML documents. You can find more information under \l{Using qmltc in a QML
+application} and \l{Generated Output Basics}.
+
+In order to enable qmltc:
+
+\list
+ \li Create a \l{qt_add_qml_module}{proper QML module} for your application.
+
+ \li Invoke qmltc, for example, through the \l{qmltc-cmake}{CMake API}.
+
+ \li \c{#include} the generated header file(s) in the application source
+ code.
+
+ \li Instantiate an object of the generated type.
+\endlist
+
+In this workflow qmltc usually runs during the build process. Thus, when qmltc
+rejects a QML document (whether due to errors or warnings, or because of
+constructs qmltc doesn't yet support), the build process will fail. This is
+similar to how you receive qmllint errors when you enable the automatic
+generation of linting targets during \l{qt_add_qml_module}{QML module creation}
+and then attempt to "build" them to run the qmllint.
+
+\warning qmltc is currently in a Tech Preview stage and might not compile an
+arbitrary QML program (see \l{Known Limitations} for more details). When qmltc
+fails, nothing is generated as your application cannot sensibly use the qmltc
+output. If your program contains errors (or unsolvable warnings), they should be
+fixed to enable the compilation. The general rule is to adhere to the best
+practices and follow \l{qmllint Reference}{qmllint} advice.
+
+\note \c qmltc does not guarantee that the generated C++ stays API-, source- or
+binary-compatible between past or future versions, even patch versions.
+Furthermore, qmltc-compiled apps using Qt's QML modules will require linking
+against private Qt API. This is because Qt's QML modules do not usually provide
+a public C++ API since their primary usage is through QML.
+
+
+\section2 Using qmltc in a QML application
+
+From the build system perspective, adding qmltc compilation is not much
+different from adding qml cache generation. Naively, the build process could be
+described as:
+
+\image qmltc-compilation-scheme.png
+
+While the real compilation process is much trickier, this diagram captures the
+core components that qmltc uses: the QML files themselves and qmldir with
+qmltypes information. Simpler applications typically have rather primitive
+qmldir yet, in general, qmldir could be complex, providing essential, nicely
+packed type information that qmltc relies on to perform correct QML-to-C++
+translation.
+
+Nevertheless, adding an extra build step is not enough in qmltc case. The
+application code must also be modified to use qmltc-generated classes instead of
+QQmlComponent or its higher-level alternatives.
+
+\section3 Compiling QML code with qmltc
+
+Qt, starting from Qt 6, uses CMake to build its various components. User
+projects can - and are encouraged to - also use CMake to build their components
+using Qt. Adding out-of-the-box qmltc compilation support to your project would
+require a CMake-driven build flow as well since this flow is centered around
+proper QML modules and their infrastructure.
+
+The easy way to add qmltc compilation is by using the dedicated
+\l{qmltc-cmake}{CMake API} as part of a QML module creation for the application.
+Consider a simple application directory structure:
+
+\badcode
+.
+├── CMakeLists.txt
+├── myspecialtype.h // C++ type exposed to QML
+├── myspecialtype.cpp
+├── myApp.qml // main QML page
+├── MyButton.qml // custom UI button
+├── MySlider.qml // custom UI slider
+└── main.cpp // main C++ application file
+\endcode
+
+Then the CMake code would usually look similar to the following:
+
+\snippet qmltc/CMakeLists.txt qmltc-app-name
+\codeline
+\snippet qmltc/CMakeLists.txt qmltc-qml-files
+\codeline
+\snippet qmltc/CMakeLists.txt qmltc-add-qml-module
+\codeline
+\snippet qmltc/CMakeLists.txt qmltc-compile-to-cpp
+
+\section3 Using the Generated C++
+
+Unlike in the case of QQmlComponent instantiation, the output of qmltc, being
+C++ code, is used directly by the application. Generally, constructing a new
+object in C++ is equivalent to creating a new object through
+QQmlComponent::create(). Once created, the object could be manipulated from C++
+or, for example, combined with QQuickWindow to be drawn on screen.
+
+If a compiled type exposes some required properties, `qmltc` will
+require an initial value for those properties in the constructor for
+the generated object.
+
+Additionally, the constructor for a qmltc object can be provided with
+with a callback to set up initial values for the component's
+properties.
+
+Given a \c{myApp.qml} file, the application code (in both cases) would
+typically look like this:
+
+\if defined(onlinedocs)
+ \tab {generated-c++}{tab-qqmlcomponent}{Using QQmlComponent}{checked}
+ \tab {generated-c++}{tab-qmltc}{Using qmltc-generated class}{}
+ \tabcontent {tab-qqmlcomponent}
+\else
+ \section4 Using QQmlComponent
+\endif
+\snippet qmltc/tst_qmltc_examples.cpp qqmlcomponent-include
+\codeline
+\snippet qmltc/tst_qmltc_examples.cpp qqmlcomponent-app-code-0
+\codeline
+\snippet qmltc/tst_qmltc_examples.cpp qqmlcomponent-app-code-1
+\codeline
+\snippet qmltc/tst_qmltc_examples.cpp qqmlcomponent-app-code-2
+\codeline
+\snippet qmltc/tst_qmltc_examples.cpp qmltc-app-exec
+\if defined(onlinedocs)
+ \endtabcontent
+ \tabcontent {tab-qmltc}
+\else
+ \section4 Using qmltc-generated class
+\endif
+\snippet qmltc/tst_qmltc_examples.cpp qmltc-include
+\codeline
+\snippet qmltc/tst_qmltc_examples.cpp qmltc-app-code
+\codeline
+\snippet qmltc/tst_qmltc_examples.cpp qmltc-app-exec
+\if defined(onlinedocs)
+ \endtabcontent
+\endif
+
+\section2 QML engine
+
+The generated code uses QQmlEngine to interact with dynamic parts of a QML
+document - mainly the JavaScript code. For this to work, no special arrangements
+are needed. Any QQmlEngine instance passed to the constructor of a
+qmltc-generated class object should work correctly as does
+\c{QQmlComponent(engine)}. This also means that you can use
+\l{QQmlEngine}{QQmlEngine methods} that affect QML behavior. However, there are
+caveats. Unlike QQmlComponent-based object creation, qmltc itself \e{does not}
+rely on QQmlEngine when compiling the code to C++. For instance,
+\c{QQmlEngine::addImportPath("/foo/bar/")} - normally resulting in an additional
+import path to scan for - would be completely ignored by the ahead-of-time qmltc
+procedure.
+
+\note To add import paths to the qmltc compilation, consider using a relevant
+argument of the \l{qmltc-cmake}{CMake command} instead.
+
+Generally, you can think of it this way: QQmlEngine involves the application
+process to run, while qmltc does not as it operates \e{before} your application
+is even compiled. Since qmltc makes no attempt to introspect your application's
+C++ source code, there is no way for it to know about certain kinds of QML
+manipulations you, as a user, do. Instead of using QQmlEngine and related
+run-time routines to expose types to QML, adding import paths, etc. you are,
+practically, required to create \l{qt_add_qml_module}{well-behaving QML modules}
+and use \l{Defining QML Types from C++}{declarative QML type registration}.
+
+\warning Despite qmltc working closely with QQmlEngine and creating C++ code,
+the generated classes cannot be further exposed to QML and used through
+QQmlComponent.
+
+\section2 Generated Output Basics
+
+\c qmltc aims to be compatible with the existing QML execution model. This
+implies that the generated code is roughly equivalent to the internal
+QQmlComponent setup logic and thus you should be able to understand your QML
+type's behavior, semantics and API the same way you do currently - by visually
+inspecting the corresponding QML document.
+
+However, the generated code is still somewhat confusing, especially given that
+your application should use the qmltc output on the C++ side directly. There are
+two parts of the generated code: CMake build files structure and the generated
+C++ format. The former is covered in the \l{qmltc-cmake}{CMake API of qmltc} and
+the latter is covered here.
+
+Consider a simple HelloWorld type, that has a \c hello property, a function to
+print that property, and a signal emitted when the object of that type is
+created:
+
+\snippet qmltc/special/HelloWorld.qml qmltc-hello-world-qml
+
+When providing a C++ alternative of this QML type, the C++ class would need a
+\l{Overview - QML and C++ Integration}{QML-specific meta-object system macro},
+Q_PROPERTY decoration for the \c hello property, \c{Q_INVOKABLE} C++ printing
+function and a regular Qt signal definition. Similarly, qmltc would translate
+the given HelloWorld type into roughly the following:
+
+\snippet qmltc/special/HelloWorld.qml.cpp qmltc-hello-world-generated
+
+Even though specific details of the generated type could differ, the universal
+aspects remain. For instance:
+
+\list
+ \li QML types within a document are translated into C++ types, according to
+ the compiler-visible information.
+ \li Properties are translated into C++ properties with Q_PROPERTY
+ declarations.
+ \li JavaScript functions become \c{Q_INVOKABLE} C++ functions.
+ \li QML signals are transformed into C++ Qt signals.
+ \li QML enumerations are converted into C++ enumerations with \c{Q_ENUM}
+ declarations.
+\endlist
+
+An additional detail is the way \c qmltc generates class names. A class name for
+a given QML type is automatically deduced from the QML document defining that
+type: the QML file name without extensions (up to and excluding the first \c{.},
+also known as the base name) becomes a class name. The file name case is
+preserved. Thus, \c{HelloWorld.qml} would result in a \c{class HelloWorld} and
+\c{helloWoRlD.qml} in a \c{class helloWoRlD}. Following the QML convention, if a
+QML document file name starts with a lower-case letter, the generated C++ class
+is assumed to be anonymous and marked with \l{QML_ANONYMOUS}.
+
+For now, although the generated code is ready to be used from the C++
+application side, you should generally limit calls to the generated APIs.
+Instead, prefer implementing the application logic in QML/JavaScript and
+hand-written C++ types exposed to QML, using the qmltc-created classes for
+simple object instantiation. While generated C++ gives you direct (and usually
+faster) access to QML-defined elements of the type, understanding such code
+could be a challenge.
+
+\section2 Known Limitations
+
+Despite covering many common QML features, qmltc is still in the early stage of
+development with some things yet to be supported.
+
+Imported QML modules that consist of QML-defined types (such as
+\c{QtQuick.Controls}) might not get compiled correctly, even if those QML-defined
+types were compiled by qmltc..
+At present, you can reliably use \c{QtQml} and \c{QtQuick} modules as well as any
+other QML module that \b{only} contains C++ classes exposed to QML.
+
+On top of this, there are some more fundamental peculiarities to consider:
+
+\list
+ \li Qt's QML modules usually rely on C++ libraries to do the heavy lifting.
+ Often enough, these libraries do not provide public C++ API (since their
+ primary usage is through QML). For the users of qmltc, this means that their
+ apps need to link against private Qt libraries.
+
+ \li Due to the nature of qmltc code generation, QML plugins are unusable for
+ compilation purposes. Instead, QML modules - that use a plugin - have to
+ ensure that the plugin data is accessible at compile time. Such QML modules
+ would then have \e optional plugins. In most cases, the compile-time
+ information can be provided through a header file (with C++ declarations)
+ and linkable library (with C++ definitions). The user code is responsible
+ (usually through CMake) for including a path to the header file and linking
+ against the QML module library.
+\endlist
+
+\note
+Given the tech preview status of the compiler, you might also encounter bugs in
+qmltc, in the generated code, or some other related part. We encourage you to
+\l{https://bugreports.qt.io/}{submit a bug report} in this case.
+
+*/
diff --git a/src/qml/doc/src/tools/qtquickcompiler/qtqml-tool-qmlcachegen.qdoc b/src/qml/doc/src/tools/qtquickcompiler/qtqml-tool-qmlcachegen.qdoc
new file mode 100644
index 0000000000..b7f6d56705
--- /dev/null
+++ b/src/qml/doc/src/tools/qtquickcompiler/qtqml-tool-qmlcachegen.qdoc
@@ -0,0 +1,13 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtqml-tool-qmlcachegen.html
+\title qmlcachegen
+\brief A tool to compile QML documents ahead of time
+\ingroup qtqml-tooling
+
+\e qmlcachegen is an internal build tool, invoked by the build system
+when using \l qt_add_qml_module in CMake or CONFIG+=qtquickcompiler in
+qmake. Users should not invoke it manually.
+*/
diff --git a/src/qml/inlinecomponentutils_p.h b/src/qml/inlinecomponentutils_p.h
new file mode 100644
index 0000000000..c7a93c870b
--- /dev/null
+++ b/src/qml/inlinecomponentutils_p.h
@@ -0,0 +1,161 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef INLINECOMPONENTUTILS_P_H
+#define INLINECOMPONENTUTILS_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/qqmlmetatype_p.h>
+#include <private/qv4compileddata_p.h>
+#include <private/qv4resolvedtypereference_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace icutils {
+struct Node {
+private:
+ using IndexType = std::vector<QV4::CompiledData::InlineComponent>::size_type;
+ using IndexField = quint32_le_bitfield_member<0, 30, IndexType>;
+ using TemporaryMarkField = quint32_le_bitfield_member<30, 1>;
+ using PermanentMarkField = quint32_le_bitfield_member<31, 1>;
+ quint32_le_bitfield_union<IndexField, TemporaryMarkField, PermanentMarkField> m_data;
+
+public:
+ Node() = default;
+ Node(const Node &) = default;
+ Node(Node &&) = default;
+ Node& operator=(Node const &) = default;
+ Node& operator=(Node &&) = default;
+ bool operator==(Node const &other) const {return m_data.data() == other.m_data.data(); }
+
+ Node(IndexType s) : m_data(QSpecialIntegerBitfieldZero) { m_data.set<IndexField>(s); }
+
+ bool hasPermanentMark() const { return m_data.get<PermanentMarkField>(); }
+ bool hasTemporaryMark() const { return m_data.get<TemporaryMarkField>(); }
+
+ void setPermanentMark()
+ {
+ m_data.set<TemporaryMarkField>(0);
+ m_data.set<PermanentMarkField>(1);
+ }
+
+ void setTemporaryMark()
+ {
+ m_data.set<TemporaryMarkField>(1);
+ }
+
+ IndexType index() const { return m_data.get<IndexField>(); }
+};
+
+using NodeList = std::vector<Node>;
+using AdjacencyList = std::vector<std::vector<Node*>>;
+
+inline bool containedInSameType(const QQmlType &a, const QQmlType &b)
+{
+ return QQmlMetaType::equalBaseUrls(a.sourceUrl(), b.sourceUrl());
+}
+
+template<typename ObjectContainer, typename InlineComponent>
+void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer,
+ AdjacencyList &adjacencyList, NodeList &nodes,
+ const std::vector<InlineComponent> &allICs)
+{
+ using CompiledObject = typename ObjectContainer::CompiledObject;
+ // add an edge from A to B if A and B are inline components with the same containing type
+ // and A inherits from B (ignore indirect chains through external types for now)
+ // or if A instantiates B
+ for (typename std::vector<InlineComponent>::size_type i = 0; i < allICs.size(); ++i) {
+ const auto& ic = allICs[i];
+ const CompiledObject *obj = objectContainer->objectAt(ic.objectIndex);
+ QV4::ResolvedTypeReference *currentICTypeRef = objectContainer->resolvedType(ic.nameIndex);
+ auto createEdgeFromTypeRef = [&](QV4::ResolvedTypeReference *targetTypeRef) {
+ if (targetTypeRef) {
+ const auto targetType = targetTypeRef->type();
+ if (targetType.isInlineComponentType()
+ && containedInSameType(targetType, currentICTypeRef->type())) {
+ auto icIt = std::find_if(allICs.cbegin(), allICs.cend(), [&](const QV4::CompiledData::InlineComponent &icSearched){
+ return objectContainer->stringAt(icSearched.nameIndex)
+ == targetType.elementName();
+ });
+ Q_ASSERT(icIt != allICs.cend());
+ Node& target = nodes[i];
+ adjacencyList[std::distance(allICs.cbegin(), icIt)].push_back(&target);
+ }
+ }
+ };
+ if (obj->inheritedTypeNameIndex != 0) {
+ QV4::ResolvedTypeReference *parentTypeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
+ createEdgeFromTypeRef(parentTypeRef);
+
+ }
+ auto referencedInICObjectIndex = ic.objectIndex + 1;
+ while (int(referencedInICObjectIndex) < objectContainer->objectCount()) {
+ auto potentiallyReferencedInICObject = objectContainer->objectAt(referencedInICObjectIndex);
+ bool stillInIC
+ = !potentiallyReferencedInICObject->hasFlag(
+ QV4::CompiledData::Object::IsInlineComponentRoot)
+ && potentiallyReferencedInICObject->hasFlag(
+ QV4::CompiledData::Object::IsPartOfInlineComponent);
+ if (!stillInIC)
+ break;
+ createEdgeFromTypeRef(objectContainer->resolvedType(potentiallyReferencedInICObject->inheritedTypeNameIndex));
+ ++referencedInICObjectIndex;
+ }
+ }
+};
+
+inline void topoVisit(Node *node, AdjacencyList &adjacencyList, bool &hasCycle,
+ NodeList &nodesSorted)
+{
+ if (node->hasPermanentMark())
+ return;
+ if (node->hasTemporaryMark()) {
+ hasCycle = true;
+ return;
+ }
+ node->setTemporaryMark();
+
+ auto const &edges = adjacencyList[node->index()];
+ for (auto edgeTarget =edges.begin(); edgeTarget != edges.end(); ++edgeTarget) {
+ topoVisit(*edgeTarget, adjacencyList, hasCycle, nodesSorted);
+ }
+
+ node->setPermanentMark();
+ nodesSorted.push_back(*node);
+};
+
+// Use DFS based topological sorting (https://en.wikipedia.org/wiki/Topological_sorting)
+inline NodeList topoSort(NodeList &nodes, AdjacencyList &adjacencyList, bool &hasCycle)
+{
+ NodeList nodesSorted;
+ nodesSorted.reserve(nodes.size());
+
+ hasCycle = false;
+ auto currentNodeIt = std::find_if(nodes.begin(), nodes.end(), [](const Node& node) {
+ return !node.hasPermanentMark();
+ });
+ // Do a topological sort of all inline components
+ // afterwards, nodesSorted contains the nodes for the inline components in reverse topological order
+ while (currentNodeIt != nodes.end() && !hasCycle) {
+ Node& currentNode = *currentNodeIt;
+ topoVisit(&currentNode, adjacencyList, hasCycle, nodesSorted);
+ currentNodeIt = std::find_if(nodes.begin(), nodes.end(), [](const Node& node) {
+ return !node.hasPermanentMark();
+ });
+ }
+ return nodesSorted;
+}
+}
+
+QT_END_NAMESPACE
+
+#endif // INLINECOMPONENTUTILS_P_H
diff --git a/src/qml/jit/jit.pri b/src/qml/jit/jit.pri
deleted file mode 100644
index 503ce0ebcd..0000000000
--- a/src/qml/jit/jit.pri
+++ /dev/null
@@ -1,12 +0,0 @@
-INCLUDEPATH += $$PWD
-INCLUDEPATH += $$OUT_PWD
-
-SOURCES += \
- $$PWD/qv4baselinejit.cpp \
- $$PWD/qv4baselineassembler.cpp \
- $$PWD/qv4assemblercommon.cpp
-
-HEADERS += \
- $$PWD/qv4baselinejit_p.h \
- $$PWD/qv4baselineassembler_p.h \
- $$PWD/qv4assemblercommon_p.h
diff --git a/src/qml/jit/qv4assemblercommon.cpp b/src/qml/jit/qv4assemblercommon.cpp
index e75f35a665..2b33d0aa10 100644
--- a/src/qml/jit/qv4assemblercommon.cpp
+++ b/src/qml/jit/qv4assemblercommon.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QBuffer>
#include <QFile>
@@ -51,13 +15,15 @@
#include <assembler/LinkBuffer.h>
#include <WTFStubs.h>
+#if QT_CONFIG(qml_jit)
+
#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
-Q_LOGGING_CATEGORY(lcAsm, "qt.v4.asm")
+Q_LOGGING_CATEGORY(lcAsm, "qt.qml.v4.asm")
namespace {
class QIODevicePrintStream: public FilePrintStream
@@ -76,15 +42,25 @@ public:
~QIODevicePrintStream()
{}
- void vprintf(const char* format, va_list argList) WTF_ATTRIBUTE_PRINTF(2, 0)
+ void vprintf(const char* format, va_list argList) override WTF_ATTRIBUTE_PRINTF(2, 0)
{
- const int written = qvsnprintf(buf.data(), buf.size(), format, argList);
- if (written > 0)
- dest->write(buf.constData(), written);
- memset(buf.data(), 0, qMin(written, buf.size()));
+ const int printed = qvsnprintf(buf.data(), buf.size(), format, argList);
+ Q_ASSERT(printed <= buf.size());
+
+ qint64 written = 0;
+ while (written < printed) {
+ const qint64 result = dest->write(buf.constData() + written, printed - written);
+ if (result < 0)
+ break;
+ written += result;
+ }
+
+ Q_ASSERT(written <= buf.size());
+ Q_ASSERT(written >= 0);
+ memset(buf.data(), 0, size_t(written));
}
- void flush()
+ void flush() override
{}
private:
@@ -110,7 +86,8 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput,
break;
const char *functionName = it.value();
processedOutput = processedOutput.insert(
- idx, padding + QByteArray(functionName ? functionName : symbols[it.key()]));
+ idx, QByteArray(padding + QByteArray(
+ functionName ? functionName : symbols[it.key()])));
}
}
@@ -146,7 +123,7 @@ void PlatformAssemblerCommon::link(Function *function, const char *jitKind)
// We use debugAddress here because it's actually for debugging and hidden behind an
// environment variable.
const QByteArray name = Function::prettyName(function, linkBuffer.debugAddress()).toUtf8();
- codeRef = linkBuffer.finalizeCodeWithDisassembly(jitKind, "function %s", name.constData());
+ codeRef = linkBuffer.finalizeCodeWithDisassembly(jitKind, name.constData());
WTF::setDataFile(stderr);
printDisassembledOutputWithCalls(buf.data(), functions);
@@ -159,7 +136,8 @@ void PlatformAssemblerCommon::link(Function *function, const char *jitKind)
generateFunctionTable(function, &codeRef);
- linkBuffer.makeExecutable();
+ if (Q_UNLIKELY(!linkBuffer.makeExecutable()))
+ function->jittedCode = nullptr; // The function is not executable, but the coderef exists.
}
void PlatformAssemblerCommon::prepareCallWithArgCount(int argc)
@@ -177,7 +155,7 @@ void PlatformAssemblerCommon::prepareCallWithArgCount(int argc)
void PlatformAssemblerCommon::storeInstructionPointer(int instructionOffset)
{
- Address addr(CppStackFrameRegister, offsetof(QV4::CppStackFrame, instructionPointer));
+ Address addr(CppStackFrameRegister, offsetof(QV4::JSTypesStackFrame, instructionPointer));
store32(TrustedImm32(instructionOffset), addr);
}
@@ -369,3 +347,5 @@ void PlatformAssemblerCommon::storeInt32AsValue(int srcInt, Address destAddr)
} // QV4 namepsace
QT_END_NAMESPACE
+
+#endif // QT_CONFIG(qml_jit)
diff --git a/src/qml/jit/qv4assemblercommon_p.h b/src/qml/jit/qv4assemblercommon_p.h
index ead1e757de..e83608ae23 100644
--- a/src/qml/jit/qv4assemblercommon_p.h
+++ b/src/qml/jit/qv4assemblercommon_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4PLATFORMASSEMBLER_P_H
#define QV4PLATFORMASSEMBLER_P_H
@@ -52,13 +16,16 @@
//
#include <private/qv4engine_p.h>
-#include <private/qv4global_p.h>
#include <private/qv4function_p.h>
-#include <QHash>
+#include <private/qv4global_p.h>
+#include <private/qv4stackframe_p.h>
+
#include <wtf/Vector.h>
#include <assembler/MacroAssembler.h>
-QT_REQUIRE_CONFIG(qml_jit);
+#include <QtCore/qhash.h>
+
+#if QT_CONFIG(qml_jit)
QT_BEGIN_NAMESPACE
@@ -66,14 +33,14 @@ namespace QV4 {
namespace JIT {
#if defined(Q_PROCESSOR_X86_64) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
-#if defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD) || defined(Q_OS_DARWIN)
+#if defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD) || defined(Q_OS_DARWIN) || defined(Q_OS_SOLARIS) || defined(Q_OS_VXWORKS)
class PlatformAssembler_X86_64_SysV : public JSC::MacroAssembler<JSC::MacroAssemblerX86_64>
{
public:
static constexpr int NativeStackAlignment = 16;
- static const RegisterID NoRegister = RegisterID(-1);
+ static const RegisterID NoRegister = RegisterID::none;
static const RegisterID ReturnValueRegister = RegisterID::eax;
static const RegisterID ReturnValueRegisterValue = ReturnValueRegister;
@@ -160,7 +127,7 @@ typedef PlatformAssembler_X86_64_SysV PlatformAssemblerBase;
class PlatformAssembler_Win64 : public JSC::MacroAssembler<JSC::MacroAssemblerX86_64>
{
public:
- static const RegisterID NoRegister = RegisterID(-1);
+ static const RegisterID NoRegister = RegisterID::none;
static const RegisterID ReturnValueRegister = RegisterID::eax;
static const RegisterID ReturnValueRegisterValue = ReturnValueRegister;
@@ -250,7 +217,7 @@ typedef PlatformAssembler_Win64 PlatformAssemblerBase;
class PlatformAssembler_X86_All : public JSC::MacroAssembler<JSC::MacroAssemblerX86>
{
public:
- static const RegisterID NoRegister = RegisterID(-1);
+ static const RegisterID NoRegister = RegisterID::none;
static const RegisterID ReturnValueRegisterValue = RegisterID::eax;
static const RegisterID ReturnValueRegisterTag = RegisterID::edx;
@@ -340,7 +307,7 @@ typedef PlatformAssembler_X86_All PlatformAssemblerBase;
class PlatformAssembler_ARM64 : public JSC::MacroAssembler<JSC::MacroAssemblerARM64>
{
public:
- static const RegisterID NoRegister = RegisterID(-1);
+ static const RegisterID NoRegister = RegisterID::none;
static const RegisterID ReturnValueRegister = JSC::ARM64Registers::x0;
static const RegisterID ReturnValueRegisterValue = ReturnValueRegister;
@@ -439,7 +406,7 @@ typedef PlatformAssembler_ARM64 PlatformAssemblerBase;
class PlatformAssembler_ARM32 : public JSC::MacroAssembler<JSC::MacroAssemblerARMv7>
{
public:
- static const RegisterID NoRegister = RegisterID(-1);
+ static const RegisterID NoRegister = RegisterID::none;
static const RegisterID ReturnValueRegisterValue = JSC::ARMRegisters::r0;
static const RegisterID ReturnValueRegisterTag = JSC::ARMRegisters::r1;
@@ -579,7 +546,7 @@ public:
Address loadFunctionPtr(RegisterID target)
{
- Address addr(CppStackFrameRegister, offsetof(CppStackFrame, v4Function));
+ Address addr(CppStackFrameRegister, offsetof(JSTypesStackFrame, v4Function));
loadPtr(addr, target);
return Address(target);
}
@@ -595,7 +562,7 @@ public:
Address loadConstAddress(int constIndex, RegisterID baseReg = ScratchRegister)
{
Address addr = loadCompilationUnitPtr(baseReg);
- addr.offset = offsetof(QV4::CompiledData::CompilationUnitBase, constants);
+ addr.offset = offsetof(QV4::CompilationUnitRuntimeData, constants);
loadPtr(addr, baseReg);
addr.offset = constIndex * int(sizeof(QV4::Value));
return addr;
@@ -604,7 +571,7 @@ public:
Address loadStringAddress(int stringId)
{
Address addr = loadCompilationUnitPtr(ScratchRegister);
- addr.offset = offsetof(QV4::CompiledData::CompilationUnitBase, runtimeStrings);
+ addr.offset = offsetof(QV4::CompilationUnitRuntimeData, runtimeStrings);
loadPtr(addr, ScratchRegister);
return Address(ScratchRegister, stringId * PointerSize);
}
@@ -653,7 +620,8 @@ public:
void generateFunctionEntry()
{
generatePlatformFunctionEntry();
- loadPtr(Address(CppStackFrameRegister, offsetof(CppStackFrame, jsFrame)), JSStackFrameRegister);
+ loadPtr(Address(CppStackFrameRegister, offsetof(JSTypesStackFrame, jsFrame)),
+ JSStackFrameRegister);
allocateStackSpace();
}
@@ -740,4 +708,6 @@ private:
QT_END_NAMESPACE
+#endif // QT_CONFIG(qml_jit)
+
#endif // QV4PLATFORMASSEMBLER_P_H
diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp
index 25652e0a63..496624c752 100644
--- a/src/qml/jit/qv4baselineassembler.cpp
+++ b/src/qml/jit/qv4baselineassembler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QBuffer>
#include <QFile>
@@ -55,6 +19,8 @@
#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES
+#if QT_CONFIG(qml_jit)
+
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
@@ -89,6 +55,8 @@ public:
PlatformAssemblerCommon::callRuntime(funcPtr);
if (dest == CallResultDestination::InAccumulator)
saveReturnValueInAccumulator();
+ else if (AccumulatorRegister == ReturnValueRegister)
+ loadUndefined();
}
void saveReturnValueInAccumulator()
@@ -178,7 +146,9 @@ public:
void toBoolean(std::function<void(RegisterID)> continuation)
{
urshift64(AccumulatorRegister, TrustedImm32(Value::IsIntegerConvertible_Shift), ScratchRegister);
- auto needsConversion = branch32(NotEqual, TrustedImm32(1), ScratchRegister);
+ auto needsConversion = branch32(
+ NotEqual, TrustedImm32(Value::IsIntegerConvertible_Value), ScratchRegister);
+
continuation(AccumulatorRegister);
Jump done = jump();
@@ -196,8 +166,10 @@ public:
void toNumber()
{
- urshift64(AccumulatorRegister, TrustedImm32(Value::QuickType_Shift), ScratchRegister);
- auto isNumber = branch32(GreaterThanOrEqual, ScratchRegister, TrustedImm32(Value::QT_Int));
+ move(TrustedImm64(Value::NumberMask), ScratchRegister);
+ and64(AccumulatorRegister, ScratchRegister);
+ move(TrustedImm64(Value::NumberDiscriminator), ScratchRegister2);
+ auto isNumber = branch64(GreaterThanOrEqual, ScratchRegister, ScratchRegister2);
move(AccumulatorRegister, registerForArg(0));
callHelper(toNumberHelper);
@@ -278,7 +250,7 @@ public:
Jump isIntOrBool()
{
urshift64(AccumulatorRegister, TrustedImm32(Value::IsIntegerOrBool_Shift), ScratchRegister);
- return branch32(Equal, TrustedImm32(3), ScratchRegister);
+ return branch32(Equal, TrustedImm32(Value::IsIntegerOrBool_Value), ScratchRegister);
}
void jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset)
@@ -312,7 +284,7 @@ public:
void encodeDoubleIntoAccumulator(FPRegisterID src)
{
moveDoubleTo64(src, AccumulatorRegister);
- move(TrustedImm64(Value::NaNEncodeMask), ScratchRegister);
+ move(TrustedImm64(Value::EncodeMask), ScratchRegister);
xor64(ScratchRegister, AccumulatorRegister);
}
@@ -351,7 +323,8 @@ public:
Jump unopIntPath(std::function<Jump(void)> fastPath)
{
urshift64(AccumulatorRegister, TrustedImm32(Value::IsIntegerConvertible_Shift), ScratchRegister);
- Jump accNotIntConvertible = branch32(NotEqual, TrustedImm32(1), ScratchRegister);
+ Jump accNotIntConvertible = branch32(
+ NotEqual, TrustedImm32(Value::IsIntegerConvertible_Value), ScratchRegister);
// both integer
Jump failure = fastPath();
@@ -388,6 +361,8 @@ public:
PlatformAssemblerCommon::callRuntime(funcPtr);
if (dest == CallResultDestination::InAccumulator)
saveReturnValueInAccumulator();
+ else if (AccumulatorRegisterValue == ReturnValueRegisterValue)
+ loadUndefined();
}
void saveReturnValueInAccumulator()
@@ -479,8 +454,12 @@ public:
void toNumber()
{
- urshift32(AccumulatorRegisterTag, TrustedImm32(Value::QuickType_Shift - 32), ScratchRegister);
- auto isNumber = branch32(GreaterThanOrEqual, ScratchRegister, TrustedImm32(Value::QT_Int));
+ and32(TrustedImm32(Value::NumberMask >> Value::Tag_Shift),
+ AccumulatorRegisterTag, ScratchRegister);
+ auto isNumber = branch32(
+ GreaterThanOrEqual, ScratchRegister,
+ TrustedImm32(Value::NumberDiscriminator >> Value::Tag_Shift));
+
if (ArgInRegCount < 2) {
subPtr(TrustedImm32(2 * PointerSize), StackPointerRegister); // stack alignment
@@ -629,7 +608,7 @@ public:
Jump isIntOrBool()
{
urshift32(AccumulatorRegisterTag, TrustedImm32(Value::IsIntegerOrBool_Shift - 32), ScratchRegister);
- return branch32(Equal, TrustedImm32(3), ScratchRegister);
+ return branch32(Equal, TrustedImm32(Value::IsIntegerOrBool_Value), ScratchRegister);
}
void pushValue(ReturnedValue v)
@@ -660,7 +639,8 @@ public:
{
urshift32(AccumulatorRegisterTag, TrustedImm32(Value::IsIntegerConvertible_Shift - 32),
ScratchRegister);
- auto needsConversion = branch32(NotEqual, TrustedImm32(1), ScratchRegister);
+ auto needsConversion = branch32(
+ NotEqual, TrustedImm32(Value::IsIntegerConvertible_Value), ScratchRegister);
continuation(AccumulatorRegisterValue);
Jump done = jump();
@@ -737,7 +717,7 @@ public:
void encodeDoubleIntoAccumulator(FPRegisterID src)
{
moveDoubleToInts(src, AccumulatorRegisterValue, AccumulatorRegisterTag);
- xor32(TrustedImm32(Value::NaNEncodeMask >> 32), AccumulatorRegisterTag);
+ xor32(TrustedImm32(Value::EncodeMask >> 32), AccumulatorRegisterTag);
}
void pushValueAligned(ReturnedValue v)
@@ -884,7 +864,7 @@ void BaselineAssembler::storeReg(int reg)
void BaselineAssembler::loadLocal(int index, int level)
{
Heap::CallContext ctx;
- Q_UNUSED(ctx)
+ Q_UNUSED(ctx);
pasm()->loadPointerFromValue(regAddr(CallData::Context), PlatformAssembler::ScratchRegister);
while (level) {
pasm()->loadPtr(Address(PlatformAssembler::ScratchRegister, ctx.outer.offset), PlatformAssembler::ScratchRegister);
@@ -896,7 +876,7 @@ void BaselineAssembler::loadLocal(int index, int level)
void BaselineAssembler::storeLocal(int index, int level)
{
Heap::CallContext ctx;
- Q_UNUSED(ctx)
+ Q_UNUSED(ctx);
pasm()->loadPtr(regAddr(CallData::Context), PlatformAssembler::ScratchRegister);
while (level) {
pasm()->loadPtr(Address(PlatformAssembler::ScratchRegister, ctx.outer.offset), PlatformAssembler::ScratchRegister);
@@ -923,7 +903,7 @@ void BaselineAssembler::storeHeapObject(int reg)
void BaselineAssembler::loadImport(int index)
{
Address addr = pasm()->loadCompilationUnitPtr(PlatformAssembler::ScratchRegister);
- addr.offset = offsetof(QV4::CompiledData::CompilationUnitBase, imports);
+ addr.offset = offsetof(QV4::CompilationUnitRuntimeData, imports);
pasm()->loadPtr(addr, PlatformAssembler::ScratchRegister);
addr.offset = index * int(sizeof(QV4::Value*));
pasm()->loadPtr(addr, PlatformAssembler::ScratchRegister);
@@ -1409,6 +1389,23 @@ int BaselineAssembler::jumpNotUndefined(int offset)
return offset;
}
+int BaselineAssembler::jumpEqNull(int offset)
+{
+ saveAccumulatorInFrame();
+ cmpeqNull();
+
+ pasm()->toBoolean([this, offset](PlatformAssembler::RegisterID resultReg) {
+ auto isFalse = pasm()->branch32(PlatformAssembler::Equal, TrustedImm32(0), resultReg);
+ loadValue(Encode::undefined());
+ pasm()->addJumpToOffset(pasm()->jump(), offset);
+ isFalse.link(pasm());
+ loadAccumulatorFromFrame();
+ });
+
+ return offset;
+}
+
+
void BaselineAssembler::prepareCallWithArgCount(int argc)
{
pasm()->prepareCallWithArgCount(argc);
@@ -1471,7 +1468,7 @@ void BaselineAssembler::loadAccumulatorFromFrame()
offsetof(CallData, accumulator)));
}
-static ReturnedValue TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing(CppStackFrame *frame, ExecutionEngine *engine)
+static ReturnedValue TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing(JSTypesStackFrame *frame, ExecutionEngine *engine)
{
return Runtime::TailCall::call(frame, engine);
}
@@ -1553,15 +1550,15 @@ void BaselineAssembler::clearUnwindHandler()
void JIT::BaselineAssembler::unwindDispatch()
{
checkException();
- pasm()->load32(Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel)), PlatformAssembler::ScratchRegister);
+ pasm()->load32(Address(PlatformAssembler::CppStackFrameRegister, offsetof(JSTypesStackFrame, unwindLevel)), PlatformAssembler::ScratchRegister);
auto noUnwind = pasm()->branch32(PlatformAssembler::Equal, PlatformAssembler::ScratchRegister, TrustedImm32(0));
pasm()->sub32(TrustedImm32(1), PlatformAssembler::ScratchRegister);
- pasm()->store32(PlatformAssembler::ScratchRegister, Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel)));
+ pasm()->store32(PlatformAssembler::ScratchRegister, Address(PlatformAssembler::CppStackFrameRegister, offsetof(JSTypesStackFrame, unwindLevel)));
auto jump = pasm()->branch32(PlatformAssembler::Equal, PlatformAssembler::ScratchRegister, TrustedImm32(0));
gotoCatchException();
jump.link(pasm());
- pasm()->loadPtr(Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLabel)), PlatformAssembler::ScratchRegister);
+ pasm()->loadPtr(Address(PlatformAssembler::CppStackFrameRegister, offsetof(JSTypesStackFrame, unwindLabel)), PlatformAssembler::ScratchRegister);
pasm()->jump(PlatformAssembler::ScratchRegister);
noUnwind.link(pasm());
@@ -1569,9 +1566,9 @@ void JIT::BaselineAssembler::unwindDispatch()
int JIT::BaselineAssembler::unwindToLabel(int level, int offset)
{
- auto l = pasm()->storePtrWithPatch(TrustedImmPtr(nullptr), Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLabel)));
+ auto l = pasm()->storePtrWithPatch(TrustedImmPtr(nullptr), Address(PlatformAssembler::CppStackFrameRegister, offsetof(JSTypesStackFrame, unwindLabel)));
pasm()->addEHTarget(l, offset);
- pasm()->store32(TrustedImm32(level), Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel)));
+ pasm()->store32(TrustedImm32(level), Address(PlatformAssembler::CppStackFrameRegister, offsetof(JSTypesStackFrame, unwindLevel)));
gotoCatchException();
return offset;
}
@@ -1588,7 +1585,7 @@ void BaselineAssembler::pushCatchContext(int index, int name)
void BaselineAssembler::popContext()
{
Heap::CallContext ctx;
- Q_UNUSED(ctx)
+ Q_UNUSED(ctx);
pasm()->loadPointerFromValue(regAddr(CallData::Context), PlatformAssembler::ScratchRegister);
pasm()->loadPtr(Address(PlatformAssembler::ScratchRegister, ctx.outer.offset), PlatformAssembler::ScratchRegister);
pasm()->storeHeapObject(PlatformAssembler::ScratchRegister, regAddr(CallData::Context));
@@ -1615,3 +1612,5 @@ void BaselineAssembler::ret()
} // QV4 namepsace
QT_END_NAMESPACE
+
+#endif // QT_CONFIG(qml_jit)
diff --git a/src/qml/jit/qv4baselineassembler_p.h b/src/qml/jit/qv4baselineassembler_p.h
index c2c735282b..888c402edc 100644
--- a/src/qml/jit/qv4baselineassembler_p.h
+++ b/src/qml/jit/qv4baselineassembler_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4BASELINEASSEMBLER_P_H
#define QV4BASELINEASSEMBLER_P_H
@@ -55,7 +19,7 @@
#include <private/qv4function_p.h>
#include <QHash>
-QT_REQUIRE_CONFIG(qml_jit);
+#if QT_CONFIG(qml_jit)
QT_BEGIN_NAMESPACE
@@ -137,6 +101,7 @@ public:
Q_REQUIRED_RESULT int jumpFalse(int offset);
Q_REQUIRED_RESULT int jumpNoException(int offset);
Q_REQUIRED_RESULT int jumpNotUndefined(int offset);
+ Q_REQUIRED_RESULT int jumpEqNull(int offset);
// stuff for runtime calls
void prepareCallWithArgCount(int argc);
@@ -182,4 +147,6 @@ private:
QT_END_NAMESPACE
+#endif // QT_CONFIG(qml_jit)
+
#endif // QV4BASELINEASSEMBLER_P_H
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index fcaa87290e..bd2e331cbc 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4baselinejit_p.h"
#include "qv4baselineassembler_p.h"
#include <private/qv4lookup_p.h>
#include <private/qv4generatorobject_p.h>
+#if QT_CONFIG(qml_jit)
+
QT_USE_NAMESPACE
using namespace QV4;
using namespace QV4::JIT;
@@ -65,6 +31,8 @@ void BaselineJIT::generate()
labels.insert(int(function->compiledFunction->labelInfoTable()[i]));
as->generatePrologue();
+ // Make sure the ACC register is initialized and not clobbered by the caller.
+ as->loadAccumulatorFromFrame();
decode(code, len);
as->generateEpilogue();
@@ -205,6 +173,7 @@ void BaselineJIT::generate_LoadName(int name)
void BaselineJIT::generate_LoadGlobalLookup(int index)
{
+ STORE_IP();
as->prepareCallWithArgCount(3);
as->passInt32AsArg(index, 2);
as->passFunctionAsArg(1);
@@ -214,6 +183,7 @@ void BaselineJIT::generate_LoadGlobalLookup(int index)
void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index)
{
+ STORE_IP();
as->prepareCallWithArgCount(2);
as->passInt32AsArg(index, 1);
as->passEngineAsArg(0);
@@ -279,6 +249,13 @@ void BaselineJIT::generate_LoadProperty(int name)
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadProperty, CallResultDestination::InAccumulator);
}
+void BaselineJIT::generate_LoadOptionalProperty(int name, int offset)
+{
+ labels.insert(as->jumpEqNull(absoluteOffset(offset)));
+
+ generate_LoadProperty(name);
+}
+
void BaselineJIT::generate_GetLookup(int index)
{
STORE_IP();
@@ -291,6 +268,13 @@ void BaselineJIT::generate_GetLookup(int index)
BASELINEJIT_GENERATE_RUNTIME_CALL(GetLookup, CallResultDestination::InAccumulator);
}
+void BaselineJIT::generate_GetOptionalLookup(int index, int offset)
+{
+ labels.insert(as->jumpEqNull(absoluteOffset(offset)));
+
+ generate_GetLookup(index);
+}
+
void BaselineJIT::generate_StoreProperty(int name, int base)
{
STORE_IP();
@@ -405,18 +389,6 @@ void BaselineJIT::generate_CallPropertyLookup(int lookupIndex, int base, int arg
BASELINEJIT_GENERATE_RUNTIME_CALL(CallPropertyLookup, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_CallElement(int base, int index, int argc, int argv)
-{
- STORE_IP();
- as->prepareCallWithArgCount(5);
- as->passInt32AsArg(argc, 4);
- as->passJSSlotAsArg(argv, 3);
- as->passJSSlotAsArg(index, 2);
- as->passJSSlotAsArg(base, 1);
- as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(CallElement, CallResultDestination::InAccumulator);
-}
-
void BaselineJIT::generate_CallName(int name, int argc, int argv)
{
STORE_IP();
@@ -536,6 +508,8 @@ void BaselineJIT::generate_ThrowException()
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(ThrowException, CallResultDestination::Ignore);
as->gotoCatchException();
+
+ // LOAD_ACC(); <- not needed here since it would be unreachable.
}
void BaselineJIT::generate_GetException() { as->getException(); }
@@ -543,9 +517,11 @@ void BaselineJIT::generate_SetException() { as->setException(); }
void BaselineJIT::generate_CreateCallContext()
{
+ STORE_ACC();
as->prepareCallWithArgCount(1);
as->passCppFrameAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(PushCallContext, CallResultDestination::Ignore);
+ LOAD_ACC();
}
void BaselineJIT::generate_PushCatchContext(int index, int name) { as->pushCatchContext(index, name); }
@@ -610,7 +586,7 @@ void BaselineJIT::generate_GetIterator(int iterator)
BASELINEJIT_GENERATE_RUNTIME_CALL(GetIterator, CallResultDestination::InAccumulator);
}
-void BaselineJIT::generate_IteratorNext(int value, int done)
+void BaselineJIT::generate_IteratorNext(int value, int offset)
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(3);
@@ -618,10 +594,10 @@ void BaselineJIT::generate_IteratorNext(int value, int done)
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(IteratorNext, CallResultDestination::InAccumulator);
- as->storeReg(done);
+ labels.insert(as->jumpTrue(absoluteOffset(offset)));
}
-void BaselineJIT::generate_IteratorNextForYieldStar(int iterator, int object)
+void BaselineJIT::generate_IteratorNextForYieldStar(int iterator, int object, int offset)
{
as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(4);
@@ -630,13 +606,13 @@ void BaselineJIT::generate_IteratorNextForYieldStar(int iterator, int object)
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(IteratorNextForYieldStar, CallResultDestination::InAccumulator);
+ labels.insert(as->jumpTrue(absoluteOffset(offset)));
}
-void BaselineJIT::generate_IteratorClose(int done)
+void BaselineJIT::generate_IteratorClose()
{
as->saveAccumulatorInFrame();
- as->prepareCallWithArgCount(3);
- as->passJSSlotAsArg(done, 2);
+ as->prepareCallWithArgCount(2);
as->passAccumulatorAsArg(1);
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(IteratorClose, CallResultDestination::InAccumulator);
@@ -827,6 +803,7 @@ void BaselineJIT::generate_CmpStrictNotEqual(int lhs) { as->cmpStrictNotEqual(lh
void BaselineJIT::generate_CmpIn(int lhs)
{
+ STORE_IP();
STORE_ACC();
as->prepareCallWithArgCount(3);
as->passAccumulatorAsArg(2);
@@ -845,6 +822,16 @@ void BaselineJIT::generate_CmpInstanceOf(int lhs)
BASELINEJIT_GENERATE_RUNTIME_CALL(Instanceof, CallResultDestination::InAccumulator);
}
+void BaselineJIT::generate_As(int lhs)
+{
+ STORE_ACC();
+ as->prepareCallWithArgCount(3);
+ as->passAccumulatorAsArg(2);
+ as->passJSSlotAsArg(lhs, 1);
+ as->passEngineAsArg(0);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(As, CallResultDestination::InAccumulator);
+}
+
void BaselineJIT::generate_UNot() { as->unot(); }
void BaselineJIT::generate_UPlus() { as->toNumber(); }
void BaselineJIT::generate_UMinus() { as->uminus(); }
@@ -928,3 +915,6 @@ void BaselineJIT::endInstruction(Instr::Type instr)
{
Q_UNUSED(instr);
}
+
+#endif // QT_CONFIG(qml_jit)
+
diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h
index 284faf0ff0..40138ea700 100644
--- a/src/qml/jit/qv4baselinejit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4JIT_P_H
#define QV4JIT_P_H
@@ -55,8 +19,9 @@
#include <private/qv4function_p.h>
#include <private/qv4instr_moth_p.h>
#include <private/qv4bytecodehandler_p.h>
+#include <QtCore/qset.h>
-QT_REQUIRE_CONFIG(qml_jit);
+#if QT_CONFIG(qml_jit)
QT_BEGIN_NAMESPACE
@@ -69,7 +34,7 @@ class BaselineJIT final: public Moth::ByteCodeHandler
{
public:
BaselineJIT(QV4::Function *);
- virtual ~BaselineJIT() Q_DECL_OVERRIDE;
+ ~BaselineJIT() override;
void generate();
@@ -102,7 +67,9 @@ public:
void generate_LoadElement(int base) override;
void generate_StoreElement(int base, int index) override;
void generate_LoadProperty(int name) override;
+ void generate_LoadOptionalProperty(int name, int offset) override;
void generate_GetLookup(int index) override;
+ void generate_GetOptionalLookup(int index, int offset) override;
void generate_StoreProperty(int name, int base) override;
void generate_SetLookup(int index, int base) override;
void generate_LoadSuperProperty(int property) override;
@@ -115,7 +82,6 @@ public:
void generate_CallWithReceiver(int name, int thisObject, int argc, int argv) override;
void generate_CallProperty(int name, int base, int argc, int argv) override;
void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv) override;
- void generate_CallElement(int base, int index, int argc, int argv) override;
void generate_CallName(int name, int argc, int argv) override;
void generate_CallPossiblyDirectEval(int argc, int argv) override;
void generate_CallGlobalLookup(int index, int argc, int argv) override;
@@ -140,9 +106,9 @@ public:
void generate_PopScriptContext() override;
void generate_PopContext() override;
void generate_GetIterator(int iterator) override;
- void generate_IteratorNext(int value, int done) override;
- void generate_IteratorNextForYieldStar(int iterator, int object) override;
- void generate_IteratorClose(int done) override;
+ void generate_IteratorNext(int value, int offset) override;
+ void generate_IteratorNextForYieldStar(int iterator, int object, int offset) override;
+ void generate_IteratorClose() override;
void generate_DestructureRestElement() override;
void generate_DeleteProperty(int base, int index) override;
void generate_DeleteName(int name) override;
@@ -178,6 +144,7 @@ public:
void generate_CmpStrictNotEqual(int lhs) override;
void generate_CmpIn(int lhs) override;
void generate_CmpInstanceOf(int lhs) override;
+ void generate_As(int lhs) override;
void generate_UNot() override;
void generate_UPlus() override;
void generate_UMinus() override;
@@ -220,4 +187,6 @@ private:
QT_END_NAMESPACE
+#endif // QT_CONFIG(qml_jit)
+
#endif // QV4JIT_P_H
diff --git a/src/qml/jsapi/jsapi.pri b/src/qml/jsapi/jsapi.pri
deleted file mode 100644
index f70588ec7b..0000000000
--- a/src/qml/jsapi/jsapi.pri
+++ /dev/null
@@ -1,12 +0,0 @@
-SOURCES += \
- $$PWD/qjsengine.cpp \
- $$PWD/qjsvalue.cpp \
- $$PWD/qjsvalueiterator.cpp \
-
-HEADERS += \
- $$PWD/qjsengine.h \
- $$PWD/qjsengine_p.h \
- $$PWD/qjsvalue.h \
- $$PWD/qjsvalue_p.h \
- $$PWD/qjsvalueiterator.h \
- $$PWD/qjsvalueiterator_p.h
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 065fbc1c0a..8346ef5d84 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qjsengine.h"
#include "qjsengine_p.h"
@@ -48,11 +12,14 @@
#include "private/qv4globalobject_p.h"
#include "private/qv4script_p.h"
#include "private/qv4runtime_p.h"
+#include <private/qv4dateobject_p.h>
#include <private/qqmlbuiltinfunctions_p.h>
#include <private/qqmldebugconnector_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4qmetaobjectwrapper_p.h>
#include <private/qv4stackframe_p.h>
#include <private/qv4module_p.h>
+#include <private/qv4symbol_p.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qmetaobject.h>
@@ -71,11 +38,6 @@
#include <private/qqmlglobal_p.h>
#include <qqmlengine.h>
-#undef Q_D
-#undef Q_Q
-#define Q_D(blah)
-#define Q_Q(blah)
-
Q_DECLARE_METATYPE(QList<int>)
/*!
@@ -154,6 +116,46 @@ Q_DECLARE_METATYPE(QList<int>)
}
\endcode
+ Modules don't have to be files. They can be values registered with
+ QJSEngine::registerModule():
+
+ \code
+ import version from "version";
+
+ export function getVersion()
+ {
+ return version;
+ }
+ \endcode
+
+ \code
+ QJSValue version(610);
+ myEngine.registerModule("version", version);
+ QJSValue module = myEngine.importModule("./myprint.mjs");
+ QJSValue getVersion = module.property("getVersion");
+ QJSValue result = getVersion.call();
+ \endcode
+
+ Named exports are supported, but because they are treated as members of an
+ object, the default export must be an ECMAScript object. Most of the newXYZ
+ functions in QJSValue will return an object.
+
+ \code
+ QJSValue name("Qt6");
+ QJSValue obj = myEngine.newObject();
+ obj.setProperty("name", name);
+ myEngine.registerModule("info", obj);
+ \endcode
+
+ \code
+ import { name } from "info";
+
+ export function getName()
+ {
+ return name;
+ }
+ \endcode
+
\section1 Engine Configuration
The globalObject() function returns the \b {Global Object}
@@ -242,7 +244,7 @@ Q_DECLARE_METATYPE(QList<int>)
\section1 Extensions
QJSEngine provides a compliant ECMAScript implementation. By default,
- familiar utilities like logging are not available, but they can can be
+ familiar utilities like logging are not available, but they can be
installed via the \l installExtensions() function.
\sa QJSValue, {Making Applications Scriptable},
@@ -257,7 +259,7 @@ Q_DECLARE_METATYPE(QList<int>)
\l installExtensions().
\value TranslationExtension Indicates that translation functions (\c qsTr(),
- for example) should be installed.
+ for example) should be installed. This also installs the Qt.uiLanguage property.
\value ConsoleExtension Indicates that console functions (\c console.log(),
for example) should be installed.
@@ -344,11 +346,8 @@ QJSEngine::QJSEngine()
*/
QJSEngine::QJSEngine(QObject *parent)
- : QObject(*new QJSEnginePrivate, parent)
- , m_v4Engine(new QV4::ExecutionEngine(this))
+ : QJSEngine(*new QJSEnginePrivate, parent)
{
- checkForApplicationInstance();
-
QJSEnginePrivate::addToDebugServer(this);
}
@@ -366,11 +365,12 @@ QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent)
Destroys this QJSEngine.
Garbage is not collected from the persistent JS heap during QJSEngine
- destruction. If you need all memory freed, call collectGarbage manually
+ destruction. If you need all memory freed, call collectGarbage() manually
right before destroying the QJSEngine.
*/
QJSEngine::~QJSEngine()
{
+ m_v4Engine->inShutdown = true;
QJSEnginePrivate::removeFromDebugServer(this);
delete m_v4Engine;
}
@@ -390,46 +390,16 @@ QJSEngine::~QJSEngine()
when the QJSEngine decides that it's wise to do so (i.e. when a certain number of new objects
have been created). However, you can call this function to explicitly request that garbage
collection should be performed as soon as possible.
-*/
-void QJSEngine::collectGarbage()
-{
- m_v4Engine->memoryManager->runGC();
-}
-
-#if QT_DEPRECATED_SINCE(5, 6)
-
-/*!
- \since 5.4
- \obsolete
-
- Installs translator functions on the given \a object, or on the Global
- Object if no object is specified.
-
- The relation between script translator functions and C++ translator
- functions is described in the following table:
-
- \table
- \header \li Script Function \li Corresponding C++ Function
- \row \li qsTr() \li QObject::tr()
- \row \li QT_TR_NOOP() \li QT_TR_NOOP()
- \row \li qsTranslate() \li QCoreApplication::translate()
- \row \li QT_TRANSLATE_NOOP() \li QT_TRANSLATE_NOOP()
- \row \li qsTrId() \li qtTrId()
- \row \li QT_TRID_NOOP() \li QT_TRID_NOOP()
- \endtable
- It also adds an arg() method to the string prototype.
- \sa {Internationalization with Qt}
-*/
-void QJSEngine::installTranslatorFunctions(const QJSValue &object)
+ \sa {Garbage Collection}
+ \sa {Qt::}{gc()}
+ */
+void QJSEngine::collectGarbage()
{
- installExtensions(TranslationExtension, object);
+ m_v4Engine->memoryManager->runGC();
}
-#endif // QT_DEPRECATED_SINCE(5, 6)
-
-
/*!
\since 5.6
@@ -456,10 +426,7 @@ void QJSEngine::installExtensions(QJSEngine::Extensions extensions, const QJSVal
}
QV4::Scope scope(m_v4Engine);
- QV4::ScopedObject obj(scope);
- QV4::Value *val = QJSValuePrivate::getValue(&object);
- if (val)
- obj = val;
+ QV4::ScopedObject obj(scope, QJSValuePrivate::asReturnedValue(&object));
if (!obj)
obj = scope.engine->globalObject;
@@ -479,7 +446,7 @@ void QJSEngine::installExtensions(QJSEngine::Extensions extensions, const QJSVal
*/
void QJSEngine::setInterrupted(bool interrupted)
{
- m_v4Engine->isInterrupted = interrupted;
+ m_v4Engine->isInterrupted.storeRelaxed(interrupted);
}
/*!
@@ -490,7 +457,7 @@ void QJSEngine::setInterrupted(bool interrupted)
*/
bool QJSEngine::isInterrupted() const
{
- return m_v4Engine->isInterrupted.loadAcquire();
+ return m_v4Engine->isInterrupted.loadRelaxed();
}
static QUrl urlForFileName(const QString &fileName)
@@ -510,6 +477,9 @@ static QUrl urlForFileName(const QString &fileName)
The script code will be evaluated in the context of the global object.
+ \note If you need to evaluate inside a QML context, use \l QQmlExpression
+ instead.
+
The evaluation of \a program can cause an \l{Script Exceptions}{exception} in the
engine; in this case the return value will be the exception
that was thrown (typically an \c{Error} object; see
@@ -527,12 +497,23 @@ static QUrl urlForFileName(const QString &fileName)
the file name is accessible through the "fileName" property if it is
provided with this function.
+ \a exceptionStackTrace is used to report whether an uncaught exception was
+ thrown. If you pass a non-null pointer to a QStringList to it, it will set
+ it to list of "stackframe messages" if the script threw an unhandled
+ exception, or an empty list otherwise. A stackframe message has the format
+ function name:line number:column:file name
+ \note In some cases, e.g. for native functions, function name and file name
+ can be empty and line number and column can be -1.
+
\note If an exception was thrown and the exception value is not an
Error instance (i.e., QJSValue::isError() returns \c false), the
- exception value will still be returned, but there is currently no
- API for detecting that an exception did occur in this case.
+ exception value will still be returned. Use \c exceptionStackTrace->isEmpty()
+ to distinguish whether the value was a normal or an exceptional return
+ value.
+
+ \sa QQmlExpression::evaluate
*/
-QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, int lineNumber)
+QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, int lineNumber, QStringList *exceptionStackTrace)
{
QV4::ExecutionEngine *v4 = m_v4Engine;
QV4::Scope scope(v4);
@@ -546,16 +527,27 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in
script.strictMode = v4->globalCode->isStrict();
script.inheritContext = true;
script.parse();
- if (!scope.engine->hasException)
+ if (!scope.hasException())
result = script.run();
- if (scope.engine->hasException)
- result = v4->catchException();
- if (v4->isInterrupted.loadAcquire())
+ if (exceptionStackTrace)
+ exceptionStackTrace->clear();
+ if (scope.hasException()) {
+ QV4::StackTrace trace;
+ result = v4->catchException(&trace);
+ if (exceptionStackTrace) {
+ for (auto &&frame: trace)
+ exceptionStackTrace->push_back(QLatin1StringView("%1:%2:%3:%4").arg(
+ frame.function,
+ QString::number(qAbs(frame.line)),
+ QString::number(frame.column),
+ frame.source)
+ );
+ }
+ }
+ if (v4->isInterrupted.loadRelaxed())
result = v4->newErrorObject(QStringLiteral("Interrupted"));
- QJSValue retval(v4, result->asReturnedValue());
-
- return retval;
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
/*!
@@ -576,26 +568,68 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in
\note If an exception is thrown during the loading of the module, the return value
will be the exception (typically an \c{Error} object; see QJSValue::isError()).
+ \sa registerModule()
+
\since 5.12
*/
QJSValue QJSEngine::importModule(const QString &fileName)
{
const QUrl url = urlForFileName(QFileInfo(fileName).canonicalFilePath());
- auto moduleUnit = m_v4Engine->loadModule(url);
+ const auto module = m_v4Engine->loadModule(url);
if (m_v4Engine->hasException)
- return QJSValue(m_v4Engine, m_v4Engine->catchException());
+ return QJSValuePrivate::fromReturnedValue(m_v4Engine->catchException());
+
+ QV4::Scope scope(m_v4Engine);
+ if (const auto compiled = module.compiled) {
+ QV4::Scoped<QV4::Module> moduleNamespace(scope, compiled->instantiate());
+ if (m_v4Engine->hasException)
+ return QJSValuePrivate::fromReturnedValue(m_v4Engine->catchException());
+ compiled->evaluate();
+ if (!m_v4Engine->isInterrupted.loadRelaxed())
+ return QJSValuePrivate::fromReturnedValue(moduleNamespace->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(
+ m_v4Engine->newErrorObject(QStringLiteral("Interrupted"))->asReturnedValue());
+ }
+
+ // If there is neither a native nor a compiled module, we should have seen an exception
+ Q_ASSERT(module.native);
+
+ return QJSValuePrivate::fromReturnedValue(module.native->asReturnedValue());
+}
+
+/*!
+ Registers a QJSValue to serve as a module. After this function is called,
+ all modules that import \a moduleName will import the value of \a value
+ instead of loading \a moduleName from the filesystem.
+ Any valid QJSValue can be registered, but named exports (i.e.
+ \c {import { name } from "info"} are treated as members of an object, so
+ the default export must be created with one of the newXYZ methods of
+ QJSEngine.
+
+ Because this allows modules that do not exist on the filesystem to be imported,
+ scripting applications can use this to provide built-in modules, similar to
+ Node.js.
+
+ Returns \c true on success, \c false otherwise.
+
+ \note The QJSValue \a value is not called or read until it is used by another module.
+ This means that there is no code to evaluate, so no errors will be seen until
+ another module throws an exception while trying to load this module.
+
+ \warning Attempting to access a named export from a QJSValue that is not an
+ object will trigger a \l{Script Exceptions}{exception}.
+
+ \sa importModule()
+ */
+bool QJSEngine::registerModule(const QString &moduleName, const QJSValue &value)
+{
QV4::Scope scope(m_v4Engine);
- QV4::Scoped<QV4::Module> moduleNamespace(scope, moduleUnit->instantiate(m_v4Engine));
+ QV4::ScopedValue v4Value(scope, QJSValuePrivate::asReturnedValue(&value));
+ m_v4Engine->registerNativeModule(QUrl(moduleName), v4Value);
if (m_v4Engine->hasException)
- return QJSValue(m_v4Engine, m_v4Engine->catchException());
- moduleUnit->evaluate();
- if (!m_v4Engine->isInterrupted.loadAcquire())
- return QJSValue(m_v4Engine, moduleNamespace->asReturnedValue());
-
- return QJSValue(
- m_v4Engine,
- m_v4Engine->newErrorObject(QStringLiteral("Interrupted"))->asReturnedValue());
+ return false;
+ return true;
}
/*!
@@ -610,7 +644,23 @@ QJSValue QJSEngine::newObject()
{
QV4::Scope scope(m_v4Engine);
QV4::ScopedValue v(scope, m_v4Engine->newObject());
- return QJSValue(m_v4Engine, v->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
+}
+
+/*!
+ \since 6.2
+
+ Creates a JavaScript object of class Symbol, with value \a name.
+
+ The prototype of the created object will be the Symbol prototype object.
+
+ \sa newObject()
+*/
+QJSValue QJSEngine::newSymbol(const QString &name)
+{
+ QV4::Scope scope(m_v4Engine);
+ QV4::ScopedValue v(scope, QV4::Symbol::create(m_v4Engine, u'@' + name));
+ return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
}
/*!
@@ -652,7 +702,7 @@ QJSValue QJSEngine::newErrorObject(QJSValue::ErrorType errorType, const QString
case QJSValue::NoError:
return QJSValue::UndefinedValue;
}
- return QJSValue(m_v4Engine, error->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(error->asReturnedValue());
}
/*!
@@ -667,7 +717,7 @@ QJSValue QJSEngine::newArray(uint length)
if (length < 0x1000)
array->arrayReserve(length);
array->setArrayLengthUnchecked(length);
- return QJSValue(m_v4Engine, array.asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(array.asReturnedValue());
}
/*!
@@ -692,7 +742,6 @@ QJSValue QJSEngine::newArray(uint length)
*/
QJSValue QJSEngine::newQObject(QObject *object)
{
- Q_D(QJSEngine);
QV4::ExecutionEngine *v4 = m_v4Engine;
QV4::Scope scope(v4);
if (object) {
@@ -701,7 +750,7 @@ QJSValue QJSEngine::newQObject(QObject *object)
QQmlEngine::setObjectOwnership(object, QQmlEngine::JavaScriptOwnership);
}
QV4::ScopedValue v(scope, QV4::QObjectWrapper::wrap(v4, object));
- return QJSValue(v4, v->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
}
/*!
@@ -719,11 +768,10 @@ QJSValue QJSEngine::newQObject(QObject *object)
*/
QJSValue QJSEngine::newQMetaObject(const QMetaObject* metaObject) {
- Q_D(QJSEngine);
QV4::ExecutionEngine *v4 = m_v4Engine;
QV4::Scope scope(v4);
QV4::ScopedValue v(scope, QV4::QMetaObjectWrapper::create(v4, metaObject));
- return QJSValue(v4, v->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
}
/*! \fn template <typename T> QJSValue QJSEngine::newQMetaObject()
@@ -750,152 +798,252 @@ QJSValue QJSEngine::globalObject() const
{
QV4::Scope scope(m_v4Engine);
QV4::ScopedValue v(scope, m_v4Engine->globalObject);
- return QJSValue(m_v4Engine, v->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
+}
+
+QJSPrimitiveValue QJSEngine::createPrimitive(QMetaType type, const void *ptr)
+{
+ QV4::Scope scope(m_v4Engine);
+ QV4::ScopedValue v(scope, m_v4Engine->metaTypeToJS(type, ptr));
+ return QV4::ExecutionEngine::createPrimitive(v);
+}
+
+QJSManagedValue QJSEngine::createManaged(QMetaType type, const void *ptr)
+{
+ QJSManagedValue result(m_v4Engine);
+ *result.d = m_v4Engine->metaTypeToJS(type, ptr);
+ return result;
}
/*!
* \internal
* used by QJSEngine::toScriptValue
*/
-QJSValue QJSEngine::create(int type, const void *ptr)
+QJSValue QJSEngine::create(QMetaType type, const void *ptr)
{
QV4::Scope scope(m_v4Engine);
QV4::ScopedValue v(scope, scope.engine->metaTypeToJS(type, ptr));
- return QJSValue(m_v4Engine, v->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(v->asReturnedValue());
+}
+
+bool QJSEngine::convertPrimitive(const QJSPrimitiveValue &value, QMetaType type, void *ptr)
+{
+ switch (value.type()) {
+ case QJSPrimitiveValue::Undefined:
+ return QV4::ExecutionEngine::metaTypeFromJS(QV4::Value::undefinedValue(), type, ptr);
+ case QJSPrimitiveValue::Null:
+ return QV4::ExecutionEngine::metaTypeFromJS(QV4::Value::nullValue(), type, ptr);
+ case QJSPrimitiveValue::Boolean:
+ return QV4::ExecutionEngine::metaTypeFromJS(QV4::Value::fromBoolean(value.toBoolean()), type, ptr);
+ case QJSPrimitiveValue::Integer:
+ return QV4::ExecutionEngine::metaTypeFromJS(QV4::Value::fromInt32(value.toInteger()), type, ptr);
+ case QJSPrimitiveValue::Double:
+ return QV4::ExecutionEngine::metaTypeFromJS(QV4::Value::fromDouble(value.toDouble()), type, ptr);
+ case QJSPrimitiveValue::String:
+ return convertString(value.toString(), type, ptr);
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+bool QJSEngine::convertManaged(const QJSManagedValue &value, int type, void *ptr)
+{
+ return convertManaged(value, QMetaType(type), ptr);
+}
+
+bool QJSEngine::convertManaged(const QJSManagedValue &value, QMetaType type, void *ptr)
+{
+ return QV4::ExecutionEngine::metaTypeFromJS(*value.d, type, ptr);
+}
+
+bool QJSEngine::convertString(const QString &string, QMetaType metaType, void *ptr)
+{
+ // have a string based value without engine. Do conversion manually
+ if (metaType == QMetaType::fromType<bool>()) {
+ *reinterpret_cast<bool*>(ptr) = string.size() != 0;
+ return true;
+ }
+ if (metaType == QMetaType::fromType<QString>()) {
+ *reinterpret_cast<QString*>(ptr) = string;
+ return true;
+ }
+ if (metaType == QMetaType::fromType<QUrl>()) {
+ *reinterpret_cast<QUrl *>(ptr) = QUrl(string);
+ return true;
+ }
+
+ double d = QV4::RuntimeHelpers::stringToNumber(string);
+ switch (metaType.id()) {
+ case QMetaType::Int:
+ *reinterpret_cast<int*>(ptr) = QV4::Value::toInt32(d);
+ return true;
+ case QMetaType::UInt:
+ *reinterpret_cast<uint*>(ptr) = QV4::Value::toUInt32(d);
+ return true;
+ case QMetaType::Long:
+ *reinterpret_cast<long*>(ptr) = QV4::Value::toInteger(d);
+ return true;
+ case QMetaType::ULong:
+ *reinterpret_cast<ulong*>(ptr) = QV4::Value::toInteger(d);
+ return true;
+ case QMetaType::LongLong:
+ *reinterpret_cast<qlonglong*>(ptr) = QV4::Value::toInteger(d);
+ return true;
+ case QMetaType::ULongLong:
+ *reinterpret_cast<qulonglong*>(ptr) = QV4::Value::toInteger(d);
+ return true;
+ case QMetaType::Double:
+ *reinterpret_cast<double*>(ptr) = d;
+ return true;
+ case QMetaType::Float:
+ *reinterpret_cast<float*>(ptr) = d;
+ return true;
+ case QMetaType::Short:
+ *reinterpret_cast<short*>(ptr) = QV4::Value::toInt32(d);
+ return true;
+ case QMetaType::UShort:
+ *reinterpret_cast<unsigned short*>(ptr) = QV4::Value::toUInt32(d);
+ return true;
+ case QMetaType::Char:
+ *reinterpret_cast<char*>(ptr) = QV4::Value::toInt32(d);
+ return true;
+ case QMetaType::UChar:
+ *reinterpret_cast<unsigned char*>(ptr) = QV4::Value::toUInt32(d);
+ return true;
+ case QMetaType::QChar:
+ *reinterpret_cast<QChar*>(ptr) = QChar(QV4::Value::toUInt32(d));
+ return true;
+ case QMetaType::Char16:
+ *reinterpret_cast<char16_t *>(ptr) = QV4::Value::toUInt32(d);
+ return true;
+ default:
+ return false;
+ }
}
/*!
\internal
convert \a value to \a type, store the result in \a ptr
*/
-bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
+bool QJSEngine::convertV2(const QJSValue &value, QMetaType metaType, void *ptr)
{
- QV4::ExecutionEngine *v4 = QJSValuePrivate::engine(&value);
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(&value, &scratch);
- if (v4) {
- QV4::Scope scope(v4);
- QV4::ScopedValue v(scope, *val);
- return scope.engine->metaTypeFromJS(v, type, ptr);
- }
+ if (const QString *string = QJSValuePrivate::asQString(&value))
+ return convertString(*string, metaType, ptr);
- if (!val) {
- QVariant *variant = QJSValuePrivate::getVariant(&value);
- Q_ASSERT(variant);
-
- if (variant->userType() == QMetaType::QString) {
- QString string = variant->toString();
- // have a string based value without engine. Do conversion manually
- if (type == QMetaType::Bool) {
- *reinterpret_cast<bool*>(ptr) = string.length() != 0;
- return true;
- }
- if (type == QMetaType::QString) {
- *reinterpret_cast<QString*>(ptr) = string;
- return true;
- }
- double d = QV4::RuntimeHelpers::stringToNumber(string);
- switch (type) {
- case QMetaType::Int:
- *reinterpret_cast<int*>(ptr) = QV4::Value::toInt32(d);
- return true;
- case QMetaType::UInt:
- *reinterpret_cast<uint*>(ptr) = QV4::Value::toUInt32(d);
- return true;
- case QMetaType::LongLong:
- *reinterpret_cast<qlonglong*>(ptr) = QV4::Value::toInteger(d);
- return true;
- case QMetaType::ULongLong:
- *reinterpret_cast<qulonglong*>(ptr) = QV4::Value::toInteger(d);
- return true;
- case QMetaType::Double:
- *reinterpret_cast<double*>(ptr) = d;
- return true;
- case QMetaType::Float:
- *reinterpret_cast<float*>(ptr) = d;
- return true;
- case QMetaType::Short:
- *reinterpret_cast<short*>(ptr) = QV4::Value::toInt32(d);
- return true;
- case QMetaType::UShort:
- *reinterpret_cast<unsigned short*>(ptr) = QV4::Value::toUInt32(d);
- return true;
- case QMetaType::Char:
- *reinterpret_cast<char*>(ptr) = QV4::Value::toInt32(d);
- return true;
- case QMetaType::UChar:
- *reinterpret_cast<unsigned char*>(ptr) = QV4::Value::toUInt32(d);
- return true;
- case QMetaType::QChar:
- *reinterpret_cast<QChar*>(ptr) = QV4::Value::toUInt32(d);
- return true;
- default:
- return false;
- }
- } else {
- return QMetaType::convert(&variant->data_ptr(), variant->userType(), ptr, type);
- }
- }
+ // Does not need scoping since QJSValue still holds on to the value.
+ return QV4::ExecutionEngine::metaTypeFromJS(QJSValuePrivate::asReturnedValue(&value), metaType, ptr);
+}
- Q_ASSERT(val);
-
- switch (type) {
- case QMetaType::Bool:
- *reinterpret_cast<bool*>(ptr) = val->toBoolean();
- return true;
- case QMetaType::Int:
- *reinterpret_cast<int*>(ptr) = val->toInt32();
- return true;
- case QMetaType::UInt:
- *reinterpret_cast<uint*>(ptr) = val->toUInt32();
- return true;
- case QMetaType::LongLong:
- *reinterpret_cast<qlonglong*>(ptr) = val->toInteger();
- return true;
- case QMetaType::ULongLong:
- *reinterpret_cast<qulonglong*>(ptr) = val->toInteger();
- return true;
- case QMetaType::Double:
- *reinterpret_cast<double*>(ptr) = val->toNumber();
- return true;
- case QMetaType::QString:
- *reinterpret_cast<QString*>(ptr) = val->toQStringNoThrow();
- return true;
- case QMetaType::Float:
- *reinterpret_cast<float*>(ptr) = val->toNumber();
- return true;
- case QMetaType::Short:
- *reinterpret_cast<short*>(ptr) = val->toInt32();
- return true;
- case QMetaType::UShort:
- *reinterpret_cast<unsigned short*>(ptr) = val->toUInt16();
- return true;
- case QMetaType::Char:
- *reinterpret_cast<char*>(ptr) = val->toInt32();
- return true;
- case QMetaType::UChar:
- *reinterpret_cast<unsigned char*>(ptr) = val->toUInt16();
- return true;
- case QMetaType::QChar:
- *reinterpret_cast<QChar*>(ptr) = val->toUInt16();
- return true;
- default:
- return false;
- }
+bool QJSEngine::convertVariant(const QVariant &value, QMetaType metaType, void *ptr)
+{
+ // TODO: We could probably avoid creating a QV4::Value in many cases, but we'd have to
+ // duplicate much of metaTypeFromJS and some methods of QV4::Value itself here.
+ QV4::Scope scope(handle());
+ QV4::ScopedValue scoped(scope, scope.engine->fromVariant(value));
+ return QV4::ExecutionEngine::metaTypeFromJS(scoped, metaType, ptr);
+}
+
+bool QJSEngine::convertMetaType(QMetaType fromType, const void *from, QMetaType toType, void *to)
+{
+ // TODO: We could probably avoid creating a QV4::Value in many cases, but we'd have to
+ // duplicate much of metaTypeFromJS and some methods of QV4::Value itself here.
+ QV4::Scope scope(handle());
+ QV4::ScopedValue scoped(scope, scope.engine->fromData(fromType, from));
+ return QV4::ExecutionEngine::metaTypeFromJS(scoped, toType, to);
+}
+
+QString QJSEngine::convertQObjectToString(QObject *object)
+{
+ return QV4::QObjectWrapper::objectToString(
+ handle(), object ? object->metaObject() : nullptr, object);
+}
+
+QString QJSEngine::convertDateTimeToString(const QDateTime &dateTime)
+{
+ return QV4::DateObject::dateTimeToString(dateTime, handle());
+}
+
+double QJSEngine::convertDateTimeToNumber(const QDateTime &dateTime)
+{
+ return QV4::DateObject::dateTimeToNumber(dateTime);
+}
+
+QDate QJSEngine::convertDateTimeToDate(const QDateTime &dateTime)
+{
+ return QV4::DateObject::dateTimeToDate(dateTime);
}
/*! \fn template <typename T> QJSValue QJSEngine::toScriptValue(const T &value)
Creates a QJSValue with the given \a value.
- \sa fromScriptValue()
+ \sa fromScriptValue(), coerceValue()
+*/
+
+/*! \fn template <typename T> QJSManagedValue QJSEngine::toManagedValue(const T &value)
+
+ Creates a QJSManagedValue with the given \a value.
+
+ \sa fromManagedValue(), coerceValue()
+*/
+
+/*! \fn template <typename T> QJSPrimitiveValue QJSEngine::toPrimitiveValue(const T &value)
+
+ Creates a QJSPrimitiveValue with the given \a value.
+
+ Since QJSPrimitiveValue can only hold int, bool, double, QString, and the
+ equivalents of JavaScript \c null and \c undefined, the value will be
+ coerced aggressively if you pass any other type.
+
+ \sa fromPrimitiveValue(), coerceValue()
*/
/*! \fn template <typename T> T QJSEngine::fromScriptValue(const QJSValue &value)
Returns the given \a value converted to the template type \c{T}.
- \sa toScriptValue()
+ \sa toScriptValue(), coerceValue()
+*/
+
+/*! \fn template <typename T> T QJSEngine::fromManagedValue(const QJSManagedValue &value)
+
+ Returns the given \a value converted to the template type \c{T}.
+
+ \sa toManagedValue(), coerceValue()
+*/
+
+/*! \fn template <typename T> T QJSEngine::fromPrimitiveValue(const QJSPrimitiveValue &value)
+
+ Returns the given \a value converted to the template type \c{T}.
+
+ Since QJSPrimitiveValue can only hold int, bool, double, QString, and the
+ equivalents of JavaScript \c null and \c undefined, the value will be
+ coerced aggressively if you request any other type.
+
+ \sa toPrimitiveValue(), coerceValue()
+*/
+
+/*! \fn template <typename T> T QJSEngine::fromVariant(const QVariant &value)
+
+ Returns the given \a value converted to the template type \c{T}.
+ The conversion is done in JavaScript semantics. Those differ from
+ qvariant_cast's semantics. There are a number of implicit
+ conversions between JavaScript-equivalent types that are not
+ performed by qvariant_cast by default.
+
+ \sa coerceValue(), fromScriptValue(), {QVariant::}{qvariant_cast()}
+*/
+
+/*! \fn template <typename From, typename To> T QJSEngine::coerceValue(const From &from)
+
+ Returns the given \a from converted to the template type \c{To}.
+ The conversion is done in JavaScript semantics. Those differ from
+ qvariant_cast's semantics. There are a number of implicit
+ conversions between JavaScript-equivalent types that are not
+ performed by qvariant_cast by default. This method is a generalization of
+ all the other conversion methods in this class.
+
+ \sa fromVariant(), {QVariant::}{qvariant_cast()}, fromScriptValue(), toScriptValue()
*/
/*!
@@ -907,7 +1055,7 @@ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
JavaScript function through QJSEngine.
When returning from C++, the engine will interrupt the normal flow of
- execution and call the the next pre-registered exception handler with
+ execution and call the next pre-registered exception handler with
an error object that contains the given \a message. The error object
will point to the location of the top-most context on the JavaScript
caller stack; specifically, it will have properties \c lineNumber,
@@ -998,12 +1146,78 @@ void QJSEngine::throwError(QJSValue::ErrorType errorType, const QString &message
{
QV4::Scope scope(m_v4Engine);
QJSValue error = newErrorObject(errorType, message);
- QV4::ScopedObject e(scope, QJSValuePrivate::getValue(&error));
+ QV4::ScopedObject e(scope, QJSValuePrivate::asReturnedValue(&error));
if (!e)
return;
m_v4Engine->throwError(e);
}
+/*!
+ \overload throwError()
+
+ Throws a pre-constructed run-time \a error (exception). This way you can
+ use \l newErrorObject() to create the error and customize it as necessary.
+
+ \since 6.1
+ \sa {Script Exceptions}, newErrorObject()
+*/
+void QJSEngine::throwError(const QJSValue &error)
+{
+ m_v4Engine->throwError(QJSValuePrivate::asReturnedValue(&error));
+}
+
+/*!
+ * Returns \c true if the last JavaScript execution resulted in an exception or
+ * if throwError() was called. Otherwise returns \c false. Mind that evaluate()
+ * catches any exceptions thrown in the evaluated code.
+ *
+ * \since Qt 6.1
+ */
+bool QJSEngine::hasError() const
+{
+ return m_v4Engine->hasException;
+}
+
+/*!
+ * If an exception is currently pending, catches it and returns it as a
+ * QJSValue. Otherwise returns undefined as QJSValue. After calling this method
+ * hasError() returns \c false.
+ *
+ * \since Qt 6.1
+ */
+QJSValue QJSEngine::catchError()
+{
+ if (m_v4Engine->hasException)
+ return QJSValuePrivate::fromReturnedValue(m_v4Engine->catchException());
+ else
+ return QJSValue();
+}
+
+/*!
+ \property QJSEngine::uiLanguage
+ \brief the language to be used for translating user interface strings
+ \since 5.15
+
+ This property holds the name of the language to be used for user interface
+ string translations. It is exposed for reading and writing as \c{Qt.uiLanguage} when
+ the QJSEngine::TranslationExtension is installed on the engine. It is always exposed
+ in instances of QQmlEngine.
+
+ You can set the value freely and use it in bindings. It is recommended to set it
+ after installing translators in your application. By convention, an empty string
+ means no translation from the language used in the source code is intended to occur.
+*/
+void QJSEngine::setUiLanguage(const QString &language) {
+ Q_D(QJSEngine);
+ d->uiLanguage = language; // property takes care of signal emission if necessary
+}
+
+QString QJSEngine::uiLanguage() const
+{
+ Q_D(const QJSEngine);
+ return d->uiLanguage;
+}
+
QJSEnginePrivate *QJSEnginePrivate::get(QV4::ExecutionEngine *e)
{
return e->jsEngine()->d_func();
@@ -1046,12 +1260,87 @@ void QJSEnginePrivate::removeFromDebugServer(QJSEngine *q)
*/
QJSEngine *qjsEngine(const QObject *object)
{
- QQmlData *data = QQmlData::get(object, false);
+ QQmlData *data = QQmlData::get(object);
if (!data || data->jsWrapper.isNullOrUndefined())
return nullptr;
return data->jsWrapper.engine()->jsEngine();
}
+
+/*!
+ \enum QJSEngine::ObjectOwnership
+
+ ObjectOwnership controls whether or not the JavaScript memory manager automatically destroys the
+ QObject when the corresponding JavaScript object is garbage collected by the
+ engine. The two ownership options are:
+
+ \value CppOwnership The object is owned by C++ code and the JavaScript memory manager will never
+ delete it. The JavaScript destroy() method cannot be used on these objects. This
+ option is similar to QScriptEngine::QtOwnership.
+
+ \value JavaScriptOwnership The object is owned by JavaScript. When the object
+ is returned to the JavaScript memory manager as the return value of a method call, the JavaScript
+ memory manager will track it and delete it if there are no remaining JavaScript references to it
+ and it has no QObject::parent(). An object tracked by one QJSEngine will be deleted during that
+ QJSEngine's destructor. Thus, JavaScript references between objects with JavaScriptOwnership from
+ two different engines will not be valid if one of these engines is deleted. This option is similar
+ to QScriptEngine::ScriptOwnership.
+
+ Generally an application doesn't need to set an object's ownership explicitly. The JavaScript
+ memory manager uses a heuristic to set the default ownership. By default, an object that is
+ created by the JavaScript memory manager has JavaScriptOwnership. The exception to this are the
+ root objects created by calling QQmlComponent::create() or QQmlComponent::beginCreate(), which
+ have CppOwnership by default. The ownership of these root-level objects is considered to have been
+ transferred to the C++ caller.
+
+ Objects not-created by the JavaScript memory manager have CppOwnership by default. The exception
+ to this are objects returned from C++ method calls; their ownership will be set to
+ JavaScriptOwnership. This applies only to explicit invocations of Q_INVOKABLE methods or slots,
+ but not to property getter invocations.
+
+ Calling setObjectOwnership() overrides the default ownership.
+
+ \sa {Data Ownership}
+*/
+
+/*!
+ Sets the \a ownership of \a object.
+
+ An object with \c JavaScriptOwnership is not garbage collected as long
+ as it still has a parent, even if there are no references to it.
+
+ \sa QJSEngine::ObjectOwnership
+*/
+void QJSEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
+{
+ if (!object)
+ return;
+
+ QQmlData *ddata = QQmlData::get(object, true);
+ if (!ddata)
+ return;
+
+ ddata->indestructible = (ownership == CppOwnership)?true:false;
+ ddata->explicitIndestructibleSet = true;
+}
+
+/*!
+ Returns the ownership of \a object.
+
+ \sa QJSEngine::ObjectOwnership
+*/
+QJSEngine::ObjectOwnership QJSEngine::objectOwnership(QObject *object)
+{
+ if (!object)
+ return CppOwnership;
+
+ QQmlData *ddata = QQmlData::get(object, false);
+ if (!ddata)
+ return CppOwnership;
+ else
+ return ddata->indestructible?CppOwnership:JavaScriptOwnership;
+}
+
QT_END_NAMESPACE
#include "moc_qjsengine.cpp"
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index 31a4d68baa..b1c99db220 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QJSENGINE_H
#define QJSENGINE_H
@@ -45,8 +9,9 @@
#include <QtCore/qvariant.h>
#include <QtCore/qsharedpointer.h>
#include <QtCore/qobject.h>
+#include <QtCore/qtimezone.h>
#include <QtQml/qjsvalue.h>
-
+#include <QtQml/qjsmanagedvalue.h>
#include <QtQml/qqmldebug.h>
QT_BEGIN_NAMESPACE
@@ -60,6 +25,7 @@ class Q_QML_EXPORT QJSEngine
: public QObject
{
Q_OBJECT
+ Q_PROPERTY(QString uiLanguage READ uiLanguage WRITE setUiLanguage NOTIFY uiLanguageChanged)
public:
QJSEngine();
explicit QJSEngine(QObject *parent);
@@ -67,11 +33,13 @@ public:
QJSValue globalObject() const;
- QJSValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1);
+ QJSValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1, QStringList *exceptionStackTrace = nullptr);
QJSValue importModule(const QString &fileName);
+ bool registerModule(const QString &moduleName, const QJSValue &value);
QJSValue newObject();
+ QJSValue newSymbol(const QString &name);
QJSValue newArray(uint length = 0);
QJSValue newQObject(QObject *object);
@@ -89,19 +57,230 @@ public:
template <typename T>
inline QJSValue toScriptValue(const T &value)
{
- return create(qMetaTypeId<T>(), &value);
+ return create(QMetaType::fromType<T>(), &value);
+ }
+
+ template <typename T>
+ inline QJSManagedValue toManagedValue(const T &value)
+ {
+ return createManaged(QMetaType::fromType<T>(), &value);
+ }
+
+ template <typename T>
+ inline QJSPrimitiveValue toPrimitiveValue(const T &value)
+ {
+ // In the common case that the argument fits into QJSPrimitiveValue, use it.
+ if constexpr (std::disjunction_v<
+ std::is_same<T, int>,
+ std::is_same<T, bool>,
+ std::is_same<T, double>,
+ std::is_same<T, QString>>) {
+ return QJSPrimitiveValue(value);
+ } else {
+ return createPrimitive(QMetaType::fromType<T>(), &value);
+ }
}
+
template <typename T>
inline T fromScriptValue(const QJSValue &value)
{
return qjsvalue_cast<T>(value);
}
+ template <typename T>
+ inline T fromManagedValue(const QJSManagedValue &value)
+ {
+ return qjsvalue_cast<T>(value);
+ }
+
+ template <typename T>
+ inline T fromPrimitiveValue(const QJSPrimitiveValue &value)
+ {
+ if constexpr (std::is_same_v<T, int>)
+ return value.toInteger();
+ if constexpr (std::is_same_v<T, bool>)
+ return value.toBoolean();
+ if constexpr (std::is_same_v<T, double>)
+ return value.toDouble();
+ if constexpr (std::is_same_v<T, QString>)
+ return value.toString();
+ if constexpr (std::is_same_v<T, QVariant>)
+ return value.toVariant();
+ if constexpr (std::is_pointer_v<T>)
+ return nullptr;
+ return qjsvalue_cast<T>(value);
+ }
+
+ template <typename T>
+ inline T fromVariant(const QVariant &value)
+ {
+ if constexpr (std::is_same_v<T, QVariant>)
+ return value;
+
+ const QMetaType sourceType = value.metaType();
+ const QMetaType targetType = QMetaType::fromType<T>();
+ if (sourceType == targetType)
+ return *reinterpret_cast<const T *>(value.constData());
+
+ if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>) {
+ using nonConstT = std::remove_const_t<std::remove_pointer_t<T>> *;
+ const QMetaType nonConstTargetType = QMetaType::fromType<nonConstT>();
+ if (value.metaType() == nonConstTargetType)
+ return *reinterpret_cast<const nonConstT *>(value.constData());
+ }
+
+ if constexpr (std::is_same_v<T, QJSValue>)
+ return toScriptValue(value);
+
+ if constexpr (std::is_same_v<T, QJSManagedValue>)
+ return toManagedValue(value);
+
+ if constexpr (std::is_same_v<T, QJSPrimitiveValue>)
+ return toPrimitiveValue(value);
+
+ if constexpr (std::is_same_v<T, QString>) {
+ if (sourceType.flags() & QMetaType::PointerToQObject) {
+ return convertQObjectToString(
+ *reinterpret_cast<QObject *const *>(value.constData()));
+ }
+ }
+
+ if constexpr (std::is_same_v<QObject, std::remove_const_t<std::remove_pointer_t<T>>>) {
+ if (sourceType.flags() & QMetaType::PointerToQObject) {
+ return *static_cast<QObject *const *>(value.constData());
+
+ // We should not access source->metaObject() here since that may trigger some
+ // rather involved code. convertVariant() can do this using property caches.
+ }
+ }
+
+ if (sourceType == QMetaType::fromType<QJSValue>())
+ return fromScriptValue<T>(*reinterpret_cast<const QJSValue *>(value.constData()));
+
+ if (sourceType == QMetaType::fromType<QJSManagedValue>()) {
+ return fromManagedValue<T>(
+ *reinterpret_cast<const QJSManagedValue *>(value.constData()));
+ }
+
+ if (sourceType == QMetaType::fromType<QJSPrimitiveValue>()) {
+ return fromPrimitiveValue<T>(
+ *reinterpret_cast<const QJSPrimitiveValue *>(value.constData()));
+ }
+
+ {
+ T t{};
+ if (value.metaType() == QMetaType::fromType<QString>()) {
+ if (convertString(value.toString(), targetType, &t))
+ return t;
+ } else if (convertVariant(value, targetType, &t)) {
+ return t;
+ }
+
+ QMetaType::convert(value.metaType(), value.constData(), targetType, &t);
+ return t;
+ }
+ }
+
+ template<typename From, typename To>
+ inline To coerceValue(const From &from)
+ {
+ if constexpr (std::is_base_of_v<To, From>)
+ return from;
+
+ if constexpr (std::is_same_v<To, QJSValue>)
+ return toScriptValue(from);
+
+ if constexpr (std::is_same_v<From, QJSValue>)
+ return fromScriptValue<To>(from);
+
+ if constexpr (std::is_same_v<To, QJSManagedValue>)
+ return toManagedValue(from);
+
+ if constexpr (std::is_same_v<From, QJSManagedValue>)
+ return fromManagedValue<To>(from);
+
+ if constexpr (std::is_same_v<To, QJSPrimitiveValue>)
+ return toPrimitiveValue(from);
+
+ if constexpr (std::is_same_v<From, QJSPrimitiveValue>)
+ return fromPrimitiveValue<To>(from);
+
+ if constexpr (std::is_same_v<From, QVariant>)
+ return fromVariant<To>(from);
+
+ if constexpr (std::is_same_v<To, QVariant>)
+ return QVariant::fromValue(from);
+
+ if constexpr (std::is_same_v<To, QString>) {
+ if constexpr (std::is_base_of_v<QObject, std::remove_const_t<std::remove_pointer_t<From>>>)
+ return convertQObjectToString(from);
+ }
+
+ if constexpr (std::is_same_v<From, QDateTime>) {
+ if constexpr (std::is_same_v<To, QDate>)
+ return convertDateTimeToDate(from.toLocalTime());
+ if constexpr (std::is_same_v<To, QTime>)
+ return from.toLocalTime().time();
+ if constexpr (std::is_same_v<To, QString>)
+ return convertDateTimeToString(from.toLocalTime());
+ if constexpr (std::is_same_v<To, double>)
+ return convertDateTimeToNumber(from.toLocalTime());
+ }
+
+ if constexpr (std::is_same_v<From, QDate>) {
+ if constexpr (std::is_same_v<To, QDateTime>)
+ return from.startOfDay(QTimeZone::UTC);
+ if constexpr (std::is_same_v<To, QTime>) {
+ // This is the current time zone offset, for better or worse
+ return coerceValue<QDateTime, QTime>(coerceValue<QDate, QDateTime>(from));
+ }
+ if constexpr (std::is_same_v<To, QString>)
+ return convertDateTimeToString(coerceValue<QDate, QDateTime>(from));
+ if constexpr (std::is_same_v<To, double>)
+ return convertDateTimeToNumber(coerceValue<QDate, QDateTime>(from));
+ }
+
+ if constexpr (std::is_same_v<From, QTime>) {
+ if constexpr (std::is_same_v<To, QDate>) {
+ // Yes. April Fools' 1971. See qv4dateobject.cpp.
+ return from.isValid() ? QDate(1971, 4, 1) : QDate();
+ }
+
+ if constexpr (std::is_same_v<To, QDateTime>)
+ return QDateTime(coerceValue<QTime, QDate>(from), from, QTimeZone::LocalTime);
+ if constexpr (std::is_same_v<To, QString>)
+ return convertDateTimeToString(coerceValue<QTime, QDateTime>(from));
+ if constexpr (std::is_same_v<To, double>)
+ return convertDateTimeToNumber(coerceValue<QTime, QDateTime>(from));
+ }
+
+ if constexpr (std::is_same_v<To, std::remove_const_t<std::remove_pointer_t<To>> const *>) {
+ using nonConstTo = std::remove_const_t<std::remove_pointer_t<To>> *;
+ if constexpr (std::is_same_v<From, nonConstTo>)
+ return from;
+ }
+
+ {
+ const QMetaType sourceType = QMetaType::fromType<From>();
+ const QMetaType targetType = QMetaType::fromType<To>();
+ To to{};
+ if constexpr (std::is_same_v<From, QString>) {
+ if (convertString(from, targetType, &to))
+ return to;
+ } else if (convertMetaType(sourceType, &from, targetType, &to)) {
+ return to;
+ }
+
+ QMetaType::convert(sourceType, &from, targetType, &to);
+ return to;
+ }
+ }
+
void collectGarbage();
-#if QT_DEPRECATED_SINCE(5, 6)
- QT_DEPRECATED void installTranslatorFunctions(const QJSValue &object = QJSValue());
-#endif
+ enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
+ static void setObjectOwnership(QObject *, ObjectOwnership);
+ static ObjectOwnership objectOwnership(QObject *);
enum Extension {
TranslationExtension = 0x1,
@@ -120,13 +299,49 @@ public:
void throwError(const QString &message);
void throwError(QJSValue::ErrorType errorType, const QString &message = QString());
+ void throwError(const QJSValue &error);
+ bool hasError() const;
+ QJSValue catchError();
+
+ QString uiLanguage() const;
+ void setUiLanguage(const QString &language);
+
+Q_SIGNALS:
+ void uiLanguageChanged();
private:
- QJSValue create(int type, const void *ptr);
+ QJSPrimitiveValue createPrimitive(QMetaType type, const void *ptr);
+ QJSManagedValue createManaged(QMetaType type, const void *ptr);
+ QJSValue create(QMetaType type, const void *ptr);
+#if QT_QML_REMOVED_SINCE(6, 5)
+ QJSValue create(int id, const void *ptr); // only there for BC reasons
+#endif
+
+ static bool convertPrimitive(const QJSPrimitiveValue &value, QMetaType type, void *ptr);
+ static bool convertManaged(const QJSManagedValue &value, int type, void *ptr);
+ static bool convertManaged(const QJSManagedValue &value, QMetaType type, void *ptr);
+#if QT_QML_REMOVED_SINCE(6, 5)
+ static bool convertV2(const QJSValue &value, int type, void *ptr); // only there for BC reasons
+#endif
+ static bool convertV2(const QJSValue &value, QMetaType metaType, void *ptr);
+ static bool convertString(const QString &string, QMetaType metaType, void *ptr);
+
+ bool convertVariant(const QVariant &value, QMetaType metaType, void *ptr);
+ bool convertMetaType(QMetaType fromType, const void *from, QMetaType toType, void *to);
+
+ QString convertQObjectToString(QObject *object);
+ QString convertDateTimeToString(const QDateTime &dateTime);
+ double convertDateTimeToNumber(const QDateTime &dateTime);
+ static QDate convertDateTimeToDate(const QDateTime &dateTime);
- static bool convertV2(const QJSValue &value, int type, void *ptr);
+ template<typename T>
+ friend inline T qjsvalue_cast(const QJSValue &);
- friend inline bool qjsvalue_cast_helper(const QJSValue &, int, void *);
+ template<typename T>
+ friend inline T qjsvalue_cast(const QJSManagedValue &);
+
+ template<typename T>
+ friend inline T qjsvalue_cast(const QJSPrimitiveValue &);
protected:
QJSEngine(QJSEnginePrivate &dd, QObject *parent = nullptr);
@@ -139,23 +354,30 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QJSEngine::Extensions)
-inline bool qjsvalue_cast_helper(const QJSValue &value, int type, void *ptr)
+template<typename T>
+T qjsvalue_cast(const QJSValue &value)
{
- return QJSEngine::convertV2(value, type, ptr);
+ if (T t; QJSEngine::convertV2(value, QMetaType::fromType<T>(), &t))
+ return t;
+ return qvariant_cast<T>(value.toVariant());
}
template<typename T>
-T qjsvalue_cast(const QJSValue &value)
+T qjsvalue_cast(const QJSManagedValue &value)
{
- T t;
- const int id = qMetaTypeId<T>();
+ if (T t; QJSEngine::convertManaged(value, QMetaType::fromType<T>(), &t))
+ return t;
- if (qjsvalue_cast_helper(value, id, &t))
+ return qvariant_cast<T>(value.toVariant());
+}
+
+template<typename T>
+T qjsvalue_cast(const QJSPrimitiveValue &value)
+{
+ if (T t; QJSEngine::convertPrimitive(value, QMetaType::fromType<T>(), &t))
return t;
- else if (value.isVariant())
- return qvariant_cast<T>(value.toVariant());
- return T();
+ return qvariant_cast<T>(value.toVariant());
}
template <>
@@ -164,6 +386,18 @@ inline QVariant qjsvalue_cast<QVariant>(const QJSValue &value)
return value.toVariant();
}
+template <>
+inline QVariant qjsvalue_cast<QVariant>(const QJSManagedValue &value)
+{
+ return value.toVariant();
+}
+
+template <>
+inline QVariant qjsvalue_cast<QVariant>(const QJSPrimitiveValue &value)
+{
+ return value.toVariant();
+}
+
Q_QML_EXPORT QJSEngine *qjsEngine(const QObject *);
QT_END_NAMESPACE
diff --git a/src/qml/jsapi/qjsengine_p.h b/src/qml/jsapi/qjsengine_p.h
index 164a70d000..735dae8d81 100644
--- a/src/qml/jsapi/qjsengine_p.h
+++ b/src/qml/jsapi/qjsengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QJSENGINE_P_H
#define QJSENGINE_P_H
@@ -53,6 +17,7 @@
#include <QtCore/private/qobject_p.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qproperty.h>
#include "qjsengine.h"
#include "private/qtqmlglobal_p.h"
#include <private/qqmlmetatype_p.h>
@@ -65,7 +30,7 @@ namespace QV4 {
struct ExecutionEngine;
}
-class Q_QML_PRIVATE_EXPORT QJSEnginePrivate : public QObjectPrivate
+class Q_QML_EXPORT QJSEnginePrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QJSEngine)
@@ -80,114 +45,10 @@ public:
static void addToDebugServer(QJSEngine *q);
static void removeFromDebugServer(QJSEngine *q);
- // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary.
- // Currently, locking is only necessary if the threaded loader is running concurrently. If it is
- // either idle, or is running with the main thread blocked, no locking is necessary. This way
- // we only pay for locking when we have to.
- // Consequently, this class should only be used to protect simple accesses or modifications of the
- // QQmlEnginePrivate structures or operations that can be guaranteed not to start activity
- // on the loader thread.
- // The Locker API is identical to QMutexLocker. Locker reuses the QQmlEnginePrivate::mutex
- // QMutex instance and multiple Lockers are recursive in the same thread.
- class Locker
- {
- public:
- inline Locker(const QJSEngine *);
- inline Locker(const QJSEnginePrivate *);
- inline ~Locker();
-
- inline void unlock();
- inline void relock();
-
- private:
- const QJSEnginePrivate *m_ep;
- quint32 m_locked:1;
- };
-
- // Shared by QQmlEngine
- mutable QRecursiveMutex mutex;
-
-
- // These methods may be called from the QML loader thread
- inline QQmlPropertyCache *cache(QObject *obj, int minorVersion = -1);
- inline QQmlPropertyCache *cache(const QMetaObject *, int minorVersion = -1);
+ void uiLanguageChanged() { Q_Q(QJSEngine); if (q) q->uiLanguageChanged(); }
+ Q_OBJECT_BINDABLE_PROPERTY(QJSEnginePrivate, QString, uiLanguage, &QJSEnginePrivate::uiLanguageChanged);
};
-QJSEnginePrivate::Locker::Locker(const QJSEngine *e)
-: m_ep(QJSEnginePrivate::get(e))
-{
- relock();
-}
-
-QJSEnginePrivate::Locker::Locker(const QJSEnginePrivate *e)
-: m_ep(e), m_locked(false)
-{
- relock();
-}
-
-QJSEnginePrivate::Locker::~Locker()
-{
- unlock();
-}
-
-void QJSEnginePrivate::Locker::unlock()
-{
- if (m_locked) {
- m_ep->mutex.unlock();
- m_locked = false;
- }
-}
-
-void QJSEnginePrivate::Locker::relock()
-{
- Q_ASSERT(!m_locked);
- m_ep->mutex.lock();
- m_locked = true;
-}
-
-/*!
-Returns a QQmlPropertyCache for \a obj if one is available.
-
-If \a obj is null, being deleted or contains a dynamic meta object 0
-is returned.
-
-The returned cache is not referenced, so if it is to be stored, call addref().
-
-XXX thread There is a potential future race condition in this and all the cache()
-functions. As the QQmlPropertyCache is returned unreferenced, when called
-from the loader thread, it is possible that the cache will have been dereferenced
-and deleted before the loader thread has a chance to use or reference it. This
-can't currently happen as the cache holds a reference to the
-QQmlPropertyCache until the QQmlEngine is destroyed.
-*/
-QQmlPropertyCache *QJSEnginePrivate::cache(QObject *obj, int minorVersion)
-{
- if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
- return nullptr;
-
- Locker locker(this);
- const QMetaObject *mo = obj->metaObject();
- return QQmlMetaType::propertyCache(mo, minorVersion);
-}
-
-/*!
-Returns a QQmlPropertyCache for \a metaObject.
-
-As the cache is persisted for the life of the engine, \a metaObject must be
-a static "compile time" meta-object, or a meta-object that is otherwise known to
-exist for the lifetime of the QQmlEngine.
-
-The returned cache is not referenced, so if it is to be stored, call addref().
-*/
-QQmlPropertyCache *QJSEnginePrivate::cache(const QMetaObject *metaObject, int minorVersion)
-{
- Q_ASSERT(metaObject);
-
- Locker locker(this);
- return QQmlMetaType::propertyCache(metaObject, minorVersion);
-}
-
-
QT_END_NAMESPACE
#endif // QJSENGINE_P_H
diff --git a/src/qml/jsapi/qjslist.cpp b/src/qml/jsapi/qjslist.cpp
new file mode 100644
index 0000000000..b3a4eed3c0
--- /dev/null
+++ b/src/qml/jsapi/qjslist.cpp
@@ -0,0 +1,18 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtQml/qjslist.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ * \class QJSListIndexClamp
+ * \internal
+ */
+
+/*!
+ * \class QJSList
+ * \internal
+ */
+
+QT_END_NAMESPACE
diff --git a/src/qml/jsapi/qjslist.h b/src/qml/jsapi/qjslist.h
new file mode 100644
index 0000000000..d604e266f2
--- /dev/null
+++ b/src/qml/jsapi/qjslist.h
@@ -0,0 +1,368 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QJSLIST_H
+#define QJSLIST_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtQml/qqmllist.h>
+#include <QtQml/qjsengine.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+
+#include <algorithm>
+
+//
+// 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. It will be kept compatible with the intended usage by
+// code generated using qmlcachegen.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+struct QJSListIndexClamp
+{
+ static qsizetype clamp(qsizetype start, qsizetype max, qsizetype min = 0)
+ {
+ Q_ASSERT(min >= 0);
+ Q_ASSERT(min <= max);
+ return std::clamp(start < 0 ? max + qsizetype(start) : qsizetype(start), min, max);
+ }
+};
+
+template<typename List, typename Value = typename List::value_type>
+struct QJSList : private QJSListIndexClamp
+{
+ Q_DISABLE_COPY_MOVE(QJSList)
+
+ QJSList(List *list, QJSEngine *engine) : m_list(list), m_engine(engine) {}
+
+ Value at(qsizetype index) const
+ {
+ Q_ASSERT(index >= 0 && index < size());
+ return *(m_list->cbegin() + index);
+ }
+
+ qsizetype size() const { return m_list->size(); }
+
+ void resize(qsizetype size)
+ {
+ m_list->resize(size);
+ }
+
+ bool includes(const Value &value) const
+ {
+ return std::find(m_list->cbegin(), m_list->cend(), value) != m_list->cend();
+ }
+
+ bool includes(const Value &value, qsizetype start) const
+ {
+ return std::find(m_list->cbegin() + clamp(start, m_list->size()), m_list->cend(), value)
+ != m_list->cend();
+ }
+
+ QString join(const QString &separator = QStringLiteral(",")) const
+ {
+ QString result;
+ bool atBegin = true;
+ std::for_each(m_list->cbegin(), m_list->cend(), [&](const Value &value) {
+ if (atBegin)
+ atBegin = false;
+ else
+ result += separator;
+ result += m_engine->coerceValue<Value, QString>(value);
+ });
+ return result;
+ }
+
+ List slice() const
+ {
+ return *m_list;
+ }
+ List slice(qsizetype start) const
+ {
+ List result;
+ std::copy(m_list->cbegin() + clamp(start, m_list->size()), m_list->cend(),
+ std::back_inserter(result));
+ return result;
+ }
+ List slice(qsizetype start, qsizetype end) const
+ {
+ const qsizetype size = m_list->size();
+ const qsizetype clampedStart = clamp(start, size);
+ const qsizetype clampedEnd = clamp(end, size, clampedStart);
+
+ List result;
+ std::copy(m_list->cbegin() + clampedStart, m_list->cbegin() + clampedEnd,
+ std::back_inserter(result));
+ return result;
+ }
+
+ qsizetype indexOf(const Value &value) const
+ {
+ const auto begin = m_list->cbegin();
+ const auto end = m_list->cend();
+ const auto it = std::find(begin, end, value);
+ if (it == end)
+ return -1;
+ const qsizetype result = it - begin;
+ Q_ASSERT(result >= 0);
+ return result;
+ }
+ qsizetype indexOf(const Value &value, qsizetype start) const
+ {
+ const auto begin = m_list->cbegin();
+ const auto end = m_list->cend();
+ const auto it = std::find(begin + clamp(start, m_list->size()), end, value);
+ if (it == end)
+ return -1;
+ const qsizetype result = it - begin;
+ Q_ASSERT(result >= 0);
+ return result;
+ }
+
+ qsizetype lastIndexOf(const Value &value) const
+ {
+ const auto begin = std::make_reverse_iterator(m_list->cend());
+ const auto end = std::make_reverse_iterator(m_list->cbegin());
+ const auto it = std::find(begin, end, value);
+ return (end - it) - 1;
+ }
+ qsizetype lastIndexOf(const Value &value, qsizetype start) const
+ {
+ const qsizetype size = m_list->size();
+ if (size == 0)
+ return -1;
+
+ // Construct a one-past-end iterator as input.
+ const qsizetype clampedStart = std::min(clamp(start, size), size - 1);
+ const auto begin = std::make_reverse_iterator(m_list->cbegin() + clampedStart + 1);
+
+ const auto end = std::make_reverse_iterator(m_list->cbegin());
+ const auto it = std::find(begin, end, value);
+ return (end - it) - 1;
+ }
+
+ QString toString() const { return join(); }
+
+private:
+ List *m_list = nullptr;
+ QJSEngine *m_engine = nullptr;
+};
+
+template<>
+struct QJSList<QQmlListProperty<QObject>, QObject *> : private QJSListIndexClamp
+{
+ Q_DISABLE_COPY_MOVE(QJSList)
+
+ QJSList(QQmlListProperty<QObject> *list, QJSEngine *engine) : m_list(list), m_engine(engine) {}
+
+ QObject *at(qsizetype index) const
+ {
+ Q_ASSERT(index >= 0 && index < size());
+ return m_list->at(m_list, index);
+ }
+
+ qsizetype size() const
+ {
+ return m_list->count(m_list);
+ }
+
+ void resize(qsizetype size)
+ {
+ qsizetype current = m_list->count(m_list);
+ if (current < size && m_list->append) {
+ do {
+ m_list->append(m_list, nullptr);
+ } while (++current < size);
+ } else if (current > size && m_list->removeLast) {
+ do {
+ m_list->removeLast(m_list);
+ } while (--current > size);
+ }
+ }
+
+ bool includes(const QObject *value) const
+ {
+ if (!m_list->count || !m_list->at)
+ return false;
+
+ const qsizetype size = m_list->count(m_list);
+ for (qsizetype i = 0; i < size; ++i) {
+ if (m_list->at(m_list, i) == value)
+ return true;
+ }
+
+ return false;
+ }
+ bool includes(const QObject *value, qsizetype start) const
+ {
+ if (!m_list->count || !m_list->at)
+ return false;
+
+ const qsizetype size = m_list->count(m_list);
+ for (qsizetype i = clamp(start, size); i < size; ++i) {
+ if (m_list->at(m_list, i) == value)
+ return true;
+ }
+
+ return false;
+ }
+
+ QString join(const QString &separator = QStringLiteral(",")) const
+ {
+ if (!m_list->count || !m_list->at)
+ return QString();
+
+ QString result;
+ for (qsizetype i = 0, end = m_list->count(m_list); i < end; ++i) {
+ if (i != 0)
+ result += separator;
+ result += m_engine->coerceValue<QObject *, QString>(m_list->at(m_list, i));
+ }
+
+ return result;
+ }
+
+ QObjectList slice() const
+ {
+ return m_list->toList<QObjectList>();
+ }
+ QObjectList slice(qsizetype start) const
+ {
+ if (!m_list->count || !m_list->at)
+ return QObjectList();
+
+ const qsizetype size = m_list->count(m_list);
+ const qsizetype clampedStart = clamp(start, size);
+ QObjectList result;
+ result.reserve(size - clampedStart);
+ for (qsizetype i = clampedStart; i < size; ++i)
+ result.append(m_list->at(m_list, i));
+ return result;
+ }
+ QObjectList slice(qsizetype start, qsizetype end) const
+ {
+ if (!m_list->count || !m_list->at)
+ return QObjectList();
+
+ const qsizetype size = m_list->count(m_list);
+ const qsizetype clampedStart = clamp(start, size);
+ const qsizetype clampedEnd = clamp(end, size, clampedStart);
+ QObjectList result;
+ result.reserve(clampedEnd - clampedStart);
+ for (qsizetype i = clampedStart; i < clampedEnd; ++i)
+ result.append(m_list->at(m_list, i));
+ return result;
+ }
+
+ qsizetype indexOf(const QObject *value) const
+ {
+ if (!m_list->count || !m_list->at)
+ return -1;
+
+ const qsizetype end = m_list->count(m_list);
+ for (qsizetype i = 0; i < end; ++i) {
+ if (m_list->at(m_list, i) == value)
+ return i;
+ }
+ return -1;
+ }
+ qsizetype indexOf(const QObject *value, qsizetype start) const
+ {
+ if (!m_list->count || !m_list->at)
+ return -1;
+
+ const qsizetype size = m_list->count(m_list);
+ for (qsizetype i = clamp(start, size); i < size; ++i) {
+ if (m_list->at(m_list, i) == value)
+ return i;
+ }
+ return -1;
+ }
+
+ qsizetype lastIndexOf(const QObject *value) const
+ {
+ if (!m_list->count || !m_list->at)
+ return -1;
+
+ for (qsizetype i = m_list->count(m_list) - 1; i >= 0; --i) {
+ if (m_list->at(m_list, i) == value)
+ return i;
+ }
+ return -1;
+ }
+ qsizetype lastIndexOf(const QObject *value, qsizetype start) const
+ {
+ if (!m_list->count || !m_list->at)
+ return -1;
+
+ const qsizetype size = m_list->count(m_list);
+ if (size == 0)
+ return -1;
+
+ qsizetype clampedStart = std::min(clamp(start, size), size - 1);
+ for (qsizetype i = clampedStart; i >= 0; --i) {
+ if (m_list->at(m_list, i) == value)
+ return i;
+ }
+ return -1;
+ }
+
+ QString toString() const { return join(); }
+
+private:
+ QQmlListProperty<QObject> *m_list = nullptr;
+ QJSEngine *m_engine = nullptr;
+};
+
+struct QJSListForInIterator
+{
+public:
+ using Ptr = QJSListForInIterator *;
+ template<typename List, typename Value>
+ void init(const QJSList<List, Value> &list)
+ {
+ m_index = 0;
+ m_size = list.size();
+ }
+
+ bool hasNext() const { return m_index < m_size; }
+ qsizetype next() { return m_index++; }
+
+private:
+ qsizetype m_index;
+ qsizetype m_size;
+};
+
+// QJSListForInIterator must not require initialization so that we can jump over it with goto.
+static_assert(std::is_trivial_v<QJSListForInIterator>);
+
+struct QJSListForOfIterator
+{
+public:
+ using Ptr = QJSListForOfIterator *;
+ void init() { m_index = 0; }
+
+ template<typename List, typename Value>
+ bool hasNext(const QJSList<List, Value> &list) const { return m_index < list.size(); }
+
+ template<typename List, typename Value>
+ Value next(const QJSList<List, Value> &list) { return list.at(m_index++); }
+
+private:
+ qsizetype m_index;
+};
+
+// QJSListForOfIterator must not require initialization so that we can jump over it with goto.
+static_assert(std::is_trivial_v<QJSListForOfIterator>);
+
+QT_END_NAMESPACE
+
+#endif // QJSLIST_H
diff --git a/src/qml/jsapi/qjsmanagedvalue.cpp b/src/qml/jsapi/qjsmanagedvalue.cpp
new file mode 100644
index 0000000000..452f991a26
--- /dev/null
+++ b/src/qml/jsapi/qjsmanagedvalue.cpp
@@ -0,0 +1,1145 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtQml/qjsmanagedvalue.h>
+#include <QtQml/qjsengine.h>
+#include <QtQml/private/qv4persistent_p.h>
+#include <QtQml/private/qv4engine_p.h>
+#include <QtQml/private/qv4mm_p.h>
+#include <QtQml/private/qjsvalue_p.h>
+#include <QtQml/private/qv4runtime_p.h>
+#include <QtQml/private/qv4functionobject_p.h>
+#include <QtQml/private/qv4jscall_p.h>
+#include <QtQml/private/qv4urlobject_p.h>
+#include <QtQml/private/qv4variantobject_p.h>
+#include <QtQml/private/qv4qobjectwrapper_p.h>
+#include <QtQml/private/qv4qmetaobjectwrapper_p.h>
+#include <QtQml/private/qv4regexpobject_p.h>
+#include <QtQml/private/qv4dateobject_p.h>
+#include <QtQml/private/qv4errorobject_p.h>
+#include <QtQml/private/qv4identifiertable_p.h>
+
+#include <QtCore/qregularexpression.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qdatetime.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ * \class QJSManagedValue
+ * \inmodule QtQml
+ * \since 6.1
+ *
+ * \inmodule QtQml
+ *
+ * \brief QJSManagedValue represents a value on the JavaScript heap belonging to a QJSEngine.
+ *
+ * The QJSManagedValue class allows interaction with JavaScript values in most
+ * ways you can interact with them from JavaScript itself. You can get and set
+ * properties and prototypes, and you can access arrays. Additionally, you can
+ * transform the value into the Qt counterparts of JavaScript objects. For
+ * example, a Url object may be transformed into a QUrl.
+ *
+ * A QJSManagedValue is always bound to a particular QJSEngine. You cannot use
+ * it independently. This means that you cannot have a QJSManagedValue from one
+ * engine be a property or a proptotype of a QJSManagedValue from a different
+ * engine.
+ *
+ * In contrast to QJSValue, almost all values held by QJSManagedValue live on
+ * the JavaScript heap. There is no inline or unmanaged storage. Therefore, you
+ * can get the prototype of a primitive value, and you can get the \c length
+ * property of a string.
+ *
+ * Only default-constructed or moved-from QJSManagedValues do not hold a value
+ * on the JavaScript heap. They represent \c undefined, which doesn't have any
+ * properties or prototypes.
+ *
+ * Also in contrast to QJSValue, QJSManagedValue does not catch any JavaScript
+ * exceptions. If an operation on a QJSManagedValue causes an error, it will
+ * generally return an \c undefined value and QJSEngine::hasError() will return
+ * \c true afterwards. You can then catch the exception using
+ * QJSEngine::catchError(), or pass it up the stack, at your own discretion.
+ *
+ * \note As the reference to the value on the JavaScript heap has to be freed
+ * on destruction, you cannot move a QJSManagedValue to a different thread.
+ * The destruction would take place in the new thread, which would create a race
+ * condition with the garbage collector on the original thread. This also means
+ * that you cannot hold a QJSManagedValue beyond the lifespan of its engine.
+ *
+ * The recommended way of working with a QJSManagedValue is creating it
+ * on the stack, possibly by moving a QJSValue and adding an engine, then
+ * performing the necessary operations on it, and finally moving it back into a
+ * QJSValue for storage. Moving between QJSManagedValue and QJSValue is fast.
+ */
+
+/*!
+ * \enum QJSManagedValue::Type
+ *
+ * This enum represents the JavaScript native types, as specified by
+ * \l{ECMA-262}.
+ *
+ * \value Undefined The \c undefined type
+ * \value Boolean The \c boolean type
+ * \value Number The \c number type
+ * \value String The \c string type
+ * \value Object The \c object type
+ * \value Symbol The \c symbol type
+ * \value Function The \c function type
+ *
+ * Note that the \c null value is not a type of itself but rather a special kind
+ * of object. You can query a QJSManagedValue for this condition using the
+ * isNull() method. Furthermore, JavaScript has no integer type, but it knows a
+ * special treatment of numbers in preparation for integer only operations. You
+ * can query a QJSManagedValue to find out whether it holds the result of such a
+ * treatment by using the isInteger() method.
+ */
+
+/*!
+ * \fn QJSManagedValue::QJSManagedValue()
+ *
+ * Creates a QJSManagedValue that represents the JavaScript \c undefined value.
+ * This is the only value not stored on the JavaScript heap. Calling engine()
+ * on a default-constructed QJSManagedValue will return nullptr.
+ */
+
+static QV4::ExecutionEngine *v4Engine(QV4::Value *d)
+{
+ if (!d)
+ return nullptr;
+
+ QV4::ExecutionEngine *v4 = QV4::PersistentValueStorage::getEngine(d);
+ Q_ASSERT(v4);
+ return v4;
+}
+
+/*!
+ * Creates a QJSManagedValue from \a value, using the heap of \a engine. If
+ * \a value is itself managed and the engine it belongs to is not \a engine,
+ * the result is an \c undefined value, and a warning is generated.
+ */
+QJSManagedValue::QJSManagedValue(QJSValue value, QJSEngine *engine)
+{
+ QV4::ExecutionEngine *v4 = engine->handle();
+
+ if (QV4::Value *m = QJSValuePrivate::takeManagedValue(&value)) {
+ if (Q_UNLIKELY(v4Engine(m) != v4)) {
+ qWarning("QJSManagedValue(QJSValue, QJSEngine *) failed: "
+ "Value was created in different engine.");
+ QV4::PersistentValueStorage::free(m);
+ return;
+ }
+
+ d = m;
+ return;
+ }
+
+ d = v4->memoryManager->m_persistentValues->allocate();
+
+ if (const QString *string = QJSValuePrivate::asQString(&value))
+ *d = v4->newString(*string);
+ else
+ *d = QJSValuePrivate::asReturnedValue(&value);
+}
+
+/*!
+ * Creates a QJSManagedValue from \a value using the heap of \a engine.
+ */
+QJSManagedValue::QJSManagedValue(const QJSPrimitiveValue &value, QJSEngine *engine) :
+ QJSManagedValue(engine->handle())
+{
+ switch (value.type()) {
+ case QJSPrimitiveValue::Undefined:
+ *d = QV4::Encode::undefined();
+ return;
+ case QJSPrimitiveValue::Null:
+ *d = QV4::Encode::null();
+ return;
+ case QJSPrimitiveValue::Boolean:
+ *d = QV4::Encode(value.asBoolean());
+ return;
+ case QJSPrimitiveValue::Integer:
+ *d = QV4::Encode(value.asInteger());
+ return;
+ case QJSPrimitiveValue::Double:
+ *d = QV4::Encode(value.asDouble());
+ return;
+ case QJSPrimitiveValue::String:
+ *d = engine->handle()->newString(value.asString());
+ return;
+ }
+
+ Q_UNREACHABLE();
+}
+
+/*!
+ * Creates a QJSManagedValue from \a variant using the heap of \a engine.
+ */
+QJSManagedValue::QJSManagedValue(const QVariant &variant, QJSEngine *engine) :
+ QJSManagedValue(engine->handle())
+{
+ *d = engine->handle()->fromVariant(variant);
+}
+
+/*!
+ * Creates a QJSManagedValue from \a string using the heap of \a engine.
+ */
+QJSManagedValue::QJSManagedValue(const QString &string, QJSEngine *engine) :
+ QJSManagedValue(engine->handle())
+{
+ *d = engine->handle()->newString(string);
+}
+
+/*!
+ * Destroys the QJSManagedValue.
+ *
+ * \note This frees the memory slot it holds on the JavaScript heap. You must
+ * not destroy a QJSManagedValue from a different thread than the one
+ * where the QJSEngine it belongs to lives.
+ */
+QJSManagedValue::~QJSManagedValue()
+{
+ QV4::PersistentValueStorage::free(d);
+}
+
+/*!
+ * Move-constructs a QJSManagedValue from \a other. This leaves \a other in
+ * the default-constructed state where it represents undefined and does not
+ * belong to any engine.
+ */
+QJSManagedValue::QJSManagedValue(QJSManagedValue &&other)
+{
+ qSwap(d, other.d);
+}
+
+/*!
+ * Move-assigns a QJSManagedValue from \a other. This leaves \a other in
+ * the default-constructed state where it represents undefined and does not
+ * belong to any engine.
+ *
+ * \note This frees the memory slot this QJSManagedValue holds on the
+ * JavaScript heap. You must not move-assign a QJSManagedValue on a
+ * different thread than the one where the QJSEngine it belongs to lives.
+ */
+QJSManagedValue &QJSManagedValue::operator=(QJSManagedValue &&other)
+{
+ if (this != &other) {
+ QV4::PersistentValueStorage::free(d);
+ d = nullptr;
+ qSwap(d, other.d);
+ }
+ return *this;
+}
+
+/*!
+ * Invokes the JavaScript '==' operator on this QJSManagedValue and \a other,
+ * and returns the result.
+ *
+ * \sa strictlyEquals
+ */
+bool QJSManagedValue::equals(const QJSManagedValue &other) const
+{
+ if (!d)
+ return !other.d || other.d->isNullOrUndefined();
+ if (!other.d)
+ return d->isNullOrUndefined();
+
+ return QV4::Runtime::CompareEqual::call(*d, *other.d);
+}
+
+/*!
+ * Invokes the JavaScript '===' operator on this QJSManagedValue and \a other,
+ * and returns the result.
+ *
+ * \sa equals
+ */
+bool QJSManagedValue::strictlyEquals(const QJSManagedValue &other) const
+{
+ if (!d)
+ return !other.d || other.d->isUndefined();
+ if (!other.d)
+ return d->isUndefined();
+
+ return QV4::RuntimeHelpers::strictEqual(*d, *other.d);
+}
+
+/*!
+ * Returns the QJSEngine this QJSManagedValue belongs to. Mind that the engine
+ * is always valid, unless the QJSManagedValue is default-constructed or moved
+ * from. In the latter case a nullptr is returned.
+ */
+QJSEngine *QJSManagedValue::engine() const
+{
+ if (!d)
+ return nullptr;
+ if (QV4::ExecutionEngine *v4 = QV4::PersistentValueStorage::getEngine(d))
+ return v4->jsEngine();
+ return nullptr;
+}
+
+/*!
+ * Returns the prototype for this QJSManagedValue. This works on any value. You
+ * can, for example retrieve the JavaScript \c boolean prototype from a \c boolean
+ * value.
+ */
+QJSManagedValue QJSManagedValue::prototype() const
+{
+ if (!d)
+ return QJSManagedValue();
+
+ QV4::ExecutionEngine *v4 = v4Engine(d);
+ QJSManagedValue result(v4);
+
+ if (auto object = d->as<QV4::Object>())
+ *result.d = object->getPrototypeOf();
+ else if (auto managed = d->as<QV4::Managed>())
+ *result.d = managed->internalClass()->prototype;
+ else if (d->isBoolean())
+ *result.d = v4->booleanPrototype();
+ else if (d->isNumber())
+ *result.d = v4->numberPrototype();
+
+ // If the prototype appears to be undefined, then it's actually null in JS terms.
+ if (result.d->isUndefined())
+ *result.d = QV4::Encode::null();
+
+ return result;
+}
+
+/*!
+ * Sets the prototype of this QJSManagedValue to \a prototype. A precondition
+ * is that \a prototype belongs to the same QJSEngine as this QJSManagedValue
+ * and is an object (including null). Furthermore, this QJSManagedValue has to
+ * be an object (excluding null), too, and you cannot create prototype cycles.
+ */
+void QJSManagedValue::setPrototype(const QJSManagedValue &prototype)
+{
+ auto object = d ? d->as<QV4::Object>() : nullptr;
+ if (!object) {
+ qWarning("QJSManagedValue::setPrototype() failed: "
+ "Can only set a prototype on an object (excluding null).");
+ return;
+ }
+
+ // Object includes null ...
+ if (prototype.type() != QJSManagedValue::Object) {
+ qWarning("QJSManagedValue::setPrototype() failed: "
+ "Can only set objects (including null) as prototypes.");
+ return;
+ }
+
+ if (Q_UNLIKELY(object->engine() != v4Engine(prototype.d))) {
+ qWarning("QJSManagedValue::setPrototype() failed: "
+ "Prototype was created in differen engine.");
+ return;
+ }
+
+ // ... Null becomes nullptr here. That is why it appears as undefined later.
+ if (!object->setPrototypeOf(prototype.d->as<QV4::Object>())) {
+ qWarning("QJSManagedValue::setPrototype() failed: "
+ "Prototype cycle detected.");
+ }
+}
+
+/*!
+ * Returns the JavaScript type of this QJSManagedValue.
+ */
+QJSManagedValue::Type QJSManagedValue::type() const
+{
+ if (!d || d->isUndefined())
+ return Undefined;
+ if (d->isBoolean())
+ return Boolean;
+ if (d->isNumber())
+ return Number;
+ if (d->isString())
+ return String;
+ if (d->isSymbol())
+ return Symbol;
+ if (d->isFunctionObject())
+ return Function;
+ return Object;
+}
+
+/*!
+ * \fn QJSManagedValue::isUndefined() const
+ *
+ * Returns \c true if the type of this QJSManagedValue is \c undefined,
+ * or \c false otherwise.
+ */
+
+/*!
+ * \fn QJSManagedValue::isBoolean() const
+ *
+ * Returns \c true if the type of this QJSManagedValue is \c boolean,
+ * or \c false otherwise.
+ */
+
+/*!
+ * \fn QJSManagedValue::isNumber() const
+ *
+ * Returns \c true if the type of this QJSManagedValue is \c number,
+ * or \c false otherwise.
+ */
+
+/*!
+ * \fn QJSManagedValue::isString() const
+ *
+ * Returns \c true if the type of this QJSManagedValue is \c string,
+ * or \c false otherwise.
+ */
+
+/*!
+ * \fn QJSManagedValue::isSymbol() const
+ *
+ * Returns \c true if the type of this QJSManagedValue is \c symbol,
+ * or \c false otherwise.
+ */
+
+/*!
+ * \fn QJSManagedValue::isObject() const
+ *
+ * Returns \c true if the type of this QJSManagedValue is \c object,
+ * or \c false otherwise.
+ */
+
+/*!
+ * \fn QJSManagedValue::isFunction() const
+ *
+ * Returns \c true if the type of this QJSManagedValue is \c function,
+ * \c false otherwise.
+ */
+
+/*!
+ * Returns \c true if this QJSManagedValue holds the JavaScript \c null value,
+ * or \c false otherwise.
+ */
+bool QJSManagedValue::isNull() const
+{
+ return d && d->isNull();
+}
+
+/*!
+ * Returns \c true if this QJSManagedValue holds an integer value, or \c false
+ * otherwise. The storage format of a number does not affect the result of any
+ * operations performed on it, but if an integer is stored, many operations are
+ * faster.
+ */
+bool QJSManagedValue::isInteger() const
+{
+ return d && d->isInteger();
+}
+
+/*!
+ * Returns \c true if this value represents a JavaScript regular expression
+ * object, or \c false otherwise.
+ */
+bool QJSManagedValue::isRegularExpression() const
+{
+ return d && d->as<QV4::RegExpObject>();
+}
+
+/*!
+ * Returns \c true if this value represents a JavaScript Array
+ * object, or \c false otherwise.
+ */
+bool QJSManagedValue::isArray() const
+{
+ return d && d->as<QV4::ArrayObject>();
+}
+
+/*!
+ * Returns \c true if this value represents a JavaScript Url
+ * object, or \c false otherwise.
+ */
+bool QJSManagedValue::isUrl() const
+{
+ return d && d->as<QV4::UrlObject>();
+}
+
+/*!
+ * Returns \c true if this value represents a QVariant managed on the JavaScript
+ * heap, or \c false otherwise.
+ */
+bool QJSManagedValue::isVariant() const
+{
+ return d && d->as<QV4::VariantObject>();
+}
+
+/*!
+ * Returns \c true if this value represents a QObject pointer managed on the
+ * JavaScript heap, or \c false otherwise.
+ */
+bool QJSManagedValue::isQObject() const
+{
+ return d && d->as<QV4::QObjectWrapper>();
+}
+
+/*!
+ * Returns \c true if this value represents a QMetaObject pointer managed on the
+ * JavaScript heap, or \c false otherwise.
+ */
+bool QJSManagedValue::isQMetaObject() const
+{
+ return d && d->as<QV4::QMetaObjectWrapper>();
+}
+
+/*!
+ * Returns \c true if this value represents a JavaScript Date object, or
+ * \c false otherwise.
+ */
+bool QJSManagedValue::isDate() const
+{
+ return d && d->as<QV4::DateObject>();
+}
+
+/*!
+ * Returns \c true if this value represents a JavaScript Error object, or
+ * \c false otherwise.
+ */
+bool QJSManagedValue::isError() const
+{
+ return d && d->as<QV4::ErrorObject>();
+}
+
+/*!
+ * \internal
+ *
+ * Returns \c true if this value represents a JavaScript meta type, or \c false
+ * otherwise.
+ */
+bool QJSManagedValue::isJsMetaType() const
+{
+ return d && d->as<QV4::InternalClass>();
+}
+
+/*!
+ * Converts the manged value to a string. If the managed value holds a string,
+ * that one is returned. Otherwise a string coercion by JavaScript rules is
+ * performed.
+ *
+ * \note Conversion of a managed value to a string can throw an exception. In
+ * particular, symbols cannot be coerced into strings, or a custom
+ * toString() method may throw. In this case the result is an empty
+ * string and the engine carries an error after the conversion.
+ */
+QString QJSManagedValue::toString() const
+{
+ return d ? d->toQString() : QStringLiteral("undefined");
+}
+
+/*!
+ * Converts the manged value to a number. If the managed value holds a number,
+ * that one is returned. Otherwise a number coercion by JavaScript rules is
+ * performed.
+ *
+ * \note Conversion of a managed value to a number can throw an exception. In
+ * particular, symbols cannot be coerced into numbers, or a custom
+ * valueOf() method may throw. In this case the result is 0 and the
+ * engine carries an error after the conversion.
+ */
+double QJSManagedValue::toNumber() const
+{
+ return d ? d->toNumber() : 0;
+}
+
+/*!
+ * Converts the manged value to a boolean. If the managed value holds a boolean,
+ * that one is returned. Otherwise a boolean coercion by JavaScript rules is
+ * performed.
+ */
+bool QJSManagedValue::toBoolean() const
+{
+ return d ? d->toBoolean() : false;
+}
+
+/*!
+ * Converts the manged value to an integer. This first converts the value to a
+ * number by the rules of toNumber(), and then clamps it into the integer range
+ * by the rules given for coercing the arguments to JavaScript bit shift
+ * operators into 32bit integers.
+ *
+ * Internally, the value may already be stored as an integer, in which case a
+ * fast path is taken.
+ *
+ * \note Conversion of a managed value to a number can throw an exception. In
+ * particular, symbols cannot be coerced into numbers, or a custom
+ * valueOf() method may throw. In this case the result is 0 and the
+ * engine carries an error after the conversion.
+ *
+ * \note The JavaScript rules for coercing numbers into 32bit integers are
+ * unintuitive.
+ */
+int QJSManagedValue::toInteger() const
+{
+ return d ? d->toInt32() : 0;
+}
+
+/*!
+ * Converts the manged value to a QJSPrimitiveValue. If the managed value holds
+ * a type supported by QJSPrimitiveValue, the value is copied. Otherwise the
+ * value is converted to a string, and the string is stored in
+ * QJSPrimitiveValue.
+ *
+ * \note Conversion of a managed value to a string can throw an exception. In
+ * particular, symbols cannot be coerced into strings, or a custom
+ * toString() method may throw. In this case the result is the undefined
+ * value and the engine carries an error after the conversion.
+ */
+QJSPrimitiveValue QJSManagedValue::toPrimitive() const
+{
+ if (!d || d->isUndefined())
+ return QJSPrimitiveUndefined();
+ if (d->isNull())
+ return QJSPrimitiveNull();
+ if (d->isBoolean())
+ return d->booleanValue();
+ if (d->isInteger())
+ return d->integerValue();
+ if (d->isNumber())
+ return d->doubleValue();
+
+ bool ok;
+ const QString result = d->toQString(&ok);
+ return ok ? QJSPrimitiveValue(result) : QJSPrimitiveValue(QJSPrimitiveUndefined());
+}
+
+/*!
+ * Copies this QJSManagedValue into a new QJSValue. This is less efficient than
+ * move-constructing a QJSValue from a QJSManagedValue, but retains the
+ * QJSManagedValue.
+ */
+QJSValue QJSManagedValue::toJSValue() const
+{
+ return d ? QJSValuePrivate::fromReturnedValue(d->asReturnedValue()) : QJSValue();
+}
+
+/*!
+ * Copies this QJSManagedValue into a new QVariant. This also creates a useful
+ * QVariant if QJSManagedValue::isVariant() returns false. QVariant can hold all
+ * types supported by QJSManagedValue.
+ */
+QVariant QJSManagedValue::toVariant() const
+{
+ if (!d || d->isUndefined())
+ return QVariant();
+ if (d->isNull())
+ return QVariant(QMetaType::fromType<std::nullptr_t>(), nullptr);
+ if (d->isBoolean())
+ return QVariant(d->booleanValue());
+ if (d->isInteger())
+ return QVariant(d->integerValue());
+ if (d->isNumber())
+ return QVariant(d->doubleValue());
+ if (d->isString())
+ return QVariant(d->toQString());
+ if (d->as<QV4::Managed>())
+ return QV4::ExecutionEngine::toVariant(*d, QMetaType{}, true);
+
+ Q_UNREACHABLE_RETURN(QVariant());
+}
+
+/*!
+ * If this QJSManagedValue holds a JavaScript regular expression object, returns
+ * an equivalent QRegularExpression. Otherwise returns an invalid one.
+ */
+QRegularExpression QJSManagedValue::toRegularExpression() const
+{
+ if (const auto *r = d ? d->as<QV4::RegExpObject>() : nullptr)
+ return r->toQRegularExpression();
+ return {};
+}
+
+/*!
+ * If this QJSManagedValue holds a JavaScript Url object, returns
+ * an equivalent QUrl. Otherwise returns an invalid one.
+ */
+QUrl QJSManagedValue::toUrl() const
+{
+ if (const auto *u = d ? d->as<QV4::UrlObject>() : nullptr)
+ return u->toQUrl();
+ return {};
+}
+
+/*!
+ * If this QJSManagedValue holds a QObject pointer, returns it. Otherwise
+ * returns nullptr.
+ */
+QObject *QJSManagedValue::toQObject() const
+{
+ if (const auto *o = d ? d->as<QV4::QObjectWrapper>() : nullptr)
+ return o->object();
+ return {};
+}
+
+/*!
+ * If this QJSManagedValue holds a QMetaObject pointer, returns it.
+ * Otherwise returns nullptr.
+ */
+const QMetaObject *QJSManagedValue::toQMetaObject() const
+{
+ if (const auto *m = d ? d->as<QV4::QMetaObjectWrapper>() : nullptr)
+ return m->metaObject();
+ return {};
+}
+
+/*!
+ * If this QJSManagedValue holds a JavaScript Date object, returns an equivalent
+ * QDateTime. Otherwise returns an invalid one.
+ */
+QDateTime QJSManagedValue::toDateTime() const
+{
+ if (const auto *t = d ? d->as<QV4::DateObject>() : nullptr)
+ return t->toQDateTime();
+ return {};
+}
+
+/*!
+ * Returns \c true if this QJSManagedValue has a property \a name, otherwise
+ * returns \c false. The properties of the prototype chain are considered.
+ */
+bool QJSManagedValue::hasProperty(const QString &name) const
+{
+ if (!d || d->isNullOrUndefined())
+ return false;
+
+ if (d->isString() && name == QStringLiteral("length"))
+ return true;
+
+ if (QV4::Object *obj = d->as<QV4::Object>()) {
+ QV4::Scope scope(obj->engine());
+ QV4::ScopedPropertyKey key(scope, scope.engine->identifierTable->asPropertyKey(name));
+ return obj->hasProperty(key);
+ }
+
+ return prototype().hasProperty(name);
+}
+
+/*!
+ * Returns \c true if this QJSManagedValue has a property \a name, otherwise
+ * returns \c false. The properties of the prototype chain are not considered.
+ */
+bool QJSManagedValue::hasOwnProperty(const QString &name) const
+{
+ if (!d || d->isNullOrUndefined())
+ return false;
+
+ if (d->isString() && name == QStringLiteral("length"))
+ return true;
+
+ if (QV4::Object *obj = d->as<QV4::Object>()) {
+ QV4::Scope scope(obj->engine());
+ QV4::ScopedPropertyKey key(scope, scope.engine->identifierTable->asPropertyKey(name));
+ return obj->getOwnProperty(key) != QV4::Attr_Invalid;
+ }
+
+ return false;
+}
+
+/*!
+ * Returns the property \a name of this QJSManagedValue. The prototype chain
+ * is searched if the property is not found on the actual object.
+ */
+QJSValue QJSManagedValue::property(const QString &name) const
+{
+ if (!d)
+ return QJSValue();
+
+ if (d->isNullOrUndefined()) {
+ QV4::ExecutionEngine *e = v4Engine(d);
+ e->throwTypeError(QStringLiteral("Cannot read property '%1' of null").arg(name));
+ return QJSValue();
+ }
+
+ if (QV4::String *string = d->as<QV4::String>()) {
+ if (name == QStringLiteral("length"))
+ return QJSValue(string->d()->length());
+ }
+
+ if (QV4::Object *obj = d->as<QV4::Object>()) {
+ QV4::Scope scope(obj->engine());
+ QV4::ScopedPropertyKey key(scope, scope.engine->identifierTable->asPropertyKey(name));
+ return QJSValuePrivate::fromReturnedValue(obj->get(key));
+ }
+
+ return prototype().property(name);
+}
+
+/*!
+ * Sets the property \a name to \a value on this QJSManagedValue. This can only
+ * be done on JavaScript values of type \c object. Furhermore, \a value has to be
+ * either a primitive or belong to the same engine as this value.
+ */
+void QJSManagedValue::setProperty(const QString &name, const QJSValue &value)
+{
+ if (!d)
+ return;
+
+ if (d->isNullOrUndefined()) {
+ v4Engine(d)->throwTypeError(
+ QStringLiteral("Value is null and could not be converted to an object"));
+ }
+
+ if (QV4::Object *obj = d->as<QV4::Object>()) {
+ QV4::Scope scope(obj->engine());
+ QV4::ExecutionEngine *v4 = QJSValuePrivate::engine(&value);
+ if (Q_UNLIKELY(v4 && v4 != scope.engine)) {
+ qWarning("QJSManagedValue::setProperty() failed: "
+ "Value was created in different engine.");
+ return;
+ }
+ QV4::ScopedPropertyKey key(scope, scope.engine->identifierTable->asPropertyKey(name));
+ obj->put(key, QJSValuePrivate::convertToReturnedValue(scope.engine, value));
+ }
+}
+
+/*!
+ * Deletes the property \a name from this QJSManagedValue. Returns \c true if
+ * the deletion succeeded, or \c false otherwise.
+ */
+bool QJSManagedValue::deleteProperty(const QString &name)
+{
+ if (!d)
+ return false;
+
+ if (QV4::Object *obj = d->as<QV4::Object>()) {
+ QV4::Scope scope(obj->engine());
+ QV4::ScopedPropertyKey key(scope, scope.engine->identifierTable->asPropertyKey(name));
+ return obj->deleteProperty(key);
+ }
+
+ return false;
+}
+
+/*!
+ * Returns \c true if this QJSManagedValue has an array index \a arrayIndex,
+ * otherwise returns \c false. The properties of the prototype chain are
+ * considered.
+ */
+bool QJSManagedValue::hasProperty(quint32 arrayIndex) const
+{
+ if (!d || d->isNullOrUndefined())
+ return false;
+
+ if (QV4::String *string = d->as<QV4::String>())
+ return arrayIndex < quint32(string->d()->length());
+
+ if (QV4::Object *obj = d->as<QV4::Object>()) {
+ bool hasProperty = false;
+ if (arrayIndex == std::numeric_limits<quint32>::max())
+ obj->get(obj->engine()->id_uintMax(), &hasProperty);
+ else
+ obj->get(arrayIndex, &hasProperty);
+ return hasProperty;
+ }
+
+ return prototype().hasProperty(arrayIndex);
+}
+
+/*!
+ * Returns \c true if this QJSManagedValue has an array index \a arrayIndex,
+ * otherwise returns \c false. The properties of the prototype chain are not
+ * considered.
+ */
+bool QJSManagedValue::hasOwnProperty(quint32 arrayIndex) const
+{
+ if (!d || d->isNullOrUndefined())
+ return false;
+
+ if (QV4::String *string = d->as<QV4::String>())
+ return arrayIndex < quint32(string->d()->length());
+
+ if (QV4::Object *obj = d->as<QV4::Object>()) {
+ if (arrayIndex == std::numeric_limits<quint32>::max()) {
+ return obj->getOwnProperty(obj->engine()->id_uintMax()->toPropertyKey())
+ != QV4::Attr_Invalid;
+ } else {
+ return obj->getOwnProperty(QV4::PropertyKey::fromArrayIndex(arrayIndex))
+ != QV4::Attr_Invalid;
+ }
+ }
+
+ return false;
+}
+
+/*!
+ * Returns the property stored at \a arrayIndex of this QJSManagedValue. The
+ * prototype chain is searched if the property is not found on the actual
+ * object.
+ */
+QJSValue QJSManagedValue::property(quint32 arrayIndex) const
+{
+ if (!d || d->isNullOrUndefined())
+ return QJSValue();
+
+ if (QV4::String *string = d->as<QV4::String>()) {
+ const QString qString = string->toQString();
+ if (arrayIndex < quint32(qString.size()))
+ return qString.sliced(arrayIndex, 1);
+ return QJSValue();
+ }
+
+ if (QV4::Object *obj = d->as<QV4::Object>()) {
+ if (arrayIndex == std::numeric_limits<quint32>::max())
+ return QJSValuePrivate::fromReturnedValue(obj->get(obj->engine()->id_uintMax()));
+ else
+ return QJSValuePrivate::fromReturnedValue(obj->get(arrayIndex));
+ }
+
+ return prototype().property(arrayIndex);
+}
+
+/*!
+ * Stores the \a value at \a arrayIndex in this QJSManagedValue. This can only
+ * be done on JavaScript values of type \c object, and it's not recommended if the
+ * value is not an array. Furhermore, \a value has to be either a primitive or
+ * belong to the same engine as this value.
+ */
+void QJSManagedValue::setProperty(quint32 arrayIndex, const QJSValue &value)
+{
+ if (!d)
+ return;
+
+ if (QV4::Object *obj = d->as<QV4::Object>()) {
+ QV4::ExecutionEngine *v4 = QJSValuePrivate::engine(&value);
+ if (Q_UNLIKELY(v4 && v4 != obj->engine())) {
+ qWarning("QJSManagedValue::setProperty() failed: "
+ "Value was created in different engine.");
+ return;
+ }
+ obj->put(arrayIndex, QJSValuePrivate::convertToReturnedValue(v4, value));
+ }
+}
+
+/*!
+ * Deletes the value stored at \a arrayIndex from this QJSManagedValue. Returns
+ * \c true if the deletion succeeded, or \c false otherwise.
+ */
+bool QJSManagedValue::deleteProperty(quint32 arrayIndex)
+{
+ if (!d)
+ return false;
+
+ if (QV4::Object *obj = d->as<QV4::Object>())
+ return obj->deleteProperty(QV4::PropertyKey::fromArrayIndex(arrayIndex));
+
+ return false;
+}
+
+static const QV4::FunctionObject *functionObjectForCall(QV4::Value *d)
+{
+ if (Q_UNLIKELY(!d)) {
+ qWarning("QJSManagedValue: Calling a default-constructed or moved-from managed value"
+ "should throw an exception, but there is no engine to receive it.");
+ return nullptr;
+ }
+
+ if (const QV4::FunctionObject *f = d->as<QV4::FunctionObject>())
+ return f;
+
+ v4Engine(d)->throwTypeError(QStringLiteral("Value is not a function"));
+ return nullptr;
+}
+
+/*!
+ * If this QJSManagedValue represents a JavaScript FunctionObject, calls it with
+ * the given \a arguments, and returns the result. Otherwise returns a
+ * JavaScript \c undefined value.
+ *
+ * The \a arguments have to be either primitive values or belong to the same
+ * QJSEngine as this QJSManagedValue. Otherwise the call is not carried
+ * out and a JavaScript \c undefined value is returned.
+ */
+QJSValue QJSManagedValue::call(const QJSValueList &arguments) const
+{
+ const QV4::FunctionObject *f = functionObjectForCall(d);
+ if (!f)
+ return QJSValue();
+
+ QV4::ExecutionEngine *engine = f->engine();
+
+ QV4::Scope scope(engine);
+ QV4::JSCallArguments jsCallData(scope, arguments.size());
+ *jsCallData.thisObject = engine->globalObject;
+ int i = 0;
+ for (const QJSValue &arg : arguments) {
+ if (Q_UNLIKELY(!QJSValuePrivate::checkEngine(engine, arg))) {
+ qWarning("QJSManagedValue::call() failed: Argument was created in different engine.");
+ return QJSValue();
+ }
+ jsCallData.args[i++] = QJSValuePrivate::convertToReturnedValue(engine, arg);
+ }
+
+ return QJSValuePrivate::fromReturnedValue(f->call(jsCallData));
+}
+
+/*!
+ * If this QJSManagedValue represents a JavaScript FunctionObject, calls it on
+ * \a instance with the given \a arguments, and returns the result. Otherwise
+ * returns a JavaScript \c undefined value.
+ *
+ * The \a arguments and the \a instance have to be either primitive values or
+ * belong to the same QJSEngine as this QJSManagedValue. Otherwise the call is
+ * not carried out and a JavaScript \c undefined value is returned.
+ */
+QJSValue QJSManagedValue::callWithInstance(const QJSValue &instance,
+ const QJSValueList &arguments) const
+{
+ const QV4::FunctionObject *f = functionObjectForCall(d);
+ if (!f)
+ return QJSValue();
+
+ QV4::ExecutionEngine *engine = f->engine();
+
+ if (Q_UNLIKELY(!QJSValuePrivate::checkEngine(engine, instance))) {
+ qWarning("QJSManagedValue::callWithInstance() failed: "
+ "Instance was created in different engine.");
+ return QJSValue();
+ }
+
+ QV4::Scope scope(engine);
+ QV4::JSCallArguments jsCallData(scope, arguments.size());
+ *jsCallData.thisObject = QJSValuePrivate::convertToReturnedValue(engine, instance);
+ int i = 0;
+ for (const QJSValue &arg : arguments) {
+ if (Q_UNLIKELY(!QJSValuePrivate::checkEngine(engine, arg))) {
+ qWarning("QJSManagedValue::callWithInstance() failed: "
+ "Argument was created in different engine.");
+ return QJSValue();
+ }
+ jsCallData.args[i++] = QJSValuePrivate::convertToReturnedValue(engine, arg);
+ }
+
+ return QJSValuePrivate::fromReturnedValue(f->call(jsCallData));
+}
+
+/*!
+ * If this QJSManagedValue represents a JavaScript FunctionObject, calls it as
+ * constructor with the given \a arguments, and returns the result. Otherwise
+ * returns a JavaScript \c undefined value.
+ *
+ * The \a arguments have to be either primitive values or belong to the same
+ * QJSEngine as this QJSManagedValue. Otherwise the call is not carried
+ * out and a JavaScript \c undefined value is returned.
+ */
+QJSValue QJSManagedValue::callAsConstructor(const QJSValueList &arguments) const
+{
+ const QV4::FunctionObject *f = functionObjectForCall(d);
+ if (!f)
+ return QJSValue();
+
+ QV4::ExecutionEngine *engine = f->engine();
+
+ QV4::Scope scope(engine);
+ QV4::JSCallArguments jsCallData(scope, arguments.size());
+ int i = 0;
+ for (const QJSValue &arg : arguments) {
+ if (Q_UNLIKELY(!QJSValuePrivate::checkEngine(engine, arg))) {
+ qWarning("QJSManagedValue::callAsConstructor() failed: "
+ "Argument was created in different engine.");
+ return QJSValue();
+ }
+ jsCallData.args[i++] = QJSValuePrivate::convertToReturnedValue(engine, arg);
+ }
+
+ return QJSValuePrivate::fromReturnedValue(f->callAsConstructor(jsCallData));
+}
+
+/*!
+ * \internal
+ *
+ * Retrieves the JavaScript meta type of this value. The JavaScript meta type
+ * represents the layout of members in an object. Instantiating a meta type is
+ * faster than re-constructing the same object using a sequence of setProperty()
+ * calls on a new object.
+ *
+ * \sa members(), instantiate()
+ */
+QJSManagedValue QJSManagedValue::jsMetaType() const
+{
+ if (!d)
+ return QJSManagedValue();
+
+ QJSManagedValue result(v4Engine(d));
+ if (QV4::Managed *m = d->as<QV4::Managed>())
+ *result.d = m->internalClass();
+
+ return result;
+}
+
+/*!
+ * \internal
+ *
+ * If this value is a JavaScript meta type, retrieves the names of its members
+ * The ordering of the names corresponds to the ordering of the values to be
+ * passed to instantiate().
+ *
+ * If the value is not a meta type, an empty list is returned.
+ *
+ * \sa isMetaType(), metaType(), instantiate()
+ */
+QStringList QJSManagedValue::jsMetaMembers() const
+{
+ if (!d)
+ return {};
+
+ if (QV4::InternalClass *c = d->as<QV4::InternalClass>()) {
+ const auto heapClass = c->d();
+ const int size = heapClass->size;
+ QStringList result;
+ result.reserve(size);
+ QV4::Scope scope(c->engine());
+ for (int i = 0; i < size; ++i) {
+ QV4::ScopedValue key(scope, heapClass->keyAt(i));
+ result.append(key->toQString());
+ }
+ return result;
+ }
+
+ return {};
+}
+
+/*!
+ * \internal
+ *
+ * If this value is a JavaScript meta type, instantiates it using the
+ * \a values, and returns the result. Otherwise returns undefined.
+ *
+ * The values are expected in the same order as the keys in the return value of
+ * members(), and that is the order in which properties were added to the object
+ * this meta type originally belongs to.
+ *
+ * \sa members(), metaType(), isMetaType().
+ */
+QJSManagedValue QJSManagedValue::jsMetaInstantiate(const QJSValueList &values) const
+{
+ if (!d)
+ return {};
+
+ if (QV4::InternalClass *c = d->as<QV4::InternalClass>()) {
+ QV4::ExecutionEngine *engine = c->engine();
+ QJSManagedValue result(engine);
+ *result.d = c->engine()->newObject(c->d());
+ QV4::Object *o = result.d->as<QV4::Object>();
+
+ for (uint i = 0, end = qMin(qsizetype(c->d()->size), values.size()); i < end; ++i) {
+ const QJSValue &arg = values[i];
+ if (Q_UNLIKELY(!QJSValuePrivate::checkEngine(engine, arg))) {
+ qWarning("QJSManagedValue::instantiate() failed: "
+ "Argument was created in different engine.");
+ return QJSManagedValue();
+ }
+ o->setProperty(i, QJSValuePrivate::convertToReturnedValue(engine, arg));
+ }
+
+ return result;
+ }
+
+ return {};
+}
+
+QJSManagedValue::QJSManagedValue(QV4::ExecutionEngine *engine) :
+ d(engine->memoryManager->m_persistentValues->allocate())
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/jsapi/qjsmanagedvalue.h b/src/qml/jsapi/qjsmanagedvalue.h
new file mode 100644
index 0000000000..a6f67b0cc0
--- /dev/null
+++ b/src/qml/jsapi/qjsmanagedvalue.h
@@ -0,0 +1,130 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QJSMANAGEDVALUE_H
+#define QJSMANAGEDVALUE_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtQml/qjsprimitivevalue.h>
+#include <QtQml/qjsvalue.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+struct Value;
+struct ExecutionEngine;
+}
+
+class QJSEngine;
+class Q_QML_EXPORT QJSManagedValue
+{
+ Q_DISABLE_COPY(QJSManagedValue)
+public:
+ enum Type {
+ Undefined,
+ Boolean,
+ Number,
+ String,
+ Object,
+ Symbol,
+ Function
+ };
+
+ QJSManagedValue() = default;
+ QJSManagedValue(QJSValue value, QJSEngine *engine);
+ QJSManagedValue(const QJSPrimitiveValue &value, QJSEngine *engine);
+ QJSManagedValue(const QVariant &variant, QJSEngine *engine);
+ QJSManagedValue(const QString &string, QJSEngine *engine);
+
+ ~QJSManagedValue();
+ QJSManagedValue(QJSManagedValue &&other);
+ QJSManagedValue &operator=(QJSManagedValue &&other);
+
+ bool equals(const QJSManagedValue &other) const;
+ bool strictlyEquals(const QJSManagedValue &other) const;
+
+ QJSEngine *engine() const;
+
+ QJSManagedValue prototype() const;
+ void setPrototype(const QJSManagedValue &prototype);
+
+ Type type() const;
+
+ // Compatibility with QJSValue
+ bool isUndefined() const { return type() == Undefined; }
+ bool isBoolean() const { return type() == Boolean; }
+ bool isNumber() const { return type() == Number; }
+ bool isString() const { return type() == String; }
+ bool isObject() const { return type() == Object; }
+ bool isSymbol() const { return type() == Symbol; }
+ bool isFunction() const { return type() == Function; }
+
+ // Special case of Number
+ bool isInteger() const;
+
+ // Selected special cases of Object
+ bool isNull() const;
+ bool isRegularExpression() const;
+ bool isArray() const;
+ bool isUrl() const;
+ bool isVariant() const;
+ bool isQObject() const;
+ bool isQMetaObject() const;
+ bool isDate() const;
+ bool isError() const;
+ bool isJsMetaType() const;
+
+ // Native type transformations
+ QString toString() const;
+ double toNumber() const;
+ bool toBoolean() const;
+
+ // Variant-like type transformations
+ QJSPrimitiveValue toPrimitive() const;
+ QJSValue toJSValue() const;
+ QVariant toVariant() const;
+
+ // Special cases
+ int toInteger() const;
+ QRegularExpression toRegularExpression() const;
+ QUrl toUrl() const;
+ QObject *toQObject() const;
+ const QMetaObject *toQMetaObject() const;
+ QDateTime toDateTime() const;
+
+ // Properties of objects
+ bool hasProperty(const QString &name) const;
+ bool hasOwnProperty(const QString &name) const;
+ QJSValue property(const QString &name) const;
+ void setProperty(const QString &name, const QJSValue &value);
+ bool deleteProperty(const QString &name);
+
+ // ### Qt 7 use qsizetype instead.
+ // Array indexing
+ bool hasProperty(quint32 arrayIndex) const;
+ bool hasOwnProperty(quint32 arrayIndex) const;
+ QJSValue property(quint32 arrayIndex) const;
+ void setProperty(quint32 arrayIndex, const QJSValue &value);
+ bool deleteProperty(quint32 arrayIndex);
+
+ // Calling functions
+ QJSValue call(const QJSValueList &arguments = {}) const;
+ QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &arguments = {}) const;
+ QJSValue callAsConstructor(const QJSValueList &arguments = {}) const;
+
+ // JavaScript metatypes
+ QJSManagedValue jsMetaType() const;
+ QStringList jsMetaMembers() const;
+ QJSManagedValue jsMetaInstantiate(const QJSValueList &values = {}) const;
+
+private:
+ friend class QJSValue;
+ friend class QJSEngine;
+
+ QJSManagedValue(QV4::ExecutionEngine *engine);
+ QV4::Value *d = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/jsapi/qjsprimitivevalue.cpp b/src/qml/jsapi/qjsprimitivevalue.cpp
new file mode 100644
index 0000000000..4bd418e082
--- /dev/null
+++ b/src/qml/jsapi/qjsprimitivevalue.cpp
@@ -0,0 +1,340 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qjsprimitivevalue.h"
+
+#include <QtQml/private/qv4runtime_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \since 6.1
+ \class QJSPrimitiveUndefined
+
+ \inmodule QtQml
+
+ \brief An empty marker type to signify the JavaScript Undefined type and its single value.
+ \inmodule QtQml
+ */
+
+/*!
+ \since 6.1
+ \class QJSPrimitiveNull
+
+ \inmodule QtQml
+
+ \brief An empty marker type to signify the JavaScript null value.
+ \inmodule QtQml
+ */
+
+/*!
+ \since 6.1
+ \class QJSPrimitiveValue
+
+ \brief The QJSPrimitiveValue class operates on primitive types in JavaScript semantics.
+
+ \ingroup qtjavascript
+ \inmodule QtQml
+
+ QJSPrimitiveValue supports most of the primitive types defined in the
+ \l{ECMA-262} standard, in particular Undefined, Boolean, Number, and String.
+ Additionally, you can store a JavaScript null in a QJSPrimitiveValue and as a
+ special case of Number, you can store an integer value.
+
+ All those values are stored immediately, without interacting with the
+ JavaScript heap. Therefore, you can pass QJSPrimitiveValues between different
+ JavaScript engines. In contrast to QJSManagedValue, there is also no danger
+ in destroying a QJSPrimitiveValue from a different thread than it was created
+ in. On the flip side, QJSPrimitiveValue does not hold a reference to any
+ JavaScript engine.
+
+ QJSPrimitiveValue implements the JavaScript arithmetic and comparison
+ operators on the supported types in JavaScript semantics. Types are coerced
+ like the JavaScript engine would coerce them if the operators were written
+ in a JavaScript expression.
+
+ The JavaScript Symbol type is not supported as it is of very limited utility
+ regarding arithmetic and comparison operators, the main purpose of
+ QJSPrimitiveValue. In particular, it causes an exception whenever you try to
+ coerce it to a number or a string, and we cannot throw exceptions without a
+ JavaScript Engine.
+ */
+
+/*!
+ \enum QJSPrimitiveValue::Type
+
+ This enum speicifies the types a QJSPrimitiveValue might contain.
+
+ \value Undefined The JavaScript Undefined value.
+ \value Null The JavaScript null value. This is in fact not a separate
+ JavaScript type but a special value of the Object type. As it is
+ very common and storable without JavaScript engine, it is still
+ supported.
+ \value Boolean A JavaScript Boolean value.
+ \value Integer An integer. This is a special case of the JavaScript Number
+ type. JavaScript does not have an actual integer type, but
+ the \l{ECMA-262} standard contains rules on how to transform a
+ Number in order to prepare it for certain operators that only
+ make sense on integers, in particular the bit shift operators.
+ QJSPrimitiveValue's Integer type represents the result of such
+ a transformation.
+ \value Double A JavaScript Number value.
+ \value String A JavaScript String value.
+ */
+
+/*!
+ \fn Type QJSPrimitiveValue::type() const
+
+ Returns the type of the QJSPrimitiveValue.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue()
+
+ Creates a QJSPrimitiveValue of type Undefined.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(QJSPrimitiveUndefined undefined)
+
+ Creates a QJSPrimitiveValue of value \a undefined and type Undefined.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(QJSPrimitiveNull null)
+
+ Creates a QJSPrimitiveValue of value \a null and type Null.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(bool value)
+
+ Creates a QJSPrimitiveValue of value \a value and type Boolean.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(int value)
+
+ Creates a QJSPrimitiveValue of value \a value and type Integer.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(double value)
+
+ Creates a QJSPrimitiveValue of value \a value and type Double.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(QString value)
+
+ Creates a QJSPrimitiveValue of value \a value and type String.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(QMetaType type, const void *value)
+ \since 6.4
+
+ Creates a QJSPrimitiveValue of type \a type, and initializes with
+ \a value if \a type can be stored in QJSPrimtiveValue. \a value must not
+ be nullptr in that case. If \a type cannot be stored this results in a
+ QJSPrimitiveValue of type Undefined.
+
+ Note that you have to pass the address of the variable you want stored.
+
+ Usually, you never have to use this constructor, use the one taking QVariant
+ instead.
+ */
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(QMetaType type)
+ \since 6.6
+ \internal
+
+ Creates a QJSPrimitiveValue of type \a type, and initializes with a
+ default-constructed value if \a type can be stored in QJSPrimtiveValue.
+ If \a type cannot be stored this results in a QJSPrimitiveValue of type
+ Undefined.
+*/
+
+/*!
+ \fn QJSPrimitiveValue::QJSPrimitiveValue(const QVariant &value)
+
+ Creates a QJSPrimitiveValue from the contents of \a value if those contents
+ can be stored in QJSPrimtiveValue. Otherwise this results in a
+ QJSPrimitiveValue of type Undefined.
+ */
+
+/*!
+ \fn bool QJSPrimitiveValue::toBoolean() const
+
+ Returns the value coerced a boolean by JavaScript rules.
+ */
+
+/*!
+ \fn int QJSPrimitiveValue::toInteger() const
+
+ Returns the value coerced to an integral 32bit number by the rules JavaScript
+ would apply when preparing it for a bit shift operation.
+ */
+
+/*!
+ \fn double QJSPrimitiveValue::toDouble() const
+
+ Returns the value coerced to a JavaScript Number by JavaScript rules.
+ */
+
+/*!
+ \fn QString QJSPrimitiveValue::toString() const
+
+ Returns the value coerced to a JavaScript String by JavaScript rules.
+ */
+
+/*!
+ \fn QJSPrimitiveValue QJSPrimitiveValue::operator+(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+
+ \since 6.1
+
+ Perfoms the JavaScript '+' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn QJSPrimitiveValue QJSPrimitiveValue::operator-(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '-' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn QJSPrimitiveValue QJSPrimitiveValue::operator*(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '*' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn QJSPrimitiveValue QJSPrimitiveValue::operator/(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '/' operation between \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn bool QJSPrimitiveValue::strictlyEquals(const QJSPrimitiveValue &other) const
+
+ Performs the JavaScript '===' operation on this QJSPrimitiveValue and
+ \a other, and returns the result.
+ */
+
+/*!
+ \fn bool QJSPrimitiveValue::equals(const QJSPrimitiveValue &other) const
+
+ Performs the JavaScript '==' operation on this QJSPrimitiveValue and
+ \a other, and returns the result.
+ */
+
+/*!
+ \fn bool QJSPrimitiveValue::operator==(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '===' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn bool QJSPrimitiveValue::operator!=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '!==' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn bool QJSPrimitiveValue::operator<(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '<' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn bool QJSPrimitiveValue::operator>(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '>' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn bool QJSPrimitiveValue::operator<=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '<=' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn bool QJSPrimitiveValue::operator>=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ \since 6.1
+
+ Performs the JavaScript '>=' operation on \a lhs and \a rhs, and returns the
+ result.
+ */
+
+/*!
+ \fn QMetaType QJSPrimitiveValue::metaType() const
+ \since 6.6
+
+ Returns the QMetaType of the value stored in the QJSPrimitiveValue.
+ */
+
+/*!
+ \fn const void *QJSPrimitiveValue::constData() const
+ \fn const void *QJSPrimitiveValue::data() const
+ \since 6.6
+
+ Returns a pointer to the contained value as a generic void* that cannot be
+ written to.
+ */
+
+/*!
+ \fn const void *QJSPrimitiveValue::data()
+ \since 6.6
+
+ Returns a pointer to the contained data as a generic void* that can be
+ written to.
+*/
+
+/*!
+ \fn template<QJSPrimitiveValue::Type type> QJSPrimitiveValue QJSPrimitiveValue::to() const
+ \since 6.6
+
+ Coerces the value to the specified \e type and returns the result as a new
+ QJSPrimitiveValue.
+
+ \sa toBoolean(), toInteger(), toDouble(), toString()
+*/
+
+QString QJSPrimitiveValue::toString(double d)
+{
+ QString result;
+ QV4::RuntimeHelpers::numberToString(&result, d);
+ return result;
+}
+
+/*!
+ \fn double QQmlPrivate::jsExponentiate(double base, double exponent)
+ \internal
+ \since 6.4
+
+ Performs JavaScript's Number::exponentiate operation on \a base and
+ \a exponent, and returns the result.
+
+ See https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-numeric-types-number-exponentiate
+ */
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/jsapi/qjsprimitivevalue.h b/src/qml/jsapi/qjsprimitivevalue.h
new file mode 100644
index 0000000000..4ba3fd7dc3
--- /dev/null
+++ b/src/qml/jsapi/qjsprimitivevalue.h
@@ -0,0 +1,966 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QJSPRIMITIVEVALUE_H
+#define QJSPRIMITIVEVALUE_H
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtQml/qjsnumbercoercion.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qnumeric.h>
+#include <QtCore/qvariant.h>
+
+#include <variant>
+#include <cmath>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 { struct ExecutionEngine; }
+
+struct QJSPrimitiveUndefined {};
+struct QJSPrimitiveNull {};
+
+class QJSPrimitiveValue
+{
+ template<typename Concrete>
+ struct StringNaNOperators
+ {
+ static constexpr double op(const QString &, QJSPrimitiveUndefined)
+ {
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+
+ static constexpr double op(QJSPrimitiveUndefined, const QString &)
+ {
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+
+ static double op(const QString &lhs, QJSPrimitiveNull) { return op(lhs, 0); }
+ static double op(QJSPrimitiveNull, const QString &rhs) { return op(0, rhs); }
+
+ template<typename T>
+ static double op(const QString &lhs, T rhs)
+ {
+ return Concrete::op(fromString(lhs).toDouble(), rhs);
+ }
+
+ template<typename T>
+ static double op(T lhs, const QString &rhs)
+ {
+ return Concrete::op(lhs, fromString(rhs).toDouble());
+ }
+
+ static double op(const QString &lhs, const QString &rhs)
+ {
+ return Concrete::op(fromString(lhs).toDouble(), fromString(rhs).toDouble());
+ }
+ };
+
+ struct AddOperators {
+ static constexpr double op(double lhs, double rhs) { return lhs + rhs; }
+ static bool opOverflow(int lhs, int rhs, int *result)
+ {
+ return qAddOverflow(lhs, rhs, result);
+ }
+
+ template<typename T>
+ static QString op(const QString &lhs, T rhs)
+ {
+ return lhs + QJSPrimitiveValue(rhs).toString();
+ }
+
+ template<typename T>
+ static QString op(T lhs, const QString &rhs)
+ {
+ return QJSPrimitiveValue(lhs).toString() + rhs;
+ }
+
+ static QString op(const QString &lhs, const QString &rhs) { return lhs + rhs; }
+ };
+
+ struct SubOperators : private StringNaNOperators<SubOperators> {
+ static constexpr double op(double lhs, double rhs) { return lhs - rhs; }
+ static bool opOverflow(int lhs, int rhs, int *result)
+ {
+ return qSubOverflow(lhs, rhs, result);
+ }
+
+ using StringNaNOperators::op;
+ };
+
+ struct MulOperators : private StringNaNOperators<MulOperators> {
+ static constexpr double op(double lhs, double rhs) { return lhs * rhs; }
+ static bool opOverflow(int lhs, int rhs, int *result)
+ {
+ // compare mul_int32 in qv4math_p.h
+ auto hadOverflow = qMulOverflow(lhs, rhs, result);
+ if (((lhs < 0) ^ (rhs < 0)) && (*result == 0))
+ return true; // result must be negative 0, does not fit into int
+ return hadOverflow;
+ }
+
+ using StringNaNOperators::op;
+ };
+
+ struct DivOperators : private StringNaNOperators<DivOperators> {
+ static constexpr double op(double lhs, double rhs) { return lhs / rhs; }
+ static constexpr bool opOverflow(int, int, int *)
+ {
+ return true;
+ }
+
+ using StringNaNOperators::op;
+ };
+
+public:
+ enum Type : quint8 {
+ Undefined,
+ Null,
+ Boolean,
+ Integer,
+ Double,
+ String
+ };
+
+ constexpr Type type() const { return Type(d.type()); }
+
+ // Prevent casting from Type to int
+ QJSPrimitiveValue(Type) = delete;
+
+ Q_IMPLICIT constexpr QJSPrimitiveValue() noexcept = default;
+ Q_IMPLICIT constexpr QJSPrimitiveValue(QJSPrimitiveUndefined undefined) noexcept : d(undefined) {}
+ Q_IMPLICIT constexpr QJSPrimitiveValue(QJSPrimitiveNull null) noexcept : d(null) {}
+ Q_IMPLICIT constexpr QJSPrimitiveValue(bool value) noexcept : d(value) {}
+ Q_IMPLICIT constexpr QJSPrimitiveValue(int value) noexcept : d(value) {}
+ Q_IMPLICIT constexpr QJSPrimitiveValue(double value) noexcept : d(value) {}
+ Q_IMPLICIT QJSPrimitiveValue(QString string) noexcept : d(std::move(string)) {}
+
+ explicit QJSPrimitiveValue(const QMetaType type, const void *value) noexcept
+ {
+ switch (type.id()) {
+ case QMetaType::UnknownType:
+ d = QJSPrimitiveUndefined();
+ break;
+ case QMetaType::Nullptr:
+ d = QJSPrimitiveNull();
+ break;
+ case QMetaType::Bool:
+ d = *static_cast<const bool *>(value);
+ break;
+ case QMetaType::Int:
+ d = *static_cast<const int *>(value);
+ break;
+ case QMetaType::Double:
+ d = *static_cast<const double *>(value);
+ break;
+ case QMetaType::QString:
+ d = *static_cast<const QString *>(value);
+ break;
+ default:
+ // Unsupported. Remains undefined.
+ break;
+ }
+ }
+
+ explicit QJSPrimitiveValue(QMetaType type) noexcept
+ {
+ switch (type.id()) {
+ case QMetaType::UnknownType:
+ d = QJSPrimitiveUndefined();
+ break;
+ case QMetaType::Nullptr:
+ d = QJSPrimitiveNull();
+ break;
+ case QMetaType::Bool:
+ d = false;
+ break;
+ case QMetaType::Int:
+ d = 0;
+ break;
+ case QMetaType::Double:
+ d = 0.0;
+ break;
+ case QMetaType::QString:
+ d = QString();
+ break;
+ default:
+ // Unsupported. Remains undefined.
+ break;
+ }
+ }
+
+ explicit QJSPrimitiveValue(const QVariant &variant) noexcept
+ : QJSPrimitiveValue(variant.metaType(), variant.data())
+ {
+ }
+
+ constexpr QMetaType metaType() const { return d.metaType(); }
+ constexpr void *data() { return d.data(); }
+ constexpr const void *data() const { return d.data(); }
+ constexpr const void *constData() const { return d.data(); }
+
+ template<Type type>
+ QJSPrimitiveValue to() const {
+ if constexpr (type == Undefined)
+ return QJSPrimitiveUndefined();
+ if constexpr (type == Null)
+ return QJSPrimitiveNull();
+ if constexpr (type == Boolean)
+ return toBoolean();
+ if constexpr (type == Integer)
+ return toInteger();
+ if constexpr (type == Double)
+ return toDouble();
+ if constexpr (type == String)
+ return toString();
+
+ Q_UNREACHABLE_RETURN(QJSPrimitiveUndefined());
+ }
+
+ constexpr bool toBoolean() const
+ {
+ switch (type()) {
+ case Undefined: return false;
+ case Null: return false;
+ case Boolean: return asBoolean();
+ case Integer: return asInteger() != 0;
+ case Double: {
+ const double v = asDouble();
+ return !QJSNumberCoercion::equals(v, 0) && !std::isnan(v);
+ }
+ case String: return !asString().isEmpty();
+ }
+
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+ #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ Q_UNREACHABLE_RETURN(false);
+ #else
+ return false;
+ #endif
+ }
+
+ constexpr int toInteger() const
+ {
+ switch (type()) {
+ case Undefined: return 0;
+ case Null: return 0;
+ case Boolean: return asBoolean();
+ case Integer: return asInteger();
+ case Double: return QJSNumberCoercion::toInteger(asDouble());
+ case String: return fromString(asString()).toInteger();
+ }
+
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+ #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ Q_UNREACHABLE_RETURN(0);
+ #else
+ return 0;
+ #endif
+ }
+
+ constexpr double toDouble() const
+ {
+ switch (type()) {
+ case Undefined: return std::numeric_limits<double>::quiet_NaN();
+ case Null: return 0;
+ case Boolean: return asBoolean();
+ case Integer: return asInteger();
+ case Double: return asDouble();
+ case String: return fromString(asString()).toDouble();
+ }
+
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+ #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ Q_UNREACHABLE_RETURN({});
+ #else
+ return {};
+ #endif
+ }
+
+ QString toString() const
+ {
+ switch (type()) {
+ case Undefined: return QStringLiteral("undefined");
+ case Null: return QStringLiteral("null");
+ case Boolean: return asBoolean() ? QStringLiteral("true") : QStringLiteral("false");
+ case Integer: return QString::number(asInteger());
+ case Double: {
+ const double result = asDouble();
+ if (std::isnan(result))
+ return QStringLiteral("NaN");
+ if (std::isfinite(result))
+ return toString(result);
+ if (result > 0)
+ return QStringLiteral("Infinity");
+ return QStringLiteral("-Infinity");
+ }
+ case String: return asString();
+ }
+
+ Q_UNREACHABLE_RETURN(QString());
+ }
+
+ QVariant toVariant() const
+ {
+ switch (type()) {
+ case Undefined: return QVariant();
+ case Null: return QVariant::fromValue<std::nullptr_t>(nullptr);
+ case Boolean: return QVariant(asBoolean());
+ case Integer: return QVariant(asInteger());
+ case Double: return QVariant(asDouble());
+ case String: return QVariant(asString());
+ }
+
+ Q_UNREACHABLE_RETURN(QVariant());
+ }
+
+ friend inline QJSPrimitiveValue operator+(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ return operate<AddOperators>(lhs, rhs);
+ }
+
+ friend inline QJSPrimitiveValue operator-(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ return operate<SubOperators>(lhs, rhs);
+ }
+
+ friend inline QJSPrimitiveValue operator*(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ return operate<MulOperators>(lhs, rhs);
+ }
+
+ friend inline QJSPrimitiveValue operator/(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ return operate<DivOperators>(lhs, rhs);
+ }
+
+ friend inline QJSPrimitiveValue operator%(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ switch (lhs.type()) {
+ case Null:
+ case Boolean:
+ case Integer:
+ switch (rhs.type()) {
+ case Boolean:
+ case Integer: {
+ const int leftInt = lhs.toInteger();
+ const int rightInt = rhs.toInteger();
+ if (leftInt >= 0 && rightInt > 0)
+ return leftInt % rightInt;
+ Q_FALLTHROUGH();
+ }
+ default:
+ break;
+ }
+ Q_FALLTHROUGH();
+ default:
+ break;
+ }
+
+ return std::fmod(lhs.toDouble(), rhs.toDouble());
+ }
+
+ QJSPrimitiveValue &operator++()
+ {
+ // ++a is modeled as a -= (-1) to avoid the potential string concatenation
+ return (*this = operate<SubOperators>(*this, -1));
+ }
+
+ QJSPrimitiveValue operator++(int)
+ {
+ // a++ is modeled as a -= (-1) to avoid the potential string concatenation
+ QJSPrimitiveValue other = operate<SubOperators>(*this, -1);
+ std::swap(other, *this);
+ return +other; // We still need to coerce the original value.
+ }
+
+ QJSPrimitiveValue &operator--()
+ {
+ return (*this = operate<SubOperators>(*this, 1));
+ }
+
+ QJSPrimitiveValue operator--(int)
+ {
+ QJSPrimitiveValue other = operate<SubOperators>(*this, 1);
+ std::swap(other, *this);
+ return +other; // We still need to coerce the original value.
+ }
+
+ QJSPrimitiveValue operator+()
+ {
+ // +a is modeled as a -= 0. That should force it to number.
+ return (*this = operate<SubOperators>(*this, 0));
+ }
+
+ QJSPrimitiveValue operator-()
+ {
+ return (*this = operate<MulOperators>(*this, -1));
+ }
+
+ constexpr bool strictlyEquals(const QJSPrimitiveValue &other) const
+ {
+ const Type myType = type();
+ const Type otherType = other.type();
+
+ if (myType != otherType) {
+ // int -> double promotion is OK in strict mode
+ if (myType == Double && otherType == Integer)
+ return strictlyEquals(double(other.asInteger()));
+ if (myType == Integer && otherType == Double)
+ return QJSPrimitiveValue(double(asInteger())).strictlyEquals(other);
+ return false;
+ }
+
+ switch (myType) {
+ case Undefined:
+ case Null:
+ return true;
+ case Boolean:
+ return asBoolean() == other.asBoolean();
+ case Integer:
+ return asInteger() == other.asInteger();
+ case Double: {
+ const double l = asDouble();
+ const double r = other.asDouble();
+ if (std::isnan(l) || std::isnan(r))
+ return false;
+ if (qIsNull(l) && qIsNull(r))
+ return true;
+ return QJSNumberCoercion::equals(l, r);
+ }
+ case String:
+ return asString() == other.asString();
+ }
+
+ return false;
+ }
+
+ // Loose operator==, in contrast to strict ===
+ constexpr bool equals(const QJSPrimitiveValue &other) const
+ {
+ const Type myType = type();
+ const Type otherType = other.type();
+
+ if (myType == otherType)
+ return strictlyEquals(other);
+
+ switch (myType) {
+ case Undefined:
+ return otherType == Null;
+ case Null:
+ return otherType == Undefined;
+ case Boolean:
+ return QJSPrimitiveValue(int(asBoolean())).equals(other);
+ case Integer:
+ // prefer rhs bool -> int promotion over promoting both to double
+ return otherType == Boolean
+ ? QJSPrimitiveValue(asInteger()).equals(int(other.asBoolean()))
+ : QJSPrimitiveValue(double(asInteger())).equals(other);
+ case Double:
+ // Promote the other side to double (or recognize lhs as undefined/null)
+ return other.equals(*this);
+ case String:
+ return fromString(asString()).parsedEquals(other);
+ }
+
+ return false;
+ }
+
+ friend constexpr inline bool operator==(const QJSPrimitiveValue &lhs, const
+ QJSPrimitiveValue &rhs)
+ {
+ return lhs.strictlyEquals(rhs);
+ }
+
+ friend constexpr inline bool operator!=(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ return !lhs.strictlyEquals(rhs);
+ }
+
+ friend constexpr inline bool operator<(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ switch (lhs.type()) {
+ case Undefined:
+ return false;
+ case Null: {
+ switch (rhs.type()) {
+ case Undefined: return false;
+ case Null: return false;
+ case Boolean: return 0 < int(rhs.asBoolean());
+ case Integer: return 0 < rhs.asInteger();
+ case Double: return double(0) < rhs.asDouble();
+ case String: return double(0) < rhs.toDouble();
+ }
+ break;
+ }
+ case Boolean: {
+ switch (rhs.type()) {
+ case Undefined: return false;
+ case Null: return int(lhs.asBoolean()) < 0;
+ case Boolean: return lhs.asBoolean() < rhs.asBoolean();
+ case Integer: return int(lhs.asBoolean()) < rhs.asInteger();
+ case Double: return double(lhs.asBoolean()) < rhs.asDouble();
+ case String: return double(lhs.asBoolean()) < rhs.toDouble();
+ }
+ break;
+ }
+ case Integer: {
+ switch (rhs.type()) {
+ case Undefined: return false;
+ case Null: return lhs.asInteger() < 0;
+ case Boolean: return lhs.asInteger() < int(rhs.asBoolean());
+ case Integer: return lhs.asInteger() < rhs.asInteger();
+ case Double: return double(lhs.asInteger()) < rhs.asDouble();
+ case String: return double(lhs.asInteger()) < rhs.toDouble();
+ }
+ break;
+ }
+ case Double: {
+ switch (rhs.type()) {
+ case Undefined: return false;
+ case Null: return lhs.asDouble() < double(0);
+ case Boolean: return lhs.asDouble() < double(rhs.asBoolean());
+ case Integer: return lhs.asDouble() < double(rhs.asInteger());
+ case Double: return lhs.asDouble() < rhs.asDouble();
+ case String: return lhs.asDouble() < rhs.toDouble();
+ }
+ break;
+ }
+ case String: {
+ switch (rhs.type()) {
+ case Undefined: return false;
+ case Null: return lhs.toDouble() < double(0);
+ case Boolean: return lhs.toDouble() < double(rhs.asBoolean());
+ case Integer: return lhs.toDouble() < double(rhs.asInteger());
+ case Double: return lhs.toDouble() < rhs.asDouble();
+ case String: return lhs.asString() < rhs.asString();
+ }
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ friend constexpr inline bool operator>(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ {
+ return rhs < lhs;
+ }
+
+ friend constexpr inline bool operator<=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ {
+ if (lhs.type() == String) {
+ if (rhs.type() == String)
+ return lhs.asString() <= rhs.asString();
+ else
+ return fromString(lhs.asString()) <= rhs;
+ }
+ if (rhs.type() == String)
+ return lhs <= fromString(rhs.asString());
+
+ if (lhs.isNanOrUndefined() || rhs.isNanOrUndefined())
+ return false;
+ return !(lhs > rhs);
+ }
+
+ friend constexpr inline bool operator>=(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ {
+ if (lhs.type() == String) {
+ if (rhs.type() == String)
+ return lhs.asString() >= rhs.asString();
+ else
+ return fromString(lhs.asString()) >= rhs;
+ }
+ if (rhs.type() == String)
+ return lhs >= fromString(rhs.asString());
+
+ if (lhs.isNanOrUndefined() || rhs.isNanOrUndefined())
+ return false;
+ return !(lhs < rhs);
+ }
+
+private:
+ friend class QJSManagedValue;
+ friend class QJSValue;
+ friend struct QV4::ExecutionEngine;
+
+ constexpr bool asBoolean() const { return d.getBool(); }
+ constexpr int asInteger() const { return d.getInt(); }
+ constexpr double asDouble() const { return d.getDouble(); }
+ QString asString() const { return d.getString(); }
+
+ constexpr bool parsedEquals(const QJSPrimitiveValue &other) const
+ {
+ return type() != Undefined && equals(other);
+ }
+
+ static QJSPrimitiveValue fromString(const QString &string)
+ {
+ bool ok;
+ const int intValue = string.toInt(&ok);
+ if (ok)
+ return intValue;
+
+ const double doubleValue = string.toDouble(&ok);
+ if (ok)
+ return doubleValue;
+ if (string == QStringLiteral("Infinity"))
+ return std::numeric_limits<double>::infinity();
+ if (string == QStringLiteral("-Infinity"))
+ return -std::numeric_limits<double>::infinity();
+ if (string == QStringLiteral("NaN"))
+ return std::numeric_limits<double>::quiet_NaN();
+ return QJSPrimitiveUndefined();
+ }
+
+ static Q_QML_EXPORT QString toString(double d);
+
+ template<typename Operators, typename Lhs, typename Rhs>
+ static QJSPrimitiveValue operateOnIntegers(const QJSPrimitiveValue &lhs,
+ const QJSPrimitiveValue &rhs)
+ {
+ int result;
+ if (Operators::opOverflow(lhs.d.get<Lhs>(), rhs.d.get<Rhs>(), &result))
+ return Operators::op(lhs.d.get<Lhs>(), rhs.d.get<Rhs>());
+ return result;
+ }
+
+ template<typename Operators>
+ static QJSPrimitiveValue operate(const QJSPrimitiveValue &lhs, const QJSPrimitiveValue &rhs)
+ {
+ switch (lhs.type()) {
+ case Undefined:
+ switch (rhs.type()) {
+ case Undefined: return std::numeric_limits<double>::quiet_NaN();
+ case Null: return std::numeric_limits<double>::quiet_NaN();
+ case Boolean: return std::numeric_limits<double>::quiet_NaN();
+ case Integer: return std::numeric_limits<double>::quiet_NaN();
+ case Double: return std::numeric_limits<double>::quiet_NaN();
+ case String: return Operators::op(QJSPrimitiveUndefined(), rhs.asString());
+ }
+ break;
+ case Null:
+ switch (rhs.type()) {
+ case Undefined: return std::numeric_limits<double>::quiet_NaN();
+ case Null: return operateOnIntegers<Operators, int, int>(0, 0);
+ case Boolean: return operateOnIntegers<Operators, int, bool>(0, rhs);
+ case Integer: return operateOnIntegers<Operators, int, int>(0, rhs);
+ case Double: return Operators::op(0, rhs.asDouble());
+ case String: return Operators::op(QJSPrimitiveNull(), rhs.asString());
+ }
+ break;
+ case Boolean:
+ switch (rhs.type()) {
+ case Undefined: return std::numeric_limits<double>::quiet_NaN();
+ case Null: return operateOnIntegers<Operators, bool, int>(lhs, 0);
+ case Boolean: return operateOnIntegers<Operators, bool, bool>(lhs, rhs);
+ case Integer: return operateOnIntegers<Operators, bool, int>(lhs, rhs);
+ case Double: return Operators::op(lhs.asBoolean(), rhs.asDouble());
+ case String: return Operators::op(lhs.asBoolean(), rhs.asString());
+ }
+ break;
+ case Integer:
+ switch (rhs.type()) {
+ case Undefined: return std::numeric_limits<double>::quiet_NaN();
+ case Null: return operateOnIntegers<Operators, int, int>(lhs, 0);
+ case Boolean: return operateOnIntegers<Operators, int, bool>(lhs, rhs);
+ case Integer: return operateOnIntegers<Operators, int, int>(lhs, rhs);
+ case Double: return Operators::op(lhs.asInteger(), rhs.asDouble());
+ case String: return Operators::op(lhs.asInteger(), rhs.asString());
+ }
+ break;
+ case Double:
+ switch (rhs.type()) {
+ case Undefined: return std::numeric_limits<double>::quiet_NaN();
+ case Null: return Operators::op(lhs.asDouble(), 0);
+ case Boolean: return Operators::op(lhs.asDouble(), rhs.asBoolean());
+ case Integer: return Operators::op(lhs.asDouble(), rhs.asInteger());
+ case Double: return Operators::op(lhs.asDouble(), rhs.asDouble());
+ case String: return Operators::op(lhs.asDouble(), rhs.asString());
+ }
+ break;
+ case String:
+ switch (rhs.type()) {
+ case Undefined: return Operators::op(lhs.asString(), QJSPrimitiveUndefined());
+ case Null: return Operators::op(lhs.asString(), QJSPrimitiveNull());
+ case Boolean: return Operators::op(lhs.asString(), rhs.asBoolean());
+ case Integer: return Operators::op(lhs.asString(), rhs.asInteger());
+ case Double: return Operators::op(lhs.asString(), rhs.asDouble());
+ case String: return Operators::op(lhs.asString(), rhs.asString());
+ }
+ break;
+ }
+
+ Q_UNREACHABLE_RETURN(QJSPrimitiveUndefined());
+ }
+
+ constexpr bool isNanOrUndefined() const
+ {
+ switch (type()) {
+ case Undefined: return true;
+ case Double: return std::isnan(asDouble());
+ default: return false;
+ }
+ }
+
+ struct QJSPrimitiveValuePrivate
+ {
+ // Can't be default because QString has a non-trivial ctor.
+ constexpr QJSPrimitiveValuePrivate() noexcept {}
+
+ Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(QJSPrimitiveUndefined) noexcept {}
+ Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(QJSPrimitiveNull) noexcept
+ : m_type(Null) {}
+ Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(bool b) noexcept
+ : m_bool(b), m_type(Boolean) {}
+ Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(int i) noexcept
+ : m_int(i), m_type(Integer) {}
+ Q_IMPLICIT constexpr QJSPrimitiveValuePrivate(double d) noexcept
+ : m_double(d), m_type(Double) {}
+ Q_IMPLICIT QJSPrimitiveValuePrivate(QString s) noexcept
+ : m_string(std::move(s)), m_type(String) {}
+
+ constexpr QJSPrimitiveValuePrivate(const QJSPrimitiveValuePrivate &other) noexcept
+ : m_type(other.m_type)
+ {
+ // Not copy-and-swap since swap() would be much more complicated.
+ if (!assignSimple(other))
+ new (&m_string) QString(other.m_string);
+ }
+
+ constexpr QJSPrimitiveValuePrivate(QJSPrimitiveValuePrivate &&other) noexcept
+ : m_type(other.m_type)
+ {
+ // Not move-and-swap since swap() would be much more complicated.
+ if (!assignSimple(other))
+ new (&m_string) QString(std::move(other.m_string));
+ }
+
+ constexpr QJSPrimitiveValuePrivate &operator=(const QJSPrimitiveValuePrivate &other) noexcept
+ {
+ if (this == &other)
+ return *this;
+
+ if (m_type == String) {
+ if (other.m_type == String) {
+ m_type = other.m_type;
+ m_string = other.m_string;
+ return *this;
+ }
+ m_string.~QString();
+ }
+
+ m_type = other.m_type;
+ if (!assignSimple(other))
+ new (&m_string) QString(other.m_string);
+ return *this;
+ }
+
+ constexpr QJSPrimitiveValuePrivate &operator=(QJSPrimitiveValuePrivate &&other) noexcept
+ {
+ if (this == &other)
+ return *this;
+
+ if (m_type == String) {
+ if (other.m_type == String) {
+ m_type = other.m_type;
+ m_string = std::move(other.m_string);
+ return *this;
+ }
+ m_string.~QString();
+ }
+
+ m_type = other.m_type;
+ if (!assignSimple(other))
+ new (&m_string) QString(std::move(other.m_string));
+ return *this;
+ }
+
+ ~QJSPrimitiveValuePrivate()
+ {
+ if (m_type == String)
+ m_string.~QString();
+ }
+
+ constexpr Type type() const noexcept { return m_type; }
+ constexpr bool getBool() const noexcept { return m_bool; }
+ constexpr int getInt() const noexcept { return m_int; }
+ constexpr double getDouble() const noexcept { return m_double; }
+ QString getString() const noexcept { return m_string; }
+
+ template<typename T>
+ constexpr T get() const noexcept {
+ if constexpr (std::is_same_v<T, QJSPrimitiveUndefined>)
+ return QJSPrimitiveUndefined();
+ else if constexpr (std::is_same_v<T, QJSPrimitiveNull>)
+ return QJSPrimitiveNull();
+ else if constexpr (std::is_same_v<T, bool>)
+ return getBool();
+ else if constexpr (std::is_same_v<T, int>)
+ return getInt();
+ else if constexpr (std::is_same_v<T, double>)
+ return getDouble();
+ else if constexpr (std::is_same_v<T, QString>)
+ return getString();
+
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+ #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ Q_UNREACHABLE_RETURN(T());
+ #else
+ return T();
+ #endif
+ }
+
+ constexpr QMetaType metaType() const noexcept {
+ switch (m_type) {
+ case Undefined:
+ return QMetaType();
+ case Null:
+ return QMetaType::fromType<std::nullptr_t>();
+ case Boolean:
+ return QMetaType::fromType<bool>();
+ case Integer:
+ return QMetaType::fromType<int>();
+ case Double:
+ return QMetaType::fromType<double>();
+ case String:
+ return QMetaType::fromType<QString>();
+ }
+
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+ #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ Q_UNREACHABLE_RETURN(QMetaType());
+ #else
+ return QMetaType();
+ #endif
+ }
+
+ constexpr void *data() noexcept {
+ switch (m_type) {
+ case Undefined:
+ case Null:
+ return nullptr;
+ case Boolean:
+ return &m_bool;
+ case Integer:
+ return &m_int;
+ case Double:
+ return &m_double;
+ case String:
+ return &m_string;
+ }
+
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+ #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ Q_UNREACHABLE_RETURN(nullptr);
+ #else
+ return nullptr;
+ #endif
+ }
+
+ constexpr const void *data() const noexcept {
+ switch (m_type) {
+ case Undefined:
+ case Null:
+ return nullptr;
+ case Boolean:
+ return &m_bool;
+ case Integer:
+ return &m_int;
+ case Double:
+ return &m_double;
+ case String:
+ return &m_string;
+ }
+
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+ #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ Q_UNREACHABLE_RETURN(nullptr);
+ #else
+ return nullptr;
+ #endif
+ }
+
+ private:
+ constexpr bool assignSimple(const QJSPrimitiveValuePrivate &other) noexcept
+ {
+ switch (other.m_type) {
+ case Undefined:
+ case Null:
+ return true;
+ case Boolean:
+ m_bool = other.m_bool;
+ return true;
+ case Integer:
+ m_int = other.m_int;
+ return true;
+ case Double:
+ m_double = other.m_double;
+ return true;
+ case String:
+ return false;
+ }
+
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+ #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ Q_UNREACHABLE_RETURN(false);
+ #else
+ return false;
+ #endif
+ }
+
+ union {
+ bool m_bool = false;
+ int m_int;
+ double m_double;
+ QString m_string;
+ };
+
+ Type m_type = Undefined;
+ };
+
+ QJSPrimitiveValuePrivate d;
+};
+
+namespace QQmlPrivate {
+ // TODO: Make this constexpr once std::isnan is constexpr.
+ inline double jsExponentiate(double base, double exponent)
+ {
+ constexpr double qNaN = std::numeric_limits<double>::quiet_NaN();
+ constexpr double inf = std::numeric_limits<double>::infinity();
+
+ if (qIsNull(exponent))
+ return 1.0;
+
+ if (std::isnan(exponent))
+ return qNaN;
+
+ if (QJSNumberCoercion::equals(base, 1.0) || QJSNumberCoercion::equals(base, -1.0))
+ return std::isinf(exponent) ? qNaN : std::pow(base, exponent);
+
+ if (!qIsNull(base))
+ return std::pow(base, exponent);
+
+ if (std::copysign(1.0, base) > 0.0)
+ return exponent < 0.0 ? inf : std::pow(base, exponent);
+
+ if (exponent < 0.0)
+ return QJSNumberCoercion::equals(std::fmod(-exponent, 2.0), 1.0) ? -inf : inf;
+
+ return QJSNumberCoercion::equals(std::fmod(exponent, 2.0), 1.0)
+ ? std::copysign(0, -1.0)
+ : 0.0;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QJSPRIMITIVEVALUE_H
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index c2957dd294..f6b97262c3 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qstring.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qdatetime.h>
-#include "qjsengine.h"
#include "qjsvalue.h"
+#include "qjsprimitivevalue.h"
+#include "qjsmanagedvalue.h"
#include "qjsvalue_p.h"
#include "qv4value_p.h"
#include "qv4object_p.h"
@@ -54,6 +19,9 @@
#include <private/qv4mm_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4qmetaobjectwrapper_p.h>
+#include <private/qv4urlobject_p.h>
+#include <private/qqmlbuiltins_p.h>
/*!
\since 5.0
@@ -139,6 +107,16 @@
integers.append(jsArray.property(i).toInt());
}
\endcode
+
+ \section2 Converting to JSON
+
+ It's possible to convert a QJSValue to a JSON type. For example,
+ to convert to an array, use \l QJSEngine::fromScriptValue():
+
+ \code
+ const QJsonValue jsonValue = engine.fromScriptValue<QJsonValue>(jsValue);
+ const QJsonArray jsonArray = jsonValue.toArray();
+ \endcode
*/
/*!
@@ -184,6 +162,18 @@
provided is malformed.
*/
+/*!
+ \enum QJSValue::ObjectConversionBehavior
+
+ This enum is used to specify how JavaScript objects and symbols without an equivalent
+ native Qt type should be treated when converting to QVariant.
+
+ \value ConvertJSObjects A best-effort, possibly lossy, conversion is attempted.
+ Symbols are converted to QString.
+
+ \value RetainJSObjects The value is retained as QJSValue wrapped in QVariant.
+*/
+
QT_BEGIN_NAMESPACE
using namespace QV4;
@@ -191,76 +181,59 @@ using namespace QV4;
/*!
Constructs a new QJSValue with a boolean \a value.
*/
-QJSValue::QJSValue(bool value)
+QJSValue::QJSValue(bool value) : d(QJSValuePrivate::encode(value))
{
- QJSValuePrivate::setVariant(this, QVariant(value));
-}
-
-/*!
- \internal
-*/
-QJSValue::QJSValue(ExecutionEngine *e, quint64 val)
-{
- QJSValuePrivate::setValue(this, e, val);
}
/*!
Constructs a new QJSValue with a number \a value.
*/
-QJSValue::QJSValue(int value)
+QJSValue::QJSValue(int value) : d(QJSValuePrivate::encode(value))
{
- QJSValuePrivate::setVariant(this, QVariant(value));
}
/*!
Constructs a new QJSValue with a number \a value.
*/
-QJSValue::QJSValue(uint value)
+QJSValue::QJSValue(uint value) : d(QJSValuePrivate::encode(value))
{
- QJSValuePrivate::setVariant(this, QVariant((double)value));
}
/*!
Constructs a new QJSValue with a number \a value.
*/
-QJSValue::QJSValue(double value)
+QJSValue::QJSValue(double value) : d(QJSValuePrivate::encode(value))
{
- QJSValuePrivate::setVariant(this, QVariant(value));
}
/*!
Constructs a new QJSValue with a string \a value.
*/
-QJSValue::QJSValue(const QString& value)
+QJSValue::QJSValue(const QString &value) : d(QJSValuePrivate::encode(value))
{
- QJSValuePrivate::setVariant(this, QVariant(value));
}
/*!
Constructs a new QJSValue with a special \a value.
*/
QJSValue::QJSValue(SpecialValue value)
- : d(0)
+ : d(value == NullValue ? QJSValuePrivate::encodeNull() : QJSValuePrivate::encodeUndefined())
{
- if (value == NullValue)
- QJSValuePrivate::setVariant(this, QVariant::fromValue(nullptr));
}
/*!
Constructs a new QJSValue with a string \a value.
*/
-QJSValue::QJSValue(const QLatin1String &value)
+QJSValue::QJSValue(const QLatin1String &value) : d(QJSValuePrivate::encode(value))
{
- QJSValuePrivate::setVariant(this, QVariant(value));
}
/*!
Constructs a new QJSValue with a string \a value.
*/
#ifndef QT_NO_CAST_FROM_ASCII
-QJSValue::QJSValue(const char *value)
+QJSValue::QJSValue(const char *value) : d(QJSValuePrivate::encode(QString::fromUtf8(value)))
{
- QJSValuePrivate::setVariant(this, QVariant(QString::fromUtf8(value)));
}
#endif
@@ -271,14 +244,23 @@ QJSValue::QJSValue(const char *value)
true), then only a reference to the underlying object is copied into
the new script value (i.e., the object itself is not copied).
*/
-QJSValue::QJSValue(const QJSValue& other)
- : d(0)
+QJSValue::QJSValue(const QJSValue &other) : d(other.d)
{
- QV4::Value *v = QJSValuePrivate::getValue(&other);
- if (v) {
- QJSValuePrivate::setValue(this, QJSValuePrivate::engine(&other), *v);
- } else if (QVariant *v = QJSValuePrivate::getVariant(&other)) {
- QJSValuePrivate::setVariant(this, *v);
+ switch (QJSValuePrivate::tag(d)) {
+ case QJSValuePrivate::Kind::Undefined:
+ case QJSValuePrivate::Kind::Null:
+ case QJSValuePrivate::Kind::IntValue:
+ case QJSValuePrivate::Kind::BoolValue:
+ return;
+ case QJSValuePrivate::Kind::DoublePtr:
+ d = QJSValuePrivate::encode(*QJSValuePrivate::doublePtr(d));
+ return;
+ case QJSValuePrivate::Kind::QV4ValuePtr:
+ d = QJSValuePrivate::encode(*QJSValuePrivate::qv4ValuePtr(d));
+ return;
+ case QJSValuePrivate::Kind::QStringPtr:
+ d = QJSValuePrivate::encode(*QJSValuePrivate::qStringPtr(d));
+ break;
}
}
@@ -310,11 +292,7 @@ QJSValue::~QJSValue()
*/
bool QJSValue::isBool() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (val)
- return val->isBoolean();
- QVariant *variant = QJSValuePrivate::getVariant(this);
- return variant && variant->type() == QVariant::Bool;
+ return QJSValuePrivate::tag(d) == QJSValuePrivate::Kind::BoolValue;
}
/*!
@@ -325,27 +303,15 @@ bool QJSValue::isBool() const
*/
bool QJSValue::isNumber() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (val)
- return val->isNumber();
- QVariant *variant = QJSValuePrivate::getVariant(this);
- if (!variant)
- return false;
-
- switch (variant->userType()) {
- case QMetaType::Double:
- case QMetaType::Int:
- case QMetaType::UInt:
- case QMetaType::Long:
- case QMetaType::ULong:
- case QMetaType::Short:
- case QMetaType::UShort:
- case QMetaType::LongLong:
- case QMetaType::ULongLong:
+ switch (QJSValuePrivate::tag(d)) {
+ case QJSValuePrivate::Kind::IntValue:
+ case QJSValuePrivate::Kind::DoublePtr:
return true;
default:
- return false;
+ break;
}
+
+ return false;
}
/*!
@@ -354,14 +320,7 @@ bool QJSValue::isNumber() const
*/
bool QJSValue::isNull() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (val)
- return val->isNull();
- QVariant *variant = QJSValuePrivate::getVariant(this);
- if (!variant)
- return false;
- const int type = variant->userType();
- return type == QMetaType::Nullptr || type == QMetaType::VoidStar;
+ return QJSValuePrivate::tag(d) == QJSValuePrivate::Kind::Null;
}
/*!
@@ -372,24 +331,35 @@ bool QJSValue::isNull() const
*/
bool QJSValue::isString() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (val)
- return val->isString();
- QVariant *variant = QJSValuePrivate::getVariant(this);
- return variant && variant->userType() == QMetaType::QString;
+ switch (QJSValuePrivate::tag(d)) {
+ case QJSValuePrivate::Kind::QStringPtr:
+ return true;
+ case QJSValuePrivate::Kind::QV4ValuePtr: {
+ return QJSValuePrivate::qv4ValuePtr(d)->isString();
+ }
+ default:
+ break;
+ }
+
+ return false;
}
/*!
- Returns true if this QJSValue is of the primitive type Undefined;
- otherwise returns false.
+ Returns true if this QJSValue is of the primitive type Undefined or if the managed value
+ has been cleared (by deleting the engine). Otherwise returns false.
*/
bool QJSValue::isUndefined() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (val)
- return val->isUndefined();
- QVariant *variant = QJSValuePrivate::getVariant(this);
- return !variant || variant->userType() == QMetaType::UnknownType || variant->userType() == QMetaType::Void;
+ switch (QJSValuePrivate::tag(d)) {
+ case QJSValuePrivate::Kind::Undefined:
+ return true;
+ case QJSValuePrivate::Kind::QV4ValuePtr:
+ return QJSValuePrivate::qv4ValuePtr(d)->isUndefined();
+ default:
+ break;
+ }
+
+ return false;
}
/*!
@@ -400,10 +370,19 @@ bool QJSValue::isUndefined() const
*/
bool QJSValue::isError() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return false;
- return val->as<ErrorObject>();
+ return QJSValuePrivate::asManagedType<ErrorObject>(this);
+}
+
+/*!
+ Returns true if this QJSValue is an object of the URL JavaScript class;
+ otherwise returns false.
+
+ \note For a QJSValue that contains a QUrl, this function returns false.
+ However, \c{toVariant().value<QUrl>()} works in both cases.
+*/
+bool QJSValue::isUrl() const
+{
+ return QJSValuePrivate::asManagedType<UrlObject>(this);
}
/*!
@@ -415,10 +394,7 @@ bool QJSValue::isError() const
*/
QJSValue::ErrorType QJSValue::errorType() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return NoError;
- QV4::ErrorObject *error = val->as<ErrorObject>();
+ const QV4::ErrorObject *error = QJSValuePrivate::asManagedType<ErrorObject>(this);
if (!error)
return NoError;
switch (error->d()->errorType) {
@@ -437,8 +413,7 @@ QJSValue::ErrorType QJSValue::errorType() const
case QV4::Heap::ErrorObject::URIError:
return URIError;
}
- Q_UNREACHABLE();
- return NoError;
+ Q_UNREACHABLE_RETURN(NoError);
}
/*!
@@ -449,10 +424,7 @@ QJSValue::ErrorType QJSValue::errorType() const
*/
bool QJSValue::isArray() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return false;
- return val->as<ArrayObject>();
+ return QJSValuePrivate::asManagedType<ArrayObject>(this);
}
/*!
@@ -466,39 +438,46 @@ bool QJSValue::isArray() const
*/
bool QJSValue::isObject() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return false;
- return val->as<QV4::Object>();
+ return QJSValuePrivate::asManagedType<QV4::Object>(this);
}
/*!
- Returns true if this QJSValue can be called a function, otherwise
+ Returns true if this QJSValue is a function, otherwise
returns false.
\sa call()
*/
bool QJSValue::isCallable() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return false;
- return val->as<FunctionObject>();
+ return QJSValuePrivate::asManagedType<FunctionObject>(this);
}
+#if QT_DEPRECATED_SINCE(6, 9)
/*!
+ \deprecated [6.9]
Returns true if this QJSValue is a variant value;
otherwise returns false.
+ \warning This function is likely to give unexpected results.
+ A variant value is only constructed by the QJSEngine in a very
+ limited number of cases. This used to be different before Qt
+ 5.14, where \l{QJSEngine::toScriptValue} would have created
+ them for more types instead of corresponding ECMAScript types.
+ You can get a valid \l QVariant via \l toVariant for many values
+ for which \c{isVariant} returns false.
+
\sa toVariant()
*/
bool QJSValue::isVariant() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return false;
- return val->as<QV4::VariantObject>();
+ if (QJSValuePrivate::asManagedType<QV4::VariantObject>(this))
+ return true;
+ if (auto vt = QJSValuePrivate::asManagedType<QV4::QQmlValueTypeWrapper>(this))
+ if (vt->metaObject() == &QQmlVarForeign::staticMetaObject)
+ return true;
+ return false;
}
+#endif
/*!
Returns the string value of this QJSValue, as defined in
@@ -514,27 +493,22 @@ bool QJSValue::isVariant() const
*/
QString QJSValue::toString() const
{
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch);
-
- if (!val) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- Q_ASSERT(variant);
- if (variant->type() == QVariant::Map)
- return QStringLiteral("[object Object]");
- else if (variant->type() == QVariant::List) {
- const QVariantList list = variant->toList();
- QString result;
- for (int i = 0; i < list.count(); ++i) {
- if (i > 0)
- result.append(QLatin1Char(','));
- result.append(list.at(i).toString());
- }
- return result;
- }
- return variant->toString();
+ if (const QString *string = QJSValuePrivate::asQString(this))
+ return *string;
+
+ return QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(this)).toQStringNoThrow();
+}
+
+template<typename T>
+T caughtResult(const QJSValue *v, T (QV4::Value::*convert)() const)
+{
+ const T result = (QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(v)).*convert)();
+ QV4::ExecutionEngine *engine = QJSValuePrivate::engine(v);
+ if (engine && engine->hasException) {
+ engine->catchException();
+ return T();
}
- return val->toQStringNoThrow();
+ return result;
}
/*!
@@ -551,28 +525,10 @@ QString QJSValue::toString() const
*/
double QJSValue::toNumber() const
{
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch);
-
- if (!val) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- Q_ASSERT(variant);
-
- if (variant->type() == QVariant::String)
- return RuntimeHelpers::stringToNumber(variant->toString());
- else if (variant->canConvert<double>())
- return variant->value<double>();
- else
- return std::numeric_limits<double>::quiet_NaN();
- }
+ if (const QString *string = QJSValuePrivate::asQString(this))
+ return RuntimeHelpers::stringToNumber(*string);
- double dbl = val->toNumber();
- QV4::ExecutionEngine *engine = QJSValuePrivate::engine(this);
- if (engine && engine->hasException) {
- engine->catchException();
- return 0;
- }
- return dbl;
+ return caughtResult<double>(this, &QV4::Value::toNumber);
}
/*!
@@ -589,24 +545,10 @@ double QJSValue::toNumber() const
*/
bool QJSValue::toBool() const
{
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch);
-
- if (!val) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- if (variant->userType() == QMetaType::QString)
- return variant->toString().length() > 0;
- else
- return variant->toBool();
- }
+ if (const QString *string = QJSValuePrivate::asQString(this))
+ return string->size() > 0;
- bool b = val->toBoolean();
- QV4::ExecutionEngine *engine = QJSValuePrivate::engine(this);
- if (engine && engine->hasException) {
- engine->catchException();
- return false;
- }
- return b;
+ return caughtResult<bool>(this, &QV4::Value::toBoolean);
}
/*!
@@ -623,24 +565,10 @@ bool QJSValue::toBool() const
*/
qint32 QJSValue::toInt() const
{
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch);
-
- if (!val) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- if (variant->userType() == QMetaType::QString)
- return QV4::Value::toInt32(RuntimeHelpers::stringToNumber(variant->toString()));
- else
- return variant->toInt();
- }
+ if (const QString *string = QJSValuePrivate::asQString(this))
+ return QV4::Value::toInt32(RuntimeHelpers::stringToNumber(*string));
- qint32 i = val->toInt32();
- QV4::ExecutionEngine *engine = QJSValuePrivate::engine(this);
- if (engine && engine->hasException) {
- engine->catchException();
- return 0;
- }
- return i;
+ return caughtResult<qint32>(this, &QV4::Value::toInt32);
}
/*!
@@ -657,30 +585,29 @@ qint32 QJSValue::toInt() const
*/
quint32 QJSValue::toUInt() const
{
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch);
+ if (const QString *string = QJSValuePrivate::asQString(this))
+ return QV4::Value::toUInt32(RuntimeHelpers::stringToNumber(*string));
- if (!val) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- if (variant->userType() == QMetaType::QString)
- return QV4::Value::toUInt32(RuntimeHelpers::stringToNumber(variant->toString()));
- else
- return variant->toUInt();
- }
+ return caughtResult<quint32>(this, &QV4::Value::toUInt32);
+}
- quint32 u = val->toUInt32();
- QV4::ExecutionEngine *engine = QJSValuePrivate::engine(this);
- if (engine && engine->hasException) {
- engine->catchException();
- return 0;
- }
- return u;
+/*!
+ \overload
+
+ Returns toVariant(ConvertJSObjects).
+
+ \sa isVariant()
+*/
+QVariant QJSValue::toVariant() const
+{
+ return toVariant(ConvertJSObjects);
}
/*!
- Returns the QVariant value of this QJSValue, if it can be
- converted to a QVariant; otherwise returns an invalid QVariant.
- The conversion is performed according to the following table:
+ Returns the QVariant value of this QJSValue, if it can be
+ converted to a QVariant; otherwise returns an invalid QVariant.
+ Some JavaScript types and objects have native expressions in Qt.
+ Those are converted to their native expressions. For example:
\table
\header \li Input Type \li Result
@@ -692,42 +619,75 @@ quint32 QJSValue::toUInt() const
\row \li QVariant Object \li The result is the QVariant value of the object (no conversion).
\row \li QObject Object \li A QVariant containing a pointer to the QObject.
\row \li Date Object \li A QVariant containing the date value (toDateTime()).
- \row \li RegExp Object \li A QVariant containing the regular expression value.
- \row \li Array Object \li The array is converted to a QVariantList. Each element is converted to a QVariant, recursively; cyclic references are not followed.
- \row \li Object \li The object is converted to a QVariantMap. Each property is converted to a QVariant, recursively; cyclic references are not followed.
+ \row \li RegularExpression Object \li A QVariant containing the regular expression value.
\endtable
- \sa isVariant()
+ For other types the \a behavior parameter is relevant. If
+ \c ConvertJSObjects is given, a best effort but possibly lossy conversion is
+ attempted. Generic JavaScript objects are converted to QVariantMap.
+ JavaScript arrays are converted to QVariantList. Each property or element is
+ converted to a QVariant, recursively; cyclic references are not followed.
+ JavaScript function objects are dropped. If \c RetainJSObjects is given, the
+ QJSValue is wrapped into a QVariant via QVariant::fromValue(). The resulting
+ conversion is lossless but the internal structure of the objects is not
+ immediately accessible.
+
+ \sa isVariant()
*/
-QVariant QJSValue::toVariant() const
+QVariant QJSValue::toVariant(QJSValue::ObjectConversionBehavior behavior) const
{
- QVariant *variant = QJSValuePrivate::getVariant(this);
- if (variant)
- return *variant;
-
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(this, &scratch);
- Q_ASSERT(val);
-
- if (QV4::Object *o = val->as<QV4::Object>())
- return o->engine()->toVariant(*val, /*typeHint*/ -1, /*createJSValueForObjects*/ false);
-
- if (String *s = val->stringValue())
- return QVariant(s->toQString());
- if (val->isBoolean())
- return QVariant(val->booleanValue());
- if (val->isNumber()) {
- if (val->isInt32())
- return QVariant(val->integerValue());
- return QVariant(val->asDouble());
+ if (const QString *string = QJSValuePrivate::asQString(this))
+ return QVariant(*string);
+
+ QV4::Value val = QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(this));
+ if (val.isUndefined())
+ return QVariant();
+ if (val.isNull())
+ return QVariant(QMetaType::fromType<std::nullptr_t>(), nullptr);
+ if (val.isBoolean())
+ return QVariant(val.booleanValue());
+ if (val.isInt32()) // Includes doubles that can be losslessly casted to int
+ return QVariant(val.integerValue());
+ if (val.isNumber())
+ return QVariant(val.doubleValue());
+
+ Q_ASSERT(val.isManaged());
+
+ if (val.isString())
+ return QVariant(val.toQString());
+ if (val.as<QV4::Managed>()) {
+ if (behavior == RetainJSObjects)
+ return QV4::ExecutionEngine::toVariant(
+ val, /*typeHint*/ QMetaType{}, /*createJSValueForObjectsAndSymbols=*/ true);
+ else
+ return QV4::ExecutionEngine::toVariantLossy(val);
}
- if (val->isNull())
- return QVariant(QMetaType::Nullptr, nullptr);
- Q_ASSERT(val->isUndefined());
+
+ Q_ASSERT(false);
return QVariant();
}
/*!
+ * Converts the value to a QJSPrimitiveValue. If the value holds a type
+ * supported by QJSPrimitiveValue, the value is copied. Otherwise the
+ * value is converted to a string, and the string is stored in
+ * QJSPrimitiveValue.
+ *
+ * \note Conversion of a managed value to a string can throw an exception. In
+ * particular, symbols cannot be coerced into strings, or a custom
+ * toString() method may throw. In this case the result is the undefined
+ * value and the engine carries an error after the conversion.
+ */
+QJSPrimitiveValue QJSValue::toPrimitive() const
+{
+ if (const QString *string = QJSValuePrivate::asQString(this))
+ return *string;
+
+ const QV4::Value val = QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(this));
+ return QV4::ExecutionEngine::createPrimitive(&val);
+}
+
+/*!
Calls this QJSValue as a function, passing \a args as arguments
to the function, and using the globalObject() as the "this"-object.
Returns the value returned from the function.
@@ -742,13 +702,9 @@ QVariant QJSValue::toVariant() const
\sa isCallable(), callWithInstance(), callAsConstructor()
*/
-QJSValue QJSValue::call(const QJSValueList &args)
+QJSValue QJSValue::call(const QJSValueList &args) const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return QJSValue();
-
- FunctionObject *f = val->as<FunctionObject>();
+ const FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(this);
if (!f)
return QJSValue();
@@ -756,23 +712,23 @@ QJSValue QJSValue::call(const QJSValueList &args)
Q_ASSERT(engine);
Scope scope(engine);
- JSCallData jsCallData(scope, args.length());
- *jsCallData->thisObject = engine->globalObject;
+ JSCallArguments jsCallData(scope, args.size());
+ *jsCallData.thisObject = engine->globalObject;
for (int i = 0; i < args.size(); ++i) {
if (!QJSValuePrivate::checkEngine(engine, args.at(i))) {
qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine");
return QJSValue();
}
- jsCallData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i));
+ jsCallData.args[i] = QJSValuePrivate::convertToReturnedValue(engine, args.at(i));
}
ScopedValue result(scope, f->call(jsCallData));
if (engine->hasException)
result = engine->catchException();
- if (engine->isInterrupted.loadAcquire())
+ if (engine->isInterrupted.loadRelaxed())
result = engine->newErrorObject(QStringLiteral("Interrupted"));
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
/*!
@@ -795,13 +751,9 @@ QJSValue QJSValue::call(const QJSValueList &args)
\sa call()
*/
-QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList &args)
+QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList &args) const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return QJSValue();
-
- FunctionObject *f = val->as<FunctionObject>();
+ const FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(this);
if (!f)
return QJSValue();
@@ -814,23 +766,23 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
return QJSValue();
}
- JSCallData jsCallData(scope, args.size());
- *jsCallData->thisObject = QJSValuePrivate::convertedToValue(engine, instance);
+ JSCallArguments jsCallData(scope, args.size());
+ *jsCallData.thisObject = QJSValuePrivate::convertToReturnedValue(engine, instance);
for (int i = 0; i < args.size(); ++i) {
if (!QJSValuePrivate::checkEngine(engine, args.at(i))) {
qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine");
return QJSValue();
}
- jsCallData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i));
+ jsCallData.args[i] = QJSValuePrivate::convertToReturnedValue(engine, args.at(i));
}
ScopedValue result(scope, f->call(jsCallData));
if (engine->hasException)
result = engine->catchException();
- if (engine->isInterrupted.loadAcquire())
+ if (engine->isInterrupted.loadRelaxed())
result = engine->newErrorObject(QStringLiteral("Interrupted"));
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
/*!
@@ -851,13 +803,9 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
\sa call(), QJSEngine::newObject()
*/
-QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
+QJSValue QJSValue::callAsConstructor(const QJSValueList &args) const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (!val)
- return QJSValue();
-
- FunctionObject *f = val->as<FunctionObject>();
+ const FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(this);
if (!f)
return QJSValue();
@@ -865,43 +813,24 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
Q_ASSERT(engine);
Scope scope(engine);
- JSCallData jsCallData(scope, args.size());
+ JSCallArguments jsCallData(scope, args.size());
for (int i = 0; i < args.size(); ++i) {
if (!QJSValuePrivate::checkEngine(engine, args.at(i))) {
qWarning("QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine");
return QJSValue();
}
- jsCallData->args[i] = QJSValuePrivate::convertedToValue(engine, args.at(i));
+ jsCallData.args[i] = QJSValuePrivate::convertToReturnedValue(engine, args.at(i));
}
ScopedValue result(scope, f->callAsConstructor(jsCallData));
if (engine->hasException)
result = engine->catchException();
- if (engine->isInterrupted.loadAcquire())
+ if (engine->isInterrupted.loadRelaxed())
result = engine->newErrorObject(QStringLiteral("Interrupted"));
- return QJSValue(engine, result->asReturnedValue());
-}
-
-#ifdef QT_DEPRECATED
-
-/*!
- \obsolete
-
- Returns the QJSEngine that created this QJSValue,
- or 0 if this QJSValue is invalid or the value is not
- associated with a particular engine.
-*/
-QJSEngine* QJSValue::engine() const
-{
- QV4::ExecutionEngine *engine = QJSValuePrivate::engine(this);
- if (engine)
- return engine->jsEngine();
- return nullptr;
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
-#endif // QT_DEPRECATED
-
/*!
If this QJSValue is an object, returns the internal prototype
(\c{__proto__} property) of this object; otherwise returns an
@@ -915,13 +844,13 @@ QJSValue QJSValue::prototype() const
if (!engine)
return QJSValue();
QV4::Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this)->as<QV4::Object>());
+ ScopedObject o(scope, QJSValuePrivate::asManagedType<QV4::Object>(this));
if (!o)
return QJSValue();
ScopedObject p(scope, o->getPrototypeOf());
if (!p)
return QJSValue(NullValue);
- return QJSValue(o->internalClass()->engine, p.asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(p.asReturnedValue());
}
/*!
@@ -942,14 +871,11 @@ void QJSValue::setPrototype(const QJSValue& prototype)
if (!engine)
return;
Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return;
- QV4::Value scratch;
- QV4::Value *val = QJSValuePrivate::valueForData(&prototype, &scratch);
- if (!val)
- return;
- if (val->isNull()) {
+ QV4::Value val = QV4::Value::fromReturnedValue(QJSValuePrivate::asReturnedValue(&prototype));
+ if (val.isNull()) {
o->setPrototypeOf(nullptr);
return;
}
@@ -980,15 +906,55 @@ QJSValue& QJSValue::operator=(const QJSValue& other)
QJSValuePrivate::free(this);
d = 0;
- QV4::Value *v = QJSValuePrivate::getValue(&other);
- if (v) {
- QJSValuePrivate::setValue(this, QJSValuePrivate::engine(&other), *v);
- } else if (QVariant *v = QJSValuePrivate::getVariant(&other)) {
- QJSValuePrivate::setVariant(this, *v);
- }
+ if (const QString *string = QJSValuePrivate::asQString(&other))
+ QJSValuePrivate::setString(this, *string);
+ else
+ QJSValuePrivate::setValue(this, QJSValuePrivate::asReturnedValue(&other));
+
return *this;
}
+QJSValue::QJSValue(QJSPrimitiveValue &&value)
+{
+ switch (value.type()) {
+ case QJSPrimitiveValue::Undefined:
+ d = QJSValuePrivate::encodeUndefined();
+ return;
+ case QJSPrimitiveValue::Null:
+ d = QJSValuePrivate::encodeNull();
+ return;
+ case QJSPrimitiveValue::Boolean:
+ d = QJSValuePrivate::encode(value.asBoolean());
+ return;
+ case QJSPrimitiveValue::Integer:
+ d = QJSValuePrivate::encode(value.asInteger());
+ return;
+ case QJSPrimitiveValue::Double:
+ d = QJSValuePrivate::encode(value.asDouble());
+ return;
+ case QJSPrimitiveValue::String:
+ d = QJSValuePrivate::encode(value.asString());
+ return;
+ }
+
+ Q_UNREACHABLE();
+}
+
+QJSValue::QJSValue(QJSManagedValue &&value)
+{
+ if (!value.d) {
+ d = QV4::Encode::undefined();
+ } else if (value.d->isManaged()) {
+ // If it's managed, we can adopt the persistent value.
+ QJSValuePrivate::adoptPersistentValue(this, value.d);
+ value.d = nullptr;
+ } else {
+ d = QJSValuePrivate::encode(*value.d);
+ QV4::PersistentValueStorage::free(value.d);
+ value.d = nullptr;
+ }
+}
+
static bool js_equal(const QString &string, const QV4::Value &value)
{
if (String *s = value.stringValue())
@@ -1031,23 +997,17 @@ static bool js_equal(const QString &string, const QV4::Value &value)
*/
bool QJSValue::equals(const QJSValue& other) const
{
- QV4::Value s1, s2;
- QV4::Value *v = QJSValuePrivate::valueForData(this, &s1);
- QV4::Value *ov = QJSValuePrivate::valueForData(&other, &s2);
-
- if (!v) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- Q_ASSERT(variant);
- if (!ov)
- return *variant == *QJSValuePrivate::getVariant(&other);
- if (variant->type() == QVariant::Map || variant->type() == QVariant::List)
- return false;
- return js_equal(variant->toString(), *ov);
- }
- if (!ov)
- return other.equals(*this);
+ if (const QString *string = QJSValuePrivate::asQString(this)) {
+ if (const QString *otherString = QJSValuePrivate::asQString(&other))
+ return *string == *otherString;
+ return js_equal(*string, QJSValuePrivate::asReturnedValue(&other));
+ }
- return Runtime::CompareEqual::call(*v, *ov);
+ if (const QString *otherString = QJSValuePrivate::asQString(&other))
+ return js_equal(*otherString, QJSValuePrivate::asReturnedValue(this));
+
+ return Runtime::CompareEqual::call(QJSValuePrivate::asReturnedValue(this),
+ QJSValuePrivate::asReturnedValue(&other));
}
/*!
@@ -1074,25 +1034,22 @@ bool QJSValue::equals(const QJSValue& other) const
*/
bool QJSValue::strictlyEquals(const QJSValue& other) const
{
- QV4::Value s1, s2;
- QV4::Value *v = QJSValuePrivate::valueForData(this, &s1);
- QV4::Value *ov = QJSValuePrivate::valueForData(&other, &s2);
-
- if (!v) {
- QVariant *variant = QJSValuePrivate::getVariant(this);
- Q_ASSERT(variant);
- if (!ov)
- return *variant == *QJSValuePrivate::getVariant(&other);
- if (variant->type() == QVariant::Map || variant->type() == QVariant::List)
- return false;
- if (String *s = ov->stringValue())
- return variant->toString() == s->toQString();
+ if (const QString *string = QJSValuePrivate::asQString(this)) {
+ if (const QString *otherString = QJSValuePrivate::asQString(&other))
+ return *string == *otherString;
+ if (const String *s = QJSValuePrivate::asManagedType<String>(&other))
+ return *string == s->toQString();
+ return false;
+ }
+
+ if (const QString *otherString = QJSValuePrivate::asQString(&other)) {
+ if (const String *s = QJSValuePrivate::asManagedType<String>(this))
+ return *otherString == s->toQString();
return false;
}
- if (!ov)
- return other.strictlyEquals(*this);
- return RuntimeHelpers::strictEqual(*v, *ov);
+ return RuntimeHelpers::strictEqual(QJSValuePrivate::asReturnedValue(this),
+ QJSValuePrivate::asReturnedValue(&other));
}
/*!
@@ -1119,7 +1076,7 @@ QJSValue QJSValue::property(const QString& name) const
return QJSValue();
QV4::Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return QJSValue();
@@ -1128,7 +1085,7 @@ QJSValue QJSValue::property(const QString& name) const
if (engine->hasException)
result = engine->catchException();
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
/*!
@@ -1167,14 +1124,14 @@ QJSValue QJSValue::property(quint32 arrayIndex) const
return QJSValue();
QV4::Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return QJSValue();
QV4::ScopedValue result(scope, arrayIndex == UINT_MAX ? o->get(engine->id_uintMax()) : o->get(arrayIndex));
if (engine->hasException)
engine->catchException();
- return QJSValue(engine, result->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
/*!
@@ -1199,7 +1156,7 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value)
return;
Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return;
@@ -1209,7 +1166,7 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value)
}
ScopedString s(scope, engine->newString(name));
- QV4::ScopedValue v(scope, QJSValuePrivate::convertedToValue(engine, value));
+ QV4::ScopedValue v(scope, QJSValuePrivate::convertToReturnedValue(engine, value));
o->put(s->toPropertyKey(), v);
if (engine->hasException)
engine->catchException();
@@ -1253,7 +1210,7 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
return;
Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return;
@@ -1262,7 +1219,7 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
return;
}
- QV4::ScopedValue v(scope, QJSValuePrivate::convertedToValue(engine, value));
+ QV4::ScopedValue v(scope, QJSValuePrivate::convertToReturnedValue(engine, value));
PropertyKey id = arrayIndex != UINT_MAX ? PropertyKey::fromArrayIndex(arrayIndex) : engine->id_uintMax()->propertyKey();
o->put(id, v);
if (engine->hasException)
@@ -1296,7 +1253,7 @@ bool QJSValue::deleteProperty(const QString &name)
return false;
Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return false;
@@ -1317,7 +1274,7 @@ bool QJSValue::hasProperty(const QString &name) const
return false;
Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return false;
@@ -1338,7 +1295,7 @@ bool QJSValue::hasOwnProperty(const QString &name) const
return false;
Scope scope(engine);
- ScopedObject o(scope, QJSValuePrivate::getValue(this));
+ ScopedObject o(scope, QJSValuePrivate::asReturnedValue(this));
if (!o)
return false;
@@ -1362,7 +1319,7 @@ QObject *QJSValue::toQObject() const
if (!engine)
return nullptr;
QV4::Scope scope(engine);
- QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, QJSValuePrivate::getValue(this));
+ QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, QJSValuePrivate::asReturnedValue(this));
if (!wrapper)
return nullptr;
@@ -1383,7 +1340,7 @@ const QMetaObject *QJSValue::toQMetaObject() const
if (!engine)
return nullptr;
QV4::Scope scope(engine);
- QV4::Scoped<QV4::QMetaObjectWrapper> wrapper(scope, QJSValuePrivate::getValue(this));
+ QV4::Scoped<QV4::QMetaObjectWrapper> wrapper(scope, QJSValuePrivate::asReturnedValue(this));
if (!wrapper)
return nullptr;
@@ -1400,12 +1357,8 @@ const QMetaObject *QJSValue::toQMetaObject() const
*/
QDateTime QJSValue::toDateTime() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- if (val) {
- QV4::DateObject *date = val->as<DateObject>();
- if (date)
- return date->toQDateTime();
- }
+ if (const QV4::DateObject *date = QJSValuePrivate::asManagedType<DateObject>(this))
+ return date->toQDateTime();
return QDateTime();
}
@@ -1415,8 +1368,7 @@ QDateTime QJSValue::toDateTime() const
*/
bool QJSValue::isDate() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- return val && val->as<DateObject>();
+ return QJSValuePrivate::asManagedType<DateObject>(this);
}
/*!
@@ -1425,8 +1377,7 @@ bool QJSValue::isDate() const
*/
bool QJSValue::isRegExp() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- return val && val->as<RegExpObject>();
+ return QJSValuePrivate::asManagedType<RegExpObject>(this);
}
/*!
@@ -1440,8 +1391,7 @@ bool QJSValue::isRegExp() const
*/
bool QJSValue::isQObject() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- return val && val->as<QV4::QObjectWrapper>() != nullptr;
+ return QJSValuePrivate::asManagedType<QV4::QObjectWrapper>(this);
}
/*!
@@ -1454,8 +1404,72 @@ bool QJSValue::isQObject() const
*/
bool QJSValue::isQMetaObject() const
{
- QV4::Value *val = QJSValuePrivate::getValue(this);
- return val && val->as<QV4::QMetaObjectWrapper>() != nullptr;
+ return QJSValuePrivate::asManagedType<QV4::QMetaObjectWrapper>(this);
+}
+
+#ifndef QT_NO_DATASTREAM
+QDataStream &operator<<(QDataStream &stream, const QJSValue &jsv)
+{
+ quint32 isNullOrUndefined = 0;
+ if (jsv.isNull())
+ isNullOrUndefined |= 0x1;
+ if (jsv.isUndefined())
+ isNullOrUndefined |= 0x2;
+ stream << isNullOrUndefined;
+ if (!isNullOrUndefined) {
+ const QVariant v = jsv.toVariant();
+ switch (v.userType()) {
+ case QMetaType::Bool:
+ case QMetaType::Double:
+ case QMetaType::Int:
+ case QMetaType::QString:
+ v.save(stream);
+ break;
+ default:
+ qWarning() << "QDataStream::operator<< was to save a non-trivial QJSValue."
+ << "This is not supported anymore, please stream a QVariant instead.";
+ QVariant().save(stream);
+ break;
+ }
+
+ }
+ return stream;
+}
+
+QDataStream &operator>>(QDataStream &stream, QJSValue &jsv)
+{
+ quint32 isNullOrUndefined;
+ stream >> isNullOrUndefined;
+
+ if (isNullOrUndefined & 0x1) {
+ jsv = QJSValue(QJSValue::NullValue);
+ } else if (isNullOrUndefined & 0x2) {
+ jsv = QJSValue();
+ } else {
+ QVariant v;
+ v.load(stream);
+
+ switch (v.userType()) {
+ case QMetaType::Bool:
+ jsv = QJSValue(v.toBool());
+ break;
+ case QMetaType::Double:
+ jsv = QJSValue(v.toDouble());
+ break;
+ case QMetaType::Int:
+ jsv = QJSValue(v.toInt());
+ break;
+ case QMetaType::QString:
+ jsv = QJSValue(v.toString());
+ break;
+ default:
+ qWarning() << "QDataStream::operator>> to restore a non-trivial QJSValue."
+ << "This is not supported anymore, please stream a QVariant instead.";
+ break;
+ }
+ }
+ return stream;
}
+#endif
QT_END_NAMESPACE
diff --git a/src/qml/jsapi/qjsvalue.h b/src/qml/jsapi/qjsvalue.h
index 2f95e0ff31..065f73f666 100644
--- a/src/qml/jsapi/qjsvalue.h
+++ b/src/qml/jsapi/qjsvalue.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QJSVALUE_H
#define QJSVALUE_H
@@ -53,13 +17,16 @@ class QVariant;
class QObject;
struct QMetaObject;
class QDateTime;
+class QJSPrimitiveValue;
typedef QList<QJSValue> QJSValueList;
namespace QV4 {
struct ExecutionEngine;
- struct Value;
}
+class QJSPrimitiveValue;
+class QJSManagedValue;
+
class Q_QML_EXPORT QJSValue
{
public:
@@ -79,16 +46,19 @@ public:
URIError
};
+ enum ObjectConversionBehavior {
+ ConvertJSObjects,
+ RetainJSObjects
+ };
+
public:
QJSValue(SpecialValue value = UndefinedValue);
~QJSValue();
QJSValue(const QJSValue &other);
-#ifdef Q_COMPILER_RVALUE_REFS
inline QJSValue(QJSValue && other) : d(other.d) { other.d = 0; }
inline QJSValue &operator=(QJSValue &&other)
- { qSwap(d, other.d); return *this; }
-#endif
+ { std::swap(d, other.d); return *this; }
QJSValue(bool value);
QJSValue(int value);
@@ -102,12 +72,18 @@ public:
QJSValue &operator=(const QJSValue &other);
+ explicit QJSValue(QJSPrimitiveValue &&value);
+ explicit QJSValue(QJSManagedValue &&value);
+
bool isBool() const;
bool isNumber() const;
bool isNull() const;
bool isString() const;
bool isUndefined() const;
+#if QT_DEPRECATED_SINCE(6, 9)
+ QT_DEPRECATED_VERSION_X_6_9("This might return unexpected results; consult documentation for more information")
bool isVariant() const;
+#endif
bool isQObject() const;
bool isQMetaObject() const;
bool isObject() const;
@@ -115,13 +91,18 @@ public:
bool isRegExp() const;
bool isArray() const;
bool isError() const;
+ bool isUrl() const;
QString toString() const;
double toNumber() const;
qint32 toInt() const;
quint32 toUInt() const;
bool toBool() const;
+
QVariant toVariant() const;
+ QVariant toVariant(ObjectConversionBehavior behavior) const;
+ QJSPrimitiveValue toPrimitive() const;
+
QObject *toQObject() const;
const QMetaObject *toQMetaObject() const;
QDateTime toDateTime() const;
@@ -144,24 +125,25 @@ public:
bool deleteProperty(const QString &name);
bool isCallable() const;
- QJSValue call(const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
- QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
- QJSValue callAsConstructor(const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
+ QJSValue call(const QJSValueList &args = QJSValueList()) const;
+ QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList()) const;
+ QJSValue callAsConstructor(const QJSValueList &args = QJSValueList()) const;
ErrorType errorType() const;
-#ifdef QT_DEPRECATED
- QT_DEPRECATED QJSEngine *engine() const;
-#endif
- QJSValue(QV4::ExecutionEngine *e, quint64 val);
private:
friend class QJSValuePrivate;
// force compile error, prevent QJSValue(bool) to be called
- QJSValue(void *) Q_DECL_EQ_DELETE;
+ QJSValue(void *) = delete;
- mutable quintptr d;
+ quint64 d;
};
+#ifndef QT_NO_DATASTREAM
+Q_QML_EXPORT QDataStream &operator<<(QDataStream &, const QJSValue &);
+Q_QML_EXPORT QDataStream &operator>>(QDataStream &, QJSValue &);
+#endif
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QJSValue)
diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h
index 2faffffbae..4624652c93 100644
--- a/src/qml/jsapi/qjsvalue_p.h
+++ b/src/qml/jsapi/qjsvalue_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
@@ -56,7 +20,6 @@
#include <private/qv4value_p.h>
#include <private/qv4string_p.h>
#include <private/qv4engine_p.h>
-#include <private/qflagpointer_p.h>
#include <private/qv4mm_p.h>
#include <private/qv4persistent_p.h>
@@ -64,132 +27,344 @@
QT_BEGIN_NAMESPACE
-class Q_AUTOTEST_EXPORT QJSValuePrivate
+class QJSValuePrivate
{
+ static constexpr quint64 s_tagBits = 3; // 3 bits mask
+ static constexpr quint64 s_tagMask = (1 << s_tagBits) - 1;
+
+ static constexpr quint64 s_pointerBit = 0x1;
+
public:
- static inline QV4::Value *getValue(const QJSValue *jsval)
+ enum class Kind {
+ Undefined = 0x0,
+ Null = 0x2,
+ IntValue = 0x4,
+ BoolValue = 0x6,
+ DoublePtr = 0x0 | s_pointerBit,
+ QV4ValuePtr = 0x2 | s_pointerBit,
+ QStringPtr = 0x4 | s_pointerBit,
+ };
+
+ static_assert(quint64(Kind::Undefined) <= s_tagMask);
+ static_assert(quint64(Kind::Null) <= s_tagMask);
+ static_assert(quint64(Kind::IntValue) <= s_tagMask);
+ static_assert(quint64(Kind::BoolValue) <= s_tagMask);
+ static_assert(quint64(Kind::DoublePtr) <= s_tagMask);
+ static_assert(quint64(Kind::QV4ValuePtr) <= s_tagMask);
+ static_assert(quint64(Kind::QStringPtr) <= s_tagMask);
+
+ static Kind tag(quint64 raw) { return Kind(raw & s_tagMask); }
+
+#if QT_POINTER_SIZE == 4
+ static void *pointer(quint64 raw)
{
- if (jsval->d & 3)
- return nullptr;
- return reinterpret_cast<QV4::Value *>(jsval->d);
+ Q_ASSERT(quint64(tag(raw)) & s_pointerBit);
+ return reinterpret_cast<void *>(raw >> 32);
}
- static inline QVariant *getVariant(const QJSValue *jsval)
+ static quint64 encodePointer(void *pointer, Kind tag)
{
- if (jsval->d & 1)
- return reinterpret_cast<QVariant *>(jsval->d & ~3);
- return nullptr;
+ Q_ASSERT(quint64(tag) & s_pointerBit);
+ return (quint64(quintptr(pointer)) << 32) | quint64(tag);
}
+#else
+ static constexpr quint64 s_minAlignment = 1 << s_tagBits;
+ static_assert(alignof(double) >= s_minAlignment);
+ static_assert(alignof(QV4::Value) >= s_minAlignment);
+ static_assert(alignof(QString) >= s_minAlignment);
- static inline void setRawValue(QJSValue *jsval, QV4::Value *v)
+ static void *pointer(quint64 raw)
{
- jsval->d = reinterpret_cast<quintptr>(v);
+ Q_ASSERT(quint64(tag(raw)) & s_pointerBit);
+ return reinterpret_cast<void *>(raw & ~s_tagMask);
}
- static inline void setVariant(QJSValue *jsval, const QVariant &v) {
- QVariant *val = new QVariant(v);
- jsval->d = reinterpret_cast<quintptr>(val) | 1;
+ static quint64 encodePointer(void *pointer, Kind tag)
+ {
+ Q_ASSERT(quint64(tag) & s_pointerBit);
+ return quintptr(pointer) | quint64(tag);
}
+#endif
- static inline void setValue(QJSValue *jsval, QV4::ExecutionEngine *engine, const QV4::Value &v) {
- QV4::Value *value = engine->memoryManager->m_persistentValues->allocate();
- *value = v;
- jsval->d = reinterpret_cast<quintptr>(value);
+ static quint64 encodeUndefined()
+ {
+ return quint64(Kind::Undefined);
}
- static inline void setValue(QJSValue *jsval, QV4::ExecutionEngine *engine, QV4::ReturnedValue v) {
- QV4::Value *value = engine->memoryManager->m_persistentValues->allocate();
- *value = v;
- jsval->d = reinterpret_cast<quintptr>(value);
+ static quint64 encodeNull()
+ {
+ return quint64(Kind::Null);
}
- static QV4::ReturnedValue convertedToValue(QV4::ExecutionEngine *e, const QJSValue &jsval)
+ static int intValue(quint64 v)
{
- QV4::Value *v = getValue(&jsval);
- if (!v) {
- QVariant *variant = getVariant(&jsval);
- v = e->memoryManager->m_persistentValues->allocate();
- *v = variant ? e->fromVariant(*variant) : QV4::Encode::undefined();
- jsval.d = reinterpret_cast<quintptr>(v);
- delete variant;
- }
+ Q_ASSERT(tag(v) == Kind::IntValue);
+ return v >> 32;
+ }
- if (QV4::PersistentValueStorage::getEngine(v) != e) {
- qWarning("JSValue can't be reassigned to another engine.");
- return QV4::Encode::undefined();
- }
+ static quint64 encode(int intValue)
+ {
+ return (quint64(intValue) << 32) | quint64(Kind::IntValue);
+ }
- return v->asReturnedValue();
+ static quint64 encode(uint uintValue)
+ {
+ return (uintValue < uint(std::numeric_limits<int>::max()))
+ ? encode(int(uintValue))
+ : encode(double(uintValue));
}
- static QV4::Value *valueForData(const QJSValue *jsval, QV4::Value *scratch)
+ static bool boolValue(quint64 v)
{
- QV4::Value *v = getValue(jsval);
- if (v)
- return v;
- v = scratch;
- QVariant *variant = getVariant(jsval);
- if (!variant) {
- *v = QV4::Encode::undefined();
- return v;
- }
+ Q_ASSERT(tag(v) == Kind::BoolValue);
+ return v >> 32;
+ }
- switch (variant->userType()) {
- case QMetaType::UnknownType:
- case QMetaType::Void:
- *v = QV4::Encode::undefined();
- break;
- case QMetaType::Nullptr:
- case QMetaType::VoidStar:
- *v = QV4::Encode::null();
- break;
- case QMetaType::Bool:
- *v = QV4::Encode(variant->toBool());
+ static quint64 encode(bool boolValue)
+ {
+ return (quint64(boolValue) << 32) | quint64(Kind::BoolValue);
+ }
+
+ static double *doublePtr(quint64 v)
+ {
+ Q_ASSERT(tag(v) == Kind::DoublePtr);
+ return static_cast<double *>(pointer(v));
+ }
+
+ static quint64 encode(double doubleValue)
+ {
+ return encodePointer(new double(doubleValue), Kind::DoublePtr);
+ }
+
+ static QV4::Value *qv4ValuePtr(quint64 v)
+ {
+ Q_ASSERT(tag(v) == Kind::QV4ValuePtr);
+ return static_cast<QV4::Value *>(pointer(v));
+ }
+
+ static quint64 encode(const QV4::Value &qv4Value)
+ {
+ switch (qv4Value.type()) {
+ case QV4::StaticValue::Boolean_Type:
+ return encode(qv4Value.booleanValue());
+ case QV4::StaticValue::Integer_Type:
+ return encode(qv4Value.integerValue());
+ case QV4::StaticValue::Managed_Type: {
+ auto managed = qv4Value.as<QV4::Managed>();
+ auto engine = managed->engine();
+ auto mm = engine->memoryManager;
+ QV4::Value *m = mm->m_persistentValues->allocate();
+ Q_ASSERT(m);
+ // we create a new strong reference to the heap managed object
+ // to avoid having to rescan the persistent values, we mark it here
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack){
+ if constexpr (QV4::WriteBarrier::isInsertionBarrier)
+ managed->heapObject()->mark(stack);
+ });
+ *m = qv4Value;
+ return encodePointer(m, Kind::QV4ValuePtr);
+ }
+ case QV4::StaticValue::Double_Type:
+ return encode(qv4Value.doubleValue());
+ case QV4::StaticValue::Null_Type:
+ return encodeNull();
+ case QV4::StaticValue::Empty_Type:
+ Q_UNREACHABLE();
break;
- case QMetaType::Double:
- *v = QV4::Encode(variant->toDouble());
+ case QV4::StaticValue::Undefined_Type:
break;
- case QMetaType::Int:
- case QMetaType::Short:
- case QMetaType::UShort:
- case QMetaType::Char:
- case QMetaType::UChar:
- *v = QV4::Encode(variant->toInt());
+ }
+
+ return encodeUndefined();
+ }
+
+ static QString *qStringPtr(quint64 v)
+ {
+ Q_ASSERT(tag(v) == Kind::QStringPtr);
+ return static_cast<QString *>(pointer(v));
+ }
+
+ static quint64 encode(QString stringValue)
+ {
+ return encodePointer(new QString(std::move(stringValue)), Kind::QStringPtr);
+ }
+
+ static quint64 encode(QLatin1String stringValue)
+ {
+ return encodePointer(new QString(std::move(stringValue)), Kind::QStringPtr);
+ }
+
+ static QJSValue fromReturnedValue(QV4::ReturnedValue d)
+ {
+ QJSValue result;
+ setValue(&result, d);
+ return result;
+ }
+
+ template<typename T>
+ static const T *asManagedType(const QJSValue *jsval)
+ {
+ if (tag(jsval->d) == Kind::QV4ValuePtr) {
+ if (const QV4::Value *value = qv4ValuePtr(jsval->d))
+ return value->as<T>();
+ }
+ return nullptr;
+ }
+
+ // This is a move operation and transfers ownership.
+ static QV4::Value *takeManagedValue(QJSValue *jsval)
+ {
+ if (tag(jsval->d) == Kind::QV4ValuePtr) {
+ if (QV4::Value *value = qv4ValuePtr(jsval->d)) {
+ jsval->d = encodeUndefined();
+ return value;
+ }
+ }
+ return nullptr;
+ }
+
+ static QV4::ReturnedValue asPrimitiveType(const QJSValue *jsval)
+ {
+ switch (tag(jsval->d)) {
+ case Kind::BoolValue:
+ return QV4::Encode(boolValue(jsval->d));
+ case Kind::IntValue:
+ return QV4::Encode(intValue(jsval->d));
+ case Kind::DoublePtr:
+ return QV4::Encode(*doublePtr(jsval->d));
+ case Kind::Null:
+ return QV4::Encode::null();
+ case Kind::Undefined:
+ case Kind::QV4ValuePtr:
+ case Kind::QStringPtr:
break;
- case QMetaType::UInt:
- *v = QV4::Encode(variant->toUInt());
+ }
+
+ return QV4::Encode::undefined();
+ }
+
+ // Beware: This only returns a non-null string if the QJSValue actually holds one.
+ // QV4::Strings are kept as managed values. Retrieve those with getValue().
+ static const QString *asQString(const QJSValue *jsval)
+ {
+ if (tag(jsval->d) == Kind::QStringPtr) {
+ if (const QString *string = qStringPtr(jsval->d))
+ return string;
+ }
+ return nullptr;
+ }
+
+ static QV4::ReturnedValue asReturnedValue(const QJSValue *jsval)
+ {
+ switch (tag(jsval->d)) {
+ case Kind::BoolValue:
+ return QV4::Encode(boolValue(jsval->d));
+ case Kind::IntValue:
+ return QV4::Encode(intValue(jsval->d));
+ case Kind::DoublePtr:
+ return QV4::Encode(*doublePtr(jsval->d));
+ case Kind::Null:
+ return QV4::Encode::null();
+ case Kind::QV4ValuePtr:
+ return qv4ValuePtr(jsval->d)->asReturnedValue();
+ case Kind::Undefined:
+ case Kind::QStringPtr:
break;
- default:
- return nullptr;
}
- return v;
+
+ return QV4::Encode::undefined();
+ }
+
+ static void setString(QJSValue *jsval, QString s)
+ {
+ jsval->d = encode(std::move(s));
+ }
+
+ // Only use this with an existing persistent value.
+ // Ownership is transferred to the QJSValue.
+ static void adoptPersistentValue(QJSValue *jsval, QV4::Value *v)
+ {
+ jsval->d = encodePointer(v, Kind::QV4ValuePtr);
+ }
+
+ static void setValue(QJSValue *jsval, const QV4::Value &v)
+ {
+ jsval->d = encode(v);
+ }
+
+ // Moves any QString onto the V4 heap, changing the value to reflect that.
+ static void manageStringOnV4Heap(QV4::ExecutionEngine *e, QJSValue *jsval)
+ {
+ if (const QString *string = asQString(jsval)) {
+ jsval->d = encode(QV4::Value::fromHeapObject(e->newString(*string)));
+ delete string;
+ }
+ }
+
+ // Converts any QString on the fly, involving an allocation.
+ // Does not change the value.
+ static QV4::ReturnedValue convertToReturnedValue(QV4::ExecutionEngine *e,
+ const QJSValue &jsval)
+ {
+ if (const QString *string = asQString(&jsval))
+ return e->newString(*string)->asReturnedValue();
+ if (const QV4::Value *val = asManagedType<QV4::Managed>(&jsval)) {
+ if (QV4::PersistentValueStorage::getEngine(val) == e)
+ return val->asReturnedValue();
+
+ qWarning("JSValue can't be reassigned to another engine.");
+ return QV4::Encode::undefined();
+ }
+ return asPrimitiveType(&jsval);
}
- static QV4::ExecutionEngine *engine(const QJSValue *jsval) {
- QV4::Value *v = getValue(jsval);
- return v ? QV4::PersistentValueStorage::getEngine(v) : nullptr;
+ static QV4::ExecutionEngine *engine(const QJSValue *jsval)
+ {
+ if (tag(jsval->d) == Kind::QV4ValuePtr) {
+ if (const QV4::Value *value = qv4ValuePtr(jsval->d))
+ return QV4::PersistentValueStorage::getEngine(value);
+ }
+
+ return nullptr;
}
- static inline bool checkEngine(QV4::ExecutionEngine *e, const QJSValue &jsval) {
+ static bool checkEngine(QV4::ExecutionEngine *e, const QJSValue &jsval)
+ {
QV4::ExecutionEngine *v4 = engine(&jsval);
return !v4 || v4 == e;
}
- static inline void free(QJSValue *jsval) {
- if (QV4::Value *v = QJSValuePrivate::getValue(jsval)) {
- if (QV4::ExecutionEngine *e = engine(jsval)) {
- if (QJSEngine *jsEngine = e->jsEngine()) {
- if (jsEngine->thread() != QThread::currentThread()) {
- QMetaObject::invokeMethod(
- jsEngine, [v](){ QV4::PersistentValueStorage::free(v); });
- return;
- }
+ static void free(QJSValue *jsval)
+ {
+ switch (tag(jsval->d)) {
+ case Kind::Undefined:
+ case Kind::Null:
+ case Kind::IntValue:
+ case Kind::BoolValue:
+ return;
+ case Kind::DoublePtr:
+ delete doublePtr(jsval->d);
+ return;
+ case Kind::QStringPtr:
+ delete qStringPtr(jsval->d);
+ return;
+ case Kind::QV4ValuePtr:
+ break;
+ }
+
+ // We need a mutable value for free(). It needs to write to the actual memory.
+ QV4::Value *m = qv4ValuePtr(jsval->d);
+ Q_ASSERT(m); // Otherwise it would have been undefined above.
+ if (QV4::ExecutionEngine *e = QV4::PersistentValueStorage::getEngine(m)) {
+ if (QJSEngine *jsEngine = e->jsEngine()) {
+ if (jsEngine->thread() != QThread::currentThread()) {
+ QMetaObject::invokeMethod(
+ jsEngine, [m](){ QV4::PersistentValueStorage::free(m); });
+ return;
}
}
- QV4::PersistentValueStorage::free(v);
- } else if (QVariant *v = QJSValuePrivate::getVariant(jsval)) {
- delete v;
}
+ QV4::PersistentValueStorage::free(m);
}
};
diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp
index 076b90c5f2..6f561e82ed 100644
--- a/src/qml/jsapi/qjsvalueiterator.cpp
+++ b/src/qml/jsapi/qjsvalueiterator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qjsvalueiterator.h"
#include "qjsvalueiterator_p.h"
@@ -58,12 +22,12 @@ void QJSValueIteratorPrivate::init(const QJSValue &v)
QV4::ExecutionEngine *e = QJSValuePrivate::engine(&v);
if (!e)
return;
- QV4::Object *o = QJSValuePrivate::getValue(&v)->objectValue();
+ const QV4::Object *o = QJSValuePrivate::asManagedType<QV4::Object>(&v);
if (!o)
return;
engine = e;
- object = o;
+ object.set(e, o->asReturnedValue());
iterator.reset(o->ownPropertyKeys(object.valueRef()));
next();
}
@@ -209,7 +173,7 @@ QJSValue QJSValueIterator::value() const
scope.engine->catchException();
return QJSValue();
}
- return QJSValue(scope.engine, val->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(val->asReturnedValue());
}
diff --git a/src/qml/jsapi/qjsvalueiterator.h b/src/qml/jsapi/qjsvalueiterator.h
index f9468a2242..bffc60358d 100644
--- a/src/qml/jsapi/qjsvalueiterator.h
+++ b/src/qml/jsapi/qjsvalueiterator.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QJSVALUEITERATOR_H
#define QJSVALUEITERATOR_H
diff --git a/src/qml/jsapi/qjsvalueiterator_p.h b/src/qml/jsapi/qjsvalueiterator_p.h
index a870850c11..1ac8f22512 100644
--- a/src/qml/jsapi/qjsvalueiterator_p.h
+++ b/src/qml/jsapi/qjsvalueiterator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QJSVALUEITERATOR_P_H
#define QJSVALUEITERATOR_P_H
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
deleted file mode 100644
index 32acc6affc..0000000000
--- a/src/qml/jsruntime/jsruntime.pri
+++ /dev/null
@@ -1,174 +0,0 @@
-INCLUDEPATH += $$PWD
-INCLUDEPATH += $$OUT_PWD
-
-SOURCES += \
- $$PWD/qv4engine.cpp \
- $$PWD/qv4context.cpp \
- $$PWD/qv4persistent.cpp \
- $$PWD/qv4lookup.cpp \
- $$PWD/qv4identifier.cpp \
- $$PWD/qv4identifiertable.cpp \
- $$PWD/qv4managed.cpp \
- $$PWD/qv4internalclass.cpp \
- $$PWD/qv4sparsearray.cpp \
- $$PWD/qv4atomics.cpp \
- $$PWD/qv4arraydata.cpp \
- $$PWD/qv4arrayobject.cpp \
- $$PWD/qv4arrayiterator.cpp \
- $$PWD/qv4argumentsobject.cpp \
- $$PWD/qv4booleanobject.cpp \
- $$PWD/qv4dateobject.cpp \
- $$PWD/qv4errorobject.cpp \
- $$PWD/qv4function.cpp \
- $$PWD/qv4functionobject.cpp \
- $$PWD/qv4generatorobject.cpp \
- $$PWD/qv4globalobject.cpp \
- $$PWD/qv4iterator.cpp \
- $$PWD/qv4jsonobject.cpp \
- $$PWD/qv4mathobject.cpp \
- $$PWD/qv4memberdata.cpp \
- $$PWD/qv4numberobject.cpp \
- $$PWD/qv4object.cpp \
- $$PWD/qv4objectproto.cpp \
- $$PWD/qv4propertykey.cpp \
- $$PWD/qv4proxy.cpp \
- $$PWD/qv4qmlcontext.cpp \
- $$PWD/qv4reflect.cpp \
- $$PWD/qv4regexpobject.cpp \
- $$PWD/qv4stackframe.cpp \
- $$PWD/qv4string.cpp \
- $$PWD/qv4stringiterator.cpp \
- $$PWD/qv4stringobject.cpp \
- $$PWD/qv4variantobject.cpp \
- $$PWD/qv4objectiterator.cpp \
- $$PWD/qv4regexp.cpp \
- $$PWD/qv4runtimecodegen.cpp \
- $$PWD/qv4script.cpp \
- $$PWD/qv4symbol.cpp \
- $$PWD/qv4setobject.cpp \
- $$PWD/qv4setiterator.cpp \
- $$PWD/qv4include.cpp \
- $$PWD/qv4qobjectwrapper.cpp \
- $$PWD/qv4arraybuffer.cpp \
- $$PWD/qv4typedarray.cpp \
- $$PWD/qv4dataview.cpp \
- $$PWD/qv4vme_moth.cpp \
- $$PWD/qv4mapobject.cpp \
- $$PWD/qv4mapiterator.cpp \
- $$PWD/qv4estable.cpp \
- $$PWD/qv4module.cpp \
- $$PWD/qv4promiseobject.cpp \
- $$PWD/qv4runtime.cpp \
- $$PWD/qv4value.cpp \
- $$PWD/qv4compilationunitmapper.cpp \
- $$PWD/qv4executablecompilationunit.cpp \
- $$PWD/qv4executableallocator.cpp
-
-qtConfig(qml-debug): SOURCES += $$PWD/qv4profiling.cpp
-
-HEADERS += \
- $$PWD/qv4global_p.h \
- $$PWD/qv4engine_p.h \
- $$PWD/qv4enginebase_p.h \
- $$PWD/qv4context_p.h \
- $$PWD/qv4math_p.h \
- $$PWD/qv4persistent_p.h \
- $$PWD/qv4debugging_p.h \
- $$PWD/qv4lookup_p.h \
- $$PWD/qv4identifier_p.h \
- $$PWD/qv4identifiertable_p.h \
- $$PWD/qv4managed_p.h \
- $$PWD/qv4internalclass_p.h \
- $$PWD/qv4jscall_p.h \
- $$PWD/qv4sparsearray_p.h \
- $$PWD/qv4atomics_p.h \
- $$PWD/qv4arraydata_p.h \
- $$PWD/qv4arrayobject_p.h \
- $$PWD/qv4arrayiterator_p.h \
- $$PWD/qv4argumentsobject_p.h \
- $$PWD/qv4booleanobject_p.h \
- $$PWD/qv4dateobject_p.h \
- $$PWD/qv4errorobject_p.h \
- $$PWD/qv4function_p.h \
- $$PWD/qv4functionobject_p.h \
- $$PWD/qv4generatorobject_p.h \
- $$PWD/qv4globalobject_p.h \
- $$PWD/qv4iterator_p.h \
- $$PWD/qv4jsonobject_p.h \
- $$PWD/qv4mathobject_p.h \
- $$PWD/qv4memberdata_p.h \
- $$PWD/qv4numberobject_p.h \
- $$PWD/qv4object_p.h \
- $$PWD/qv4objectproto_p.h \
- $$PWD/qv4propertykey_p.h \
- $$PWD/qv4proxy_p.h \
- $$PWD/qv4qmlcontext_p.h \
- $$PWD/qv4reflect_p.h \
- $$PWD/qv4regexpobject_p.h \
- $$PWD/qv4runtimecodegen_p.h \
- $$PWD/qv4stackframe_p.h \
- $$PWD/qv4string_p.h \
- $$PWD/qv4stringiterator_p.h \
- $$PWD/qv4stringobject_p.h \
- $$PWD/qv4variantobject_p.h \
- $$PWD/qv4property_p.h \
- $$PWD/qv4objectiterator_p.h \
- $$PWD/qv4regexp_p.h \
- $$PWD/qv4script_p.h \
- $$PWD/qv4symbol_p.h \
- $$PWD/qv4setobject_p.h \
- $$PWD/qv4setiterator_p.h \
- $$PWD/qv4scopedvalue_p.h \
- $$PWD/qv4executableallocator_p.h \
- $$PWD/qv4include_p.h \
- $$PWD/qv4qobjectwrapper_p.h \
- $$PWD/qv4profiling_p.h \
- $$PWD/qv4arraybuffer_p.h \
- $$PWD/qv4typedarray_p.h \
- $$PWD/qv4dataview_p.h \
- $$PWD/qv4vme_moth_p.h \
- $$PWD/qv4mapobject_p.h \
- $$PWD/qv4mapiterator_p.h \
- $$PWD/qv4estable_p.h \
- $$PWD/qv4vtable_p.h \
- $$PWD/qv4module_p.h \
- $$PWD/qv4promiseobject_p.h \
- $$PWD/qv4runtime_p.h \
- $$PWD/qv4value_p.h \
- $$PWD/qv4compilationunitmapper_p.h \
- $$PWD/qv4executablecompilationunit_p.h \
- $$PWD/qv4functiontable_p.h \
- $$PWD/qv4runtimeapi_p.h
-
-qtConfig(qml-sequence-object) {
- HEADERS += \
- $$PWD/qv4sequenceobject_p.h
-
- SOURCES += \
- $$PWD/qv4sequenceobject.cpp
-}
-
-unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
-else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
-
-win32 {
- !winrt:equals(QT_ARCH, x86_64) {
- SOURCES += \
- $$PWD/qv4functiontable_win64.cpp
- } else {
- SOURCES += \
- $$PWD/qv4functiontable_noop.cpp
- }
-} else {
- SOURCES += \
- $$PWD/qv4functiontable_unix.cpp
-}
-
-
-valgrind {
- DEFINES += V4_USE_VALGRIND
-}
-
-heaptrack {
- DEFINES += V4_USE_HEAPTRACK
-}
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 206e2b9aa4..74b79cb400 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -1,57 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include <qv4argumentsobject_p.h>
-#include <qv4arrayobject_p.h>
-#include <qv4scopedvalue_p.h>
-#include <qv4string_p.h>
-#include <qv4function_p.h>
-#include <qv4jscall_p.h>
-#include <qv4symbol_p.h>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qv4argumentsobject_p.h"
#include <private/qv4alloca_p.h>
+#include <private/qv4arrayobject_p.h>
+#include <private/qv4function_p.h>
+#include <private/qv4jscall_p.h>
+#include <private/qv4scopedvalue_p.h>
+#include <private/qv4stackframe_p.h>
+#include <private/qv4string_p.h>
+#include <private/qv4symbol_p.h>
using namespace QV4;
DEFINE_OBJECT_VTABLE(ArgumentsObject);
DEFINE_OBJECT_VTABLE(StrictArgumentsObject);
-void Heap::StrictArgumentsObject::init(QV4::CppStackFrame *frame)
+void Heap::StrictArgumentsObject::init(QV4::JSTypesStackFrame *frame)
{
Q_ASSERT(vtable() == QV4::StrictArgumentsObject::staticVTable());
@@ -68,11 +34,11 @@ void Heap::StrictArgumentsObject::init(QV4::CppStackFrame *frame)
Scope scope(v4);
Scoped<QV4::StrictArgumentsObject> args(scope, this);
- args->arrayReserve(frame->originalArgumentsCount);
- args->arrayPut(0, frame->originalArguments, frame->originalArgumentsCount);
+ args->arrayReserve(frame->argc());
+ args->arrayPut(0, frame->argv(), frame->argc());
Q_ASSERT(args->internalClass()->verifyIndex(v4->id_length()->propertyKey(), LengthPropertyIndex));
- setProperty(v4, LengthPropertyIndex, Value::fromInt32(frame->originalArgumentsCount));
+ setProperty(v4, LengthPropertyIndex, Value::fromInt32(frame->argc()));
}
void Heap::ArgumentsObject::init(QV4::CppStackFrame *frame)
@@ -93,7 +59,7 @@ void Heap::ArgumentsObject::init(QV4::CppStackFrame *frame)
setProperty(v4, SymbolIteratorPropertyIndex, *v4->arrayProtoValues());
fullyCreated = false;
- argCount = frame->originalArgumentsCount;
+ argCount = frame->argc();
uint nFormals = frame->v4Function->nFormals;
mapped = nFormals > 63 ? std::numeric_limits<quint64>::max() : (1ull << nFormals) - 1;
}
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index f0e2192c7e..0487bd22f8 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4ARGUMENTSOBJECTS_H
#define QV4ARGUMENTSOBJECTS_H
@@ -51,7 +15,6 @@
//
#include "qv4object_p.h"
-#include "qv4functionobject_p.h"
QT_BEGIN_NAMESPACE
@@ -66,7 +29,7 @@ namespace Heap {
Member(class, NoMark, quint64, mapped)
DECLARE_HEAP_OBJECT(ArgumentsObject, Object) {
- DECLARE_MARKOBJECTS(ArgumentsObject);
+ DECLARE_MARKOBJECTS(ArgumentsObject)
enum {
LengthPropertyIndex = 0,
SymbolIteratorPropertyIndex = 1,
@@ -84,7 +47,7 @@ DECLARE_HEAP_OBJECT(StrictArgumentsObject, Object) {
CalleePropertyIndex = 2,
CalleeSetterPropertyIndex = 3
};
- void init(CppStackFrame *frame);
+ void init(JSTypesStackFrame *frame);
};
}
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
index a99ec16943..f2be552cf8 100644
--- a/src/qml/jsruntime/qv4arraybuffer.cpp
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -1,46 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4arraybuffer_p.h"
#include "qv4typedarray_p.h"
#include "qv4dataview_p.h"
-#include "qv4string_p.h"
-#include "qv4jscall_p.h"
#include "qv4symbol_p.h"
using namespace QV4;
@@ -66,14 +28,15 @@ ReturnedValue SharedArrayBufferCtor::virtualCallAsConstructor(const FunctionObje
if (newTarget->isUndefined())
return scope.engine->throwTypeError();
- qint64 len = argc ? argv[0].toIndex() : 0;
- if (scope.engine->hasException)
+ const double len = argc ? argv[0].toInteger() : 0;
+ if (scope.hasException())
return Encode::undefined();
- if (len < 0 || len >= INT_MAX)
+ if (len < 0 || len >= std::numeric_limits<int>::max())
return scope.engine->throwRangeError(QStringLiteral("SharedArrayBuffer: Invalid length."));
- Scoped<SharedArrayBuffer> a(scope, scope.engine->memoryManager->allocate<SharedArrayBuffer>(len));
- if (scope.engine->hasException)
+ Scoped<SharedArrayBuffer> a(
+ scope, scope.engine->memoryManager->allocate<SharedArrayBuffer>(size_t(len)));
+ if (scope.hasException())
return Encode::undefined();
return a->asReturnedValue();
@@ -105,7 +68,7 @@ ReturnedValue ArrayBufferCtor::virtualCallAsConstructor(const FunctionObject *f,
if (o)
a->setPrototypeOf(o);
}
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
return a->asReturnedValue();
@@ -127,13 +90,18 @@ ReturnedValue ArrayBufferCtor::method_isView(const FunctionObject *, const Value
void Heap::SharedArrayBuffer::init(size_t length)
{
Object::init();
+ QPair<QTypedArrayData<char> *, char *> pair;
if (length < UINT_MAX)
- data = QTypedArrayData<char>::allocate(length + 1);
- if (!data) {
+ pair = QTypedArrayData<char>::allocate(length + 1);
+ if (!pair.first) {
+ new (&arrayDataPointerStorage) QArrayDataPointer<char>();
internalClass->engine->throwRangeError(QStringLiteral("ArrayBuffer: out of memory"));
return;
}
- data->size = int(length);
+ auto data = new (&arrayDataPointerStorage) QArrayDataPointer<char>{
+ pair.first, pair.second, qsizetype(length) };
+
+ // can't use appendInitialize() because we want to set the terminating '\0'
memset(data->data(), 0, length + 1);
isShared = true;
}
@@ -141,41 +109,24 @@ void Heap::SharedArrayBuffer::init(size_t length)
void Heap::SharedArrayBuffer::init(const QByteArray& array)
{
Object::init();
- data = const_cast<QByteArray&>(array).data_ptr();
- data->ref.ref();
+ new (&arrayDataPointerStorage) QArrayDataPointer<char>(*const_cast<QByteArray &>(array).data_ptr());
isShared = true;
}
void Heap::SharedArrayBuffer::destroy()
{
- if (data && !data->ref.deref())
- QTypedArrayData<char>::deallocate(data);
+ arrayDataPointer().~QArrayDataPointer();
Object::destroy();
}
QByteArray ArrayBuffer::asByteArray() const
{
- QByteArrayDataPtr ba = { d()->data };
- ba.ptr->ref.ref();
- return QByteArray(ba);
+ return QByteArray(constArrayData(), arrayDataLength());
}
-void ArrayBuffer::detach() {
- if (!d()->data->ref.isShared())
- return;
-
- QTypedArrayData<char> *oldData = d()->data;
-
- d()->data = QTypedArrayData<char>::allocate(oldData->size + 1);
- if (!d()->data) {
- engine()->throwRangeError(QStringLiteral("ArrayBuffer: out of memory"));
- return;
- }
-
- memcpy(d()->data->data(), oldData->data(), oldData->size + 1);
-
- if (!oldData->ref.deref())
- QTypedArrayData<char>::deallocate(oldData);
+void ArrayBuffer::detach()
+{
+ detachArrayData();
}
@@ -197,10 +148,10 @@ void SharedArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor)
ReturnedValue SharedArrayBufferPrototype::method_get_byteLength(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
const SharedArrayBuffer *a = thisObject->as<SharedArrayBuffer>();
- if (!a || a->isDetachedBuffer() || !a->isSharedArrayBuffer())
+ if (!a || a->hasDetachedArrayData() || !a->isSharedArrayBuffer())
return b->engine()->throwTypeError();
- return Encode(a->d()->data->size);
+ return Encode(a->arrayDataLength());
}
ReturnedValue SharedArrayBufferPrototype::method_slice(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
@@ -212,17 +163,18 @@ ReturnedValue SharedArrayBufferPrototype::slice(const FunctionObject *b, const V
{
Scope scope(b);
const SharedArrayBuffer *a = thisObject->as<SharedArrayBuffer>();
- if (!a || a->isDetachedBuffer() || (a->isSharedArrayBuffer() != shared))
+ if (!a || a->hasDetachedArrayData() || (a->isSharedArrayBuffer() != shared))
return scope.engine->throwTypeError();
+ const uint aDataLength = a->arrayDataLength();
+
double start = argc > 0 ? argv[0].toInteger() : 0;
- double end = (argc < 2 || argv[1].isUndefined()) ?
- a->d()->data->size : argv[1].toInteger();
+ double end = (argc < 2 || argv[1].isUndefined()) ? aDataLength : argv[1].toInteger();
if (scope.hasException())
return QV4::Encode::undefined();
- double first = (start < 0) ? qMax(a->d()->data->size + start, 0.) : qMin(start, (double)a->d()->data->size);
- double final = (end < 0) ? qMax(a->d()->data->size + end, 0.) : qMin(end, (double)a->d()->data->size);
+ double first = (start < 0) ? qMax(aDataLength + start, 0.) : qMin(start, double(aDataLength));
+ double final = (end < 0) ? qMax(aDataLength + end, 0.) : qMin(end, double(aDataLength));
const FunctionObject *constructor = a->speciesConstructor(scope, shared ? scope.engine->sharedArrayBufferCtor() : scope.engine->arrayBufferCtor());
if (!constructor)
@@ -231,13 +183,13 @@ ReturnedValue SharedArrayBufferPrototype::slice(const FunctionObject *b, const V
double newLen = qMax(final - first, 0.);
ScopedValue argument(scope, QV4::Encode(newLen));
QV4::Scoped<SharedArrayBuffer> newBuffer(scope, constructor->callAsConstructor(argument, 1));
- if (!newBuffer || newBuffer->d()->data->size < (int)newLen ||
- newBuffer->isDetachedBuffer() || (newBuffer->isSharedArrayBuffer() != shared) ||
+ if (!newBuffer || newBuffer->arrayDataLength() < newLen ||
+ newBuffer->hasDetachedArrayData() || (newBuffer->isSharedArrayBuffer() != shared) ||
newBuffer->sameValue(*a) ||
- a->isDetachedBuffer())
+ a->hasDetachedArrayData())
return scope.engine->throwTypeError();
- memcpy(newBuffer->d()->data->data(), a->d()->data->data() + (uint)first, newLen);
+ memcpy(newBuffer->arrayData(), a->constArrayData() + (uint)first, newLen);
return newBuffer->asReturnedValue();
}
@@ -262,10 +214,13 @@ void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor)
ReturnedValue ArrayBufferPrototype::method_get_byteLength(const FunctionObject *f, const Value *thisObject, const Value *, int)
{
const ArrayBuffer *a = thisObject->as<ArrayBuffer>();
- if (!a || a->isDetachedBuffer() || a->isSharedArrayBuffer())
+ if (!a || a->isSharedArrayBuffer())
return f->engine()->throwTypeError();
- return Encode(a->d()->data->size);
+ if (a->hasDetachedArrayData())
+ return Encode(0);
+
+ return Encode(a->arrayDataLength());
}
ReturnedValue ArrayBufferPrototype::method_slice(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
index 8344fa2554..aafa3c6335 100644
--- a/src/qml/jsruntime/qv4arraybuffer_p.h
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4ARRAYBUFFER_H
#define QV4ARRAYBUFFER_H
@@ -52,6 +16,7 @@
#include "qv4object_p.h"
#include "qv4functionobject_p.h"
+#include <QtCore/qarraydatapointer.h>
QT_BEGIN_NAMESPACE
@@ -67,36 +32,53 @@ struct ArrayBufferCtor : SharedArrayBufferCtor {
void init(QV4::ExecutionContext *scope);
};
-struct Q_QML_PRIVATE_EXPORT SharedArrayBuffer : Object {
+struct Q_QML_EXPORT SharedArrayBuffer : Object {
void init(size_t length);
void init(const QByteArray& array);
void destroy();
- QTypedArrayData<char> *data;
- bool isShared;
- uint byteLength() const { return data ? data->size : 0; }
+ void setSharedArrayBuffer(bool shared) noexcept { isShared = shared; }
+ bool isSharedArrayBuffer() const noexcept { return isShared; }
+
+ char *arrayData() noexcept { return arrayDataPointer()->data(); }
+ const char *constArrayData() const noexcept { return constArrayDataPointer()->data(); }
+ uint arrayDataLength() const noexcept { return constArrayDataPointer().size; }
+
+ bool hasSharedArrayData() const noexcept { return constArrayDataPointer().isShared(); }
+ bool hasDetachedArrayData() const noexcept { return constArrayDataPointer().isNull(); }
+ void detachArrayData() noexcept { arrayDataPointer().clear(); }
+
+ bool arrayDataNeedsDetach() const noexcept { return constArrayDataPointer().needsDetach(); }
+
+private:
+ const QArrayDataPointer<const char> &constArrayDataPointer() const noexcept
+ {
+ return *reinterpret_cast<const QArrayDataPointer<const char> *>(&arrayDataPointerStorage);
+ }
+ QArrayDataPointer<char> &arrayDataPointer() noexcept
+ {
+ return *reinterpret_cast<QArrayDataPointer<char> *>(&arrayDataPointerStorage);
+ }
+
+ template <typename T>
+ struct storage_t { alignas(T) unsigned char data[sizeof(T)]; };
- bool isDetachedBuffer() const { return !data; }
- bool isSharedArrayBuffer() const { return isShared; }
+ storage_t<QArrayDataPointer<char>>
+ arrayDataPointerStorage;
+ bool isShared;
};
-struct Q_QML_PRIVATE_EXPORT ArrayBuffer : SharedArrayBuffer {
+struct Q_QML_EXPORT ArrayBuffer : SharedArrayBuffer {
void init(size_t length) {
SharedArrayBuffer::init(length);
- isShared = false;
+ setSharedArrayBuffer(false);
}
void init(const QByteArray& array) {
SharedArrayBuffer::init(array);
- isShared = false;
- }
- void detachArrayBuffer() {
- if (data && !data->ref.deref())
- QTypedArrayData<char>::deallocate(data);
- data = nullptr;
+ setSharedArrayBuffer(false);
}
};
-
}
struct SharedArrayBufferCtor : FunctionObject
@@ -116,37 +98,38 @@ struct ArrayBufferCtor : SharedArrayBufferCtor
static ReturnedValue method_isView(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
-struct Q_QML_PRIVATE_EXPORT SharedArrayBuffer : Object
+struct Q_QML_EXPORT SharedArrayBuffer : Object
{
V4_OBJECT2(SharedArrayBuffer, Object)
V4_NEEDS_DESTROY
V4_PROTOTYPE(sharedArrayBufferPrototype)
QByteArray asByteArray() const;
- uint byteLength() const { return d()->byteLength(); }
- char *data() { Q_ASSERT(d()->data); return d()->data->data(); }
- const char *constData() { Q_ASSERT(d()->data); return d()->data->data(); }
- bool isShared() { return d()->data->ref.isShared(); }
- bool isDetachedBuffer() const { return !d()->data; }
- bool isSharedArrayBuffer() const { return d()->isShared; }
+ uint arrayDataLength() const { return d()->arrayDataLength(); }
+ char *arrayData() { return d()->arrayData(); }
+ const char *constArrayData() const { return d()->constArrayData(); }
+
+ bool hasSharedArrayData() { return d()->hasSharedArrayData(); }
+ bool hasDetachedArrayData() const { return d()->hasDetachedArrayData(); }
+ bool isSharedArrayBuffer() const { return d()->isSharedArrayBuffer(); }
};
-struct Q_QML_PRIVATE_EXPORT ArrayBuffer : SharedArrayBuffer
+struct Q_QML_EXPORT ArrayBuffer : SharedArrayBuffer
{
V4_OBJECT2(ArrayBuffer, SharedArrayBuffer)
V4_NEEDS_DESTROY
V4_PROTOTYPE(arrayBufferPrototype)
QByteArray asByteArray() const;
- uint byteLength() const { return d()->byteLength(); }
- char *data() { detach(); return d()->data ? d()->data->data() : nullptr; }
+ uint arrayDataLength() const { return d()->arrayDataLength(); }
+ char *dataData() { if (d()->arrayDataNeedsDetach()) detach(); return d()->arrayData(); }
// ### is that detach needed?
- const char *constData() { detach(); return d()->data ? d()->data->data() : nullptr; }
+ const char *constArrayData() const { return d()->constArrayData(); }
+ bool hasSharedArrayData() { return d()->hasSharedArrayData(); }
+ void detachArrayData() { d()->detachArrayData(); }
- bool isShared() { return d()->data && d()->data->ref.isShared(); }
void detach();
- void detachArrayBuffer() { d()->detachArrayBuffer(); }
};
struct SharedArrayBufferPrototype : Object
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index 654d33b8d1..e1da807c21 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4arraydata_p.h"
#include "qv4object_p.h"
#include "qv4functionobject_p.h"
@@ -563,7 +527,7 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n)
ScopedValue v(scope);
for (uint i = 0; i < n; ++i)
obj->arraySet(oldSize + i, (v = otherObj->get(i)));
- } else if (other && other->isSparse()) {
+ } else if (other->isSparse()) {
Heap::SparseArrayData *os = static_cast<Heap::SparseArrayData *>(other->d());
if (other->hasAttributes()) {
ScopedValue v(scope);
@@ -623,21 +587,6 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor)
s->setArrayData(o->engine(), n->value + Object::SetterOffset, v[Object::SetterOffset]);
}
-
-class ArrayElementLessThan
-{
-public:
- inline ArrayElementLessThan(ExecutionEngine *engine, const Value &comparefn)
- : m_engine(engine), m_comparefn(comparefn) {}
-
- bool operator()(Value v1, Value v2) const;
-
-private:
- ExecutionEngine *m_engine;
- const Value &m_comparefn;
-};
-
-
bool ArrayElementLessThan::operator()(Value v1, Value v2) const
{
Scope scope(m_engine);
@@ -650,72 +599,26 @@ bool ArrayElementLessThan::operator()(Value v1, Value v2) const
if (o) {
Scope scope(o->engine());
ScopedValue result(scope);
- JSCallData jsCallData(scope, 2);
- jsCallData->args[0] = v1;
- jsCallData->args[1] = v2;
+ JSCallArguments jsCallData(scope, 2);
+ jsCallData.args[0] = v1;
+ jsCallData.args[1] = v2;
result = o->call(jsCallData);
+ if (scope.hasException())
+ return false;
return result->toNumber() < 0;
}
ScopedString p1s(scope, v1.toString(scope.engine));
ScopedString p2s(scope, v2.toString(scope.engine));
- return p1s->toQString() < p2s->toQString();
-}
-
-template <typename RandomAccessIterator, typename T, typename LessThan>
-void sortHelper(RandomAccessIterator start, RandomAccessIterator end, const T &t, LessThan lessThan)
-{
-top:
- int span = int(end - start);
- if (span < 2)
- return;
-
- --end;
- RandomAccessIterator low = start, high = end - 1;
- RandomAccessIterator pivot = start + span / 2;
-
- if (lessThan(*end, *start))
- qSwap(*end, *start);
- if (span == 2)
- return;
-
- if (lessThan(*pivot, *start))
- qSwap(*pivot, *start);
- if (lessThan(*end, *pivot))
- qSwap(*end, *pivot);
- if (span == 3)
- return;
- qSwap(*pivot, *end);
-
- while (low < high) {
- while (low < high && lessThan(*low, *end))
- ++low;
-
- while (high > low && lessThan(*end, *high))
- --high;
-
- if (low < high) {
- qSwap(*low, *high);
- ++low;
- --high;
- } else {
- break;
- }
- }
-
- if (lessThan(*low, *end))
- ++low;
-
- qSwap(*end, *low);
- sortHelper(start, low, t, lessThan);
+ if (!p1s)
+ return false;
+ if (!p2s)
+ return true;
- start = low + 1;
- ++end;
- goto top;
+ return p1s->toQString() < p2s->toQString();
}
-
void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &comparefn, uint len)
{
if (!len)
@@ -806,10 +709,38 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
}
- ArrayElementLessThan lessThan(engine, static_cast<const FunctionObject &>(comparefn));
+ ArrayElementLessThan lessThan(engine, comparefn);
- Value *begin = thisObject->arrayData()->values.values;
- sortHelper(begin, begin + len, *begin, lessThan);
+ const auto thisArrayData = thisObject->arrayData();
+ uint startIndex = thisArrayData->mappedIndex(0);
+ uint endIndex = thisArrayData->mappedIndex(len - 1) + 1;
+ if (startIndex < endIndex) {
+ // Values are contiguous. Sort right away.
+ sortHelper(
+ thisArrayData->values.values + startIndex,
+ thisArrayData->values.values + endIndex,
+ lessThan);
+ } else {
+ // Values wrap around the end of the allocation. Close the gap to form a contiguous array.
+ // We're going to sort anyway. So we don't need to care about order.
+
+ // ArrayElementLessThan sorts empty and undefined to the end of the array anyway, but we
+ // probably shouldn't rely on the unused slots to be actually undefined or empty.
+
+ const uint gap = startIndex - endIndex;
+ const uint allocEnd = thisArrayData->values.alloc - 1;
+ for (uint i = 0; i < gap; ++i) {
+ const uint from = allocEnd - i;
+ const uint to = endIndex + i;
+ if (from < startIndex)
+ break;
+
+ std::swap(thisArrayData->values.values[from], thisArrayData->values.values[to]);
+ }
+
+ thisArrayData->offset = 0;
+ sortHelper(thisArrayData->values.values, thisArrayData->values.values + len, lessThan);
+ }
#ifdef CHECK_SPARSE_ARRAYS
thisObject->initSparseArray();
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index 64b2161ef5..a7ab1f4a71 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4ARRAYDATA_H
#define QV4ARRAYDATA_H
@@ -129,7 +93,7 @@ DECLARE_HEAP_OBJECT(ArrayData, Base) {
uint mappedIndex(uint index) const;
};
-Q_STATIC_ASSERT(std::is_trivial< ArrayData >::value);
+Q_STATIC_ASSERT(std::is_trivial_v<ArrayData>);
struct SimpleArrayData : public ArrayData {
uint mappedIndex(uint index) const { index += offset; if (index >= values.alloc) index -= values.alloc; return index; }
@@ -142,7 +106,7 @@ struct SimpleArrayData : public ArrayData {
return attrs ? attrs[i] : Attr_Data;
}
};
-Q_STATIC_ASSERT(std::is_trivial< SimpleArrayData >::value);
+Q_STATIC_ASSERT(std::is_trivial_v<SimpleArrayData>);
struct SparseArrayData : public ArrayData {
void destroy() {
@@ -267,6 +231,74 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData
static uint length(const Heap::ArrayData *d);
};
+class ArrayElementLessThan
+{
+public:
+ inline ArrayElementLessThan(ExecutionEngine *engine, const Value &comparefn)
+ : m_engine(engine), m_comparefn(comparefn) {}
+
+ bool operator()(Value v1, Value v2) const;
+
+private:
+ ExecutionEngine *m_engine;
+ const Value &m_comparefn;
+};
+
+template <typename RandomAccessIterator, typename LessThan>
+void sortHelper(RandomAccessIterator start, RandomAccessIterator end, LessThan lessThan)
+{
+top:
+ using std::swap;
+
+ int span = int(end - start);
+ if (span < 2)
+ return;
+
+ --end;
+ RandomAccessIterator low = start, high = end - 1;
+ RandomAccessIterator pivot = start + span / 2;
+
+ if (lessThan(*end, *start))
+ swap(*end, *start);
+ if (span == 2)
+ return;
+
+ if (lessThan(*pivot, *start))
+ swap(*pivot, *start);
+ if (lessThan(*end, *pivot))
+ swap(*end, *pivot);
+ if (span == 3)
+ return;
+
+ swap(*pivot, *end);
+
+ while (low < high) {
+ while (low < high && lessThan(*low, *end))
+ ++low;
+
+ while (high > low && lessThan(*end, *high))
+ --high;
+
+ if (low < high) {
+ swap(*low, *high);
+ ++low;
+ --high;
+ } else {
+ break;
+ }
+ }
+
+ if (lessThan(*low, *end))
+ ++low;
+
+ swap(*end, *low);
+ sortHelper(start, low, lessThan);
+
+ start = low + 1;
+ ++end;
+ goto top;
+}
+
namespace Heap {
inline uint ArrayData::mappedIndex(uint index) const
diff --git a/src/qml/jsruntime/qv4arrayiterator.cpp b/src/qml/jsruntime/qv4arrayiterator.cpp
index 199b1a728a..15e0bf4e4c 100644
--- a/src/qml/jsruntime/qv4arrayiterator.cpp
+++ b/src/qml/jsruntime/qv4arrayiterator.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Crimson AS <info@crimson.no>
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 Crimson AS <info@crimson.no>
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qv4iterator_p.h>
#include <private/qv4arrayiterator_p.h>
@@ -72,7 +36,6 @@ ReturnedValue ArrayIteratorPrototype::method_next(const FunctionObject *b, const
quint32 index = thisObject->d()->nextIndex;
IteratorKind itemKind = thisObject->d()->iterationKind;
- Scoped<TypedArray> ta(scope, a->as<TypedArray>());
quint32 len = a->getLength();
if (index >= len) {
@@ -86,18 +49,18 @@ ReturnedValue ArrayIteratorPrototype::method_next(const FunctionObject *b, const
return IteratorPrototype::createIterResultObject(scope.engine, Value::fromInt32(index), false);
}
- ReturnedValue elementValue = a->get(index);
+ QV4::ScopedValue elementValue(scope, a->get(index));
CHECK_EXCEPTION();
if (itemKind == ValueIteratorKind) {
- return IteratorPrototype::createIterResultObject(scope.engine, Value::fromReturnedValue(elementValue), false);
+ return IteratorPrototype::createIterResultObject(scope.engine, elementValue, false);
} else {
Q_ASSERT(itemKind == KeyValueIteratorKind);
ScopedArrayObject resultArray(scope, scope.engine->newArrayObject());
resultArray->arrayReserve(2);
resultArray->arrayPut(0, Value::fromInt32(index));
- resultArray->arrayPut(1, Value::fromReturnedValue(elementValue));
+ resultArray->arrayPut(1, elementValue);
resultArray->setArrayLengthUnchecked(2);
return IteratorPrototype::createIterResultObject(scope.engine, resultArray, false);
diff --git a/src/qml/jsruntime/qv4arrayiterator_p.h b/src/qml/jsruntime/qv4arrayiterator_p.h
index 6d6bb466f1..79f0898fb6 100644
--- a/src/qml/jsruntime/qv4arrayiterator_p.h
+++ b/src/qml/jsruntime/qv4arrayiterator_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Crimson AS <info@crimson.no>
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 Crimson AS <info@crimson.no>
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4ARRAYITERATOR_P_H
#define QV4ARRAYITERATOR_P_H
@@ -54,7 +18,6 @@
#include "qv4object_p.h"
#include "qv4iterator_p.h"
-#include "qv4arraydata_p.h"
QT_BEGIN_NAMESPACE
@@ -69,7 +32,7 @@ namespace Heap {
Member(class, NoMark, quint32, nextIndex)
DECLARE_HEAP_OBJECT(ArrayIteratorObject, Object) {
- DECLARE_MARKOBJECTS(ArrayIteratorObject);
+ DECLARE_MARKOBJECTS(ArrayIteratorObject)
void init(Object *obj, QV4::ExecutionEngine *engine)
{
Object::init();
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index af1a2d1de0..a32017210a 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -1,55 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Crimson AS <info@crimson.no>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Crimson AS <info@crimson.no>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4arrayobject_p.h"
-#include "qv4objectiterator_p.h"
#include "qv4arrayiterator_p.h"
-#include "qv4sparsearray_p.h"
#include "qv4objectproto_p.h"
-#include "qv4jscall_p.h"
#include "qv4argumentsobject_p.h"
#include "qv4runtime_p.h"
-#include "qv4string_p.h"
#include "qv4symbol_p.h"
#include <QtCore/qscopedvaluerollback.h>
-#include "qv4proxy_p.h"
using namespace QV4;
@@ -235,9 +194,8 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V
// sets them into the created array.
forever {
if (k > (static_cast<qint64>(1) << 53) - 1) {
- ScopedValue falsey(scope, Encode(false));
ScopedValue error(scope, scope.engine->throwTypeError());
- return Runtime::IteratorClose::call(scope.engine, iterator, falsey);
+ return Runtime::IteratorClose::call(scope.engine, iterator);
}
// Retrieve the next value. If the iteration ends, we're done here.
@@ -254,11 +212,12 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V
}
if (mapfn) {
+ Q_ASSERT(mapArguments); // if mapfn is set, we always setup mapArguments with scope.alloc
mapArguments[0] = *nextValue;
mapArguments[1] = Value::fromDouble(k);
mappedValue = mapfn->call(thisArg, mapArguments, 2);
- if (scope.engine->hasException)
- return Runtime::IteratorClose::call(scope.engine, iterator, Value::fromBoolean(false));
+ if (scope.hasException())
+ return Runtime::IteratorClose::call(scope.engine, iterator);
} else {
mappedValue = *nextValue;
}
@@ -270,10 +229,8 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V
scope.engine->throwTypeError(QString::fromLatin1("Cannot redefine property: %1").arg(k));
}
- if (scope.engine->hasException) {
- ScopedValue falsey(scope, Encode(false));
- return Runtime::IteratorClose::call(scope.engine, iterator, falsey);
- }
+ if (scope.hasException())
+ return Runtime::IteratorClose::call(scope.engine, iterator);
k++;
}
@@ -297,6 +254,7 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V
CHECK_EXCEPTION();
if (mapfn) {
+ Q_ASSERT(mapArguments); // if mapfn is set, we always setup mapArguments with scope.alloc
mapArguments[0] = kValue;
mapArguments[1] = Value::fromDouble(k);
mappedValue = mapfn->call(thisArg, mapArguments, 2);
@@ -362,7 +320,7 @@ ReturnedValue ArrayPrototype::method_toString(const FunctionObject *builtin, con
ScopedString string(scope, scope.engine->newString(QStringLiteral("join")));
ScopedFunctionObject f(scope, that->get(string));
if (f)
- return f->call(that, argv, argc);
+ return checkedResult(scope.engine, f->call(that, argv, argc));
return ObjectPrototype::method_toString(builtin, that, argv, argc);
}
@@ -381,6 +339,9 @@ ReturnedValue ArrayPrototype::method_toLocaleString(const FunctionObject *b, con
ScopedValue v(scope);
ScopedString s(scope);
+ ScopedPropertyKey tolocaleString(scope, scope.engine->id_toLocaleString()->toPropertyKey());
+ Q_ASSERT(!scope.engine->hasException);
+
for (uint k = 0; k < len; ++k) {
if (k)
R += separator;
@@ -388,7 +349,18 @@ ReturnedValue ArrayPrototype::method_toLocaleString(const FunctionObject *b, con
v = instance->get(k);
if (v->isNullOrUndefined())
continue;
- v = Runtime::CallElement::call(scope.engine, v, *scope.engine->id_toLocaleString(), nullptr, 0);
+
+ ScopedObject valueAsObject(scope, v->toObject(scope.engine));
+ Q_ASSERT(valueAsObject); // null and undefined handled above
+
+ ScopedFunctionObject function(scope, valueAsObject->get(tolocaleString));
+ if (!function)
+ return scope.engine->throwTypeError();
+
+ v = function->call(valueAsObject, nullptr, 0);
+ if (scope.hasException())
+ return Encode::undefined();
+
s = v->toString(scope.engine);
if (scope.hasException())
return Encode::undefined();
@@ -421,7 +393,7 @@ ReturnedValue ArrayPrototype::method_concat(const FunctionObject *b, const Value
} else if (eltAsObj && eltAsObj->isConcatSpreadable()) {
const uint startIndex = result->getLength();
const uint len = eltAsObj->getLength();
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
for (uint i = 0; i < len; ++i) {
@@ -432,7 +404,7 @@ ReturnedValue ArrayPrototype::method_concat(const FunctionObject *b, const Value
return scope.engine->throwTypeError();
}
}
- } else if (eltAsObj && eltAsObj->isListType()) {
+ } else if (eltAsObj && eltAsObj->isArrayLike()) {
const uint startIndex = result->getLength();
for (int i = 0, len = eltAsObj->getLength(); i < len; ++i) {
entry = eltAsObj->get(i);
@@ -597,65 +569,63 @@ ReturnedValue ArrayPrototype::method_findIndex(const FunctionObject *b, const Va
return Encode(-1);
}
-ReturnedValue ArrayPrototype::method_join(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue ArrayPrototype::method_join(const FunctionObject *functionObject,
+ const Value *thisObject, const Value *argv, int argc)
{
- Scope scope(b);
+ Scope scope(functionObject);
ScopedObject instance(scope, thisObject->toObject(scope.engine));
if (!instance)
return Encode(scope.engine->newString());
- ScopedValue arg(scope, argc ? argv[0] : Value::undefinedValue());
-
- QString r4;
- if (arg->isUndefined())
- r4 = QStringLiteral(",");
- else
- r4 = arg->toQString();
+ // We cannot optimize the resolution of the argument away in case of length == 0
+ // It may have side effects.
+ ScopedValue argument(scope, argc ? argv[0] : Value::undefinedValue());
+ const QString separator = argument->isUndefined()
+ ? QStringLiteral(",")
+ : argument->toQString();
- ScopedValue length(scope, instance->get(scope.engine->id_length()));
- const quint32 r2 = length->isUndefined() ? 0 : length->toUInt32();
-
- if (!r2)
+ ScopedValue scopedLength(scope, instance->get(scope.engine->id_length()));
+ const quint32 genericLength = scopedLength->isUndefined() ? 0 : scopedLength->toUInt32();
+ if (!genericLength)
return Encode(scope.engine->newString());
- QString R;
-
- // ### FIXME
- if (ArrayObject *a = instance->as<ArrayObject>()) {
- ScopedValue e(scope);
- for (uint i = 0; i < a->getLength(); ++i) {
+ QString result;
+ if (auto *arrayObject = instance->as<ArrayObject>()) {
+ ScopedValue entry(scope);
+ const qint64 arrayLength = arrayObject->getLength();
+ Q_ASSERT(arrayLength >= 0);
+ Q_ASSERT(arrayLength <= std::numeric_limits<quint32>::max());
+ for (quint32 i = 0; i < quint32(arrayLength); ++i) {
if (i)
- R += r4;
+ result += separator;
- e = a->get(i);
+ entry = arrayObject->get(i);
CHECK_EXCEPTION();
- if (!e->isNullOrUndefined())
- R += e->toQString();
+ if (!entry->isNullOrUndefined())
+ result += entry->toQString();
}
} else {
- //
- // crazy!
- //
ScopedString name(scope, scope.engine->newString(QStringLiteral("0")));
- ScopedValue r6(scope, instance->get(name));
- if (!r6->isNullOrUndefined())
- R = r6->toQString();
+ ScopedValue value(scope, instance->get(name));
+ CHECK_EXCEPTION();
+
+ if (!value->isNullOrUndefined())
+ result = value->toQString();
- ScopedValue r12(scope);
- for (quint32 k = 1; k < r2; ++k) {
- R += r4;
+ for (quint32 i = 1; i < genericLength; ++i) {
+ result += separator;
- name = Value::fromDouble(k).toString(scope.engine);
- r12 = instance->get(name);
+ name = Value::fromDouble(i).toString(scope.engine);
+ value = instance->get(name);
CHECK_EXCEPTION();
- if (!r12->isNullOrUndefined())
- R += r12->toQString();
+ if (!value->isNullOrUndefined())
+ result += value->toQString();
}
}
- return Encode(scope.engine->newString(R));
+ return Encode(scope.engine->newString(result));
}
ReturnedValue ArrayPrototype::method_pop(const FunctionObject *b, const Value *thisObject, const Value *, int)
@@ -1050,8 +1020,9 @@ ReturnedValue ArrayPrototype::method_includes(const FunctionObject *b, const Val
}
}
+ ScopedValue val(scope);
while (k < len) {
- ScopedValue val(scope, instance->get(k));
+ val = instance->get(k);
if (val->sameValueZero(argv[0])) {
return Encode(true);
}
@@ -1210,6 +1181,7 @@ ReturnedValue ArrayPrototype::method_every(const FunctionObject *b, const Value
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
r = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
ok = r->toBoolean();
}
return Encode(ok);
@@ -1222,31 +1194,38 @@ ReturnedValue ArrayPrototype::method_fill(const FunctionObject *b, const Value *
if (!instance)
RETURN_UNDEFINED();
- uint len = instance->getLength();
- int relativeStart = argc > 1 ? argv[1].toInteger() : 0;
- int relativeEnd = len;
- if (argc > 2 && !argv[2].isUndefined()) {
+ const qsizetype len = instance->getLength();
+ Q_ASSERT(len >= 0);
+
+ const qsizetype relativeStart = argc > 1 ? argv[1].toInteger() : 0;
+ qsizetype relativeEnd = len;
+ if (argc > 2 && !argv[2].isUndefined())
relativeEnd = argv[2].toInteger();
- }
- uint k = 0;
- uint fin = 0;
+
+ qsizetype k = 0;
+ qsizetype fin = 0;
if (relativeStart < 0) {
- k = std::max(len+relativeStart, uint(0));
+ if (relativeStart > -len)
+ k = std::max(len + relativeStart, qsizetype(0));
} else {
- k = std::min(uint(relativeStart), len);
+ k = std::min(relativeStart, len);
}
+ Q_ASSERT(k >= 0);
if (relativeEnd < 0) {
- fin = std::max(len + relativeEnd, uint(0));
+ if (relativeEnd > -len)
+ fin = std::max(len + relativeEnd, qsizetype(0));
} else {
- fin = std::min(uint(relativeEnd), len);
+ fin = std::min(relativeEnd, len);
}
+ Q_ASSERT(fin >= 0);
- while (k < fin) {
- instance->setIndexed(k, argv[0], QV4::Object::DoThrowOnRejection);
- k++;
- }
+ if (sizeof(qsizetype) > sizeof(uint) && fin > qsizetype(std::numeric_limits<uint>::max()))
+ return scope.engine->throwRangeError(QString::fromLatin1("Array length out of range."));
+
+ for (; k < fin; ++k)
+ instance->setIndexed(uint(k), argv[0], QV4::Object::DoThrowOnRejection);
return instance.asReturnedValue();
}
@@ -1277,6 +1256,7 @@ ReturnedValue ArrayPrototype::method_some(const FunctionObject *b, const Value *
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
result = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
if (result->toBoolean())
return Encode(true);
}
@@ -1346,6 +1326,7 @@ ReturnedValue ArrayPrototype::method_map(const FunctionObject *b, const Value *t
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
mapped = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
a->arraySet(k, mapped);
}
return a.asReturnedValue();
@@ -1381,6 +1362,7 @@ ReturnedValue ArrayPrototype::method_filter(const FunctionObject *b, const Value
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
selected = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
if (selected->toBoolean()) {
a->arraySet(to, arguments[0]);
++to;
@@ -1431,6 +1413,7 @@ ReturnedValue ArrayPrototype::method_reduce(const FunctionObject *b, const Value
arguments[2] = Value::fromDouble(k);
arguments[3] = instance;
acc = callback->call(nullptr, arguments, 4);
+ CHECK_EXCEPTION();
}
++k;
}
@@ -1484,6 +1467,7 @@ ReturnedValue ArrayPrototype::method_reduceRight(const FunctionObject *b, const
arguments[2] = Value::fromDouble(k - 1);
arguments[3] = instance;
acc = callback->call(nullptr, arguments, 4);
+ CHECK_EXCEPTION();
}
--k;
}
diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h
index c959b71bc6..b07e27b24f 100644
--- a/src/qml/jsruntime/qv4arrayobject_p.h
+++ b/src/qml/jsruntime/qv4arrayobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4ARRAYOBJECT_H
#define QV4ARRAYOBJECT_H
@@ -56,6 +20,31 @@
QT_BEGIN_NAMESPACE
+inline bool qIsAtMostUintLimit(qsizetype length, uint limit = std::numeric_limits<uint>::max())
+{
+ // Use the type with the larger positive range to do the comparison.
+
+ Q_ASSERT(length >= 0);
+ if constexpr (sizeof(qsizetype) > sizeof(uint)) {
+ return length <= qsizetype(limit);
+ } else {
+ return uint(length) <= limit;
+ }
+}
+
+inline bool qIsAtMostSizetypeLimit(uint length, qsizetype limit = std::numeric_limits<qsizetype>::max())
+{
+ // Use the type with the larger positive range to do the comparison.
+
+ Q_ASSERT(limit >= 0);
+ if constexpr (sizeof(qsizetype) > sizeof(uint)) {
+ return qsizetype(length) <= limit;
+ } else {
+ return length <= uint(limit);
+ }
+}
+
+
namespace QV4 {
namespace Heap {
diff --git a/src/qml/jsruntime/qv4atomics.cpp b/src/qml/jsruntime/qv4atomics.cpp
index 4299aef859..ccbdef145b 100644
--- a/src/qml/jsruntime/qv4atomics.cpp
+++ b/src/qml/jsruntime/qv4atomics.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4arraybuffer_p.h"
#include "qv4typedarray_p.h"
#include "qv4atomics_p.h"
@@ -87,7 +51,7 @@ static SharedArrayBuffer *validateSharedIntegerTypedArray(Scope &scope, const Va
scope.engine->throwTypeError();
return nullptr;
}
- Q_ASSERT(!buffer->isDetachedBuffer());
+ Q_ASSERT(!buffer->hasDetachedArrayData());
return buffer;
}
@@ -125,7 +89,7 @@ ReturnedValue atomicReadModifyWrite(const FunctionObject *f, const Value *argv,
int bytesPerElement = a.d()->type->bytesPerElement;
int byteOffset = a.d()->byteOffset + index * bytesPerElement;
- return a.d()->type->atomicModifyOps[modify](buffer->data() + byteOffset, v);
+ return a.d()->type->atomicModifyOps[modify](buffer->arrayData() + byteOffset, v);
}
ReturnedValue Atomics::method_add(const FunctionObject *f, const Value *, const Value *argv, int argc)
@@ -162,7 +126,7 @@ ReturnedValue Atomics::method_compareExchange(const FunctionObject *f, const Val
int bytesPerElement = a.d()->type->bytesPerElement;
int byteOffset = a.d()->byteOffset + index * bytesPerElement;
- return a.d()->type->atomicCompareExchange(buffer->data() + byteOffset, expected, v);
+ return a.d()->type->atomicCompareExchange(buffer->arrayData() + byteOffset, expected, v);
}
ReturnedValue Atomics::method_exchange(const FunctionObject *f, const Value *, const Value *argv, int argc)
@@ -203,7 +167,7 @@ ReturnedValue Atomics::method_load(const FunctionObject *f, const Value *, const
int bytesPerElement = a.d()->type->bytesPerElement;
int byteOffset = a.d()->byteOffset + index * bytesPerElement;
- return a.d()->type->atomicLoad(buffer->data() + byteOffset);
+ return a.d()->type->atomicLoad(buffer->arrayData() + byteOffset);
}
ReturnedValue Atomics::method_or(const FunctionObject *f, const Value *, const Value *argv, int argc)
@@ -232,7 +196,7 @@ ReturnedValue Atomics::method_store(const FunctionObject *f, const Value *, cons
int bytesPerElement = a.d()->type->bytesPerElement;
int byteOffset = a.d()->byteOffset + index * bytesPerElement;
- return a.d()->type->atomicStore(buffer->data() + byteOffset, v);
+ return a.d()->type->atomicStore(buffer->arrayData() + byteOffset, v);
}
ReturnedValue Atomics::method_sub(const FunctionObject *f, const Value *, const Value *argv, int argc)
diff --git a/src/qml/jsruntime/qv4atomics_p.h b/src/qml/jsruntime/qv4atomics_p.h
index 35b64bf4fe..d55e6bb983 100644
--- a/src/qml/jsruntime/qv4atomics_p.h
+++ b/src/qml/jsruntime/qv4atomics_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4ATOMICS_H
#define QV4ATOMICS_H
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index a9b4ecb607..3110ec7992 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -1,44 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4booleanobject_p.h"
-#include "qv4string_p.h"
using namespace QV4;
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index 276ec8393b..e009b0413a 100644
--- a/src/qml/jsruntime/qv4booleanobject_p.h
+++ b/src/qml/jsruntime/qv4booleanobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4BOOLEANOBJECT_H
#define QV4BOOLEANOBJECT_H
diff --git a/src/qml/jsruntime/qv4compilationunitmapper.cpp b/src/qml/jsruntime/qv4compilationunitmapper.cpp
index 74f34a284d..e9915c7d26 100644
--- a/src/qml/jsruntime/qv4compilationunitmapper.cpp
+++ b/src/qml/jsruntime/qv4compilationunitmapper.cpp
@@ -1,62 +1,81 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4compilationunitmapper_p.h"
#include <private/qv4compileddata_p.h>
-#include <QFileInfo>
-#include <QDateTime>
-#include <QCoreApplication>
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qhash.h>
QT_BEGIN_NAMESPACE
using namespace QV4;
-CompilationUnitMapper::CompilationUnitMapper()
- : dataPtr(nullptr)
+class StaticUnitCache
+{
+public:
+ StaticUnitCache() : m_lock(&s_mutex) {}
+
+ CompilationUnitMapper get(const QString &file)
+ {
+ const auto it = s_staticUnits.constFind(file);
+ return it == s_staticUnits.constEnd() ? CompilationUnitMapper() : *it;
+ }
+
+ void set(const QString &file, const CompilationUnitMapper &staticUnit) {
+ s_staticUnits.insert(file, staticUnit);
+ }
+
+ void remove(const QString &file)
+ {
+ s_staticUnits.remove(file);
+ }
+
+private:
+ QMutexLocker<QMutex> m_lock;
+
+ static QMutex s_mutex;
+
+ // We can copy the mappers around because they're all static.
+ // We never unmap the files.
+ static QHash<QString, CompilationUnitMapper> s_staticUnits;
+};
+
+QHash<QString, CompilationUnitMapper> StaticUnitCache::s_staticUnits;
+QMutex StaticUnitCache::s_mutex;
+
+CompiledData::Unit *CompilationUnitMapper::get(
+ const QString &cacheFilePath, const QDateTime &sourceTimeStamp, QString *errorString)
{
+ StaticUnitCache cache;
+
+ CompilationUnitMapper mapper = cache.get(cacheFilePath);
+ if (mapper.dataPtr) {
+ auto *unit = reinterpret_cast<CompiledData::Unit *>(mapper.dataPtr);
+ if (unit->verifyHeader(sourceTimeStamp, errorString)) {
+ *this = mapper;
+ return unit;
+ }
+
+ return nullptr;
+ }
+ CompiledData::Unit *data = open(cacheFilePath, sourceTimeStamp, errorString);
+ if (data && (data->flags & CompiledData::Unit::StaticData)) {
+ cache.set(cacheFilePath, *this);
+ return data;
+ } else {
+ close();
+ return nullptr;
+ }
}
-CompilationUnitMapper::~CompilationUnitMapper()
+void CompilationUnitMapper::invalidate(const QString &cacheFilePath)
{
- close();
+ StaticUnitCache cache;
+ cache.remove(cacheFilePath);
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4compilationunitmapper_p.h b/src/qml/jsruntime/qv4compilationunitmapper_p.h
index 80f914c141..c214141804 100644
--- a/src/qml/jsruntime/qv4compilationunitmapper_p.h
+++ b/src/qml/jsruntime/qv4compilationunitmapper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4COMPILATIONUNITMAPPER_H
#define QV4COMPILATIONUNITMAPPER_H
@@ -65,17 +29,19 @@ struct Unit;
class CompilationUnitMapper
{
public:
- CompilationUnitMapper();
- ~CompilationUnitMapper();
+ CompiledData::Unit *get(
+ const QString &cacheFilePath, const QDateTime &sourceTimeStamp, QString *errorString);
+ static void invalidate(const QString &cacheFilePath);
- CompiledData::Unit *open(const QString &cacheFilePath, const QDateTime &sourceTimeStamp, QString *errorString);
+private:
+ CompiledData::Unit *open(
+ const QString &cacheFilePath, const QDateTime &sourceTimeStamp, QString *errorString);
void close();
-private:
#if defined(Q_OS_UNIX)
- size_t length;
+ size_t length = 0;
#endif
- void *dataPtr;
+ void *dataPtr = nullptr;
};
}
diff --git a/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp b/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp
index a9ab2f5ccb..204e222121 100644
--- a/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp
+++ b/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp
@@ -1,51 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4compilationunitmapper_p.h"
-#include <sys/mman.h>
-#include <functional>
#include <private/qcore_unix_p.h>
-#include <QScopeGuard>
-#include <QDateTime>
+#include <private/qv4compileddata_p.h>
-#include "qv4executablecompilationunit_p.h"
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qdatetime.h>
+
+#include <functional>
+#include <sys/mman.h>
QT_BEGIN_NAMESPACE
@@ -73,12 +38,22 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
return nullptr;
}
- if (!ExecutableCompilationUnit::verifyHeader(&header, sourceTimeStamp, errorString))
+ if (!header.verifyHeader(sourceTimeStamp, errorString))
return nullptr;
// Data structure and qt version matched, so now we can access the rest of the file safely.
length = static_cast<size_t>(lseek(fd, 0, SEEK_END));
+ /* Error out early on file corruption. We assume we can read header.unitSize bytes
+ later (even before verifying the checksum), potentially causing out-of-bound
+ reads
+ Also, no need to wait until checksum verification if we know beforehand
+ that the cached unit is bogus
+ */
+ if (length != header.unitSize) {
+ *errorString = QStringLiteral("Potential file corruption, file too small");
+ return nullptr;
+ }
void *ptr = mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, /*offset*/0);
if (ptr == MAP_FAILED) {
diff --git a/src/qml/jsruntime/qv4compilationunitmapper_win.cpp b/src/qml/jsruntime/qv4compilationunitmapper_win.cpp
index 9e8babc5e6..73096207b4 100644
--- a/src/qml/jsruntime/qv4compilationunitmapper_win.cpp
+++ b/src/qml/jsruntime/qv4compilationunitmapper_win.cpp
@@ -1,48 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4compilationunitmapper_p.h"
-#include "qv4executablecompilationunit_p.h"
-#include <QScopeGuard>
-#include <QFileInfo>
-#include <QDateTime>
+#include <private/qv4compileddata_p.h>
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qscopeguard.h>
+
#include <qt_windows.h>
QT_BEGIN_NAMESPACE
@@ -56,16 +22,10 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
// ### TODO: fix up file encoding/normalization/unc handling once QFileSystemEntry
// is exported from QtCore.
HANDLE handle =
-#if defined(Q_OS_WINRT)
- CreateFile2(reinterpret_cast<const wchar_t*>(cacheFileName.constData()),
- GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ,
- OPEN_EXISTING, nullptr);
-#else
CreateFile(reinterpret_cast<const wchar_t*>(cacheFileName.constData()),
GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr);
-#endif
if (handle == INVALID_HANDLE_VALUE) {
*errorString = qt_error_string(GetLastError());
return nullptr;
@@ -87,11 +47,28 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
return nullptr;
}
- if (!ExecutableCompilationUnit::verifyHeader(&header, sourceTimeStamp, errorString))
+ if (!header.verifyHeader(sourceTimeStamp, errorString))
return nullptr;
// Data structure and qt version matched, so now we can access the rest of the file safely.
+ /* Error out early on file corruption. We assume we can read header.unitSize bytes
+ later (even before verifying the checksum), potentially causing out-of-bound
+ reads
+ Also, no need to wait until checksum verification if we know beforehand
+ that the cached unit is bogus
+ */
+ LARGE_INTEGER fileSize;
+ if (!GetFileSizeEx(handle, &fileSize)) {
+ *errorString = QStringLiteral("Could not determine file size");
+ return nullptr;
+ }
+ if (header.unitSize != fileSize.QuadPart) {
+ *errorString = QStringLiteral("Potential file corruption, file too small");
+ return nullptr;
+ }
+
+
HANDLE fileMappingHandle = CreateFileMapping(handle, 0, PAGE_READONLY, 0, 0, 0);
if (!fileMappingHandle) {
*errorString = qt_error_string(GetLastError());
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 018571e325..3ae3e5d24c 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -1,53 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QString>
-#include "qv4debugging_p.h"
#include <qv4context_p.h>
#include <qv4object_p.h>
#include <qv4objectproto_p.h>
#include <private/qv4mm_p.h>
#include <qv4argumentsobject_p.h>
#include "qv4function_p.h"
-#include "qv4errorobject_p.h"
-#include "qv4string_p.h"
-#include "qv4qmlcontext_p.h"
#include "qv4stackframe_p.h"
#include "qv4symbol_p.h"
@@ -71,8 +31,13 @@ Heap::CallContext *ExecutionContext::newBlockContext(CppStackFrame *frame, int b
Heap::ExecutionContext *outer = static_cast<Heap::ExecutionContext *>(frame->context()->m());
c->outer.set(v4, outer);
- c->function.set(v4, static_cast<Heap::FunctionObject *>(
- Value::fromStaticValue(frame->jsFrame->function).m()));
+ if (frame->isJSTypesFrame()) {
+ c->function.set(v4, static_cast<Heap::FunctionObject *>(
+ Value::fromStaticValue(
+ static_cast<JSTypesStackFrame *>(frame)->jsFrame->function).m()));
+ } else {
+ c->function.set(v4, nullptr);
+ }
c->locals.size = nLocals;
c->locals.alloc = nLocals;
@@ -95,12 +60,12 @@ Heap::CallContext *ExecutionContext::cloneBlockContext(ExecutionEngine *engine,
return c;
}
-Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame)
+Heap::CallContext *ExecutionContext::newCallContext(JSTypesStackFrame *frame)
{
Function *function = frame->v4Function;
Heap::ExecutionContext *outer = static_cast<Heap::ExecutionContext *>(frame->context()->m());
- uint nFormals = qMax(static_cast<uint>(frame->originalArgumentsCount), function->nFormals);
+ uint nFormals = qMax(static_cast<uint>(frame->argc()), function->nFormals);
uint localsAndFormals = function->compiledFunction->nLocals + nFormals;
size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * (localsAndFormals);
@@ -122,9 +87,9 @@ Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame)
c->setupLocalTemporalDeadZone(compiledFunction);
Value *args = c->locals.values + nLocals;
- ::memcpy(args, frame->originalArguments, frame->originalArgumentsCount * sizeof(Value));
- c->nArgs = frame->originalArgumentsCount;
- for (uint i = frame->originalArgumentsCount; i < function->nFormals; ++i)
+ ::memcpy(args, frame->argv(), frame->argc() * sizeof(Value));
+ c->nArgs = frame->argc();
+ for (uint i = frame->argc(); i < function->nFormals; ++i)
args[i] = Encode::undefined();
return c;
@@ -334,9 +299,14 @@ ReturnedValue ExecutionContext::getProperty(String *name)
case Heap::ExecutionContext::Type_CallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
- uint index = c->internalClass->indexOfValueOrGetter(id);
- if (index < UINT_MAX)
+ const uint index = c->internalClass->indexOfValueOrGetter(id);
+ if (index < c->locals.alloc)
return c->locals[index].asReturnedValue();
+
+ // TODO: We should look up the module imports here, but those are part of the CU:
+ // imports[index - c->locals.size];
+ // See QTBUG-118478
+
Q_FALLTHROUGH();
}
case Heap::ExecutionContext::Type_WithContext:
@@ -384,9 +354,14 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
case Heap::ExecutionContext::Type_CallContext: {
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
- uint index = c->internalClass->indexOfValueOrGetter(id);
- if (index < UINT_MAX)
+ const uint index = c->internalClass->indexOfValueOrGetter(id);
+ if (index < c->locals.alloc)
return c->locals[index].asReturnedValue();
+
+ // TODO: We should look up the module imports here, but those are part of the CU:
+ // imports[index - c->locals.size];
+ // See QTBUG-118478
+
Q_FALLTHROUGH();
}
case Heap::ExecutionContext::Type_GlobalContext: {
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 75fa2d08e6..82a9472223 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMLJS_ENVIRONMENT_H
#define QMLJS_ENVIRONMENT_H
@@ -65,7 +29,7 @@ namespace Heap {
Member(class, Pointer, Object *, activation)
DECLARE_HEAP_OBJECT(ExecutionContext, Base) {
- DECLARE_MARKOBJECTS(ExecutionContext);
+ DECLARE_MARKOBJECTS(ExecutionContext)
enum ContextType {
Type_GlobalContext = 0x1,
@@ -92,7 +56,7 @@ DECLARE_HEAP_OBJECT(ExecutionContext, Base) {
quint8 padding_[4];
#endif
};
-Q_STATIC_ASSERT(std::is_trivial< ExecutionContext >::value);
+Q_STATIC_ASSERT(std::is_trivial_v<ExecutionContext>);
Q_STATIC_ASSERT(sizeof(ExecutionContext) == sizeof(Base) + sizeof(ExecutionContextData) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(std::is_standard_layout<ExecutionContextData>::value);
@@ -104,7 +68,7 @@ Q_STATIC_ASSERT(offsetof(ExecutionContextData, activation) == offsetof(Execution
Member(class, ValueArray, ValueArray, locals)
DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) {
- DECLARE_MARKOBJECTS(CallContext);
+ DECLARE_MARKOBJECTS(CallContext)
void init()
{
@@ -125,7 +89,7 @@ DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) {
locals.values[i] = Value::emptyValue();
}
};
-Q_STATIC_ASSERT(std::is_trivial< CallContext >::value);
+Q_STATIC_ASSERT(std::is_trivial_v<CallContext>);
Q_STATIC_ASSERT(std::is_standard_layout<CallContextData>::value);
Q_STATIC_ASSERT(offsetof(CallContextData, function) == 0);
//### The following size check fails on Win8. With the ValueArray at the end of the
@@ -152,7 +116,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
static Heap::CallContext *newBlockContext(QV4::CppStackFrame *frame, int blockIndex);
static Heap::CallContext *cloneBlockContext(ExecutionEngine *engine,
Heap::CallContext *callContext);
- static Heap::CallContext *newCallContext(QV4::CppStackFrame *frame);
+ static Heap::CallContext *newCallContext(JSTypesStackFrame *frame);
Heap::ExecutionContext *newWithContext(Heap::Object *with) const;
static Heap::ExecutionContext *newCatchContext(CppStackFrame *frame, int blockIndex, Heap::String *exceptionVarName);
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index 5ab8cf2dcb..f4ca09a127 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -1,45 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4dataview_p.h"
#include "qv4arraybuffer_p.h"
-#include "qv4string_p.h"
#include "qv4symbol_p.h"
#include <QtCore/private/qnumeric_p.h>
@@ -79,20 +42,20 @@ ReturnedValue DataViewCtor::virtualCallAsConstructor(const FunctionObject *f, co
if (!newTarget || !buffer)
return scope.engine->throwTypeError();
- uint offset = ::toIndex(scope.engine, argc > 1 ? argv[1]: Value::undefinedValue());
+ uint offset = ::toIndex(scope.engine, argc > 1 ? argv[1] : Value::undefinedValue());
if (scope.hasException())
return Encode::undefined();
- if (buffer->isDetachedBuffer())
+ if (buffer->hasDetachedArrayData())
return scope.engine->throwTypeError();
- uint bufferLength = buffer->d()->data->size;
+ uint bufferLength = buffer->arrayDataLength();
if (offset > bufferLength)
return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range"));
uint byteLength = (argc < 3 || argv[2].isUndefined()) ? (bufferLength - offset) : ::toIndex(scope.engine, argv[2]);
if (scope.hasException())
return Encode::undefined();
- if (offset + byteLength > bufferLength)
+ if (offset > bufferLength || byteLength > bufferLength - offset)
return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range"));
Scoped<DataView> a(scope, scope.engine->memoryManager->allocate<DataView>());
@@ -163,7 +126,7 @@ ReturnedValue DataViewPrototype::method_get_byteLength(const FunctionObject *b,
if (!v)
return b->engine()->throwTypeError();
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->d()->buffer->hasDetachedArrayData())
return b->engine()->throwTypeError();
return Encode(v->d()->byteLength);
@@ -175,7 +138,7 @@ ReturnedValue DataViewPrototype::method_get_byteOffset(const FunctionObject *b,
if (!v)
return b->engine()->throwTypeError();
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->d()->buffer->hasDetachedArrayData())
return b->engine()->throwTypeError();
return Encode(v->d()->byteOffset);
@@ -191,13 +154,13 @@ ReturnedValue DataViewPrototype::method_getChar(const FunctionObject *b, const V
uint idx = ::toIndex(e, argc ? argv[0] : Value::undefinedValue());
if (e->hasException)
return Encode::undefined();
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->d()->buffer->hasDetachedArrayData())
return e->throwTypeError();
if (idx + sizeof(T) > v->d()->byteLength)
return e->throwRangeError(QStringLiteral("index out of range"));
idx += v->d()->byteOffset;
- T t = T(v->d()->buffer->data->data()[idx]);
+ T t = T(v->d()->buffer->constArrayData()[idx]);
return Encode((int)t);
}
@@ -212,7 +175,7 @@ ReturnedValue DataViewPrototype::method_get(const FunctionObject *b, const Value
uint idx = ::toIndex(e, argc ? argv[0] : Value::undefinedValue());
if (e->hasException)
return Encode::undefined();
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->d()->buffer->hasDetachedArrayData())
return e->throwTypeError();
if (idx + sizeof(T) > v->d()->byteLength)
return e->throwRangeError(QStringLiteral("index out of range"));
@@ -221,8 +184,8 @@ ReturnedValue DataViewPrototype::method_get(const FunctionObject *b, const Value
bool littleEndian = argc < 2 ? false : argv[1].toBoolean();
T t = littleEndian
- ? qFromLittleEndian<T>((uchar *)v->d()->buffer->data->data() + idx)
- : qFromBigEndian<T>((uchar *)v->d()->buffer->data->data() + idx);
+ ? qFromLittleEndian<T>((const uchar *)v->d()->buffer->constArrayData() + idx)
+ : qFromBigEndian<T>((const uchar *)v->d()->buffer->constArrayData() + idx);
return Encode(t);
}
@@ -237,7 +200,7 @@ ReturnedValue DataViewPrototype::method_getFloat(const FunctionObject *b, const
uint idx = ::toIndex(e, argc ? argv[0] : Value::undefinedValue());
if (e->hasException)
return Encode::undefined();
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->d()->buffer->hasDetachedArrayData())
return e->throwTypeError();
if (idx + sizeof(T) > v->d()->byteLength)
return e->throwRangeError(QStringLiteral("index out of range"));
@@ -252,8 +215,8 @@ ReturnedValue DataViewPrototype::method_getFloat(const FunctionObject *b, const
float f;
} u;
u.i = littleEndian
- ? qFromLittleEndian<uint>((uchar *)v->d()->buffer->data->data() + idx)
- : qFromBigEndian<uint>((uchar *)v->d()->buffer->data->data() + idx);
+ ? qFromLittleEndian<uint>((const uchar *)v->d()->buffer->constArrayData() + idx)
+ : qFromBigEndian<uint>((const uchar *)v->d()->buffer->constArrayData() + idx);
return Encode(u.f);
} else {
Q_ASSERT(sizeof(T) == 8);
@@ -262,8 +225,8 @@ ReturnedValue DataViewPrototype::method_getFloat(const FunctionObject *b, const
double d;
} u;
u.i = littleEndian
- ? qFromLittleEndian<quint64>((uchar *)v->d()->buffer->data->data() + idx)
- : qFromBigEndian<quint64>((uchar *)v->d()->buffer->data->data() + idx);
+ ? qFromLittleEndian<quint64>((const uchar *)v->d()->buffer->constArrayData() + idx)
+ : qFromBigEndian<quint64>((const uchar *)v->d()->buffer->constArrayData() + idx);
return Encode(u.d);
}
}
@@ -281,14 +244,14 @@ ReturnedValue DataViewPrototype::method_setChar(const FunctionObject *b, const V
int val = argc >= 2 ? argv[1].toInt32() : 0;
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->d()->buffer->hasDetachedArrayData())
return e->throwTypeError();
if (idx + sizeof(T) > v->d()->byteLength)
return e->throwRangeError(QStringLiteral("index out of range"));
idx += v->d()->byteOffset;
- v->d()->buffer->data->data()[idx] = (char)val;
+ v->d()->buffer->arrayData()[idx] = (char)val;
RETURN_UNDEFINED();
}
@@ -307,7 +270,7 @@ ReturnedValue DataViewPrototype::method_set(const FunctionObject *b, const Value
int val = argc >= 2 ? argv[1].toInt32() : 0;
bool littleEndian = argc < 3 ? false : argv[2].toBoolean();
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->d()->buffer->hasDetachedArrayData())
return e->throwTypeError();
if (idx + sizeof(T) > v->d()->byteLength)
@@ -316,9 +279,9 @@ ReturnedValue DataViewPrototype::method_set(const FunctionObject *b, const Value
if (littleEndian)
- qToLittleEndian<T>(val, (uchar *)v->d()->buffer->data->data() + idx);
+ qToLittleEndian<T>(val, (uchar *)v->d()->buffer->arrayData() + idx);
else
- qToBigEndian<T>(val, (uchar *)v->d()->buffer->data->data() + idx);
+ qToBigEndian<T>(val, (uchar *)v->d()->buffer->arrayData() + idx);
RETURN_UNDEFINED();
}
@@ -337,7 +300,7 @@ ReturnedValue DataViewPrototype::method_setFloat(const FunctionObject *b, const
double val = argc >= 2 ? argv[1].toNumber() : qt_qnan();
bool littleEndian = argc < 3 ? false : argv[2].toBoolean();
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->d()->buffer->hasDetachedArrayData())
return e->throwTypeError();
if (idx + sizeof(T) > v->d()->byteLength)
@@ -352,9 +315,9 @@ ReturnedValue DataViewPrototype::method_setFloat(const FunctionObject *b, const
} u;
u.f = val;
if (littleEndian)
- qToLittleEndian(u.i, (uchar *)v->d()->buffer->data->data() + idx);
+ qToLittleEndian(u.i, (uchar *)v->d()->buffer->arrayData() + idx);
else
- qToBigEndian(u.i, (uchar *)v->d()->buffer->data->data() + idx);
+ qToBigEndian(u.i, (uchar *)v->d()->buffer->arrayData() + idx);
} else {
Q_ASSERT(sizeof(T) == 8);
union {
@@ -363,9 +326,9 @@ ReturnedValue DataViewPrototype::method_setFloat(const FunctionObject *b, const
} u;
u.d = val;
if (littleEndian)
- qToLittleEndian(u.i, (uchar *)v->d()->buffer->data->data() + idx);
+ qToLittleEndian(u.i, (uchar *)v->d()->buffer->arrayData() + idx);
else
- qToBigEndian(u.i, (uchar *)v->d()->buffer->data->data() + idx);
+ qToBigEndian(u.i, (uchar *)v->d()->buffer->arrayData() + idx);
}
RETURN_UNDEFINED();
}
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index 199a6f9f80..ab2e1e589a 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4DATAVIEW_H
#define QV4DATAVIEW_H
@@ -69,7 +33,7 @@ struct DataViewCtor : FunctionObject {
Member(class, NoMark, uint, byteOffset)
DECLARE_HEAP_OBJECT(DataView, Object) {
- DECLARE_MARKOBJECTS(DataView);
+ DECLARE_MARKOBJECTS(DataView)
void init() { Object::init(); }
};
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index cc89947cec..6b64be3abb 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -1,83 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4dateobject_p.h"
-#include "qv4objectproto_p.h"
-#include "qv4scopedvalue_p.h"
#include "qv4runtime_p.h"
-#include "qv4string_p.h"
-#include "qv4jscall_p.h"
#include "qv4symbol_p.h"
#include <QtCore/QDebug>
#include <QtCore/QDateTime>
+#include <QtCore/private/qlocaltime_p.h>
#include <QtCore/QStringList>
-
-#include <time.h>
+#include <QtCore/QTimeZone>
#include <wtf/MathExtras.h>
-#if defined(Q_OS_LINUX) && QT_CONFIG(timezone) && !defined(Q_OS_ANDROID)
-/*
- See QTBUG-56899. Although we don't (yet) have a proper way to reset the
- system zone, the code below, that uses QTimeZone::systemTimeZone(), works
- adequately on Linux, when the TZ environment variable is changed.
- */
-#define USE_QTZ_SYSTEM_ZONE
-#endif
-
-#ifdef USE_QTZ_SYSTEM_ZONE
-#include <QtCore/QTimeZone>
-#else
-# ifdef Q_OS_WIN
-# include <windows.h>
-# else
-# ifndef Q_OS_VXWORKS
-# include <sys/time.h>
-# else
-# include "qplatformdefs.h"
-# endif
-# include <unistd.h> // for _POSIX_THREAD_SAFE_FUNCTIONS
-# endif
-#endif // USE_QTZ_SYSTEM_ZONE
-
using namespace QV4;
static const double HoursPerDay = 24.0;
@@ -323,7 +258,6 @@ static inline double MakeDate(double day, double time)
return day * msPerDay + time;
}
-#ifdef USE_QTZ_SYSTEM_ZONE
/*
ECMAScript specifies use of a fixed (current, standard) time-zone offset,
LocalTZA; and LocalTZA + DaylightSavingTA(t) is taken to be (see LocalTime and
@@ -339,37 +273,12 @@ static inline double MakeDate(double day, double time)
mean a whole day of DST offset for some zones, that have crossed the
international date line. This shall confuse client code.) The bug report
against the ECMAScript spec is https://github.com/tc39/ecma262/issues/725
+ and they've now changed the spec so that the following conforms to it ;^>
*/
-
static inline double DaylightSavingTA(double t, double localTZA) // t is a UTC time
{
- return QTimeZone::systemTimeZone().offsetFromUtc(
- QDateTime::fromMSecsSinceEpoch(qint64(t), Qt::UTC)) * 1e3 - localTZA;
-}
-#else
-// This implementation fails to take account of past changes in standard offset.
-static inline double DaylightSavingTA(double t, double /*localTZA*/)
-{
- struct tm tmtm;
-#if defined(Q_CC_MSVC)
- __time64_t tt = (__time64_t)(t / msPerSecond);
- // _localtime_64_s returns non-zero on failure
- if (_localtime64_s(&tmtm, &tt) != 0)
-#elif !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
- long int tt = (long int)(t / msPerSecond);
- if (!localtime_r((const time_t*) &tt, &tmtm))
-#else
- // Returns shared static data which may be overwritten at any time
- // (for MinGW/Windows localtime is luckily thread safe)
- long int tt = (long int)(t / msPerSecond);
- if (struct tm *tmtm_p = localtime((const time_t*) &tt))
- tmtm = *tmtm_p;
- else
-#endif
- return 0;
- return (tmtm.tm_isdst > 0) ? msPerHour : 0;
+ return QLocalTime::getUtcOffset(qint64(t)) * 1e3 - localTZA;
}
-#endif // USE_QTZ_SYSTEM_ZONE
static inline double LocalTime(double t, double localTZA)
{
@@ -393,7 +302,7 @@ static inline double currentTime()
static inline double TimeClip(double t)
{
- if (! qt_is_finite(t) || fabs(t) > 8.64e15)
+ if (!qt_is_finite(t) || fabs(t) > Date::MaxDateVal)
return qt_qnan();
// +0 looks weird, but is correct. See ES6 20.3.1.15. We must not return -0.
@@ -406,14 +315,14 @@ static inline double ParseString(const QString &s, double localTZA)
First, try the format defined in ECMA 262's "Date Time String Format";
only if that fails, fall back to QDateTime for parsing
- The defined string format is YYYY-MM-DDTHH:mm:ss.sssZ; the time (T and all
- after it) may be omitted; in each part, the second and later components
- are optional; and there's an extended syntax for negative and large
- positive years: +/-YYYYYY; the leading sign, even when +, isn't optional.
- If month or day is omitted, it is 01; if minute or second is omitted, it's
- 00; if milliseconds are omitted, they're 000.
+ The defined string format is yyyy-MM-ddTHH:mm:ss.zzzt; the time (T and all
+ after it) may be omitted. In each part, the second and later components
+ are optional. There's an extended syntax for negative and large positive
+ years: ±yyyyyy; the leading sign, even when +, isn't optional. If month
+ (MM) or day (dd) is omitted, it is 01; if minute (mm) or second (ss) is
+ omitted, it's 00; if milliseconds (zzz) are omitted, they're 000.
- When the time zone offset is absent, date-only forms are interpreted as
+ When the time zone offset (t) is absent, date-only forms are interpreted as
indicating a UTC time and date-time forms are interpreted in local time.
*/
@@ -431,7 +340,7 @@ static inline double ParseString(const QString &s, double localTZA)
};
const QChar *ch = s.constData();
- const QChar *end = ch + s.length();
+ const QChar *end = ch + s.size();
uint format = Year;
int current = 0;
@@ -452,16 +361,16 @@ static inline double ParseString(const QString &s, double localTZA)
bool seenZ = false; // Have seen zone, i.e. +HH:mm or literal Z.
bool error = false;
- if (*ch == '+' || *ch == '-') {
+ if (*ch == u'+' || *ch == u'-') {
extendedYear = true;
- if (*ch == '-')
+ if (*ch == u'-')
yearSign = -1;
++ch;
}
for (; ch <= end && !error && format != Done; ++ch) {
- if (*ch >= '0' && *ch <= '9') {
+ if (*ch >= u'0' && *ch <= u'9') {
current *= 10;
- current += ch->unicode() - '0';
+ current += ch->unicode() - u'0';
++currentSize;
} else { // other char, delimits field
switch (format) {
@@ -507,12 +416,12 @@ static inline double ParseString(const QString &s, double localTZA)
error = (currentSize != 2) || current >= 60;
break;
}
- if (*ch == 'T') {
+ if (*ch == u'T') {
if (format >= Hour)
error = true;
format = Hour;
seenT = true;
- } else if (*ch == '-') {
+ } else if (*ch == u'-') {
if (format < Day)
++format;
else if (format < Minute)
@@ -524,19 +433,19 @@ static inline double ParseString(const QString &s, double localTZA)
offsetSign = -1;
format = TimezoneHour;
}
- } else if (*ch == ':') {
+ } else if (*ch == u':') {
if (format != Hour && format != Minute && format != TimezoneHour)
error = true;
++format;
- } else if (*ch == '.') {
+ } else if (*ch == u'.') {
if (format != Second)
error = true;
++format;
- } else if (*ch == '+') {
+ } else if (*ch == u'+') {
if (seenZ || format < Minute || format >= TimezoneHour)
error = true;
format = TimezoneHour;
- } else if (*ch == 'Z') {
+ } else if (*ch == u'Z') {
if (seenZ || format < Minute || format >= TimezoneHour)
error = true;
else
@@ -614,13 +523,16 @@ static inline double ParseString(const QString &s, double localTZA)
QStringLiteral("d MMMM, yyyy"),
QStringLiteral("d MMMM, yyyy hh:mm"),
QStringLiteral("d MMMM, yyyy hh:mm:ss"),
+
+ // ISO 8601 and RFC 2822 with a GMT as prefix on its offset, or GMT as zone.
+ QStringLiteral("yyyy-MM-dd hh:mm:ss t"),
+ QStringLiteral("ddd, d MMM yyyy hh:mm:ss t"),
};
for (const QString &format : formats) {
dt = format.indexOf(QLatin1String("hh:mm")) < 0
- ? QDateTime(QDate::fromString(s, format),
- QTime(0, 0, 0), Qt::UTC)
- : QDateTime::fromString(s, format); // as local time
+ ? QDate::fromString(s, format).startOfDay(QTimeZone::UTC)
+ : QDateTime::fromString(s, format); // as local time
if (dt.isValid())
break;
}
@@ -633,21 +545,21 @@ static inline double ParseString(const QString &s, double localTZA)
/*!
\internal
- Converts the ECMA Date value \tt (in UTC form) to QDateTime
+ Converts the ECMA Date value \a t (in UTC form) to QDateTime
according to \a spec.
*/
-static inline QDateTime ToDateTime(double t, Qt::TimeSpec spec)
+static inline QDateTime ToDateTime(double t, QTimeZone zone)
{
if (std::isnan(t))
- return QDateTime();
- return QDateTime::fromMSecsSinceEpoch(t, Qt::UTC).toTimeSpec(spec);
+ return QDateTime().toTimeZone(zone);
+ return QDateTime::fromMSecsSinceEpoch(t, zone);
}
static inline QString ToString(double t, double localTZA)
{
if (std::isnan(t))
return QStringLiteral("Invalid Date");
- QString str = ToDateTime(t, Qt::LocalTime).toString() + QLatin1String(" GMT");
+ QString str = ToDateTime(t, QTimeZone::LocalTime).toString() + QLatin1String(" GMT");
double tzoffset = localTZA + DaylightSavingTA(t, localTZA);
if (tzoffset) {
int hours = static_cast<int>(::fabs(tzoffset) / 1000 / 60 / 60);
@@ -667,74 +579,78 @@ static inline QString ToUTCString(double t)
{
if (std::isnan(t))
return QStringLiteral("Invalid Date");
- return ToDateTime(t, Qt::UTC).toString();
+ return ToDateTime(t, QTimeZone::UTC).toString();
}
static inline QString ToDateString(double t)
{
- return ToDateTime(t, Qt::LocalTime).date().toString();
+ return ToDateTime(t, QTimeZone::LocalTime).date().toString();
}
static inline QString ToTimeString(double t)
{
- return ToDateTime(t, Qt::LocalTime).time().toString();
+ return ToDateTime(t, QTimeZone::LocalTime).time().toString();
}
static inline QString ToLocaleString(double t)
{
- return ToDateTime(t, Qt::LocalTime).toString(Qt::DefaultLocaleShortDate);
+ return QLocale().toString(ToDateTime(t, QTimeZone::LocalTime), QLocale::ShortFormat);
}
static inline QString ToLocaleDateString(double t)
{
- return ToDateTime(t, Qt::LocalTime).date().toString(Qt::DefaultLocaleShortDate);
+ return QLocale().toString(ToDateTime(t, QTimeZone::LocalTime).date(), QLocale::ShortFormat);
}
static inline QString ToLocaleTimeString(double t)
{
- return ToDateTime(t, Qt::LocalTime).time().toString(Qt::DefaultLocaleShortDate);
+ return QLocale().toString(ToDateTime(t, QTimeZone::LocalTime).time(), QLocale::ShortFormat);
}
static double getLocalTZA()
{
-#ifndef Q_OS_WIN
- tzset();
-#endif
-#ifdef USE_QTZ_SYSTEM_ZONE
- // TODO: QTimeZone::resetSystemTimeZone(), see QTBUG-56899 and comment above.
- // Standard offset, with no daylight-savings adjustment, in ms:
- return QTimeZone::systemTimeZone().standardTimeOffset(QDateTime::currentDateTime()) * 1e3;
-#else
-# ifdef Q_OS_WIN
- TIME_ZONE_INFORMATION tzInfo;
- GetTimeZoneInformation(&tzInfo);
- return -tzInfo.Bias * 60.0 * 1000.0;
-# else
- struct tm t;
- time_t curr;
- time(&curr);
- localtime_r(&curr, &t); // Wrong: includes DST offset
- time_t locl = mktime(&t);
- gmtime_r(&curr, &t);
- time_t globl = mktime(&t);
- return (double(locl) - double(globl)) * 1000.0;
-# endif
-#endif // USE_QTZ_SYSTEM_ZONE
+ return QLocalTime::getCurrentStandardUtcOffset() * 1e3;
}
DEFINE_OBJECT_VTABLE(DateObject);
-void Heap::DateObject::init(const QDateTime &date)
+quint64 Date::encode(double value)
+{
+ if (std::isnan(value) || fabs(value) > MaxDateVal)
+ return InvalidDateVal;
+
+ // Do the addition in qint64. This way we won't overflow if value is negative
+ // and we will round value in the right direction.
+ // We know we can do this because we know we have more than one bit left in quint64.
+ const quint64 encoded = quint64(qint64(value) + qint64(MaxDateVal));
+
+ return encoded + Extra;
+}
+
+quint64 Date::encode(const QDateTime &dateTime)
+{
+ return encode(dateTime.isValid() ? dateTime.toMSecsSinceEpoch() : qt_qnan());
+}
+
+void Date::init(double value)
+{
+ storage = encode(value);
+}
+
+void Date::init(const QDateTime &when)
+{
+ storage = encode(when) | HasQDate | HasQTime;
+}
+
+void Date::init(QDate date)
{
- Object::init();
- this->date = date.isValid() ? TimeClip(date.toMSecsSinceEpoch()) : qt_qnan();
+ storage = encode(date.startOfDay(QTimeZone::UTC)) | HasQDate;
}
-void Heap::DateObject::init(const QTime &time)
+void Date::init(QTime time, ExecutionEngine *engine)
{
- Object::init();
if (!time.isValid()) {
- date = qt_qnan();
+ storage = encode(qt_qnan()) | HasQTime;
return;
}
@@ -754,12 +670,98 @@ void Heap::DateObject::init(const QTime &time)
*/
static const double d = MakeDay(1971, 3, 1);
double t = MakeTime(time.hour(), time.minute(), time.second(), time.msec());
- date = TimeClip(UTC(MakeDate(d, t), internalClass->engine->localTZA));
+ storage = encode(UTC(MakeDate(d, t), engine->localTZA)) | HasQTime;
+}
+
+QDate Date::toQDate() const
+{
+ return toQDateTime().date();
+}
+
+QTime Date::toQTime() const
+{
+ return toQDateTime().time();
+}
+
+QDateTime Date::toQDateTime() const
+{
+ return ToDateTime(operator double(), QTimeZone::LocalTime);
+}
+
+QVariant Date::toVariant() const
+{
+ switch (storage & (HasQDate | HasQTime)) {
+ case HasQDate:
+ return toQDate();
+ case HasQTime:
+ return toQTime();
+ case (HasQDate | HasQTime):
+ return toQDateTime();
+ default:
+ return QVariant();
+ }
}
QDateTime DateObject::toQDateTime() const
{
- return ToDateTime(date(), Qt::LocalTime);
+ return d()->toQDateTime();
+}
+
+QString DateObject::toString() const
+{
+ return ToString(d()->date(), engine()->localTZA);
+}
+
+QString DateObject::dateTimeToString(const QDateTime &dateTime, ExecutionEngine *engine)
+{
+ if (!dateTime.isValid())
+ return QStringLiteral("Invalid Date");
+ return ToString(TimeClip(dateTime.toMSecsSinceEpoch()), engine->localTZA);
+}
+
+double DateObject::dateTimeToNumber(const QDateTime &dateTime)
+{
+ if (!dateTime.isValid())
+ return qQNaN();
+ return TimeClip(dateTime.toMSecsSinceEpoch());
+}
+
+QDateTime DateObject::stringToDateTime(const QString &string, ExecutionEngine *engine)
+{
+ return ToDateTime(ParseString(string, engine->localTZA), QTimeZone::LocalTime);
+}
+
+QDateTime DateObject::timestampToDateTime(double timestamp, QTimeZone zone)
+{
+ return ToDateTime(timestamp, zone);
+}
+
+double DateObject::componentsToTimestamp(
+ double year, double month, double day, double hours,
+ double mins, double secs, double ms, ExecutionEngine *v4)
+{
+ if (year >= 0 && year <= 99)
+ year += 1900;
+ const double t = MakeDate(MakeDay(year, month, day), MakeTime(hours, mins, secs, ms));
+ return UTC(t, v4->localTZA);
+}
+
+QDate DateObject::dateTimeToDate(const QDateTime &dateTime)
+{
+ // If the Date object was parse()d from a string with no time part
+ // or zone specifier it's really the UTC start of the relevant day,
+ // but it's here represented as a local time, which may fall in the
+ // preceding day. See QTBUG-92466 for the gory details.
+ const auto utc = dateTime.toUTC();
+ if (utc.date() != dateTime.date() && utc.addSecs(-1).date() == dateTime.date())
+ return utc.date();
+
+ // This may, of course, be The Wrong Thing if the date was
+ // constructed as a full local date-time that happens to coincide
+ // with the start of a UTC day; however, that would be an odd value
+ // to give to something that, apparently, someone thinks belongs in
+ // a QDate.
+ return dateTime.date();
}
DEFINE_OBJECT_VTABLE(DateCtor);
@@ -788,25 +790,22 @@ ReturnedValue DateCtor::virtualCallAsConstructor(const FunctionObject *that, con
if (String *s = arg->stringValue())
t = ParseString(s->toQString(), v4->localTZA);
else
- t = TimeClip(arg->toNumber());
+ t = arg->toNumber();
}
}
else { // d.argc > 1
- double year = argv[0].toNumber();
- double month = argv[1].toNumber();
- double day = argc >= 3 ? argv[2].toNumber() : 1;
- double hours = argc >= 4 ? argv[3].toNumber() : 0;
- double mins = argc >= 5 ? argv[4].toNumber() : 0;
- double secs = argc >= 6 ? argv[5].toNumber() : 0;
- double ms = argc >= 7 ? argv[6].toNumber() : 0;
- if (year >= 0 && year <= 99)
- year += 1900;
- t = MakeDate(MakeDay(year, month, day), MakeTime(hours, mins, secs, ms));
- t = TimeClip(UTC(t, v4->localTZA));
+ const double year = argv[0].toNumber();
+ const double month = argv[1].toNumber();
+ const double day = argc >= 3 ? argv[2].toNumber() : 1;
+ const double hours = argc >= 4 ? argv[3].toNumber() : 0;
+ const double mins = argc >= 5 ? argv[4].toNumber() : 0;
+ const double secs = argc >= 6 ? argv[5].toNumber() : 0;
+ const double ms = argc >= 7 ? argv[6].toNumber() : 0;
+ t = DateObject::componentsToTimestamp(year, month, day, hours, mins, secs, ms, v4);
}
- ReturnedValue o = Encode(v4->newDateObject(Value::fromDouble(t)));
+ ReturnedValue o = Encode(v4->newDateObject(t));
if (!newTarget)
return o;
Scope scope(v4);
@@ -1179,7 +1178,7 @@ ReturnedValue DatePrototype::method_setTime(const FunctionObject *b, const Value
double t = argc ? argv[0].toNumber() : qt_qnan();
if (v4->hasException)
return QV4::Encode::undefined();
- self->setDate(TimeClip(t));
+ self->setDate(t);
return Encode(self->date());
}
@@ -1196,7 +1195,7 @@ ReturnedValue DatePrototype::method_setMilliseconds(const FunctionObject *b, con
double ms = argc ? argv[0].toNumber() : qt_qnan();
if (v4->hasException)
return QV4::Encode::undefined();
- self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)), v4->localTZA)));
+ self->setDate(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)), v4->localTZA));
return Encode(self->date());
}
@@ -1213,7 +1212,7 @@ ReturnedValue DatePrototype::method_setUTCMilliseconds(const FunctionObject *b,
double ms = argc ? argv[0].toNumber() : qt_qnan();
if (v4->hasException)
return QV4::Encode::undefined();
- self->setDate(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))));
+ self->setDate(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)));
return Encode(self->date());
}
@@ -1233,7 +1232,7 @@ ReturnedValue DatePrototype::method_setSeconds(const FunctionObject *b, const Va
double ms = (argc < 2) ? msFromTime(t) : argv[1].toNumber();
if (v4->hasException)
return QV4::Encode::undefined();
- t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)), v4->localTZA));
+ t = UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)), v4->localTZA);
self->setDate(t);
return Encode(self->date());
}
@@ -1248,7 +1247,7 @@ ReturnedValue DatePrototype::method_setUTCSeconds(const FunctionObject *b, const
double t = self->date();
double sec = argc ? argv[0].toNumber() : qt_qnan();
double ms = (argc < 2) ? msFromTime(t) : argv[1].toNumber();
- t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)));
+ t = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms));
self->setDate(t);
return Encode(self->date());
}
@@ -1272,7 +1271,7 @@ ReturnedValue DatePrototype::method_setMinutes(const FunctionObject *b, const Va
double ms = (argc < 3) ? msFromTime(t) : argv[2].toNumber();
if (v4->hasException)
return QV4::Encode::undefined();
- t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)), v4->localTZA));
+ t = UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)), v4->localTZA);
self->setDate(t);
return Encode(self->date());
}
@@ -1288,7 +1287,7 @@ ReturnedValue DatePrototype::method_setUTCMinutes(const FunctionObject *b, const
double min = argc ? argv[0].toNumber() : qt_qnan();
double sec = (argc < 2) ? SecFromTime(t) : argv[1].toNumber();
double ms = (argc < 3) ? msFromTime(t) : argv[2].toNumber();
- t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)));
+ t = MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms));
self->setDate(t);
return Encode(self->date());
}
@@ -1315,7 +1314,7 @@ ReturnedValue DatePrototype::method_setHours(const FunctionObject *b, const Valu
double ms = (argc < 4) ? msFromTime(t) : argv[3].toNumber();
if (v4->hasException)
return QV4::Encode::undefined();
- t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)), v4->localTZA));
+ t = UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)), v4->localTZA);
self->setDate(t);
return Encode(self->date());
}
@@ -1332,7 +1331,7 @@ ReturnedValue DatePrototype::method_setUTCHours(const FunctionObject *b, const V
double min = (argc < 2) ? MinFromTime(t) : argv[1].toNumber();
double sec = (argc < 3) ? SecFromTime(t) : argv[2].toNumber();
double ms = (argc < 4) ? msFromTime(t) : argv[3].toNumber();
- t = TimeClip(MakeDate(Day(t), MakeTime(hour, min, sec, ms)));
+ t = MakeDate(Day(t), MakeTime(hour, min, sec, ms));
self->setDate(t);
return Encode(self->date());
}
@@ -1350,7 +1349,7 @@ ReturnedValue DatePrototype::method_setDate(const FunctionObject *b, const Value
double date = argc ? argv[0].toNumber() : qt_qnan();
if (v4->hasException)
return QV4::Encode::undefined();
- t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)), v4->localTZA));
+ t = UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)), v4->localTZA);
self->setDate(t);
return Encode(self->date());
}
@@ -1368,7 +1367,7 @@ ReturnedValue DatePrototype::method_setUTCDate(const FunctionObject *b, const Va
double date = argc ? argv[0].toNumber() : qt_qnan();
if (v4->hasException)
return QV4::Encode::undefined();
- t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)));
+ t = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t));
self->setDate(t);
return Encode(self->date());
}
@@ -1389,7 +1388,7 @@ ReturnedValue DatePrototype::method_setMonth(const FunctionObject *b, const Valu
double date = (argc < 2) ? DateFromTime(t) : argv[1].toNumber();
if (v4->hasException)
return QV4::Encode::undefined();
- t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)), v4->localTZA));
+ t = UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)), v4->localTZA);
self->setDate(t);
return Encode(self->date());
}
@@ -1404,7 +1403,7 @@ ReturnedValue DatePrototype::method_setUTCMonth(const FunctionObject *b, const V
double t = self->date();
double month = argc ? argv[0].toNumber() : qt_qnan();
double date = (argc < 2) ? DateFromTime(t) : argv[1].toNumber();
- t = TimeClip(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)));
+ t = MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t));
self->setDate(t);
return Encode(self->date());
}
@@ -1430,7 +1429,6 @@ ReturnedValue DatePrototype::method_setYear(const FunctionObject *b, const Value
year += 1900;
r = MakeDay(year, MonthFromTime(t), DateFromTime(t));
r = UTC(MakeDate(r, TimeWithinDay(t)), v4->localTZA);
- r = TimeClip(r);
}
self->setDate(r);
return Encode(self->date());
@@ -1447,7 +1445,7 @@ ReturnedValue DatePrototype::method_setUTCFullYear(const FunctionObject *b, cons
double year = argc ? argv[0].toNumber() : qt_qnan();
double month = (argc < 2) ? MonthFromTime(t) : argv[1].toNumber();
double date = (argc < 3) ? DateFromTime(t) : argv[2].toNumber();
- t = TimeClip(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)));
+ t = MakeDate(MakeDay(year, month, date), TimeWithinDay(t));
self->setDate(t);
return Encode(self->date());
}
@@ -1473,7 +1471,7 @@ ReturnedValue DatePrototype::method_setFullYear(const FunctionObject *b, const V
double date = (argc < 3) ? DateFromTime(t) : argv[2].toNumber();
if (v4->hasException)
return QV4::Encode::undefined();
- t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)), v4->localTZA));
+ t = UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)), v4->localTZA);
self->setDate(t);
return Encode(self->date());
}
@@ -1561,7 +1559,7 @@ ReturnedValue DatePrototype::method_toJSON(const FunctionObject *b, const Value
if (!toIso)
return v4->throwTypeError();
- return toIso->call(O, nullptr, 0);
+ return checkedResult(v4, toIso->call(O, nullptr, 0));
}
ReturnedValue DatePrototype::method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index a87eb92caf..7debcff4e9 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4DATEOBJECT_P_H
#define QV4DATEOBJECT_P_H
@@ -52,7 +16,9 @@
#include "qv4object_p.h"
#include "qv4functionobject_p.h"
+#include "qv4referenceobject_p.h"
#include <QtCore/private/qnumeric_p.h>
+#include <QtCore/qdatetime.h>
QT_BEGIN_NAMESPACE
@@ -60,24 +26,165 @@ class QDateTime;
namespace QV4 {
+struct Date
+{
+ static constexpr quint64 MaxDateVal = 8.64e15;
+
+ void init() { storage = InvalidDateVal; }
+ void init(double value);
+ void init(const QDateTime &dateTime);
+ void init(QDate date);
+ void init(QTime time, ExecutionEngine *engine);
+
+ Date &operator=(double value)
+ {
+ storage = (storage & (HasQDate | HasQTime)) | encode(value);
+ return *this;
+ }
+
+ operator double() const
+ {
+ const quint64 raw = (storage & ~(HasQDate | HasQTime));
+ if (raw == 0)
+ return qt_qnan();
+
+ if (raw > MaxDateVal)
+ return double(raw - MaxDateVal - Extra);
+
+ return double(raw) - double(MaxDateVal) - double(Extra);
+ }
+
+ QDate toQDate() const;
+ QTime toQTime() const;
+ QDateTime toQDateTime() const;
+ QVariant toVariant() const;
+
+ template<typename Function>
+ bool withStoragePointer(Function function)
+ {
+ switch (storage & (HasQDate | HasQTime)) {
+ case HasQDate: {
+ QDate date = toQDate();
+ return function(&date);
+ }
+ case HasQTime: {
+ QTime time = toQTime();
+ return function(&time);
+ }
+ case (HasQTime | HasQDate): {
+ QDateTime dateTime = toQDateTime();
+ return function(&dateTime);
+ }
+ default:
+ return false;
+ }
+ }
+
+private:
+ static constexpr quint64 InvalidDateVal = 0;
+ static constexpr quint64 Extra = 1;
+ static constexpr quint64 HasQDate = 1ull << 63;
+ static constexpr quint64 HasQTime = 1ull << 62;
+
+ // Make all our dates fit into quint64, leaving space for the flags
+ static_assert(((MaxDateVal * 2 + Extra) & (HasQDate | HasQTime)) == 0ull);
+
+ static quint64 encode(double value);
+ static quint64 encode(const QDateTime &dateTime);
+
+ quint64 storage;
+};
+
namespace Heap {
-struct DateObject : Object {
+#define DateObjectMembers(class, Member)
+DECLARE_HEAP_OBJECT(DateObject, ReferenceObject) {
+ DECLARE_MARKOBJECTS(DateObject);
+
+ void doSetLocation()
+ {
+ if (CppStackFrame *frame = internalClass->engine->currentStackFrame)
+ setLocation(frame->v4Function, frame->statementNumber());
+ }
+
void init()
{
- Object::init();
- date = qt_qnan();
+ ReferenceObject::init(nullptr, -1, {});
+ m_date.init();
+ }
+
+ void init(double dateTime)
+ {
+ ReferenceObject::init(nullptr, -1, {});
+ m_date.init(dateTime);
+ }
+
+ void init(const QDateTime &dateTime)
+ {
+ ReferenceObject::init(nullptr, -1, {});
+ m_date.init(dateTime);
}
- void init(const Value &date)
+ void init(const QDateTime &dateTime, Heap::Object *parent, int property, Flags flags)
+ {
+ ReferenceObject::init(parent, property, flags | EnforcesLocation);
+ doSetLocation();
+ m_date.init(dateTime);
+ };
+
+ void init(QDate date, Heap::Object *parent, int property, Flags flags)
{
- Object::init();
- this->date = date.toNumber();
+ ReferenceObject::init(parent, property, flags | EnforcesLocation);
+ doSetLocation();
+ m_date.init(date);
+ };
+
+ void init(QTime time, Heap::Object *parent, int property, Flags flags)
+ {
+ ReferenceObject::init(parent, property, flags | EnforcesLocation);
+ doSetLocation();
+ m_date.init(time, internalClass->engine);
+ };
+
+ void setDate(double newDate)
+ {
+ m_date = newDate;
+ if (isAttachedToProperty())
+ writeBack();
+ }
+
+ double date() const
+ {
+ return m_date;
+ }
+
+ QVariant toVariant() const { return m_date.toVariant(); }
+ QDateTime toQDateTime() const { return m_date.toQDateTime(); }
+
+private:
+ bool writeBack()
+ {
+ if (!object() || !canWriteBack())
+ return false;
+
+ QV4::Scope scope(internalClass->engine);
+ QV4::ScopedObject o(scope, object());
+
+ int flags = 0;
+ int status = -1;
+ if (isVariant()) {
+ QVariant variant = toVariant();
+ void *a[] = { &variant, nullptr, &status, &flags };
+ return o->metacall(QMetaObject::WriteProperty, property(), a);
+ }
+
+ return m_date.withStoragePointer([&](void *storagePointer) {
+ void *a[] = { storagePointer, nullptr, &status, &flags };
+ return o->metacall(QMetaObject::WriteProperty, property(), a);
+ });
}
- void init(const QDateTime &date);
- void init(const QTime &time);
- double date;
+ Date m_date;
};
@@ -87,16 +194,26 @@ struct DateCtor : FunctionObject {
}
-struct DateObject: Object {
- V4_OBJECT2(DateObject, Object)
+struct DateObject: ReferenceObject {
+ V4_OBJECT2(DateObject, ReferenceObject)
Q_MANAGED_TYPE(DateObject)
V4_PROTOTYPE(datePrototype)
+ void setDate(double date) { d()->setDate(date); }
+ double date() const { return d()->date(); }
- double date() const { return d()->date; }
- void setDate(double date) { d()->date = date; }
+ Q_QML_EXPORT QDateTime toQDateTime() const;
+ QString toString() const;
- Q_QML_PRIVATE_EXPORT QDateTime toQDateTime() const;
+ static QString dateTimeToString(const QDateTime &dateTime, ExecutionEngine *engine);
+ static double dateTimeToNumber(const QDateTime &dateTime);
+ static QDate dateTimeToDate(const QDateTime &dateTime);
+ static QDateTime stringToDateTime(const QString &string, ExecutionEngine *engine);
+ static QDateTime timestampToDateTime(double timestamp, QTimeZone zone = QTimeZone::LocalTime);
+ static double componentsToTimestamp(
+ double year, double month, double day,
+ double hours, double mins, double secs, double ms,
+ ExecutionEngine *v4);
};
template<>
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp
new file mode 100644
index 0000000000..57ddaaa2f1
--- /dev/null
+++ b/src/qml/jsruntime/qv4debugging.cpp
@@ -0,0 +1,17 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qv4debugging_p.h"
+
+#if QT_CONFIG(qml_debug)
+
+QT_BEGIN_NAMESPACE
+
+QV4::Debugging::Debugger::~Debugger()
+ = default;
+
+QT_END_NAMESPACE
+
+#include "moc_qv4debugging_p.cpp"
+
+#endif // QT_CONFIG(qml_debug)
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index 52263105fa..b80567b339 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4DEBUGGING_H
#define QV4DEBUGGING_H
@@ -51,8 +15,8 @@
// We mean it.
//
-#include "qv4global_p.h"
-#include <private/qv4staticvalue_p.h>
+#include <QtQml/private/qv4global_p.h>
+#include <QtQml/private/qv4staticvalue_p.h>
#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
@@ -79,7 +43,7 @@ class Q_QML_EXPORT Debugger : public QObject
Q_OBJECT
public:
- ~Debugger() override {}
+ ~Debugger() override;
virtual bool pauseAtNextOpportunity() const = 0;
virtual void maybeBreakAtInstruction() = 0;
virtual void enteringFunction() = 0;
diff --git a/src/qml/qml/v8/qv4domerrors.cpp b/src/qml/jsruntime/qv4domerrors.cpp
index 7ad37d098f..cd26858aa3 100644
--- a/src/qml/qml/v8/qv4domerrors.cpp
+++ b/src/qml/jsruntime/qv4domerrors.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4domerrors_p.h"
#include "qv4object_p.h"
diff --git a/src/qml/jsruntime/qv4domerrors_p.h b/src/qml/jsruntime/qv4domerrors_p.h
new file mode 100644
index 0000000000..2238418404
--- /dev/null
+++ b/src/qml/jsruntime/qv4domerrors_p.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QV8DOMERRORS_P_H
+#define QV8DOMERRORS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+// From DOM-Level-3-Core spec
+// http://www.w3.org/TR/DOM-Level-3-Core/core.html
+#define DOMEXCEPTION_INDEX_SIZE_ERR 1
+#define DOMEXCEPTION_DOMSTRING_SIZE_ERR 2
+#define DOMEXCEPTION_HIERARCHY_REQUEST_ERR 3
+#define DOMEXCEPTION_WRONG_DOCUMENT_ERR 4
+#define DOMEXCEPTION_INVALID_CHARACTER_ERR 5
+#define DOMEXCEPTION_NO_DATA_ALLOWED_ERR 6
+#define DOMEXCEPTION_NO_MODIFICATION_ALLOWED_ERR 7
+#define DOMEXCEPTION_NOT_FOUND_ERR 8
+#define DOMEXCEPTION_NOT_SUPPORTED_ERR 9
+#define DOMEXCEPTION_INUSE_ATTRIBUTE_ERR 10
+#define DOMEXCEPTION_INVALID_STATE_ERR 11
+#define DOMEXCEPTION_SYNTAX_ERR 12
+#define DOMEXCEPTION_INVALID_MODIFICATION_ERR 13
+#define DOMEXCEPTION_NAMESPACE_ERR 14
+#define DOMEXCEPTION_INVALID_ACCESS_ERR 15
+#define DOMEXCEPTION_VALIDATION_ERR 16
+#define DOMEXCEPTION_TYPE_MISMATCH_ERR 17
+
+#define THROW_DOM(error, string) { \
+ QV4::ScopedValue v(scope, scope.engine->newString(QStringLiteral(string))); \
+ QV4::ScopedObject ex(scope, scope.engine->newErrorObject(v)); \
+ ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, QV4::Value::fromInt32(error))); \
+ return scope.engine->throwError(ex); \
+}
+
+namespace QV4 {
+struct ExecutionEngine;
+}
+
+
+void qt_add_domexceptions(QV4::ExecutionEngine *e);
+
+QT_END_NAMESPACE
+
+#endif // QV8DOMERRORS_P_H
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 590cebfa7c..a2a2e99a01 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qv4engine_p.h>
#include <private/qv4compileddata_p.h>
@@ -50,6 +14,8 @@
#if QT_CONFIG(regularexpression)
#include <QRegularExpression>
#endif
+#include <QtCore/QTimeZone>
+#include <QtCore/qiterable.h>
#include <qv4qmlcontext_p.h>
#include <qv4value_p.h>
@@ -89,13 +55,13 @@
#include "qv4reflect_p.h"
#include "qv4proxy_p.h"
#include "qv4stackframe_p.h"
+#include "qv4stacklimits_p.h"
#include "qv4atomics_p.h"
-
-#if QT_CONFIG(qml_sequence_object)
+#include "qv4urlobject_p.h"
+#include "qv4variantobject_p.h"
#include "qv4sequenceobject_p.h"
-#endif
-
#include "qv4qobjectwrapper_p.h"
+#include "qv4qmetaobjectwrapper_p.h"
#include "qv4memberdata_p.h"
#include "qv4arraybuffer_p.h"
#include "qv4dataview_p.h"
@@ -118,71 +84,250 @@
#endif
#include <private/qv4sqlerrors_p.h>
#include <qqmlfile.h>
+#include <qmetatype.h>
+#include <qsequentialiterable.h>
-#if USE(PTHREADS)
-# include <pthread.h>
-#if !defined(Q_OS_INTEGRITY)
-# include <sys/resource.h>
-#endif
-#if HAVE(PTHREAD_NP_H)
-# include <pthread_np.h>
-#endif
-#endif
+#include <private/qqmlengine_p.h>
#ifdef V4_USE_VALGRIND
#include <valgrind/memcheck.h>
#endif
-Q_DECLARE_METATYPE(QList<int>)
-
QT_BEGIN_NAMESPACE
+DEFINE_BOOL_CONFIG_OPTION(disableDiskCache, QML_DISABLE_DISK_CACHE);
+DEFINE_BOOL_CONFIG_OPTION(forceDiskCache, QML_FORCE_DISK_CACHE);
+
using namespace QV4;
+// While engineSerial is odd the statics haven't been initialized. The engine that receives ID 1
+// initializes the statics and sets engineSerial to 2 afterwards.
+// Each engine does engineSerial.fetchAndAddOrdered(2) on creation. Therefore engineSerial stays
+// odd while the statics are being initialized, and stays even afterwards.
+// Any further engines created while the statics are being initialized busy-wait until engineSerial
+// is even.
static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1);
+int ExecutionEngine::s_maxCallDepth = -1;
+int ExecutionEngine::s_jitCallCountThreshold = 3;
+int ExecutionEngine::s_maxJSStackSize = 4 * 1024 * 1024;
+int ExecutionEngine::s_maxGCStackSize = 2 * 1024 * 1024;
ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int)
{
return b->engine()->throwTypeError();
}
-qint32 ExecutionEngine::maxCallDepth = -1;
template <typename ReturnType>
ReturnType convertJSValueToVariantType(const QJSValue &value)
{
- return value.toVariant().value<ReturnType>();
+ const QVariant variant = value.toVariant();
+ return variant.metaType() == QMetaType::fromType<QJSValue>()
+ ? ReturnType()
+ : variant.value<ReturnType>();
}
-static void saveJSValue(QDataStream &stream, const void *data)
+struct JSArrayIterator {
+ QJSValue const* data;
+ quint32 index;
+};
+
+namespace {
+void createNewIteratorIfNonExisting(void **iterator) {
+ if (*iterator == nullptr)
+ *iterator = new JSArrayIterator;
+}
+}
+
+static QtMetaContainerPrivate::QMetaSequenceInterface emptySequenceInterface()
{
- const QJSValue *jsv = reinterpret_cast<const QJSValue *>(data);
- quint32 isNullOrUndefined = 0;
- if (jsv->isNull())
- isNullOrUndefined |= 0x1;
- if (jsv->isUndefined())
- isNullOrUndefined |= 0x2;
- stream << isNullOrUndefined;
- if (!isNullOrUndefined)
- reinterpret_cast<const QJSValue*>(data)->toVariant().save(stream);
+ // set up some functions so that non-array QSequentialIterables do not crash
+ // but instead appear as an empty sequence
+
+ using namespace QtMetaContainerPrivate;
+ QMetaSequenceInterface iface;
+ iface.sizeFn = [](const void *) { return qsizetype(0); };
+ iface.valueAtIndexFn = [](const void *, qsizetype, void *) {};
+ iface.createIteratorFn = [](void *, QMetaSequenceInterface::Position) -> void * {
+ return nullptr;
+ };
+ iface.advanceIteratorFn = [](void *, qsizetype) {};
+ iface.compareIteratorFn = [](const void *, const void *) {
+ return true; /*all iterators are nullptr*/
+ };
+ iface.destroyIteratorFn = [](const void *) {};
+ iface.copyIteratorFn = [](void *, const void *) {};
+ iface.diffIteratorFn = [](const void *, const void *) { return qsizetype(0); };
+ return iface;
}
-static void restoreJSValue(QDataStream &stream, void *data)
+static QtMetaContainerPrivate::QMetaSequenceInterface sequenceInterface()
{
- QJSValue *jsv = reinterpret_cast<QJSValue*>(data);
+ using namespace QtMetaContainerPrivate;
+ QMetaSequenceInterface iface;
+ iface.valueMetaType = QtPrivate::qMetaTypeInterfaceForType<QVariant>();
+ iface.iteratorCapabilities = RandomAccessCapability | BiDirectionalCapability | ForwardCapability;
+ iface.addRemoveCapabilities = CanAddAtEnd;
+ iface.sizeFn = [](const void *p) -> qsizetype {
+ return static_cast<QJSValue const *>(p)->property(QString::fromLatin1("length")).toInt();
+ };
+
+ /* Lifetime management notes:
+ * valueAtIndexFn and valueAtIteratorFn return a pointer to a JSValue allocated via
+ * QMetaType::create Because we set QVariantConstructionFlags::ShouldDeleteVariantData,
+ * QSequentialIterable::at and QSequentialIterable::operator*() will free that memory
+ */
+
+ iface.valueAtIndexFn = [](const void *iterable, qsizetype index, void *dataPtr) -> void {
+ auto *data = static_cast<QVariant *>(dataPtr);
+ *data = static_cast<QJSValue const *>(iterable)->property(quint32(index)).toVariant();
+ };
+ iface.createIteratorFn = [](void *iterable, QMetaSequenceInterface::Position pos) {
+ void *iterator = nullptr;
+ createNewIteratorIfNonExisting(&iterator);
+ auto jsArrayIterator = static_cast<JSArrayIterator *>(iterator);
+ jsArrayIterator->index = 0;
+ jsArrayIterator->data = reinterpret_cast<QJSValue const*>(iterable);
+ if (pos == QMetaSequenceInterface::AtEnd) {
+ auto length = static_cast<QJSValue const *>(iterable)->property(
+ QString::fromLatin1("length")).toInt();
+ jsArrayIterator->index = quint32(length);
+ }
+ return iterator;
+ };
+ iface.createConstIteratorFn = [](const void *iterable, QMetaSequenceInterface::Position pos) {
+ void *iterator = nullptr;
+ createNewIteratorIfNonExisting(&iterator);
+ auto jsArrayIterator = static_cast<JSArrayIterator *>(iterator);
+ jsArrayIterator->index = 0;
+ jsArrayIterator->data = reinterpret_cast<QJSValue const*>(iterable);
+ if (pos == QMetaSequenceInterface::AtEnd) {
+ auto length = static_cast<QJSValue const *>(iterable)->property(
+ QString::fromLatin1("length")).toInt();
+ jsArrayIterator->index = quint32(length);
+ }
+ return iterator;
+ };
+ iface.advanceIteratorFn = [](void *iterator, qsizetype advanceBy) {
+ static_cast<JSArrayIterator *>(iterator)->index += quint32(advanceBy);
+ };
+ iface.advanceConstIteratorFn = [](void *iterator, qsizetype advanceBy) {
+ static_cast<JSArrayIterator *>(iterator)->index += quint32(advanceBy);
+ };
+ iface.valueAtIteratorFn = [](const void *iterator, void *dataPtr) -> void {
+ const auto *arrayIterator = static_cast<const JSArrayIterator *>(iterator);
+ const QJSValue *jsArray = arrayIterator->data;
+ auto *data = static_cast<QVariant *>(dataPtr);
+ *data = jsArray->property(arrayIterator->index).toVariant();
+ };
+ iface.valueAtConstIteratorFn = [](const void *iterator, void *dataPtr) -> void {
+ const auto *arrayIterator = static_cast<const JSArrayIterator *>(iterator);
+ const QJSValue *jsArray = arrayIterator->data;
+ auto *data = static_cast<QVariant *>(dataPtr);
+ *data = jsArray->property(arrayIterator->index).toVariant();
+ };
+ iface.destroyIteratorFn = [](const void *iterator) {
+ delete static_cast<const JSArrayIterator *>(iterator);
+ };
+ iface.destroyConstIteratorFn = [](const void *iterator) {
+ delete static_cast<const JSArrayIterator *>(iterator);
+ };
+ iface.compareIteratorFn = [](const void *p, const void *other) {
+ auto this_ = static_cast<const JSArrayIterator *>(p);
+ auto that_ = static_cast<const JSArrayIterator *>(other);
+ return this_->index == that_->index && this_->data == that_->data;
+ };
+ iface.compareConstIteratorFn = [](const void *p, const void *other) {
+ auto this_ = static_cast<const JSArrayIterator *>(p);
+ auto that_ = static_cast<const JSArrayIterator *>(other);
+ return this_->index == that_->index && this_->data == that_->data;
+ };
+ iface.copyIteratorFn = [](void *iterator, const void *otherIterator) {
+ auto *otherIter = (static_cast<JSArrayIterator const *>(otherIterator));
+ static_cast<JSArrayIterator *>(iterator)->index = otherIter->index;
+ static_cast<JSArrayIterator *>(iterator)->data = otherIter->data;
+ };
+ iface.copyConstIteratorFn = [](void *iterator, const void *otherIterator) {
+ auto *otherIter = (static_cast<JSArrayIterator const *>(otherIterator));
+ static_cast<JSArrayIterator *>(iterator)->index = otherIter->index;
+ static_cast<JSArrayIterator *>(iterator)->data = otherIter->data;
+ };
+ iface.diffIteratorFn = [](const void *iterator, const void *otherIterator) -> qsizetype {
+ const auto *self = static_cast<const JSArrayIterator *>(iterator);
+ const auto *other = static_cast<const JSArrayIterator *>(otherIterator);
+ return self->index - other->index;
+ };
+ iface.diffConstIteratorFn = [](const void *iterator, const void *otherIterator) -> qsizetype {
+ const auto *self = static_cast<const JSArrayIterator *>(iterator);
+ const auto *other = static_cast<const JSArrayIterator *>(otherIterator);
+ return self->index - other->index;
+ };
+ iface.addValueFn = [](void *iterable, const void *data, QMetaSequenceInterface::Position) {
+ auto *jsvalue = static_cast<QJSValue *>(iterable);
+ QV4::Scope scope(QJSValuePrivate::engine(jsvalue));
+ QV4::ScopedArrayObject a(scope, QJSValuePrivate::asManagedType<QV4::ArrayObject>(jsvalue));
+ QV4::ScopedValue v(scope, scope.engine->fromVariant(*static_cast<const QVariant *>(data)));
+ if (!a)
+ return;
+ int len = a->getLength();
+ a->setIndexed(len, v, QV4::Object::DoNotThrow);
+ };
+ return iface;
+}
+
+static QSequentialIterable jsvalueToSequence (const QJSValue& value) {
+ using namespace QtMetaTypePrivate;
+ using namespace QtMetaContainerPrivate;
- quint32 isNullOrUndefined;
- stream >> isNullOrUndefined;
- if (isNullOrUndefined & 0x1) {
- *jsv = QJSValue(QJSValue::NullValue);
- } else if (isNullOrUndefined & 0x2) {
- *jsv = QJSValue();
+ if (!value.isArray()) {
+ static QMetaSequenceInterface emptySequence = emptySequenceInterface();
+ return QSequentialIterable(QMetaSequence(&emptySequence), nullptr);
+ }
+
+ static QMetaSequenceInterface sequence = sequenceInterface();
+ return QSequentialIterable(QMetaSequence(&sequence), &value);
+}
+
+void ExecutionEngine::initializeStaticMembers()
+{
+ bool ok = false;
+
+ const int envMaxJSStackSize = qEnvironmentVariableIntValue("QV4_JS_MAX_STACK_SIZE", &ok);
+ if (ok && envMaxJSStackSize > 0)
+ s_maxJSStackSize = envMaxJSStackSize;
+
+ const int envMaxGCStackSize = qEnvironmentVariableIntValue("QV4_GC_MAX_STACK_SIZE", &ok);
+ if (ok && envMaxGCStackSize > 0)
+ s_maxGCStackSize = envMaxGCStackSize;
+
+ if (qEnvironmentVariableIsSet("QV4_CRASH_ON_STACKOVERFLOW")) {
+ s_maxCallDepth = std::numeric_limits<qint32>::max();
} else {
- QVariant v;
- v.load(stream);
- QJSValuePrivate::setVariant(jsv, v);
+ ok = false;
+ s_maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
+ if (!ok || s_maxCallDepth <= 0)
+ s_maxCallDepth = -1;
}
+
+ ok = false;
+ s_jitCallCountThreshold = qEnvironmentVariableIntValue("QV4_JIT_CALL_THRESHOLD", &ok);
+ if (!ok)
+ s_jitCallCountThreshold = 3;
+ if (qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER"))
+ s_jitCallCountThreshold = std::numeric_limits<int>::max();
+
+ qMetaTypeId<QJSValue>();
+ qMetaTypeId<QList<int> >();
+
+ if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantMap>())
+ QMetaType::registerConverter<QJSValue, QVariantMap>(convertJSValueToVariantType<QVariantMap>);
+ if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantList>())
+ QMetaType::registerConverter<QJSValue, QVariantList>(convertJSValueToVariantType<QVariantList>);
+ if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QStringList>())
+ QMetaType::registerConverter<QJSValue, QStringList>(convertJSValueToVariantType<QStringList>);
+ if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QSequentialIterable>())
+ QMetaType::registerConverter<QJSValue, QSequentialIterable>(jsvalueToSequence);
}
ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
@@ -193,7 +338,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
, gcStack(new WTF::PageAllocation)
, globalCode(nullptr)
, publicEngine(jsEngine)
- , m_engineId(engineSerial.fetchAndAddOrdered(1))
+ , m_engineId(engineSerial.fetchAndAddOrdered(2))
, regExpCache(nullptr)
, m_multiplyWrappedQObjects(nullptr)
#if QT_CONFIG(qml_jit)
@@ -204,41 +349,36 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
#endif
, m_qmlEngine(nullptr)
{
- bool ok = false;
- const int envMaxJSStackSize = qEnvironmentVariableIntValue("QV4_JS_MAX_STACK_SIZE", &ok);
- if (ok && envMaxJSStackSize > 0)
- m_maxJSStackSize = envMaxJSStackSize;
-
- const int envMaxGCStackSize = qEnvironmentVariableIntValue("QV4_GC_MAX_STACK_SIZE", &ok);
- if (ok && envMaxGCStackSize > 0)
- m_maxGCStackSize = envMaxGCStackSize;
-
- memoryManager = new QV4::MemoryManager(this);
-
- if (maxCallDepth == -1) {
- if (qEnvironmentVariableIsSet("QV4_CRASH_ON_STACKOVERFLOW")) {
- maxCallDepth = std::numeric_limits<qint32>::max();
- } else {
- ok = false;
- maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
- if (!ok || maxCallDepth <= 0) {
-#if defined(QT_NO_DEBUG) && !defined(__SANITIZE_ADDRESS__) && !QT_HAS_FEATURE(address_sanitizer)
- maxCallDepth = 1234;
-#else
- // no (tail call) optimization is done, so there'll be a lot mare stack frames active
- maxCallDepth = 200;
-#endif
- }
+ if (m_engineId == 1) {
+ initializeStaticMembers();
+ engineSerial.storeRelease(2); // make it even
+ } else if (Q_UNLIKELY(m_engineId & 1)) {
+ // This should be rare. You usually don't create lots of engines at the same time.
+ while (engineSerial.loadAcquire() & 1) {
+ QThread::yieldCurrentThread();
}
}
- Q_ASSERT(maxCallDepth > 0);
+ if (s_maxCallDepth < 0) {
+ const StackProperties stack = stackProperties();
+ cppStackBase = stack.base;
+ cppStackLimit = stack.softLimit;
+ } else {
+ callDepth = 0;
+ }
+
+ // We allocate guard pages around our stacks.
+ const size_t guardPages = 2 * WTF::pageSize();
+
+ memoryManager = new QV4::MemoryManager(this);
+ // we don't want to run the gc while the initial setup is not done; not even in aggressive mode
+ GCCriticalSection gcCriticalSection(this);
// reserve space for the JS stack
// we allow it to grow to a bit more than m_maxJSStackSize, as we can overshoot due to ScopedValues
// allocated outside of JIT'ed methods.
- *jsStack = WTF::PageAllocation::allocate(m_maxJSStackSize + 256*1024, WTF::OSAllocator::JSVMStackPages,
- /* writable */ true, /* executable */ false,
- /* includesGuardPages */ true);
+ *jsStack = WTF::PageAllocation::allocate(
+ s_maxJSStackSize + 256*1024 + guardPages, WTF::OSAllocator::JSVMStackPages,
+ /* writable */ true, /* executable */ false, /* includesGuardPages */ true);
jsStackBase = (Value *)jsStack->base();
#ifdef V4_USE_VALGRIND
VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, m_maxJSStackSize + 256*1024);
@@ -246,18 +386,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsStackTop = jsStackBase;
- *gcStack = WTF::PageAllocation::allocate(m_maxGCStackSize, WTF::OSAllocator::JSVMStackPages,
- /* writable */ true, /* executable */ false,
- /* includesGuardPages */ true);
-
- {
- ok = false;
- jitCallCountThreshold = qEnvironmentVariableIntValue("QV4_JIT_CALL_THRESHOLD", &ok);
- if (!ok)
- jitCallCountThreshold = 3;
- if (qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER"))
- jitCallCountThreshold = std::numeric_limits<int>::max();
- }
+ *gcStack = WTF::PageAllocation::allocate(
+ s_maxGCStackSize + guardPages, WTF::OSAllocator::JSVMStackPages,
+ /* writable */ true, /* executable */ false, /* includesGuardPages */ true);
exceptionValue = jsAlloca(1);
*exceptionValue = Encode::undefined();
@@ -269,7 +400,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsSymbols = jsAlloca(NJSSymbols);
// set up stack limits
- jsStackLimit = jsStackBase + m_maxJSStackSize/sizeof(Value);
+ jsStackLimit = jsStackBase + s_maxJSStackSize/sizeof(Value);
identifierTable = new IdentifierTable(this);
@@ -493,10 +624,8 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsObjects[VariantProto] = memoryManager->allocate<VariantPrototype>();
Q_ASSERT(variantPrototype()->getPrototypeOf() == objectPrototype()->d());
-#if QT_CONFIG(qml_sequence_object)
ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this));
jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(ic->d()));
-#endif
ExecutionContext *global = rootContext();
@@ -530,6 +659,15 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
ic = newInternalClass(StringIteratorPrototype::staticVTable(), iteratorPrototype());
jsObjects[StringIteratorProto] = memoryManager->allocObject<StringIteratorPrototype>(ic);
+ //
+ // url
+ //
+
+ jsObjects[Url_Ctor] = memoryManager->allocate<UrlCtor>(global);
+ jsObjects[UrlProto] = memoryManager->allocate<UrlPrototype>();
+ jsObjects[UrlSearchParams_Ctor] = memoryManager->allocate<UrlSearchParamsCtor>(global);
+ jsObjects[UrlSearchParamsProto] = memoryManager->allocate<UrlSearchParamsPrototype>();
+
str = newString(QStringLiteral("get [Symbol.species]"));
jsObjects[GetSymbolSpecies] = FunctionObject::createBuiltinFunction(this, str, ArrayPrototype::method_get_species, 0);
@@ -539,7 +677,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
static_cast<NumberPrototype *>(numberPrototype())->init(this, numberCtor());
static_cast<BooleanPrototype *>(booleanPrototype())->init(this, booleanCtor());
static_cast<ArrayPrototype *>(arrayPrototype())->init(this, arrayCtor());
- static_cast<PropertyListPrototype *>(propertyListPrototype())->init(this);
+ static_cast<PropertyListPrototype *>(propertyListPrototype())->init();
static_cast<DatePrototype *>(datePrototype())->init(this, dateCtor());
static_cast<FunctionPrototype *>(functionPrototype())->init(this, functionCtor());
static_cast<GeneratorPrototype *>(generatorPrototype())->init(this, generatorFunctionCtor());
@@ -551,6 +689,8 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype())->init(this, syntaxErrorCtor());
static_cast<TypeErrorPrototype *>(typeErrorPrototype())->init(this, typeErrorCtor());
static_cast<URIErrorPrototype *>(uRIErrorPrototype())->init(this, uRIErrorCtor());
+ static_cast<UrlPrototype *>(urlPrototype())->init(this, urlCtor());
+ static_cast<UrlSearchParamsPrototype *>(urlSearchParamsPrototype())->init(this, urlSearchParamsCtor());
static_cast<IteratorPrototype *>(iteratorPrototype())->init(this);
static_cast<ForInIteratorPrototype *>(forInIteratorPrototype())->init(this);
@@ -561,9 +701,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
static_cast<VariantPrototype *>(variantPrototype())->init();
-#if QT_CONFIG(qml_sequence_object)
sequencePrototype()->cast<SequencePrototype>()->init();
-#endif
jsObjects[WeakMap_Ctor] = memoryManager->allocate<WeakMapCtor>(global);
jsObjects[WeakMapProto] = memoryManager->allocate<WeakMapPrototype>();
@@ -640,6 +778,8 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
globalObject->defineDefaultProperty(QStringLiteral("TypeError"), *typeErrorCtor());
globalObject->defineDefaultProperty(QStringLiteral("URIError"), *uRIErrorCtor());
globalObject->defineDefaultProperty(QStringLiteral("Promise"), *promiseCtor());
+ globalObject->defineDefaultProperty(QStringLiteral("URL"), *urlCtor());
+ globalObject->defineDefaultProperty(QStringLiteral("URLSearchParams"), *urlSearchParamsCtor());
globalObject->defineDefaultProperty(QStringLiteral("SharedArrayBuffer"), *sharedArrayBufferCtor());
globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor());
@@ -703,33 +843,30 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
functionPrototype()->insertMember(id_caller(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable);
functionPrototype()->insertMember(id_arguments(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable);
- qMetaTypeId<QJSValue>();
- qMetaTypeId<QList<int> >();
-
- if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantMap>())
- QMetaType::registerConverter<QJSValue, QVariantMap>(convertJSValueToVariantType<QVariantMap>);
- if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantList>())
- QMetaType::registerConverter<QJSValue, QVariantList>(convertJSValueToVariantType<QVariantList>);
- if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QStringList>())
- QMetaType::registerConverter<QJSValue, QStringList>(convertJSValueToVariantType<QStringList>);
- QMetaType::registerStreamOperators(qMetaTypeId<QJSValue>(), saveJSValue, restoreJSValue);
-
QV4::QObjectWrapper::initializeBindings(this);
m_delayedCallQueue.init(this);
+ isInitialized = true;
}
ExecutionEngine::~ExecutionEngine()
{
- modules.clear();
+ for (auto val : nativeModules) {
+ PersistentValueStorage::free(val);
+ }
+ nativeModules.clear();
qDeleteAll(m_extensionData);
delete m_multiplyWrappedQObjects;
m_multiplyWrappedQObjects = nullptr;
delete identifierTable;
delete memoryManager;
- while (!compilationUnits.isEmpty())
- (*compilationUnits.begin())->unlink();
+ for (const auto &cu : std::as_const(m_compilationUnits)) {
+ Q_ASSERT(cu->engine == this);
+ cu->clear();
+ cu->engine = nullptr;
+ }
+ m_compilationUnits.clear();
delete bumperPointerAllocator;
delete regExpCache;
@@ -746,11 +883,6 @@ ExecutionEngine::~ExecutionEngine()
#endif
}
-ExecutionContext *ExecutionEngine::currentContext() const
-{
- return static_cast<ExecutionContext *>(&currentStackFrame->jsFrame->context);
-}
-
#if QT_CONFIG(qml_debug)
void ExecutionEngine::setDebugger(Debugging::Debugger *debugger)
{
@@ -768,7 +900,7 @@ void ExecutionEngine::setProfiler(Profiling::Profiler *profiler)
void ExecutionEngine::initRootContext()
{
Scope scope(this);
- Scoped<ExecutionContext> r(scope, memoryManager->allocManaged<ExecutionContext>(sizeof(ExecutionContext::Data)));
+ Scoped<ExecutionContext> r(scope, memoryManager->allocManaged<ExecutionContext>());
r->d_unchecked()->init(Heap::ExecutionContext::Type_GlobalContext);
r->d()->activation.set(this, globalObject->d());
jsObjects[RootContext] = r;
@@ -802,13 +934,13 @@ Heap::Object *ExecutionEngine::newObject(Heap::InternalClass *internalClass)
Heap::String *ExecutionEngine::newString(const QString &s)
{
- return memoryManager->allocWithStringData<String>(s.length() * sizeof(QChar), s);
+ return memoryManager->allocWithStringData<String>(s.size() * sizeof(QChar), s);
}
Heap::String *ExecutionEngine::newIdentifier(const QString &text)
{
Scope scope(this);
- ScopedString s(scope, memoryManager->allocWithStringData<String>(text.length() * sizeof(QChar), text));
+ ScopedString s(scope, memoryManager->allocWithStringData<String>(text.size() * sizeof(QChar), text));
s->toPropertyKey();
return s->d();
}
@@ -888,24 +1020,35 @@ Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(size_t length)
return memoryManager->allocate<ArrayBuffer>(length);
}
+Heap::DateObject *ExecutionEngine::newDateObject(double dateTime)
+{
+ return memoryManager->allocate<DateObject>(dateTime);
+}
-Heap::DateObject *ExecutionEngine::newDateObject(const Value &value)
+Heap::DateObject *ExecutionEngine::newDateObject(const QDateTime &dateTime)
{
- return memoryManager->allocate<DateObject>(value);
+ return memoryManager->allocate<DateObject>(dateTime);
}
-Heap::DateObject *ExecutionEngine::newDateObject(const QDateTime &dt)
+Heap::DateObject *ExecutionEngine::newDateObject(
+ QDate date, Heap::Object *parent, int index, uint flags)
{
- Scope scope(this);
- Scoped<DateObject> object(scope, memoryManager->allocate<DateObject>(dt));
- return object->d();
+ return memoryManager->allocate<DateObject>(
+ date, parent, index, Heap::ReferenceObject::Flags(flags));
}
-Heap::DateObject *ExecutionEngine::newDateObjectFromTime(const QTime &t)
+Heap::DateObject *ExecutionEngine::newDateObject(
+ QTime time, Heap::Object *parent, int index, uint flags)
{
- Scope scope(this);
- Scoped<DateObject> object(scope, memoryManager->allocate<DateObject>(t));
- return object->d();
+ return memoryManager->allocate<DateObject>(
+ time, parent, index, Heap::ReferenceObject::Flags(flags));
+}
+
+Heap::DateObject *ExecutionEngine::newDateObject(
+ QDateTime dateTime, Heap::Object *parent, int index, uint flags)
+{
+ return memoryManager->allocate<DateObject>(
+ dateTime, parent, index, Heap::ReferenceObject::Flags(flags));
}
Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
@@ -920,11 +1063,6 @@ Heap::RegExpObject *ExecutionEngine::newRegExpObject(RegExp *re)
return memoryManager->allocate<RegExpObject>(re);
}
-Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re)
-{
- return memoryManager->allocate<RegExpObject>(re);
-}
-
#if QT_CONFIG(regularexpression)
Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegularExpression &re)
{
@@ -932,6 +1070,24 @@ Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegularExpression &r
}
#endif
+Heap::UrlObject *ExecutionEngine::newUrlObject()
+{
+ return memoryManager->allocate<UrlObject>();
+}
+
+Heap::UrlObject *ExecutionEngine::newUrlObject(const QUrl &url)
+{
+ Scope scope(this);
+ Scoped<UrlObject> urlObject(scope, newUrlObject());
+ urlObject->setUrl(url);
+ return urlObject->d();
+}
+
+Heap::UrlSearchParamsObject *ExecutionEngine::newUrlSearchParamsObject()
+{
+ return memoryManager->allocate<UrlSearchParamsObject>();
+}
+
Heap::Object *ExecutionEngine::newErrorObject(const Value &value)
{
return ErrorObject::create<ErrorObject>(this, value, errorCtor());
@@ -1021,9 +1177,9 @@ Heap::Object *ExecutionEngine::newEvalErrorObject(const QString &message)
return ErrorObject::create<EvalErrorObject>(this, message);
}
-Heap::Object *ExecutionEngine::newVariantObject(const QVariant &v)
+Heap::Object *ExecutionEngine::newVariantObject(const QMetaType type, const void *data)
{
- return memoryManager->allocate<VariantObject>(v);
+ return memoryManager->allocate<VariantObject>(type, data);
}
Heap::Object *ExecutionEngine::newForInIteratorObject(Object *o)
@@ -1050,21 +1206,9 @@ Heap::Object *ExecutionEngine::newArrayIteratorObject(Object *o)
Heap::QmlContext *ExecutionEngine::qmlContext() const
{
- if (!currentStackFrame)
- return nullptr;
- Heap::ExecutionContext *ctx = currentContext()->d();
-
- if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer)
- return nullptr;
-
- while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext)
- ctx = ctx->outer;
-
- Q_ASSERT(ctx);
- if (ctx->type != Heap::ExecutionContext::Type_QmlContext)
- return nullptr;
-
- return static_cast<Heap::QmlContext *>(ctx);
+ return currentStackFrame
+ ? static_cast<Heap::QmlContext *>(qmlContext(currentContext()->d()))
+ : nullptr;
}
QObject *ExecutionEngine::qmlScopeObject() const
@@ -1076,19 +1220,17 @@ QObject *ExecutionEngine::qmlScopeObject() const
return ctx->qml()->scopeObject;
}
-QQmlContextData *ExecutionEngine::callingQmlContext() const
+QQmlRefPointer<QQmlContextData> ExecutionEngine::callingQmlContext() const
{
Heap::QmlContext *ctx = qmlContext();
if (!ctx)
return nullptr;
- return ctx->qml()->context->contextData();
+ return ctx->qml()->context;
}
StackTrace ExecutionEngine::stackTrace(int frameLimit) const
{
- Scope scope(const_cast<ExecutionEngine *>(this));
- ScopedString name(scope);
StackTrace stack;
CppStackFrame *f = currentStackFrame;
@@ -1096,16 +1238,18 @@ StackTrace ExecutionEngine::stackTrace(int frameLimit) const
QV4::StackFrame frame;
frame.source = f->source();
frame.function = f->function();
- frame.line = qAbs(f->lineNumber());
- frame.column = -1;
+ frame.line = f->lineNumber();
+
stack.append(frame);
- if (f->isTailCalling) {
- QV4::StackFrame frame;
- frame.function = QStringLiteral("[elided tail calls]");
- stack.append(frame);
+ if (f->isJSTypesFrame()) {
+ if (static_cast<JSTypesStackFrame *>(f)->isTailCalling()) {
+ QV4::StackFrame frame;
+ frame.function = QStringLiteral("[elided tail calls]");
+ stack.append(frame);
+ }
}
--frameLimit;
- f = f->parent;
+ f = f->parentFrame();
}
return stack;
@@ -1132,7 +1276,7 @@ static inline char *v4StackTrace(const ExecutionContext *context)
const QString fileName = url.isLocalFile() ? url.toLocalFile() : url.toString();
str << "frame={level=\"" << i << "\",func=\"" << stackTrace.at(i).function
<< "\",file=\"" << fileName << "\",fullname=\"" << fileName
- << "\",line=\"" << stackTrace.at(i).line << "\",language=\"js\"}";
+ << "\",line=\"" << qAbs(stackTrace.at(i).line) << "\",language=\"js\"}";
}
}
str << ']';
@@ -1163,7 +1307,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
base = f->v4Function->finalUrl();
break;
}
- f = f->parent;
+ f = f->parentFrame();
}
if (base.isEmpty() && globalCode)
@@ -1177,17 +1321,15 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
void ExecutionEngine::markObjects(MarkStack *markStack)
{
- for (int i = 0; i < NClasses; ++i)
- if (classes[i])
- classes[i]->mark(markStack);
- markStack->drain();
+ for (int i = 0; i < NClasses; ++i) {
+ if (Heap::InternalClass *c = classes[i])
+ c->mark(markStack);
+ }
identifierTable->markObjects(markStack);
- for (auto compilationUnit: compilationUnits) {
+ for (const auto &compilationUnit : std::as_const(m_compilationUnits))
compilationUnit->markObjects(markStack);
- markStack->drain();
- }
}
ReturnedValue ExecutionEngine::throwError(const Value &value)
@@ -1329,7 +1471,7 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError()
if (!trace.isEmpty()) {
QV4::StackFrame frame = trace.constFirst();
error.setUrl(QUrl(frame.source));
- error.setLine(frame.line);
+ error.setLine(qAbs(frame.line));
error.setColumn(frame.column);
}
QV4::Scoped<QV4::ErrorObject> errorObj(scope, exception);
@@ -1340,47 +1482,47 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError()
// Variant conversion code
typedef QSet<QV4::Heap::Object *> V4ObjectSet;
-static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects);
-static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value);
-static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects = nullptr);
-static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value,
- const QByteArray &targetType,
- void **result);
-static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst);
-static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst);
+enum class JSToQVariantConversionBehavior {Never, Safish, Aggressive };
+static QVariant toVariant(
+ const QV4::Value &value, QMetaType typeHint, JSToQVariantConversionBehavior conversionBehavior,
+ V4ObjectSet *visitedObjects);
+static QObject *qtObjectFromJS(const QV4::Value &value);
+static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObjects = nullptr,
+ JSToQVariantConversionBehavior behavior = JSToQVariantConversionBehavior::Safish);
+static bool convertToNativeQObject(const QV4::Value &value, QMetaType targetType, void **result);
static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVariantMap &vmap);
static QV4::ReturnedValue variantToJS(QV4::ExecutionEngine *v4, const QVariant &value)
{
- return v4->metaTypeToJS(value.userType(), value.constData());
-}
-
-
-QVariant ExecutionEngine::toVariant(const Value &value, int typeHint, bool createJSValueForObjects)
-{
- return ::toVariant(this, value, typeHint, createJSValueForObjects, nullptr);
+ return v4->metaTypeToJS(value.metaType(), value.constData());
}
-
-static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects)
+static QVariant toVariant(const QV4::Value &value, QMetaType metaType, JSToQVariantConversionBehavior conversionBehavior,
+ V4ObjectSet *visitedObjects)
{
Q_ASSERT (!value.isEmpty());
- QV4::Scope scope(e);
if (const QV4::VariantObject *v = value.as<QV4::VariantObject>())
return v->d()->data();
- if (typeHint == QVariant::Bool)
+ if (metaType == QMetaType::fromType<bool>())
return QVariant(value.toBoolean());
- if (typeHint == QMetaType::QJsonValue)
+ if (metaType == QMetaType::fromType<double>())
+ return QVariant(value.toNumber());
+
+ if (metaType == QMetaType::fromType<float>())
+ return QVariant(float(value.toNumber()));
+
+ if (metaType == QMetaType::fromType<QJsonValue>())
return QVariant::fromValue(QV4::JsonObject::toJsonValue(value));
- if (typeHint == qMetaTypeId<QJSValue>())
- return QVariant::fromValue(QJSValue(e, value.asReturnedValue()));
+ if (metaType == QMetaType::fromType<QJSValue>())
+ return QVariant::fromValue(QJSValuePrivate::fromReturnedValue(value.asReturnedValue()));
- if (value.as<QV4::Object>()) {
- QV4::ScopedObject object(scope, value);
- if (typeHint == QMetaType::QJsonObject
+ if (const QV4::Object *o = value.as<QV4::Object>()) {
+ QV4::Scope scope(o->engine());
+ QV4::ScopedObject object(scope, o);
+ if (metaType == QMetaType::fromType<QJsonObject>()
&& !value.as<ArrayObject>() && !value.as<FunctionObject>()) {
return QVariant::fromValue(QV4::JsonObject::toJsonObject(object));
} else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) {
@@ -1393,16 +1535,15 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return v->toVariant();
} else if (QV4::QmlListWrapper *l = object->as<QV4::QmlListWrapper>()) {
return l->toVariant();
-#if QT_CONFIG(qml_sequence_object)
- } else if (object->isListType()) {
- return QV4::SequencePrototype::toVariant(object);
-#endif
+ } else if (QV4::Sequence *s = object->as<QV4::Sequence>()) {
+ return QV4::SequencePrototype::toVariant(s);
}
}
- if (value.as<ArrayObject>()) {
- QV4::ScopedArrayObject a(scope, value);
- if (typeHint == qMetaTypeId<QList<QObject *> >()) {
+ if (const QV4::ArrayObject *o = value.as<ArrayObject>()) {
+ QV4::Scope scope(o->engine());
+ QV4::ScopedArrayObject a(scope, o);
+ if (metaType == QMetaType::fromType<QList<QObject *>>()) {
QList<QObject *> list;
uint length = a->getLength();
QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope);
@@ -1416,16 +1557,64 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
}
return QVariant::fromValue<QList<QObject*> >(list);
- } else if (typeHint == QMetaType::QJsonArray) {
+ } else if (metaType == QMetaType::fromType<QJsonArray>()) {
return QVariant::fromValue(QV4::JsonObject::toJsonArray(a));
}
-#if QT_CONFIG(qml_sequence_object)
- bool succeeded = false;
- QVariant retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded);
- if (succeeded)
+ QVariant retn = QV4::SequencePrototype::toVariant(value, metaType);
+ if (retn.isValid())
return retn;
-#endif
+
+ if (metaType.isValid()) {
+ retn = QVariant(metaType, nullptr);
+ auto retnAsIterable = retn.value<QSequentialIterable>();
+ if (retnAsIterable.metaContainer().canAddValue()) {
+ QMetaType valueMetaType = retnAsIterable.metaContainer().valueMetaType();
+ auto const length = a->getLength();
+ QV4::ScopedValue arrayValue(scope);
+ for (qint64 i = 0; i < length; ++i) {
+ arrayValue = a->get(i);
+ QVariant asVariant = QQmlValueTypeProvider::createValueType(
+ arrayValue, valueMetaType);
+ if (asVariant.isValid()) {
+ retnAsIterable.metaContainer().addValue(retn.data(), asVariant.constData());
+ continue;
+ }
+
+ if (QMetaType::canConvert(QMetaType::fromType<QJSValue>(), valueMetaType)) {
+ // before attempting a conversion from the concrete types,
+ // check if there exists a conversion from QJSValue -> out type
+ // prefer that one for compatibility reasons
+ asVariant = QVariant::fromValue(QJSValuePrivate::fromReturnedValue(
+ arrayValue->asReturnedValue()));
+ if (asVariant.convert(valueMetaType)) {
+ retnAsIterable.metaContainer().addValue(retn.data(), asVariant.constData());
+ continue;
+ }
+ }
+
+ asVariant = toVariant(arrayValue, valueMetaType, JSToQVariantConversionBehavior::Never, visitedObjects);
+ if (valueMetaType == QMetaType::fromType<QVariant>()) {
+ retnAsIterable.metaContainer().addValue(retn.data(), &asVariant);
+ } else {
+ auto originalType = asVariant.metaType();
+ bool couldConvert = asVariant.convert(valueMetaType);
+ if (!couldConvert && originalType.isValid()) {
+ // If the original type was void, we're converting a "hole" in a sparse
+ // array. There is no point in warning about that.
+ qWarning().noquote()
+ << QLatin1String("Could not convert array value "
+ "at position %1 from %2 to %3")
+ .arg(QString::number(i),
+ QString::fromUtf8(originalType.name()),
+ QString::fromUtf8(valueMetaType.name()));
+ }
+ retnAsIterable.metaContainer().addValue(retn.data(), asVariant.constData());
+ }
+ }
+ return retn;
+ }
+ }
}
if (value.isUndefined())
@@ -1441,38 +1630,93 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
if (String *s = value.stringValue()) {
const QString &str = s->toQString();
// QChars are stored as a strings
- if (typeHint == QVariant::Char && str.size() == 1)
+ if (metaType == QMetaType::fromType<QChar>() && str.size() == 1)
return str.at(0);
return str;
}
-#if QT_CONFIG(qml_locale)
- if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>())
- return *ld->d()->locale;
-#endif
- if (const QV4::DateObject *d = value.as<DateObject>())
+ if (const QV4::DateObject *d = value.as<DateObject>()) {
+ // NOTE: since we convert QTime to JS Date,
+ // round trip will change the variant type (to QDateTime)!
+
+ if (metaType == QMetaType::fromType<QDate>())
+ return DateObject::dateTimeToDate(d->toQDateTime());
+
+ if (metaType == QMetaType::fromType<QTime>())
+ return d->toQDateTime().time();
+
+ if (metaType == QMetaType::fromType<QString>())
+ return d->toString();
+
return d->toQDateTime();
+ }
+ if (const QV4::UrlObject *d = value.as<UrlObject>())
+ return d->toQUrl();
if (const ArrayBuffer *d = value.as<ArrayBuffer>())
return d->asByteArray();
- // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
+ if (const Symbol *symbol = value.as<Symbol>()) {
+ return conversionBehavior == JSToQVariantConversionBehavior::Never
+ ? QVariant::fromValue(QJSValuePrivate::fromReturnedValue(symbol->asReturnedValue()))
+ : symbol->descriptiveString();
+ }
- QV4::ScopedObject o(scope, value);
- Q_ASSERT(o);
+ const QV4::Object *object = value.as<QV4::Object>();
+ Q_ASSERT(object);
+ QV4::Scope scope(object->engine());
+ QV4::ScopedObject o(scope, object);
- if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>()) {
#if QT_CONFIG(regularexpression)
- if (typeHint != QMetaType::QRegExp)
- return re->toQRegularExpression();
+ if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>())
+ return re->toQRegularExpression();
#endif
- return re->toQRegExp();
+
+ if (metaType.isValid() && !(metaType.flags() & QMetaType::PointerToQObject)) {
+ const QVariant result = QQmlValueTypeProvider::createValueType(value, metaType);
+ if (result.isValid())
+ return result;
}
- if (createJSValueForObjects)
- return QVariant::fromValue(QJSValue(scope.engine, o->asReturnedValue()));
+ if (conversionBehavior == JSToQVariantConversionBehavior::Never)
+ return QVariant::fromValue(QJSValuePrivate::fromReturnedValue(o->asReturnedValue()));
+
+ return objectToVariant(o, visitedObjects, conversionBehavior);
+}
+
+QVariant ExecutionEngine::toVariantLossy(const Value &value)
+{
+ return ::toVariant(value, QMetaType(), JSToQVariantConversionBehavior::Aggressive, nullptr);
+}
+
+QVariant ExecutionEngine::toVariant(
+ const Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols)
+{
+ auto behavior = createJSValueForObjectsAndSymbols ? JSToQVariantConversionBehavior::Never
+ : JSToQVariantConversionBehavior::Safish;
+ return ::toVariant(value, typeHint, behavior, nullptr);
+}
+
+static QVariantMap objectToVariantMap(const QV4::Object *o, V4ObjectSet *visitedObjects,
+ JSToQVariantConversionBehavior conversionBehvior)
+{
+ QVariantMap map;
+ QV4::Scope scope(o->engine());
+ QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
+ QV4::ScopedValue name(scope);
+ QV4::ScopedValue val(scope);
+ while (1) {
+ name = it.nextPropertyNameAsString(val);
+ if (name->isNull())
+ break;
- return objectToVariant(e, o, visitedObjects);
+ QString key = name->toQStringNoThrow();
+ map.insert(key, ::toVariant(
+ val, /*type hint*/ QMetaType {},
+ conversionBehvior, visitedObjects));
+ }
+ return map;
}
-static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects)
+static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObjects,
+ JSToQVariantConversionBehavior conversionBehvior)
{
Q_ASSERT(o);
@@ -1492,7 +1736,7 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V
QVariant result;
if (o->as<ArrayObject>()) {
- QV4::Scope scope(e);
+ QV4::Scope scope(o->engine());
QV4::ScopedArrayObject a(scope, o->asReturnedValue());
QV4::ScopedValue v(scope);
QVariantList list;
@@ -1500,37 +1744,51 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V
int length = a->getLength();
for (int ii = 0; ii < length; ++ii) {
v = a->get(ii);
- list << ::toVariant(e, v, -1, /*createJSValueForObjects*/false, visitedObjects);
+ list << ::toVariant(v, QMetaType {}, conversionBehvior,
+ visitedObjects);
}
result = list;
- } else if (!o->as<FunctionObject>()) {
- QVariantMap map;
- QV4::Scope scope(e);
- QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
- QV4::ScopedValue name(scope);
- QV4::ScopedValue val(scope);
- while (1) {
- name = it.nextPropertyNameAsString(val);
- if (name->isNull())
- break;
-
- QString key = name->toQStringNoThrow();
- map.insert(key, ::toVariant(e, val, /*type hint*/-1, /*createJSValueForObjects*/false, visitedObjects));
- }
-
- result = map;
+ } else if (o->getPrototypeOf() == o->engine()->objectPrototype()->d()
+ || (conversionBehvior == JSToQVariantConversionBehavior::Aggressive &&
+ !o->as<QV4::FunctionObject>())) {
+ /* FunctionObject is excluded for historical reasons, even though
+ objects with a custom prototype risk losing information
+ But the Aggressive path is used only in QJSValue::toVariant
+ which is documented to be lossy
+ */
+ result = objectToVariantMap(o, visitedObjects, conversionBehvior);
+ } else {
+ // If it's not a plain object, we can only save it as QJSValue.
+ result = QVariant::fromValue(QJSValuePrivate::fromReturnedValue(o->asReturnedValue()));
}
visitedObjects->remove(o->d());
return result;
}
-QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
+/*!
+ \internal
+
+ Transform the given \a metaType and \a ptr into a JavaScript representation.
+ */
+QV4::ReturnedValue ExecutionEngine::fromData(
+ QMetaType metaType, const void *ptr,
+ QV4::Heap::Object *container, int property, uint flags)
{
- int type = variant.userType();
- const void *ptr = variant.constData();
+ const auto createSequence = [&](const QMetaSequence metaSequence) {
+ QV4::Scope scope(this);
+ QV4::Scoped<Sequence> sequence(scope);
+ if (container) {
+ return QV4::SequencePrototype::newSequence(
+ this, metaType, metaSequence, ptr,
+ container, property, Heap::ReferenceObject::Flags(flags));
+ } else {
+ return QV4::SequencePrototype::fromData(this, metaType, metaSequence, ptr);
+ }
+ };
+ const int type = metaType.id();
if (type < QMetaType::User) {
switch (QMetaType::Type(type)) {
case QMetaType::UnknownType:
@@ -1545,6 +1803,10 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return QV4::Encode(*reinterpret_cast<const int*>(ptr));
case QMetaType::UInt:
return QV4::Encode(*reinterpret_cast<const uint*>(ptr));
+ case QMetaType::Long:
+ return QV4::Encode((double)*reinterpret_cast<const long *>(ptr));
+ case QMetaType::ULong:
+ return QV4::Encode((double)*reinterpret_cast<const ulong *>(ptr));
case QMetaType::LongLong:
return QV4::Encode((double)*reinterpret_cast<const qlonglong*>(ptr));
case QMetaType::ULongLong:
@@ -1565,35 +1827,34 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return QV4::Encode((int)*reinterpret_cast<const char*>(ptr));
case QMetaType::UChar:
return QV4::Encode((int)*reinterpret_cast<const unsigned char*>(ptr));
+ case QMetaType::SChar:
+ return QV4::Encode((int)*reinterpret_cast<const signed char*>(ptr));
case QMetaType::QChar:
return newString(*reinterpret_cast<const QChar *>(ptr))->asReturnedValue();
+ case QMetaType::Char16:
+ return newString(QChar(*reinterpret_cast<const char16_t *>(ptr)))->asReturnedValue();
case QMetaType::QDateTime:
- return QV4::Encode(newDateObject(*reinterpret_cast<const QDateTime *>(ptr)));
+ return QV4::Encode(newDateObject(
+ *reinterpret_cast<const QDateTime *>(ptr),
+ container, property, flags));
case QMetaType::QDate:
- return QV4::Encode(newDateObject(QDateTime(*reinterpret_cast<const QDate *>(ptr), QTime(0, 0, 0), Qt::UTC)));
+ return QV4::Encode(newDateObject(
+ *reinterpret_cast<const QDate *>(ptr),
+ container, property, flags));
case QMetaType::QTime:
- return QV4::Encode(newDateObjectFromTime(*reinterpret_cast<const QTime *>(ptr)));
- case QMetaType::QRegExp:
- return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(ptr)));
+ return QV4::Encode(newDateObject(
+ *reinterpret_cast<const QTime *>(ptr),
+ container, property, flags));
#if QT_CONFIG(regularexpression)
case QMetaType::QRegularExpression:
return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegularExpression *>(ptr)));
#endif
case QMetaType::QObjectStar:
return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
-#if QT_CONFIG(qml_sequence_object)
case QMetaType::QStringList:
- {
- bool succeeded = false;
- QV4::Scope scope(this);
- QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(this, variant, &succeeded));
- if (succeeded)
- return retn->asReturnedValue();
- return QV4::Encode(newArrayObject(*reinterpret_cast<const QStringList *>(ptr)));
- }
-#endif
+ return createSequence(QMetaSequence::fromContainer<QStringList>());
case QMetaType::QVariantList:
- return variantListToJS(this, *reinterpret_cast<const QVariantList *>(ptr));
+ return createSequence(QMetaSequence::fromContainer<QVariantList>());
case QMetaType::QVariantMap:
return variantMapToJS(this, *reinterpret_cast<const QVariantMap *>(ptr));
case QMetaType::QJsonValue:
@@ -1602,112 +1863,123 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return QV4::JsonObject::fromJsonObject(this, *reinterpret_cast<const QJsonObject *>(ptr));
case QMetaType::QJsonArray:
return QV4::JsonObject::fromJsonArray(this, *reinterpret_cast<const QJsonArray *>(ptr));
-#if QT_CONFIG(qml_locale)
- case QMetaType::QLocale:
- return QQmlLocale::wrap(this, *reinterpret_cast<const QLocale*>(ptr));
-#endif
case QMetaType::QPixmap:
case QMetaType::QImage:
// Scarce value types
- return QV4::Encode(newVariantObject(variant));
+ return QV4::Encode(newVariantObject(metaType, ptr));
default:
break;
}
+ }
- if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(type))
- return QV4::QQmlValueTypeWrapper::create(this, variant, vtmo, type);
- } else {
- QV4::Scope scope(this);
- if (type == qMetaTypeId<QQmlListReference>()) {
- typedef QQmlListReferencePrivate QDLRP;
- QDLRP *p = QDLRP::get((QQmlListReference*)const_cast<void *>(ptr));
- if (p->object) {
- return QV4::QmlListWrapper::create(scope.engine, p->property, p->propertyType);
- } else {
- return QV4::Encode::null();
- }
- } else if (type == qMetaTypeId<QJSValue>()) {
- const QJSValue *value = reinterpret_cast<const QJSValue *>(ptr);
- return QJSValuePrivate::convertedToValue(this, *value);
- } else if (type == qMetaTypeId<QList<QObject *> >()) {
- // XXX Can this be made more by using Array as a prototype and implementing
- // directly against QList<QObject*>?
- const QList<QObject *> &list = *(const QList<QObject *>*)ptr;
- QV4::ScopedArrayObject a(scope, newArrayObject());
- a->arrayReserve(list.count());
- QV4::ScopedValue v(scope);
- for (int ii = 0; ii < list.count(); ++ii)
- a->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(this, list.at(ii))));
- a->setArrayLengthUnchecked(list.count());
- return a.asReturnedValue();
- } else if (QMetaType::typeFlags(type) & QMetaType::PointerToQObject) {
+ if (metaType.flags() & QMetaType::IsEnumeration)
+ return fromData(metaType.underlyingType(), ptr, container, property, flags);
+
+ QV4::Scope scope(this);
+ if (metaType == QMetaType::fromType<QQmlListReference>()) {
+ typedef QQmlListReferencePrivate QDLRP;
+ QDLRP *p = QDLRP::get((QQmlListReference*)const_cast<void *>(ptr));
+ if (p->object)
+ return QV4::QmlListWrapper::create(scope.engine, p->property, p->propertyType);
+ else
+ return QV4::Encode::null();
+ } else if (auto flags = metaType.flags(); flags & QMetaType::IsQmlList) {
+ // casting to QQmlListProperty<QObject> is slightly nasty, but it's the
+ // same QQmlListReference does.
+ const auto *p = static_cast<const QQmlListProperty<QObject> *>(ptr);
+ if (p->object)
+ return QV4::QmlListWrapper::create(scope.engine, *p, metaType);
+ else
+ return QV4::Encode::null();
+ } else if (metaType == QMetaType::fromType<QJSValue>()) {
+ return QJSValuePrivate::convertToReturnedValue(
+ this, *reinterpret_cast<const QJSValue *>(ptr));
+ } else if (metaType == QMetaType::fromType<QList<QObject *> >()) {
+ // XXX Can this be made more by using Array as a prototype and implementing
+ // directly against QList<QObject*>?
+ const QList<QObject *> &list = *(const QList<QObject *>*)ptr;
+ QV4::ScopedArrayObject a(scope, newArrayObject());
+ a->arrayReserve(list.size());
+ QV4::ScopedValue v(scope);
+ for (int ii = 0; ii < list.size(); ++ii)
+ a->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(this, list.at(ii))));
+ a->setArrayLengthUnchecked(list.size());
+ return a.asReturnedValue();
+ } else if (auto flags = metaType.flags(); flags & QMetaType::PointerToQObject) {
+ if (flags.testFlag(QMetaType::IsConst))
+ return QV4::QObjectWrapper::wrapConst(this, *reinterpret_cast<QObject* const *>(ptr));
+ else
return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
+ } else if (metaType == QMetaType::fromType<QJSPrimitiveValue>()) {
+ const QJSPrimitiveValue *primitive = static_cast<const QJSPrimitiveValue *>(ptr);
+ switch (primitive->type()) {
+ case QJSPrimitiveValue::Boolean:
+ return Encode(primitive->asBoolean());
+ case QJSPrimitiveValue::Integer:
+ return Encode(primitive->asInteger());
+ case QJSPrimitiveValue::String:
+ return newString(primitive->asString())->asReturnedValue();
+ case QJSPrimitiveValue::Undefined:
+ return Encode::undefined();
+ case QJSPrimitiveValue::Null:
+ return Encode::null();
+ case QJSPrimitiveValue::Double:
+ return Encode(primitive->asDouble());
}
+ }
- bool objOk;
- QObject *obj = QQmlMetaType::toQObject(variant, &objOk);
- if (objOk)
- return QV4::QObjectWrapper::wrap(this, obj);
+ if (const QMetaObject *vtmo = QQmlMetaType::metaObjectForValueType(metaType)) {
+ if (container) {
+ return QV4::QQmlValueTypeWrapper::create(
+ this, ptr, vtmo, metaType,
+ container, property, Heap::ReferenceObject::Flags(flags));
+ } else {
+ return QV4::QQmlValueTypeWrapper::create(this, ptr, vtmo, metaType);
+ }
+ }
-#if QT_CONFIG(qml_sequence_object)
- bool succeeded = false;
- QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(this, variant, &succeeded));
- if (succeeded)
- return retn->asReturnedValue();
-#endif
+ const QQmlType listType = QQmlMetaType::qmlListType(metaType);
+ if (listType.isSequentialContainer())
+ return createSequence(listType.listMetaSequence());
- if (QMetaType::hasRegisteredConverterFunction(type, qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) {
- QSequentialIterable lst = variant.value<QSequentialIterable>();
- return sequentialIterableToJS(this, lst);
- }
+ QSequentialIterable iterable;
+ if (QMetaType::convert(metaType, ptr, QMetaType::fromType<QSequentialIterable>(), &iterable)) {
- if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(type))
- return QV4::QQmlValueTypeWrapper::create(this, variant, vtmo, type);
- }
+ // If the resulting iterable is useful for anything, turn it into a QV4::Sequence.
+ const QMetaSequence sequence = iterable.metaContainer();
+ if (sequence.hasSize() && sequence.canGetValueAtIndex())
+ return createSequence(sequence);
- // XXX TODO: To be compatible, we still need to handle:
- // + QObjectList
- // + QList<int>
+ // As a last resort, try to read the contents of the container via an iterator
+ // and build a JS array from them.
+ if (sequence.hasConstIterator() && sequence.canGetValueAtConstIterator()) {
+ QV4::ScopedArrayObject a(scope, newArrayObject());
+ for (auto it = iterable.constBegin(), end = iterable.constEnd(); it != end; ++it)
+ a->push_back(fromVariant(*it));
+ return a.asReturnedValue();
+ }
+ }
- return QV4::Encode(newVariantObject(variant));
+ return QV4::Encode(newVariantObject(metaType, ptr));
}
-QVariantMap ExecutionEngine::variantMapFromJS(const Object *o)
+QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
{
- return objectToVariant(this, o).toMap();
+ return fromData(variant.metaType(), variant.constData());
}
-
-// Converts a QVariantList to JS.
-// The result is a new Array object with length equal to the length
-// of the QVariantList, and the elements being the QVariantList's
-// elements converted to JS, recursively.
-static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst)
+ReturnedValue ExecutionEngine::fromVariant(
+ const QVariant &variant, Heap::Object *parent, int property, uint flags)
{
- QV4::Scope scope(v4);
- QV4::ScopedArrayObject a(scope, v4->newArrayObject());
- a->arrayReserve(lst.size());
- QV4::ScopedValue v(scope);
- for (int i = 0; i < lst.size(); i++)
- a->arrayPut(i, (v = variantToJS(v4, lst.at(i))));
- a->setArrayLengthUnchecked(lst.size());
- return a.asReturnedValue();
+ return fromData(variant.metaType(), variant.constData(), parent, property, flags);
}
-// Converts a QSequentialIterable to JS.
-// The result is a new Array object with length equal to the length
-// of the QSequentialIterable, and the elements being the QSequentialIterable's
-// elements converted to JS, recursively.
-static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst)
+QVariantMap ExecutionEngine::variantMapFromJS(const Object *o)
{
- QV4::Scope scope(v4);
- QV4::ScopedArrayObject a(scope, v4->newArrayObject());
- a->arrayReserve(lst.size());
- QV4::ScopedValue v(scope);
- for (int i = 0; i < lst.size(); i++)
- a->arrayPut(i, (v = variantToJS(v4, lst.at(i))));
- a->setArrayLengthUnchecked(lst.size());
- return a.asReturnedValue();
+ Q_ASSERT(o);
+ V4ObjectSet visitedObjects;
+ visitedObjects.insert(o->d());
+ return objectToVariantMap(o, &visitedObjects, JSToQVariantConversionBehavior::Safish);
}
// Converts a QVariantMap to JS.
@@ -1735,27 +2007,49 @@ static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVarian
// Converts the meta-type defined by the given type and data to JS.
// Returns the value if conversion succeeded, an empty handle otherwise.
-QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
+QV4::ReturnedValue ExecutionEngine::metaTypeToJS(QMetaType type, const void *data)
{
Q_ASSERT(data != nullptr);
- QVariant variant(type, data);
- if (QMetaType::Type(variant.type()) == QMetaType::QVariant) {
+ if (type == QMetaType::fromType<QVariant>()) {
// unwrap it: this is tested in QJSEngine, and makes the most sense for
// end-user code too.
- return variantToJS(this, *reinterpret_cast<const QVariant*>(data));
+ return fromVariant(*reinterpret_cast<const QVariant*>(data));
+ } else if (type == QMetaType::fromType<QUrl>()) {
+ // Create a proper URL object here, rather than a variant.
+ return newUrlObject(*reinterpret_cast<const QUrl *>(data))->asReturnedValue();
}
- return fromVariant(variant);
+
+ return fromData(type, data);
}
int ExecutionEngine::maxJSStackSize() const
{
- return m_maxJSStackSize;
+ return s_maxJSStackSize;
}
int ExecutionEngine::maxGCStackSize() const
{
- return m_maxGCStackSize;
+ return s_maxGCStackSize;
+}
+
+/*!
+ \internal
+ Returns \a length converted to int if its safe to
+ pass to \c Scope::alloc.
+ Otherwise it throws a RangeError, and returns 0.
+ */
+int ExecutionEngine::safeForAllocLength(qint64 len64)
+{
+ if (len64 < 0ll || len64 > qint64(std::numeric_limits<int>::max())) {
+ throwRangeError(QStringLiteral("Invalid array length."));
+ return 0;
+ }
+ if (len64 > qint64(this->jsStackLimit - this->jsStackTop)) {
+ throwRangeError(QStringLiteral("Array too large for apply()."));
+ return 0;
+ }
+ return len64;
}
ReturnedValue ExecutionEngine::global()
@@ -1766,9 +2060,19 @@ ReturnedValue ExecutionEngine::global()
QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compileModule(const QUrl &url)
{
QQmlMetaType::CachedUnitLookupError cacheError = QQmlMetaType::CachedUnitLookupError::NoError;
- if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url, &cacheError)) {
- return ExecutableCompilationUnit::create(
- QV4::CompiledData::CompilationUnit(cachedUnit, url.fileName(), url.toString()));
+ const DiskCacheOptions options = diskCacheOptions();
+ if (const QQmlPrivate::CachedQmlUnit *cachedUnit = (options & DiskCache::Aot)
+ ? QQmlMetaType::findCachedCompilationUnit(
+ url,
+ (options & DiskCache::AotByteCode)
+ ? QQmlMetaType::AcceptUntyped
+ : QQmlMetaType::RequireFullyTyped,
+ &cacheError)
+ : nullptr) {
+ return executableCompilationUnit(
+ QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>(
+ cachedUnit->qmlData, cachedUnit->aotCompiledFunctions, url.fileName(),
+ url.toString()));
}
QFile f(QQmlFile::urlToLocalFileOrQrc(url));
@@ -1794,73 +2098,192 @@ QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compileModule(
sourceCode, sourceTimeStamp, &diagnostics);
for (const QQmlJS::DiagnosticMessage &m : diagnostics) {
if (m.isError()) {
- throwSyntaxError(m.message, url.toString(), m.line, m.column);
+ throwSyntaxError(m.message, url.toString(), m.loc.startLine, m.loc.startColumn);
return nullptr;
} else {
- qWarning() << url << ':' << m.line << ':' << m.column
+ qWarning() << url << ':' << m.loc.startLine << ':' << m.loc.startColumn
<< ": warning: " << m.message;
}
}
- return ExecutableCompilationUnit::create(std::move(unit));
+ return insertCompilationUnit(std::move(unit));
}
-void ExecutionEngine::injectModule(const QQmlRefPointer<ExecutableCompilationUnit> &moduleUnit)
+QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compilationUnitForUrl(const QUrl &url) const
{
- // Injection can happen from the QML type loader thread for example, but instantiation and
- // evaluation must be limited to the ExecutionEngine's thread.
- QMutexLocker moduleGuard(&moduleMutex);
- modules.insert(moduleUnit->finalUrl(), moduleUnit);
+ // Gives the _most recently inserted_ CU of that URL. That's what we want.
+ return m_compilationUnits.value(url);
+}
+
+QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::executableCompilationUnit(
+ QQmlRefPointer<CompiledData::CompilationUnit> &&unit)
+{
+ const QUrl url = unit->finalUrl();
+ auto [begin, end] = std::as_const(m_compilationUnits).equal_range(url);
+
+ for (auto it = begin; it != end; ++it) {
+ if ((*it)->baseCompilationUnit() == unit)
+ return *it;
+ }
+
+ auto executableUnit = m_compilationUnits.insert(
+ url, ExecutableCompilationUnit::create(std::move(unit), this));
+ // runtime data should not be initialized yet, so we don't need to mark the CU
+ Q_ASSERT(!(*executableUnit)->runtimeStrings);
+ return *executableUnit;
+}
+
+QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::insertCompilationUnit(QQmlRefPointer<CompiledData::CompilationUnit> &&unit) {
+ QUrl url = unit->finalUrl();
+ auto executableUnit = ExecutableCompilationUnit::create(std::move(unit), this);
+ /* Compilation Units stored in the engine are part of the gc roots,
+ so we don't trigger any write-barrier when they are added. Use
+ markCustom to make sure they are still marked when we insert them */
+ QV4::WriteBarrier::markCustom(this, [&executableUnit](QV4::MarkStack *ms) {
+ executableUnit->markObjects(ms);
+ });
+ return *m_compilationUnits.insert(std::move(url), std::move(executableUnit));
+}
+
+void ExecutionEngine::trimCompilationUnits()
+{
+ for (auto it = m_compilationUnits.begin(); it != m_compilationUnits.end();) {
+ if ((*it)->count() == 1)
+ it = m_compilationUnits.erase(it);
+ else
+ ++it;
+ }
+}
+
+ExecutionEngine::Module ExecutionEngine::moduleForUrl(
+ const QUrl &url, const ExecutableCompilationUnit *referrer) const
+{
+ const auto nativeModule = nativeModules.find(url);
+ if (nativeModule != nativeModules.end())
+ return Module { nullptr, *nativeModule };
+
+ const QUrl resolved = referrer
+ ? referrer->finalUrl().resolved(QQmlTypeLoader::normalize(url))
+ : QQmlTypeLoader::normalize(url);
+ auto existingModule = m_compilationUnits.find(resolved);
+ if (existingModule == m_compilationUnits.end())
+ return Module { nullptr, nullptr };
+ return Module { *existingModule, nullptr };
}
-QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer) const
+ExecutionEngine::Module ExecutionEngine::loadModule(const QUrl &url, const ExecutableCompilationUnit *referrer)
{
- QUrl url = QQmlTypeLoader::normalize(_url);
- if (referrer)
- url = referrer->finalUrl().resolved(url);
+ const auto nativeModule = nativeModules.constFind(url);
+ if (nativeModule != nativeModules.cend())
+ return Module { nullptr, *nativeModule };
- QMutexLocker moduleGuard(&moduleMutex);
- auto existingModule = modules.find(url);
- if (existingModule == modules.end())
+ const QUrl resolved = referrer
+ ? referrer->finalUrl().resolved(QQmlTypeLoader::normalize(url))
+ : QQmlTypeLoader::normalize(url);
+ auto existingModule = m_compilationUnits.constFind(resolved);
+ if (existingModule != m_compilationUnits.cend())
+ return Module { *existingModule, nullptr };
+
+ auto newModule = compileModule(resolved);
+ Q_ASSERT(!newModule || m_compilationUnits.contains(resolved, newModule));
+
+ return Module { newModule, nullptr };
+}
+
+QV4::Value *ExecutionEngine::registerNativeModule(const QUrl &url, const QV4::Value &module)
+{
+ const auto existingModule = nativeModules.constFind(url);
+ if (existingModule != nativeModules.cend())
return nullptr;
- return *existingModule;
+
+ QV4::Value *val = this->memoryManager->m_persistentValues->allocate();
+ *val = module.asReturnedValue();
+ nativeModules.insert(url, val);
+
+ // Make sure the type loader doesn't try to resolve the script anymore.
+ if (m_qmlEngine)
+ QQmlEnginePrivate::get(m_qmlEngine)->typeLoader.injectScript(url, *val);
+
+ return val;
}
-QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer)
+static ExecutionEngine::DiskCacheOptions transFormDiskCache(const char *v)
{
- QUrl url = QQmlTypeLoader::normalize(_url);
- if (referrer)
- url = referrer->finalUrl().resolved(url);
+ using DiskCache = ExecutionEngine::DiskCache;
+
+ if (v == nullptr)
+ return DiskCache::Enabled;
+
+ ExecutionEngine::DiskCacheOptions result = DiskCache::Disabled;
+ const QList<QByteArray> options = QByteArray(v).split(',');
+ for (const QByteArray &option : options) {
+ if (option == "aot-bytecode")
+ result |= DiskCache::AotByteCode;
+ else if (option == "aot-native")
+ result |= DiskCache::AotNative;
+ else if (option == "aot")
+ result |= DiskCache::Aot;
+ else if (option == "qmlc-read")
+ result |= DiskCache::QmlcRead;
+ else if (option == "qmlc-write")
+ result |= DiskCache::QmlcWrite;
+ else if (option == "qmlc")
+ result |= DiskCache::Qmlc;
+ else
+ qWarning() << "Ignoring unknown option to QML_DISK_CACHE:" << option;
+ }
- QMutexLocker moduleGuard(&moduleMutex);
- auto existingModule = modules.find(url);
- if (existingModule != modules.end())
- return *existingModule;
+ return result;
+}
- moduleGuard.unlock();
+ExecutionEngine::DiskCacheOptions ExecutionEngine::diskCacheOptions() const
+{
+ if (forceDiskCache())
+ return DiskCache::Enabled;
+ if (disableDiskCache() || debugger())
+ return DiskCache::Disabled;
+ static const DiskCacheOptions options = qmlGetConfigOption<
+ DiskCacheOptions, transFormDiskCache>("QML_DISK_CACHE");
+ return options;
+}
- auto newModule = compileModule(url);
- if (newModule) {
- moduleGuard.relock();
- modules.insert(url, newModule);
+void ExecutionEngine::callInContext(QV4::Function *function, QObject *self,
+ QV4::ExecutionContext *context, int argc, void **args,
+ QMetaType *types)
+{
+ if (!args) {
+ Q_ASSERT(argc == 0);
+ void *dummyArgs[] = { nullptr };
+ QMetaType dummyTypes[] = { QMetaType::fromType<void>() };
+ function->call(self, dummyArgs, dummyTypes, argc, context);
+ return;
}
+ Q_ASSERT(types); // both args and types must be present
+ // implicitly sets the return value, which is args[0]
+ function->call(self, args, types, argc, context);
+}
- return newModule;
+QV4::ReturnedValue ExecutionEngine::callInContext(QV4::Function *function, QObject *self,
+ QV4::ExecutionContext *context, int argc,
+ const QV4::Value *argv)
+{
+ QV4::Scope scope(this);
+ QV4::ScopedObject jsSelf(scope, QV4::QObjectWrapper::wrap(this, self));
+ Q_ASSERT(jsSelf);
+ return function->call(jsSelf, argv, argc, context);
}
void ExecutionEngine::initQmlGlobalObject()
{
initializeGlobal();
- freezeObject(*globalObject);
+ lockObject(*globalObject);
}
void ExecutionEngine::initializeGlobal()
{
- QV4::Scope scope(this);
- QV4::GlobalExtensions::init(globalObject, QJSEngine::AllExtensions);
+ createQtObject();
- QV4::ScopedObject qt(scope, memoryManager->allocate<QV4::QtObject>(qmlEngine()));
- globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt);
+ QV4::GlobalExtensions::init(globalObject, QJSEngine::AllExtensions);
#if QT_CONFIG(qml_locale)
QQmlLocale::registerStringLocaleCompare(this);
@@ -1885,6 +2308,25 @@ void ExecutionEngine::initializeGlobal()
}
}
+void ExecutionEngine::createQtObject()
+{
+ QV4::Scope scope(this);
+ QtObject *qtObject = new QtObject(this);
+ QJSEngine::setObjectOwnership(qtObject, QJSEngine::JavaScriptOwnership);
+
+ QV4::ScopedObject qtObjectWrapper(
+ scope, QV4::QObjectWrapper::wrap(this, qtObject));
+ QV4::ScopedObject qtNamespaceWrapper(
+ scope, QV4::QMetaObjectWrapper::create(this, &Qt::staticMetaObject));
+ QV4::ScopedObject qtObjectProtoWrapper(
+ scope, qtObjectWrapper->getPrototypeOf());
+
+ qtNamespaceWrapper->setPrototypeOf(qtObjectProtoWrapper);
+ qtObjectWrapper->setPrototypeOf(qtNamespaceWrapper);
+
+ globalObject->defineDefaultProperty(QStringLiteral("Qt"), qtObjectWrapper);
+}
+
const QSet<QString> &ExecutionEngine::illegalNames() const
{
return m_illegalNames;
@@ -1892,13 +2334,16 @@ const QSet<QString> &ExecutionEngine::illegalNames() const
void ExecutionEngine::setQmlEngine(QQmlEngine *engine)
{
+ // Second stage of initialization. We're updating some more prototypes here.
+ isInitialized = false;
m_qmlEngine = engine;
initQmlGlobalObject();
+ isInitialized = true;
}
static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object)
{
- if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isFrozen)
+ if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isFrozen())
return;
QV4::Scope scope(v4);
@@ -1935,6 +2380,58 @@ void ExecutionEngine::freezeObject(const QV4::Value &value)
freeze_recursive(this, o);
}
+void ExecutionEngine::lockObject(const QV4::Value &value)
+{
+ QV4::Scope scope(this);
+ ScopedObject object(scope, value);
+ if (!object)
+ return;
+
+ std::vector<Heap::Object *> stack { object->d() };
+
+ // Methods meant to be overridden
+ const PropertyKey writableMembers[] = {
+ id_toString()->propertyKey(),
+ id_toLocaleString()->propertyKey(),
+ id_valueOf()->propertyKey(),
+ id_constructor()->propertyKey()
+ };
+ const auto writableBegin = std::begin(writableMembers);
+ const auto writableEnd = std::end(writableMembers);
+
+ while (!stack.empty()) {
+ object = stack.back();
+ stack.pop_back();
+
+ if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isLocked())
+ continue;
+
+ Scoped<InternalClass> locked(scope, object->internalClass()->locked());
+ QV4::ScopedObject member(scope);
+
+ // Taking this copy is cheap. It's refcounted. This avoids keeping a reference
+ // to the original IC.
+ const SharedInternalClassData<PropertyKey> nameMap = locked->d()->nameMap;
+
+ for (uint i = 0, end = locked->d()->size; i < end; ++i) {
+ const PropertyKey key = nameMap.at(i);
+ if (!key.isStringOrSymbol())
+ continue;
+ if ((member = *object->propertyData(i))) {
+ stack.push_back(member->d());
+ if (std::find(writableBegin, writableEnd, key) == writableEnd) {
+ PropertyAttributes attributes = locked->d()->find(key).attributes;
+ attributes.setConfigurable(false);
+ attributes.setWritable(false);
+ locked = locked->changeMember(key, attributes);
+ }
+ }
+ }
+
+ object->setInternalClass(locked->d());
+ }
+}
+
void ExecutionEngine::startTimer(const QString &timerName)
{
if (!m_time.isValid())
@@ -1964,7 +2461,7 @@ int ExecutionEngine::consoleCountHelper(const QString &file, quint16 line, quint
void ExecutionEngine::setExtensionData(int index, Deletable *data)
{
- if (m_extensionData.count() <= index)
+ if (m_extensionData.size() <= index)
m_extensionData.resize(index + 1);
if (m_extensionData.at(index))
@@ -1973,97 +2470,159 @@ void ExecutionEngine::setExtensionData(int index, Deletable *data)
m_extensionData[index] = data;
}
+template<typename Source>
+bool convertToIterable(QMetaType metaType, void *data, Source *sequence)
+{
+ QSequentialIterable iterable;
+ if (!QMetaType::view(metaType, data, QMetaType::fromType<QSequentialIterable>(), &iterable))
+ return false;
+
+ const QMetaType elementMetaType = iterable.valueMetaType();
+ QVariant element(elementMetaType);
+ for (qsizetype i = 0, end = sequence->getLength(); i < end; ++i) {
+ if (!ExecutionEngine::metaTypeFromJS(sequence->get(i), elementMetaType, element.data()))
+ element = QVariant(elementMetaType);
+ iterable.addValue(element, QSequentialIterable::AtEnd);
+ }
+ return true;
+}
+
// Converts a JS value to a meta-type.
// data must point to a place that can store a value of the given type.
// Returns true if conversion succeeded, false otherwise.
-bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
+bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, void *data)
{
// check if it's one of the types we know
- switch (QMetaType::Type(type)) {
+ switch (metaType.id()) {
case QMetaType::Bool:
- *reinterpret_cast<bool*>(data) = value->toBoolean();
+ *reinterpret_cast<bool*>(data) = value.toBoolean();
return true;
case QMetaType::Int:
- *reinterpret_cast<int*>(data) = value->toInt32();
+ *reinterpret_cast<int*>(data) = value.toInt32();
return true;
case QMetaType::UInt:
- *reinterpret_cast<uint*>(data) = value->toUInt32();
+ *reinterpret_cast<uint*>(data) = value.toUInt32();
+ return true;
+ case QMetaType::Long:
+ *reinterpret_cast<long*>(data) = long(value.toInteger());
+ return true;
+ case QMetaType::ULong:
+ *reinterpret_cast<ulong*>(data) = ulong(value.toInteger());
return true;
case QMetaType::LongLong:
- *reinterpret_cast<qlonglong*>(data) = qlonglong(value->toInteger());
+ *reinterpret_cast<qlonglong*>(data) = qlonglong(value.toInteger());
return true;
case QMetaType::ULongLong:
- *reinterpret_cast<qulonglong*>(data) = qulonglong(value->toInteger());
+ *reinterpret_cast<qulonglong*>(data) = qulonglong(value.toInteger());
return true;
case QMetaType::Double:
- *reinterpret_cast<double*>(data) = value->toNumber();
+ *reinterpret_cast<double*>(data) = value.toNumber();
return true;
case QMetaType::QString:
- if (value->isUndefined() || value->isNull())
- *reinterpret_cast<QString*>(data) = QString();
+ if (value.isUndefined())
+ *reinterpret_cast<QString*>(data) = QStringLiteral("undefined");
+ else if (value.isNull())
+ *reinterpret_cast<QString*>(data) = QStringLiteral("null");
else
- *reinterpret_cast<QString*>(data) = value->toQString();
+ *reinterpret_cast<QString*>(data) = value.toQString();
return true;
case QMetaType::QByteArray:
- if (const ArrayBuffer *ab = value->as<ArrayBuffer>())
+ if (const ArrayBuffer *ab = value.as<ArrayBuffer>()) {
*reinterpret_cast<QByteArray*>(data) = ab->asByteArray();
- else
+ } else if (const String *string = value.as<String>()) {
+ *reinterpret_cast<QByteArray*>(data) = string->toQString().toUtf8();
+ } else if (const ArrayObject *ao = value.as<ArrayObject>()) {
+ // Since QByteArray is sequentially iterable, we have to construct it from a JS Array.
+ QByteArray result;
+ const qint64 length = ao->getLength();
+ result.reserve(length);
+ for (qint64 i = 0; i < length; ++i) {
+ char value = 0;
+ ExecutionEngine::metaTypeFromJS(ao->get(i), QMetaType::fromType<char>(), &value);
+ result.push_back(value);
+ }
+ *reinterpret_cast<QByteArray*>(data) = std::move(result);
+ } else {
*reinterpret_cast<QByteArray*>(data) = QByteArray();
+ }
return true;
case QMetaType::Float:
- *reinterpret_cast<float*>(data) = value->toNumber();
+ *reinterpret_cast<float*>(data) = value.toNumber();
return true;
case QMetaType::Short:
- *reinterpret_cast<short*>(data) = short(value->toInt32());
+ *reinterpret_cast<short*>(data) = short(value.toInt32());
return true;
case QMetaType::UShort:
- *reinterpret_cast<unsigned short*>(data) = value->toUInt16();
+ *reinterpret_cast<unsigned short*>(data) = value.toUInt16();
return true;
case QMetaType::Char:
- *reinterpret_cast<char*>(data) = char(value->toInt32());
+ *reinterpret_cast<char*>(data) = char(value.toInt32());
return true;
case QMetaType::UChar:
- *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->toInt32());
+ *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value.toInt32());
+ return true;
+ case QMetaType::SChar:
+ *reinterpret_cast<signed char*>(data) = (signed char)(value.toInt32());
return true;
case QMetaType::QChar:
- if (String *s = value->stringValue()) {
+ if (String *s = value.stringValue()) {
QString str = s->toQString();
*reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0);
} else {
- *reinterpret_cast<QChar*>(data) = QChar(ushort(value->toUInt16()));
+ *reinterpret_cast<QChar*>(data) = QChar(ushort(value.toUInt16()));
}
return true;
case QMetaType::QDateTime:
- if (const QV4::DateObject *d = value->as<DateObject>()) {
+ if (const QV4::DateObject *d = value.as<DateObject>()) {
*reinterpret_cast<QDateTime *>(data) = d->toQDateTime();
return true;
} break;
case QMetaType::QDate:
- if (const QV4::DateObject *d = value->as<DateObject>()) {
- *reinterpret_cast<QDate *>(data) = d->toQDateTime().date();
+ if (const QV4::DateObject *d = value.as<DateObject>()) {
+ *reinterpret_cast<QDate *>(data) = DateObject::dateTimeToDate(d->toQDateTime());
return true;
} break;
- case QMetaType::QRegExp:
- if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) {
- *reinterpret_cast<QRegExp *>(data) = r->toQRegExp();
+ case QMetaType::QTime:
+ if (const QV4::DateObject *d = value.as<DateObject>()) {
+ *reinterpret_cast<QTime *>(data) = d->toQDateTime().time();
return true;
} break;
+ case QMetaType::QUrl:
+ if (String *s = value.stringValue()) {
+ *reinterpret_cast<QUrl *>(data) = QUrl(s->toQString());
+ return true;
+ } else if (const QV4::UrlObject *d = value.as<UrlObject>()) {
+ *reinterpret_cast<QUrl *>(data) = d->toQUrl();
+ return true;
+ } else if (const QV4::VariantObject *d = value.as<VariantObject>()) {
+ const QVariant *variant = &d->d()->data();
+ if (variant->metaType() == QMetaType::fromType<QUrl>()) {
+ *reinterpret_cast<QUrl *>(data)
+ = *reinterpret_cast<const QUrl *>(variant->constData());
+ return true;
+ }
+ }
+ break;
#if QT_CONFIG(regularexpression)
case QMetaType::QRegularExpression:
- if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) {
+ if (const QV4::RegExpObject *r = value.as<QV4::RegExpObject>()) {
*reinterpret_cast<QRegularExpression *>(data) = r->toQRegularExpression();
return true;
} break;
#endif
case QMetaType::QObjectStar: {
- const QV4::QObjectWrapper *qobjectWrapper = value->as<QV4::QObjectWrapper>();
- if (qobjectWrapper || value->isNull()) {
- *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(this, *value);
+ if (value.isNull()) {
+ *reinterpret_cast<QObject* *>(data) = nullptr;
return true;
- } break;
+ }
+ if (value.as<QV4::QObjectWrapper>()) {
+ *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(value);
+ return true;
+ }
+ break;
}
case QMetaType::QStringList: {
- const QV4::ArrayObject *a = value->as<QV4::ArrayObject>();
+ const QV4::ArrayObject *a = value.as<QV4::ArrayObject>();
if (a) {
*reinterpret_cast<QStringList *>(data) = a->toQStringList();
return true;
@@ -2071,33 +2630,48 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
break;
}
case QMetaType::QVariantList: {
- const QV4::ArrayObject *a = value->as<QV4::ArrayObject>();
+ const QV4::ArrayObject *a = value.as<QV4::ArrayObject>();
if (a) {
- *reinterpret_cast<QVariantList *>(data) = toVariant(*a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList();
+ *reinterpret_cast<QVariantList *>(data) = ExecutionEngine::toVariant(
+ *a, /*typeHint*/QMetaType{}, /*createJSValueForObjectsAndSymbols*/false)
+ .toList();
return true;
}
break;
}
case QMetaType::QVariantMap: {
- const QV4::Object *o = value->as<QV4::Object>();
+ const QV4::Object *o = value.as<QV4::Object>();
if (o) {
- *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(o);
+ *reinterpret_cast<QVariantMap *>(data) = o->engine()->variantMapFromJS(o);
return true;
}
break;
}
case QMetaType::QVariant:
- *reinterpret_cast<QVariant*>(data) = toVariant(*value, /*typeHint*/-1, /*createJSValueForObjects*/false);
+ if (value.as<QV4::Managed>()) {
+ *reinterpret_cast<QVariant*>(data) = ExecutionEngine::toVariant(
+ value, /*typeHint*/QMetaType{}, /*createJSValueForObjectsAndSymbols*/false);
+ } else if (value.isNull()) {
+ *reinterpret_cast<QVariant*>(data) = QVariant::fromValue(nullptr);
+ } else if (value.isUndefined()) {
+ *reinterpret_cast<QVariant*>(data) = QVariant();
+ } else if (value.isBoolean()) {
+ *reinterpret_cast<QVariant*>(data) = QVariant(value.booleanValue());
+ } else if (value.isInteger()) {
+ *reinterpret_cast<QVariant*>(data) = QVariant(value.integerValue());
+ } else if (value.isDouble()) {
+ *reinterpret_cast<QVariant*>(data) = QVariant(value.doubleValue());
+ }
return true;
case QMetaType::QJsonValue:
- *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(*value);
+ *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(value);
return true;
case QMetaType::QJsonObject: {
- *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(value->as<Object>());
+ *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(value.as<Object>());
return true;
}
case QMetaType::QJsonArray: {
- const QV4::ArrayObject *a = value->as<ArrayObject>();
+ const QV4::ArrayObject *a = value.as<ArrayObject>();
if (a) {
*reinterpret_cast<QJsonArray *>(data) = JsonObject::toJsonArray(a);
return true;
@@ -2105,92 +2679,166 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
break;
}
default:
- ;
+ break;
}
- {
- const QQmlValueTypeWrapper *vtw = value->as<QQmlValueTypeWrapper>();
- if (vtw && vtw->typeId() == type) {
- return vtw->toGadget(data);
- }
+ if (metaType.flags() & QMetaType::IsEnumeration) {
+ *reinterpret_cast<int *>(data) = value.toInt32();
+ return true;
}
-#if 0
- if (isQtVariant(value)) {
- const QVariant &var = variantValue(value);
- // ### Enable once constructInPlace() is in qt master.
- if (var.userType() == type) {
- QMetaType::constructInPlace(type, data, var.constData());
+ if (const QV4::QmlListWrapper *wrapper = value.as<QV4::QmlListWrapper>()) {
+ if (metaType == QMetaType::fromType<QQmlListReference>()) {
+ *reinterpret_cast<QQmlListReference *>(data) = wrapper->toListReference();
return true;
}
- if (var.canConvert(type)) {
- QVariant vv = var;
- vv.convert(type);
- Q_ASSERT(vv.userType() == type);
- QMetaType::constructInPlace(type, data, vv.constData());
+
+ const auto wrapperPrivate = wrapper->d();
+ if (wrapperPrivate->propertyType() == metaType) {
+ *reinterpret_cast<QQmlListProperty<QObject> *>(data) = *wrapperPrivate->property();
return true;
}
+ }
+ if (const QQmlValueTypeWrapper *vtw = value.as<QQmlValueTypeWrapper>()) {
+ const QMetaType valueType = vtw->type();
+ if (valueType == metaType)
+ return vtw->toGadget(data);
+
+ Heap::QQmlValueTypeWrapper *d = vtw->d();
+ if (d->isReference())
+ d->readReference();
+
+ if (void *gadgetPtr = d->gadgetPtr()) {
+ if (QQmlValueTypeProvider::populateValueType(metaType, data, valueType, gadgetPtr))
+ return true;
+ if (QMetaType::canConvert(valueType, metaType))
+ return QMetaType::convert(valueType, gadgetPtr, metaType, data);
+ } else {
+ QVariant empty(valueType);
+ if (QQmlValueTypeProvider::populateValueType(metaType, data, valueType, empty.data()))
+ return true;
+ if (QMetaType::canConvert(valueType, metaType))
+ return QMetaType::convert(valueType, empty.data(), metaType, data);
+ }
}
-#endif
// Try to use magic; for compatibility with qjsvalue_cast.
- QByteArray name = QMetaType::typeName(type);
- if (convertToNativeQObject(this, *value, name, reinterpret_cast<void* *>(data)))
+ if (convertToNativeQObject(value, metaType, reinterpret_cast<void **>(data)))
return true;
- if (value->as<QV4::VariantObject>() && name.endsWith('*')) {
- int valueType = QMetaType::type(name.left(name.size()-1));
- QVariant &var = value->as<QV4::VariantObject>()->d()->data();
- if (valueType == var.userType()) {
- // We have T t, T* is requested, so return &t.
- *reinterpret_cast<void* *>(data) = var.data();
+
+ const bool isPointer = (metaType.flags() & QMetaType::IsPointer);
+ const QV4::VariantObject *variantObject = value.as<QV4::VariantObject>();
+ if (variantObject) {
+ // Actually a reference, because we're poking it for its data() below and we want
+ // the _original_ data, not some copy.
+ QVariant &var = variantObject->d()->data();
+
+ if (var.metaType() == metaType) {
+ metaType.destruct(data);
+ metaType.construct(data, var.data());
return true;
- } else if (Object *o = value->objectValue()) {
- // Look in the prototype chain.
- QV4::Scope scope(this);
- QV4::ScopedObject proto(scope, o->getPrototypeOf());
- while (proto) {
- bool canCast = false;
- if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) {
- const QVariant &v = vo->d()->data();
- canCast = (type == v.userType()) || (valueType && (valueType == v.userType()));
- }
- else if (proto->as<QV4::QObjectWrapper>()) {
- QByteArray className = name.left(name.size()-1);
- QV4::ScopedObject p(scope, proto.getPointer());
- if (QObject *qobject = qtObjectFromJS(this, p))
- canCast = qobject->qt_metacast(className) != nullptr;
- }
- if (canCast) {
- QByteArray varTypeName = QMetaType::typeName(var.userType());
- if (varTypeName.endsWith('*'))
- *reinterpret_cast<void* *>(data) = *reinterpret_cast<void* *>(var.data());
- else
- *reinterpret_cast<void* *>(data) = var.data();
- return true;
+ }
+
+ if (isPointer) {
+ const QByteArray pointedToTypeName = QByteArray(metaType.name()).chopped(1);
+ const QMetaType valueType = QMetaType::fromName(pointedToTypeName);
+
+ if (valueType == var.metaType()) {
+ // ### Qt7: Remove this. Returning pointers to potentially gc'd data is crazy.
+ // We have T t, T* is requested, so return &t.
+ *reinterpret_cast<const void **>(data) = var.data();
+ return true;
+ } else if (Object *o = value.objectValue()) {
+ // Look in the prototype chain.
+ QV4::Scope scope(o->engine());
+ QV4::ScopedObject proto(scope, o->getPrototypeOf());
+ while (proto) {
+ bool canCast = false;
+ if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) {
+ const QVariant &v = vo->d()->data();
+ canCast = (metaType == v.metaType());
+ }
+ else if (proto->as<QV4::QObjectWrapper>()) {
+ QV4::ScopedObject p(scope, proto.getPointer());
+ if (QObject *qobject = qtObjectFromJS(p)) {
+ if (const QMetaObject *metaObject = metaType.metaObject())
+ canCast = metaObject->cast(qobject) != nullptr;
+ else
+ canCast = qobject->qt_metacast(pointedToTypeName);
+ }
+ }
+ if (canCast) {
+ const QMetaType varType = var.metaType();
+ if (varType.flags() & QMetaType::IsPointer) {
+ *reinterpret_cast<const void **>(data)
+ = *reinterpret_cast<void *const *>(var.data());
+ } else {
+ *reinterpret_cast<const void **>(data) = var.data();
+ }
+ return true;
+ }
+ proto = proto->getPrototypeOf();
}
- proto = proto->getPrototypeOf();
}
+ } else if (QQmlValueTypeProvider::populateValueType(
+ metaType, data, var.metaType(), var.data())) {
+ return true;
}
- } else if (value->isNull() && name.endsWith('*')) {
+ } else if (value.isNull() && isPointer) {
*reinterpret_cast<void* *>(data) = nullptr;
return true;
- } else if (type == qMetaTypeId<QJSValue>()) {
- *reinterpret_cast<QJSValue*>(data) = QJSValue(this, value->asReturnedValue());
+ } else if (metaType == QMetaType::fromType<QJSValue>()) {
+ QJSValuePrivate::setValue(reinterpret_cast<QJSValue*>(data), value.asReturnedValue());
+ return true;
+ } else if (metaType == QMetaType::fromType<QJSPrimitiveValue>()) {
+ *reinterpret_cast<QJSPrimitiveValue *>(data) = createPrimitive(&value);
return true;
+ } else if (!isPointer) {
+ if (QQmlValueTypeProvider::populateValueType(metaType, data, value))
+ return true;
+ }
+
+ if (const QV4::Sequence *sequence = value.as<Sequence>()) {
+ const QVariant result = QV4::SequencePrototype::toVariant(sequence);
+ if (result.metaType() == metaType) {
+ metaType.destruct(data);
+ metaType.construct(data, result.constData());
+ return true;
+ }
+
+ if (convertToIterable(metaType, data, sequence))
+ return true;
+ }
+
+ if (const QV4::ArrayObject *array = value.as<ArrayObject>()) {
+ if (convertToIterable(metaType, data, array))
+ return true;
}
return false;
}
-static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value, const QByteArray &targetType, void **result)
+static bool convertToNativeQObject(const QV4::Value &value, QMetaType targetType, void **result)
{
- if (!targetType.endsWith('*'))
+ if (!(targetType.flags() & QMetaType::IsPointer))
return false;
- if (QObject *qobject = qtObjectFromJS(e, value)) {
- int start = targetType.startsWith("const ") ? 6 : 0;
- QByteArray className = targetType.mid(start, targetType.size()-start-1);
+ if (QObject *qobject = qtObjectFromJS(value)) {
+ // If the target type has a metaObject, use that for casting.
+ if (const QMetaObject *targetMetaObject = targetType.metaObject()) {
+ if (QObject *instance = targetMetaObject->cast(qobject)) {
+ *result = instance;
+ return true;
+ }
+ return false;
+ }
+
+ // We have to call the generated qt_metacast rather than metaObject->cast() here so that
+ // it works for types without QMetaObject, such as QStandardItem.
+ const QByteArray targetTypeName = targetType.name();
+ const int start = targetTypeName.startsWith("const ") ? 6 : 0;
+ const QByteArray className = targetTypeName.mid(start, targetTypeName.size() - start - 1);
if (void *instance = qobject->qt_metacast(className)) {
*result = instance;
return true;
@@ -2199,12 +2847,12 @@ static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &va
return false;
}
-static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value)
+static QObject *qtObjectFromJS(const QV4::Value &value)
{
if (!value.isObject())
return nullptr;
- QV4::Scope scope(engine);
+ QV4::Scope scope(value.as<QV4::Managed>()->engine());
QV4::Scoped<QV4::VariantObject> v(scope, value);
if (v) {
@@ -2214,9 +2862,14 @@ static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &v
return *reinterpret_cast<QObject* const *>(variant.constData());
}
QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, value);
- if (!wrapper)
- return nullptr;
- return wrapper->object();
+ if (wrapper)
+ return wrapper->object();
+
+ QV4::Scoped<QV4::QQmlTypeWrapper> typeWrapper(scope, value);
+ if (typeWrapper)
+ return typeWrapper->object();
+
+ return nullptr;
}
struct QV4EngineRegistrationData
@@ -2238,4 +2891,11 @@ int ExecutionEngine::registerExtension()
return registrationData()->extensionCount++;
}
+#if QT_CONFIG(qml_network)
+QNetworkAccessManager *QV4::detail::getNetworkAccessManager(ExecutionEngine *engine)
+{
+ return engine->qmlEngine()->networkAccessManager();
+}
+#endif // qml_network
+
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index d233347060..8e1bd24f6b 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4ENGINE_H
#define QV4ENGINE_H
@@ -50,20 +14,21 @@
// We mean it.
//
-#include "qv4global_p.h"
-#include "qv4managed_p.h"
-#include "qv4context_p.h"
-#include "qv4stackframe_p.h"
#include <private/qintrusivelist_p.h>
-#include "qv4enginebase_p.h"
-#include <private/qqmlrefcount_p.h>
#include <private/qqmldelayedcallqueue_p.h>
-#include <QtCore/qelapsedtimer.h>
-#include <QtCore/qmutex.h>
-
-#include "qv4function_p.h"
+#include <private/qqmlrefcount_p.h>
#include <private/qv4compileddata_p.h>
+#include <private/qv4context_p.h>
+#include <private/qv4enginebase_p.h>
#include <private/qv4executablecompilationunit_p.h>
+#include <private/qv4function_p.h>
+#include <private/qv4global_p.h>
+#include <private/qv4stacklimits_p.h>
+
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qprocessordetection.h>
+#include <QtCore/qset.h>
namespace WTF {
class BumpPointerAllocator;
@@ -91,7 +56,18 @@ class PageAllocation;
QT_BEGIN_NAMESPACE
+#if QT_CONFIG(qml_network)
+class QNetworkAccessManager;
+
+namespace QV4 {
+struct QObjectMethod;
+namespace detail {
+QNetworkAccessManager *getNetworkAccessManager(ExecutionEngine *engine);
+}
+}
+#else
namespace QV4 { struct QObjectMethod; }
+#endif // qml_network
// Used to allow a QObject method take and return raw V4 handles without having to expose
// 48 in the public API.
@@ -99,7 +75,7 @@ namespace QV4 { struct QObjectMethod; }
// class MyClass : public QObject {
// Q_OBJECT
// ...
-// Q_INVOKABLE void myMethod(QQmlV4Function*);
+// Q_INVOKABLE void myMethod(QQmlV4FunctionPtr);
// };
// The QQmlV8Function - and consequently the arguments and return value - only remains
// valid during the call. If the return value isn't set within myMethod(), the will return
@@ -133,6 +109,7 @@ class QQmlError;
class QJSEngine;
class QQmlEngine;
class QQmlContextData;
+class QQmlTypeLoader;
namespace QV4 {
namespace Debugging {
@@ -158,12 +135,24 @@ class ReactionHandler;
struct Q_QML_EXPORT ExecutionEngine : public EngineBase
{
private:
- static qint32 maxCallDepth;
-
friend struct ExecutionContextSaver;
friend struct ExecutionContext;
friend struct Heap::ExecutionContext;
public:
+ enum class DiskCache {
+ Disabled = 0,
+ AotByteCode = 1 << 0,
+ AotNative = 1 << 1,
+ QmlcRead = 1 << 2,
+ QmlcWrite = 1 << 3,
+ Aot = AotByteCode | AotNative,
+ Qmlc = QmlcRead | QmlcWrite,
+ Enabled = Aot | Qmlc,
+
+ };
+
+ Q_DECLARE_FLAGS(DiskCacheOptions, DiskCache);
+
ExecutableAllocator *executableAllocator;
ExecutableAllocator *regExpAllocator;
@@ -185,6 +174,14 @@ public:
QQmlEngine *qmlEngine() const { return m_qmlEngine; }
QJSEngine *publicEngine;
+ template<typename TypeLoader = QQmlTypeLoader>
+ TypeLoader *typeLoader()
+ {
+ if (m_qmlEngine)
+ return TypeLoader::get(m_qmlEngine);
+ return nullptr;
+ }
+
enum JSObjects {
RootContext,
ScriptContext,
@@ -210,9 +207,7 @@ public:
URIErrorProto,
PromiseProto,
VariantProto,
-#if QT_CONFIG(qml_sequence_object)
SequenceProto,
-#endif
SharedArrayBufferProto,
ArrayBufferProto,
DataViewProto,
@@ -229,6 +224,8 @@ public:
MapIteratorProto,
ArrayIteratorProto,
StringIteratorProto,
+ UrlProto,
+ UrlSearchParamsProto,
Object_Ctor,
String_Ctor,
@@ -256,6 +253,8 @@ public:
WeakMap_Ctor,
Map_Ctor,
IntrinsicTypedArray_Ctor,
+ Url_Ctor,
+ UrlSearchParams_Ctor,
GetSymbolSpecies,
@@ -296,6 +295,14 @@ public:
FunctionObject *weakMapCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + WeakMap_Ctor); }
FunctionObject *mapCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Map_Ctor); }
FunctionObject *intrinsicTypedArrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + IntrinsicTypedArray_Ctor); }
+ FunctionObject *urlCtor() const
+ {
+ return reinterpret_cast<FunctionObject *>(jsObjects + Url_Ctor);
+ }
+ FunctionObject *urlSearchParamsCtor() const
+ {
+ return reinterpret_cast<FunctionObject *>(jsObjects + UrlSearchParams_Ctor);
+ }
FunctionObject *typedArrayCtors;
FunctionObject *getSymbolSpecies() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetSymbolSpecies); }
@@ -321,9 +328,7 @@ public:
Object *uRIErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + URIErrorProto); }
Object *promisePrototype() const { return reinterpret_cast<Object *>(jsObjects + PromiseProto); }
Object *variantPrototype() const { return reinterpret_cast<Object *>(jsObjects + VariantProto); }
-#if QT_CONFIG(qml_sequence_object)
Object *sequencePrototype() const { return reinterpret_cast<Object *>(jsObjects + SequenceProto); }
-#endif
Object *sharedArrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + SharedArrayBufferProto); }
Object *arrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayBufferProto); }
@@ -343,11 +348,17 @@ public:
Object *mapIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + MapIteratorProto); }
Object *arrayIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayIteratorProto); }
Object *stringIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringIteratorProto); }
+ Object *urlPrototype() const { return reinterpret_cast<Object *>(jsObjects + UrlProto); }
+ Object *urlSearchParamsPrototype() const { return reinterpret_cast<Object *>(jsObjects + UrlSearchParamsProto); }
EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); }
FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); }
FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); }
+#if QT_CONFIG(qml_network)
+ QNetworkAccessManager* (*networkAccessManager)(ExecutionEngine*) = detail::getNetworkAccessManager;
+#endif
+
enum JSStrings {
String_Empty,
String_undefined,
@@ -485,8 +496,6 @@ public:
Symbol *symbol_unscopables() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_unscopables); }
Symbol *symbol_revokableProxy() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_revokableProxy); }
- QIntrusiveList<ExecutableCompilationUnit, &ExecutableCompilationUnit::nextCompilationUnit> compilationUnits;
-
quint32 m_engineId;
RegExpCache *regExpCache;
@@ -499,7 +508,8 @@ public:
// calling preserve() on the object which removes it from this scarceResource list.
class ScarceResourceData {
public:
- ScarceResourceData(const QVariant &data = QVariant()) : data(data) {}
+ ScarceResourceData() = default;
+ ScarceResourceData(const QMetaType type, const void *data) : data(type, data) {}
QVariant data;
QIntrusiveListNode node;
};
@@ -532,7 +542,14 @@ public:
void setProfiler(Profiling::Profiler *profiler);
#endif // QT_CONFIG(qml_debug)
- ExecutionContext *currentContext() const;
+ // We don't want to #include <private/qv4stackframe_p.h> here, but we still want
+ // currentContext() to be inline. Therefore we shift the requirement to provide the
+ // complete type of CppStackFrame to the caller by making this a template.
+ template<typename StackFrame = CppStackFrame>
+ ExecutionContext *currentContext() const
+ {
+ return static_cast<const StackFrame *>(currentStackFrame)->context();
+ }
// ensure we always get odd prototype IDs. This helps make marking in QV4::Lookup fast
quintptr newProtoId() { return (protoIdCount += 2); }
@@ -542,6 +559,7 @@ public:
Heap::Object *newObject();
Heap::Object *newObject(Heap::InternalClass *internalClass);
+ Heap::String *newString(char16_t c) { return newString(QChar(c)); }
Heap::String *newString(const QString &s = QString());
Heap::String *newIdentifier(const QString &text);
@@ -558,17 +576,22 @@ public:
Heap::ArrayBuffer *newArrayBuffer(const QByteArray &array);
Heap::ArrayBuffer *newArrayBuffer(size_t length);
- Heap::DateObject *newDateObject(const Value &value);
- Heap::DateObject *newDateObject(const QDateTime &dt);
- Heap::DateObject *newDateObjectFromTime(const QTime &t);
+ Heap::DateObject *newDateObject(double dateTime);
+ Heap::DateObject *newDateObject(const QDateTime &dateTime);
+ Heap::DateObject *newDateObject(QDate date, Heap::Object *parent, int index, uint flags);
+ Heap::DateObject *newDateObject(QTime time, Heap::Object *parent, int index, uint flags);
+ Heap::DateObject *newDateObject(QDateTime dateTime, Heap::Object *parent, int index, uint flags);
Heap::RegExpObject *newRegExpObject(const QString &pattern, int flags);
Heap::RegExpObject *newRegExpObject(RegExp *re);
- Heap::RegExpObject *newRegExpObject(const QRegExp &re);
#if QT_CONFIG(regularexpression)
Heap::RegExpObject *newRegExpObject(const QRegularExpression &re);
#endif
+ Heap::UrlObject *newUrlObject();
+ Heap::UrlObject *newUrlObject(const QUrl &url);
+ Heap::UrlSearchParamsObject *newUrlSearchParamsObject();
+
Heap::Object *newErrorObject(const Value &value);
Heap::Object *newErrorObject(const QString &message);
Heap::Object *newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column);
@@ -585,16 +608,35 @@ public:
Heap::Object *newPromiseObject(const QV4::FunctionObject *thisObject, const QV4::PromiseCapability *capability);
Promise::ReactionHandler *getPromiseReactionHandler();
- Heap::Object *newVariantObject(const QVariant &v);
+ Heap::Object *newVariantObject(const QMetaType type, const void *data);
Heap::Object *newForInIteratorObject(Object *o);
Heap::Object *newSetIteratorObject(Object *o);
Heap::Object *newMapIteratorObject(Object *o);
Heap::Object *newArrayIteratorObject(Object *o);
+ static Heap::ExecutionContext *qmlContext(Heap::ExecutionContext *ctx)
+ {
+ Heap::ExecutionContext *outer = ctx->outer;
+
+ if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !outer)
+ return nullptr;
+
+ while (outer && outer->type != Heap::ExecutionContext::Type_GlobalContext) {
+ ctx = outer;
+ outer = ctx->outer;
+ }
+
+ Q_ASSERT(ctx);
+ if (ctx->type != Heap::ExecutionContext::Type_QmlContext)
+ return nullptr;
+
+ return ctx;
+ }
+
Heap::QmlContext *qmlContext() const;
QObject *qmlScopeObject() const;
- QQmlContextData *callingQmlContext() const;
+ QQmlRefPointer<QQmlContextData> callingQmlContext() const;
StackTrace stackTrace(int frameLimit = -1) const;
@@ -628,26 +670,34 @@ public:
QQmlError catchExceptionAsQmlError();
// variant conversions
- QVariant toVariant(const QV4::Value &value, int typeHint, bool createJSValueForObjects = true);
+ static QVariant toVariant(
+ const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols = true);
+ static QVariant toVariantLossy(const QV4::Value &value);
QV4::ReturnedValue fromVariant(const QVariant &);
+ QV4::ReturnedValue fromVariant(
+ const QVariant &variant, Heap::Object *parent, int property, uint flags);
- QVariantMap variantMapFromJS(const QV4::Object *o);
+ static QVariantMap variantMapFromJS(const QV4::Object *o);
- bool metaTypeFromJS(const Value *value, int type, void *data);
- QV4::ReturnedValue metaTypeToJS(int type, const void *data);
+ static bool metaTypeFromJS(const Value &value, QMetaType type, void *data);
+ QV4::ReturnedValue metaTypeToJS(QMetaType type, const void *data);
int maxJSStackSize() const;
int maxGCStackSize() const;
bool checkStackLimits();
+ int safeForAllocLength(qint64 len64);
bool canJIT(Function *f = nullptr)
{
#if QT_CONFIG(qml_jit)
if (!m_canAllocateExecutableMemory)
return false;
- if (f)
- return !f->isGenerator() && f->interpreterCallCount >= jitCallCountThreshold;
+ if (f) {
+ return f->kind != Function::AotCompiled
+ && !f->isGenerator()
+ && f->interpreterCallCount >= s_jitCallCountThreshold;
+ }
return true;
#else
Q_UNUSED(f);
@@ -658,8 +708,10 @@ public:
QV4::ReturnedValue global();
void initQmlGlobalObject();
void initializeGlobal();
+ void createQtObject();
void freezeObject(const QV4::Value &value);
+ void lockObject(const QV4::Value &value);
// Return the list of illegal id names (the names of the properties on the global object)
const QSet<QString> &illegalNames() const;
@@ -689,7 +741,7 @@ public:
void setExtensionData(int, Deletable *);
Deletable *extensionData(int index) const
{
- if (index < m_extensionData.count())
+ if (index < m_extensionData.size())
return m_extensionData[index];
else
return nullptr;
@@ -701,19 +753,117 @@ public:
QQmlRefPointer<ExecutableCompilationUnit> compileModule(
const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp);
- mutable QMutex moduleMutex;
- QHash<QUrl, QQmlRefPointer<ExecutableCompilationUnit>> modules;
- void injectModule(const QQmlRefPointer<ExecutableCompilationUnit> &moduleUnit);
- QQmlRefPointer<ExecutableCompilationUnit> moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr) const;
- QQmlRefPointer<ExecutableCompilationUnit> loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr);
+ QQmlRefPointer<ExecutableCompilationUnit> compilationUnitForUrl(const QUrl &url) const;
+
+ QQmlRefPointer<ExecutableCompilationUnit> executableCompilationUnit(
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> &&unit);
+
+ QQmlRefPointer<ExecutableCompilationUnit> insertCompilationUnit(
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> &&unit);
+
+ QMultiHash<QUrl, QQmlRefPointer<ExecutableCompilationUnit>> compilationUnits() const
+ {
+ return m_compilationUnits;
+ }
+ void clearCompilationUnits() { m_compilationUnits.clear(); }
+ void trimCompilationUnits();
+
+ QV4::Value *registerNativeModule(const QUrl &url, const QV4::Value &module);
+
+ struct Module {
+ QQmlRefPointer<ExecutableCompilationUnit> compiled;
+
+ // We can pass a raw value pointer here, but nowhere else. See below.
+ Value *native = nullptr;
+ };
+
+ Module moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr) const;
+ Module loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr);
+
+ DiskCacheOptions diskCacheOptions() const;
+
+ void callInContext(QV4::Function *function, QObject *self, QV4::ExecutionContext *ctxt,
+ int argc, void **args, QMetaType *types);
+ QV4::ReturnedValue callInContext(QV4::Function *function, QObject *self,
+ QV4::ExecutionContext *ctxt, int argc, const QV4::Value *argv);
+
+ QV4::ReturnedValue fromData(
+ QMetaType type, const void *ptr,
+ Heap::Object *parent = nullptr, int property = -1, uint flags = 0);
+
+
+ static void setMaxCallDepth(int maxCallDepth) { s_maxCallDepth = maxCallDepth; }
+ static int maxCallDepth() { return s_maxCallDepth; }
+
+ template<typename Value>
+ static QJSPrimitiveValue createPrimitive(const Value &v)
+ {
+ if (v->isUndefined())
+ return QJSPrimitiveValue(QJSPrimitiveUndefined());
+ if (v->isNull())
+ return QJSPrimitiveValue(QJSPrimitiveNull());
+ if (v->isBoolean())
+ return QJSPrimitiveValue(v->toBoolean());
+ if (v->isInteger())
+ return QJSPrimitiveValue(v->integerValue());
+ if (v->isDouble())
+ return QJSPrimitiveValue(v->doubleValue());
+ bool ok;
+ const QString result = v->toQString(&ok);
+ return ok ? QJSPrimitiveValue(result) : QJSPrimitiveValue(QJSPrimitiveUndefined());
+ }
private:
+ template<int Frames>
+ friend struct ExecutionEngineCallDepthRecorder;
+
+ static void initializeStaticMembers();
+
+ bool inStack(const void *current) const
+ {
+#if Q_STACK_GROWTH_DIRECTION > 0
+ return current < cppStackLimit && current >= cppStackBase;
+#else
+ return current > cppStackLimit && current <= cppStackBase;
+#endif
+ }
+
+ bool hasCppStackOverflow()
+ {
+ if (s_maxCallDepth >= 0)
+ return callDepth >= s_maxCallDepth;
+
+ if (inStack(currentStackPointer()))
+ return false;
+
+ // Double check the stack limits on failure.
+ // We may have moved to a different thread.
+ const StackProperties stack = stackProperties();
+ cppStackBase = stack.base;
+ cppStackLimit = stack.softLimit;
+ return !inStack(currentStackPointer());
+ }
+
+ bool hasJsStackOverflow() const
+ {
+ return jsStackTop > jsStackLimit;
+ }
+
+ bool hasStackOverflow()
+ {
+ return hasJsStackOverflow() || hasCppStackOverflow();
+ }
+
+ static int s_maxCallDepth;
+ static int s_jitCallCountThreshold;
+ static int s_maxJSStackSize;
+ static int s_maxGCStackSize;
+
#if QT_CONFIG(qml_debug)
QScopedPointer<QV4::Debugging::Debugger> m_debugger;
QScopedPointer<QV4::Profiling::Profiler> m_profiler;
#endif
QSet<QString> m_illegalNames;
- int jitCallCountThreshold;
// used by generated Promise objects to handle 'then' events
QScopedPointer<QV4::Promise::ReactionHandler> m_reactionHandler;
@@ -733,24 +883,46 @@ private:
QVector<Deletable *> m_extensionData;
- int m_maxJSStackSize = 4 * 1024 * 1024;
- int m_maxGCStackSize = 2 * 1024 * 1024;
+ QMultiHash<QUrl, QQmlRefPointer<ExecutableCompilationUnit>> m_compilationUnits;
+
+ // QV4::PersistentValue would be preferred, but using QHash will create copies,
+ // and QV4::PersistentValue doesn't like creating copies.
+ // Instead, we allocate a raw pointer using the same manual memory management
+ // technique in QV4::PersistentValue.
+ QHash<QUrl, Value *> nativeModules;
};
-#define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \
+#define CHECK_STACK_LIMITS(v4) \
+ if (v4->checkStackLimits()) \
+ return Encode::undefined(); \
ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4);
+template<int Frames = 1>
struct ExecutionEngineCallDepthRecorder
{
ExecutionEngine *ee;
- ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ++ee->callDepth; }
- ~ExecutionEngineCallDepthRecorder() { --ee->callDepth; }
+ ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e)
+ {
+ if (ExecutionEngine::s_maxCallDepth >= 0)
+ ee->callDepth += Frames;
+ }
+
+ ~ExecutionEngineCallDepthRecorder()
+ {
+ if (ExecutionEngine::s_maxCallDepth >= 0)
+ ee->callDepth -= Frames;
+ }
+
+ bool hasOverflow() const
+ {
+ return ee->hasCppStackOverflow();
+ }
};
inline bool ExecutionEngine::checkStackLimits()
{
- if (Q_UNLIKELY((jsStackTop > jsStackLimit) || (callDepth >= maxCallDepth))) {
+ if (Q_UNLIKELY(hasStackOverflow())) {
throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
return true;
}
@@ -758,6 +930,8 @@ inline bool ExecutionEngine::checkStackLimits()
return false;
}
+Q_DECLARE_OPERATORS_FOR_FLAGS(ExecutionEngine::DiskCacheOptions);
+
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h
index 788897bdad..68e906baa1 100644
--- a/src/qml/jsruntime/qv4enginebase_p.h
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4ENGINEBASE_P_H
#define QV4ENGINEBASE_P_H
@@ -60,10 +24,6 @@ namespace QV4 {
struct CppStackFrame;
// Base class for the execution engine
-
-#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
-#pragma pack(push, 1)
-#endif
struct Q_QML_EXPORT EngineBase {
CppStackFrame *currentStackFrame = nullptr;
@@ -84,16 +44,27 @@ struct Q_QML_EXPORT EngineBase {
#endif
quint8 isExecutingInRegExpJIT = false;
- quint8 padding[3];
+ quint8 isInitialized = false;
+ quint8 inShutdown = false;
+ quint8 isGCOngoing = false; // incremental gc is ongoing (but mutator might be running)
MemoryManager *memoryManager = nullptr;
- Runtime runtime;
- qint32 callDepth = 0;
+ union {
+ const void *cppStackBase = nullptr;
+ struct {
+ qint32 callDepth;
+#if QT_POINTER_SIZE == 8
+ quint32 padding2;
+#endif
+ };
+ };
+ const void *cppStackLimit = nullptr;
+
+ Object *globalObject = nullptr;
Value *jsStackLimit = nullptr;
Value *jsStackBase = nullptr;
IdentifierTable *identifierTable = nullptr;
- Object *globalObject = nullptr;
// Exception handling
Value *exceptionValue = nullptr;
@@ -137,17 +108,14 @@ struct Q_QML_EXPORT EngineBase {
Heap::InternalClass *classes[NClasses];
Heap::InternalClass *internalClasses(InternalClassType icType) { return classes[icType]; }
};
-#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
-#pragma pack(pop)
-#endif
Q_STATIC_ASSERT(std::is_standard_layout<EngineBase>::value);
Q_STATIC_ASSERT(offsetof(EngineBase, currentStackFrame) == 0);
Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, currentStackFrame) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + 8);
-Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE);
Q_STATIC_ASSERT(offsetof(EngineBase, isInterrupted) + sizeof(EngineBase::isInterrupted) <= offsetof(EngineBase, hasException) + 4);
+Q_STATIC_ASSERT(offsetof(EngineBase, globalObject) % QT_POINTER_SIZE == 0);
}
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 525d3458f4..35b5952d38 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4errorobject_p.h"
@@ -45,7 +9,6 @@
#include <QtCore/QStringList>
#include <QtCore/QDebug>
-#include "qv4string_p.h"
#include <private/qv4mm_p.h>
#include <private/qv4codegen_p.h>
@@ -57,7 +20,7 @@
# include "qplatformdefs.h"
# endif
#else
-# include <windows.h>
+# include <qt_windows.h>
#endif
using namespace QV4;
@@ -93,7 +56,7 @@ void Heap::ErrorObject::init(const Value &message, ErrorType t)
e->d()->stackTrace = new StackTrace(scope.engine->stackTrace());
if (!e->d()->stackTrace->isEmpty()) {
setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source));
- setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Value::fromInt32(e->d()->stackTrace->at(0).line));
+ setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Value::fromInt32(qAbs(e->d()->stackTrace->at(0).line)));
}
if (!message.isUndefined())
@@ -121,7 +84,7 @@ void Heap::ErrorObject::init(const Value &message, const QString &fileName, int
Q_ASSERT(!e->d()->stackTrace->isEmpty());
setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source));
- setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Value::fromInt32(e->d()->stackTrace->at(0).line));
+ setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Value::fromInt32(qAbs(e->d()->stackTrace->at(0).line)));
if (!message.isUndefined())
setProperty(scope.engine, QV4::ErrorObject::Index_Message, message);
@@ -156,7 +119,7 @@ ReturnedValue ErrorObject::method_get_stack(const FunctionObject *b, const Value
return v4->throwTypeError();
if (!This->d()->stack) {
QString trace;
- for (int i = 0; i < This->d()->stackTrace->count(); ++i) {
+ for (int i = 0; i < This->d()->stackTrace->size(); ++i) {
if (i > 0)
trace += QLatin1Char('\n');
const StackFrame &frame = This->d()->stackTrace->at(i);
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 139bcc9754..541f5cae36 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4ERROROBJECT_H
#define QV4ERROROBJECT_H
@@ -52,7 +16,6 @@
#include "qv4object_p.h"
#include "qv4functionobject_p.h"
-#include "qv4string_p.h"
QT_BEGIN_NAMESPACE
@@ -67,7 +30,7 @@ namespace Heap {
Member(class, Pointer, String *, stack)
DECLARE_HEAP_OBJECT(ErrorObject, Object) {
- DECLARE_MARKOBJECTS(ErrorObject);
+ DECLARE_MARKOBJECTS(ErrorObject)
enum ErrorType {
Error,
EvalError,
diff --git a/src/qml/jsruntime/qv4estable.cpp b/src/qml/jsruntime/qv4estable.cpp
index 99f6bf6aa0..fb36b10728 100644
--- a/src/qml/jsruntime/qv4estable.cpp
+++ b/src/qml/jsruntime/qv4estable.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Crimson AS <info@crimson.no>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Crimson AS <info@crimson.no>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4estable_p.h"
#include "qv4object_p.h"
@@ -147,21 +111,18 @@ ReturnedValue ESTable::get(const Value &key, bool *hasValue) const
// Removes the given \a key from the table
bool ESTable::remove(const Value &key)
{
- bool found = false;
- uint idx = 0;
- for (; idx < m_size; ++idx) {
- if (m_keys[idx].sameValueZero(key)) {
- found = true;
- break;
+ for (uint index = 0; index < m_size; ++index) {
+ if (m_keys[index].sameValueZero(key)) {
+ // Remove the element at |index| by moving all elements to the right
+ // of |index| one place to the left.
+ size_t count = (m_size - (index + 1)) * sizeof(Value);
+ memmove(m_keys + index, m_keys + index + 1, count);
+ memmove(m_values + index, m_values + index + 1, count);
+ m_size--;
+ return true;
}
}
-
- if (found == true) {
- memmove(m_keys + idx, m_keys + idx + 1, (m_size - idx)*sizeof(Value));
- memmove(m_values + idx, m_values + idx + 1, (m_size - idx)*sizeof(Value));
- m_size--;
- }
- return found;
+ return false;
}
// Returns the size of the table. Note that the size may not match the underlying allocation.
diff --git a/src/qml/jsruntime/qv4estable_p.h b/src/qml/jsruntime/qv4estable_p.h
index f54fc37a7b..f0c5c7cb81 100644
--- a/src/qml/jsruntime/qv4estable_p.h
+++ b/src/qml/jsruntime/qv4estable_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Crimson AS <info@crimson.no>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Crimson AS <info@crimson.no>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
@@ -53,12 +17,13 @@
#include "qv4value_p.h"
+class tst_qv4estable;
+
QT_BEGIN_NAMESPACE
-namespace QV4
-{
+namespace QV4 {
-class ESTable
+class Q_AUTOTEST_EXPORT ESTable
{
public:
ESTable();
@@ -76,13 +41,15 @@ public:
void removeUnmarkedKeys();
private:
+ friend class ::tst_qv4estable;
+
Value *m_keys = nullptr;
Value *m_values = nullptr;
uint m_size = 0;
uint m_capacity = 0;
};
-}
+} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4executableallocator.cpp b/src/qml/jsruntime/qv4executableallocator.cpp
index 7ee6f39aa2..71d8061d65 100644
--- a/src/qml/jsruntime/qv4executableallocator.cpp
+++ b/src/qml/jsruntime/qv4executableallocator.cpp
@@ -1,56 +1,30 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4executableallocator_p.h"
-#include "qv4functiontable_p.h"
+#include <QtQml/private/qv4functiontable_p.h>
#include <wtf/StdLibExtras.h>
#include <wtf/PageAllocation.h>
using namespace QV4;
-void *ExecutableAllocator::Allocation::exceptionHandler() const
+void *ExecutableAllocator::Allocation::exceptionHandlerStart() const
{
return reinterpret_cast<void*>(addr);
}
-void *ExecutableAllocator::Allocation::start() const
+size_t ExecutableAllocator::Allocation::exceptionHandlerSize() const
+{
+ return QV4::exceptionHandlerSize();
+}
+
+void *ExecutableAllocator::Allocation::memoryStart() const
+{
+ return reinterpret_cast<void*>(addr);
+}
+
+void *ExecutableAllocator::Allocation::codeStart() const
{
return reinterpret_cast<void*>(addr + exceptionHandlerSize());
}
@@ -151,7 +125,7 @@ ExecutableAllocator::ExecutableAllocator()
ExecutableAllocator::~ExecutableAllocator()
{
- for (ChunkOfPages *chunk : qAsConst(chunks)) {
+ for (ChunkOfPages *chunk : std::as_const(chunks)) {
for (Allocation *allocation = chunk->firstAllocation; allocation; allocation = allocation->next)
if (!allocation->free)
allocation->invalidate();
diff --git a/src/qml/jsruntime/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h
index f98f2c7d33..8181bf17ae 100644
--- a/src/qml/jsruntime/qv4executableallocator_p.h
+++ b/src/qml/jsruntime/qv4executableallocator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4EXECUTABLEALLOCATOR_H
#define QV4EXECUTABLEALLOCATOR_H
@@ -51,14 +15,14 @@
// We mean it.
//
-#include "qv4global_p.h"
-
#include <QMultiMap>
#include <QHash>
#include <QVector>
#include <QByteArray>
#include <QMutex>
+#include <QtQml/private/qtqmlglobal_p.h>
+
namespace WTF {
class PageAllocation;
}
@@ -86,8 +50,14 @@ public:
, free(true)
{}
- void *exceptionHandler() const;
- void *start() const;
+ void *memoryStart() const;
+ size_t memorySize() const { return size; }
+
+ void *exceptionHandlerStart() const;
+ size_t exceptionHandlerSize() const;
+
+ void *codeStart() const;
+
void invalidate() { addr = 0; }
bool isValid() const { return addr != 0; }
void deallocate(ExecutableAllocator *allocator);
@@ -109,8 +79,8 @@ public:
};
// for debugging / unit-testing
- int freeAllocationCount() const { return freeAllocations.count(); }
- int chunkCount() const { return chunks.count(); }
+ int freeAllocationCount() const { return freeAllocations.size(); }
+ int chunkCount() const { return chunks.size(); }
struct ChunkOfPages
{
@@ -130,7 +100,7 @@ public:
private:
QMultiMap<size_t, Allocation*> freeAllocations;
QMap<quintptr, ChunkOfPages*> chunks;
- mutable QRecursiveMutex mutex;
+ mutable QMutex mutex;
};
}
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index d51e986006..34d737cdae 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -1,42 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qml/qqmlprivate.h"
+#include "qv4engine_p.h"
#include "qv4executablecompilationunit_p.h"
#include <private/qv4engine_p.h>
@@ -51,31 +17,15 @@
#include <private/qqmlscriptdata_p.h>
#include <private/qv4module_p.h>
#include <private/qv4compilationunitmapper_p.h>
-#include <private/qml_compile_hash_p.h>
#include <private/qqmltypewrapper_p.h>
+#include <private/qv4resolvedtypereference_p.h>
+#include <private/qv4objectiterator_p.h>
-#include <QtQml/qqmlfile.h>
#include <QtQml/qqmlpropertymap.h>
-#include <QtCore/qdir.h>
-#include <QtCore/qstandardpaths.h>
#include <QtCore/qfileinfo.h>
-#include <QtCore/qscopeguard.h>
#include <QtCore/qcryptographichash.h>
-#if defined(QML_COMPILE_HASH)
-# ifdef Q_OS_LINUX
-// Place on a separate section on Linux so it's easier to check from outside
-// what the hash version is.
-__attribute__((section(".qml_compile_hash")))
-# endif
-const char qml_compile_hash[48 + 1] = QML_COMPILE_HASH;
-static_assert(sizeof(QV4::CompiledData::Unit::libraryVersionHash) >= QML_COMPILE_HASH_LENGTH + 1,
- "Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version");
-#else
-# error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
-#endif
-
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -83,24 +33,16 @@ namespace QV4 {
ExecutableCompilationUnit::ExecutableCompilationUnit() = default;
ExecutableCompilationUnit::ExecutableCompilationUnit(
- CompiledData::CompilationUnit &&compilationUnit)
- : CompiledData::CompilationUnit(std::move(compilationUnit))
-{}
-
-ExecutableCompilationUnit::~ExecutableCompilationUnit()
+ QQmlRefPointer<CompiledData::CompilationUnit> &&compilationUnit)
+ : m_compilationUnit(std::move(compilationUnit))
{
- unlink();
+ constants = m_compilationUnit->constants;
}
-QString ExecutableCompilationUnit::localCacheFilePath(const QUrl &url)
+ExecutableCompilationUnit::~ExecutableCompilationUnit()
{
- const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- const QString cacheFileSuffix = QFileInfo(localSourcePath + QLatin1Char('c')).completeSuffix();
- QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
- fileNameHash.addData(localSourcePath.toUtf8());
- QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
- QDir::root().mkpath(directory);
- return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + cacheFileSuffix;
+ if (engine)
+ clear();
}
static QString toString(QV4::ReturnedValue v)
@@ -128,31 +70,36 @@ static void dumpConstantTable(const StaticValue *constants, uint count)
}
}
-QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
+void ExecutableCompilationUnit::populate()
{
- this->engine = engine;
- engine->compilationUnits.insert(this);
+ /* In general, we should use QV4::Scope whenever we allocate heap objects, and employ write barriers
+ for member variables pointing to heap objects. However, ExecutableCompilationUnit is special, as it
+ is always part of the root set. So instead of using scopde allocations and write barriers, we use a
+ slightly different approach: We temporarily block the gc from running. Afterwards, at the end of the
+ function we check whether the gc was already running, and mark the ExecutableCompilationUnit. This
+ ensures that all the newly allocated objects of the compilation unit will be marked in turn.
+ If the gc was not running, we don't have to do anything, because everything will be marked when the
+ gc starts marking the root set at the start of a run.
+ */
+ const CompiledData::Unit *data = m_compilationUnit->data;
+ GCCriticalSection<ExecutableCompilationUnit> criticalSection(engine, this);
Q_ASSERT(!runtimeStrings);
+ Q_ASSERT(engine);
Q_ASSERT(data);
const quint32 stringCount = totalStringCount();
- runtimeStrings = (QV4::Heap::String **)malloc(stringCount * sizeof(QV4::Heap::String*));
- // memset the strings to 0 in case a GC run happens while we're within the loop below
- memset(runtimeStrings, 0, stringCount * sizeof(QV4::Heap::String*));
+ runtimeStrings = (QV4::Heap::String **)calloc(stringCount, sizeof(QV4::Heap::String*));
for (uint i = 0; i < stringCount; ++i)
runtimeStrings[i] = engine->newString(stringAt(i));
runtimeRegularExpressions
= new QV4::Value[data->regexpTableSize];
- // memset the regexps to 0 in case a GC run happens while we're within the loop below
- memset(runtimeRegularExpressions, 0,
- data->regexpTableSize * sizeof(QV4::Value));
for (uint i = 0; i < data->regexpTableSize; ++i) {
const CompiledData::RegExp *re = data->regexpAt(i);
- uint f = re->flags;
+ uint f = re->flags();
const CompiledData::RegExp::Flags flags = static_cast<CompiledData::RegExp::Flags>(f);
runtimeRegularExpressions[i] = QV4::RegExp::create(
- engine, stringAt(re->stringIndex), flags);
+ engine, stringAt(re->stringIndex()), flags);
}
if (data->lookupTableSize) {
@@ -163,7 +110,7 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
QV4::Lookup *l = runtimeLookups + i;
CompiledData::Lookup::Type type
- = CompiledData::Lookup::Type(uint(compiledLookups[i].type_and_flags));
+ = CompiledData::Lookup::Type(uint(compiledLookups[i].type()));
if (type == CompiledData::Lookup::Type_Getter)
l->getter = QV4::Lookup::getterGeneric;
else if (type == CompiledData::Lookup::Type_Setter)
@@ -172,17 +119,16 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
l->globalGetter = QV4::Lookup::globalGetterGeneric;
else if (type == CompiledData::Lookup::Type_QmlContextPropertyGetter)
l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
- l->nameIndex = compiledLookups[i].nameIndex;
+ l->forCall = compiledLookups[i].mode() == CompiledData::Lookup::Mode_ForCall;
+ l->nameIndex = compiledLookups[i].nameIndex();
}
}
if (data->jsClassTableSize) {
runtimeClasses
- = (QV4::Heap::InternalClass **)malloc(data->jsClassTableSize
- * sizeof(QV4::Heap::InternalClass *));
- // memset the regexps to 0 in case a GC run happens while we're within the loop below
- memset(runtimeClasses, 0,
- data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *));
+ = (QV4::Heap::InternalClass **)calloc(data->jsClassTableSize,
+ sizeof(QV4::Heap::InternalClass *));
+
for (uint i = 0; i < data->jsClassTableSize; ++i) {
int memberCount = 0;
const CompiledData::JSClassMember *member
@@ -193,17 +139,37 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
runtimeClasses[i]
= runtimeClasses[i]->addMember(
engine->identifierTable->asPropertyKey(
- runtimeStrings[member->nameOffset]),
- member->isAccessor
+ runtimeStrings[member->nameOffset()]),
+ member->isAccessor()
? QV4::Attr_Accessor
: QV4::Attr_Data);
}
}
runtimeFunctions.resize(data->functionTableSize);
+ static bool ignoreAotCompiledFunctions
+ = qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER")
+ || !(engine->diskCacheOptions() & ExecutionEngine::DiskCache::AotNative);
+
+ const QQmlPrivate::AOTCompiledFunction *aotFunction
+ = ignoreAotCompiledFunctions ? nullptr : m_compilationUnit->aotCompiledFunctions;
+
+ auto advanceAotFunction = [&](int i) -> const QQmlPrivate::AOTCompiledFunction * {
+ if (aotFunction) {
+ if (aotFunction->functionPtr) {
+ if (aotFunction->functionIndex == i)
+ return aotFunction++;
+ } else {
+ aotFunction = nullptr;
+ }
+ }
+ return nullptr;
+ };
+
for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
const QV4::CompiledData::Function *compiledFunction = data->functionAt(i);
- runtimeFunctions[i] = QV4::Function::create(engine, this, compiledFunction);
+ runtimeFunctions[i] = QV4::Function::create(engine, this, compiledFunction,
+ advanceAotFunction(i));
}
Scope scope(engine);
@@ -237,15 +203,14 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
<< (data->indexOfRootFunction != -1
? data->indexOfRootFunction : 0);
}
-
- if (data->indexOfRootFunction != -1)
- return runtimeFunctions[data->indexOfRootFunction];
- else
- return nullptr;
}
Heap::Object *ExecutableCompilationUnit::templateObjectAt(int index) const
{
+ const CompiledData::Unit *data = m_compilationUnit->data;
+ Q_ASSERT(data);
+ Q_ASSERT(engine);
+
Q_ASSERT(index < int(data->templateObjectTableSize));
if (!templateObjects.size())
templateObjects.resize(data->templateObjectTableSize);
@@ -274,56 +239,21 @@ Heap::Object *ExecutableCompilationUnit::templateObjectAt(int index) const
return templateObjects.at(index);
}
-void ExecutableCompilationUnit::unlink()
+void ExecutableCompilationUnit::clear()
{
- if (engine)
- nextCompilationUnit.remove();
-
- if (isRegisteredWithEngine) {
- Q_ASSERT(data && propertyCaches.count() > 0 && propertyCaches.at(/*root object*/0));
- if (qmlEngine)
- qmlEngine->unregisterInternalCompositeType(this);
- QQmlMetaType::unregisterInternalCompositeType(this);
- isRegisteredWithEngine = false;
- }
-
- propertyCaches.clear();
+ delete [] imports;
+ imports = nullptr;
if (runtimeLookups) {
- for (uint i = 0; i < data->lookupTableSize; ++i) {
- QV4::Lookup &l = runtimeLookups[i];
- if (l.getter == QV4::QObjectWrapper::lookupGetter
- || l.getter == QQmlTypeWrapper::lookupSingletonProperty) {
- if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
- pc->release();
- } else if (l.getter == QQmlValueTypeWrapper::lookupGetter
- || l.getter == QQmlTypeWrapper::lookupSingletonProperty) {
- if (QQmlPropertyCache *pc = l.qgadgetLookup.propertyCache)
- pc->release();
- }
-
- if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty
- || l.qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty) {
- if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
- pc->release();
- }
- }
+ const uint lookupTableSize = unitData()->lookupTableSize;
+ for (uint i = 0; i < lookupTableSize; ++i)
+ runtimeLookups[i].releasePropertyCache();
}
- dependentScripts.clear();
-
- typeNameCache = nullptr;
-
- qDeleteAll(resolvedTypes);
- resolvedTypes.clear();
-
- engine = nullptr;
- qmlEngine = nullptr;
-
delete [] runtimeLookups;
runtimeLookups = nullptr;
- for (QV4::Function *f : qAsConst(runtimeFunctions))
+ for (QV4::Function *f : std::as_const(runtimeFunctions))
f->destroy();
runtimeFunctions.clear();
@@ -335,8 +265,10 @@ void ExecutableCompilationUnit::unlink()
runtimeClasses = nullptr;
}
-void ExecutableCompilationUnit::markObjects(QV4::MarkStack *markStack)
+void ExecutableCompilationUnit::markObjects(QV4::MarkStack *markStack) const
{
+ const CompiledData::Unit *data = m_compilationUnit->data;
+
if (runtimeStrings) {
for (uint i = 0, end = totalStringCount(); i < end; ++i)
if (runtimeStrings[i])
@@ -351,14 +283,14 @@ void ExecutableCompilationUnit::markObjects(QV4::MarkStack *markStack)
if (runtimeClasses[i])
runtimeClasses[i]->mark(markStack);
}
- for (QV4::Function *f : qAsConst(runtimeFunctions))
+ for (QV4::Function *f : std::as_const(runtimeFunctions))
if (f && f->internalClass)
f->internalClass->mark(markStack);
- for (QV4::Heap::InternalClass *c : qAsConst(runtimeBlocks))
+ for (QV4::Heap::InternalClass *c : std::as_const(runtimeBlocks))
if (c)
c->mark(markStack);
- for (QV4::Heap::Object *o : qAsConst(templateObjects))
+ for (QV4::Heap::Object *o : std::as_const(templateObjects))
if (o)
o->mark(markStack);
@@ -378,92 +310,35 @@ IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int com
const quint32_le *namedObjectIndexPtr = component->namedObjectsInComponentTable();
for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
const CompiledData::Object *namedObject = objectAt(*namedObjectIndexPtr);
- namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id);
+ namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->objectId());
}
+ Q_ASSERT(!namedObjectCache.isEmpty());
return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache);
}
-void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine)
-{
- this->qmlEngine = qmlEngine;
-
- // Add to type registry of composites
- if (propertyCaches.needsVMEMetaObject(/*root object*/0)) {
- QQmlMetaType::registerInternalCompositeType(this);
- qmlEngine->registerInternalCompositeType(this);
- } else {
- const QV4::CompiledData::Object *obj = objectAt(/*root object*/0);
- auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
- Q_ASSERT(typeRef);
- if (typeRef->compilationUnit) {
- metaTypeId = typeRef->compilationUnit->metaTypeId;
- listMetaTypeId = typeRef->compilationUnit->listMetaTypeId;
- } else {
- metaTypeId = typeRef->type.typeId();
- listMetaTypeId = typeRef->type.qListTypeId();
- }
- }
-
- // Collect some data for instantiation later.
- int bindingCount = 0;
- int parserStatusCount = 0;
- int objectCount = 0;
- for (quint32 i = 0, count = this->objectCount(); i < count; ++i) {
- const QV4::CompiledData::Object *obj = objectAt(i);
- bindingCount += obj->nBindings;
- if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
- if (typeRef->type.isValid()) {
- if (typeRef->type.parserStatusCast() != -1)
- ++parserStatusCount;
- }
- ++objectCount;
- if (typeRef->compilationUnit) {
- bindingCount += typeRef->compilationUnit->totalBindingsCount;
- parserStatusCount += typeRef->compilationUnit->totalParserStatusCount;
- objectCount += typeRef->compilationUnit->totalObjectCount;
- }
- }
- }
-
- totalBindingsCount = bindingCount;
- totalParserStatusCount = parserStatusCount;
- totalObjectCount = objectCount;
-}
-
-bool ExecutableCompilationUnit::verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const
+QQmlRefPointer<ExecutableCompilationUnit> ExecutableCompilationUnit::create(
+ QQmlRefPointer<CompiledData::CompilationUnit> &&compilationUnit, ExecutionEngine *engine)
{
- if (!dependencyHasher) {
- for (size_t i = 0; i < sizeof(data->dependencyMD5Checksum); ++i) {
- if (data->dependencyMD5Checksum[i] != 0)
- return false;
- }
- return true;
- }
- const QByteArray checksum = dependencyHasher();
- return checksum.size() == sizeof(data->dependencyMD5Checksum)
- && memcmp(data->dependencyMD5Checksum, checksum.constData(),
- sizeof(data->dependencyMD5Checksum)) == 0;
+ auto result = QQmlRefPointer<ExecutableCompilationUnit>(
+ new ExecutableCompilationUnit(std::move(compilationUnit)),
+ QQmlRefPointer<ExecutableCompilationUnit>::Adopt);
+ result->engine = engine;
+ return result;
}
-QStringList ExecutableCompilationUnit::moduleRequests() const
+Heap::Module *ExecutableCompilationUnit::instantiate()
{
- QStringList requests;
- requests.reserve(data->moduleRequestTableSize);
- for (uint i = 0; i < data->moduleRequestTableSize; ++i)
- requests << stringAt(data->moduleRequestTable()[i]);
- return requests;
-}
+ const CompiledData::Unit *data = m_compilationUnit->data;
-Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine)
-{
if (isESModule() && module())
return module();
if (data->indexOfRootFunction < 0)
return nullptr;
- if (!this->engine)
- linkToEngine(engine);
+ Q_ASSERT(engine);
+ if (!runtimeStrings)
+ populate();
Scope scope(engine);
Scoped<Module> module(scope, engine->memoryManager->allocate<Module>(engine, this));
@@ -471,11 +346,14 @@ Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine)
if (isESModule())
setModule(module->d());
- for (const QString &request: moduleRequests()) {
- auto dependentModuleUnit = engine->loadModule(QUrl(request), this);
+ const QStringList moduleRequests = m_compilationUnit->moduleRequests();
+ for (const QString &request: moduleRequests) {
+ const QUrl url(request);
+ const auto dependentModuleUnit = engine->loadModule(url, this);
if (engine->hasException)
return nullptr;
- dependentModuleUnit->instantiate(engine);
+ if (dependentModuleUnit.compiled)
+ dependentModuleUnit.compiled->instantiate();
}
ScopedString importName(scope);
@@ -487,30 +365,87 @@ Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine)
}
for (uint i = 0; i < importCount; ++i) {
const CompiledData::ImportEntry &entry = data->importEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this);
+ QUrl url = urlAt(entry.moduleRequest);
importName = runtimeStrings[entry.importName];
- const Value *valuePtr = dependentModuleUnit->resolveExport(importName);
- if (!valuePtr) {
- QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference ");
- referenceErrorMessage += importName->toQString();
- engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column);
- return nullptr;
+
+ const auto module = engine->loadModule(url, this);
+ if (module.compiled) {
+ const Value *valuePtr = module.compiled->resolveExport(importName);
+ if (!valuePtr) {
+ QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference ");
+ referenceErrorMessage += importName->toQString();
+ engine->throwReferenceError(
+ referenceErrorMessage, fileName(),
+ entry.location.line(), entry.location.column());
+ return nullptr;
+ }
+ imports[i] = valuePtr;
+ } else if (Value *value = module.native) {
+ const QString name = importName->toQString();
+ if (value->isNullOrUndefined()) {
+ QString errorMessage = name;
+ errorMessage += QStringLiteral(" from ");
+ errorMessage += url.toString();
+ errorMessage += QStringLiteral(" is null");
+ engine->throwError(errorMessage);
+ return nullptr;
+ }
+
+ if (name == QStringLiteral("default")) {
+ imports[i] = value;
+ } else {
+ url.setFragment(name);
+ const auto fragment = engine->moduleForUrl(url, this);
+ if (fragment.native) {
+ imports[i] = fragment.native;
+ } else {
+ Scope scope(this->engine);
+ ScopedObject o(scope, value);
+ if (!o) {
+ QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference ");
+ referenceErrorMessage += name;
+ referenceErrorMessage += QStringLiteral(" because ");
+ referenceErrorMessage += url.toString(QUrl::RemoveFragment);
+ referenceErrorMessage += QStringLiteral(" is not an object");
+ engine->throwReferenceError(
+ referenceErrorMessage, fileName(),
+ entry.location.line(), entry.location.column());
+ return nullptr;
+ }
+
+ const ScopedPropertyKey key(scope, scope.engine->identifierTable->asPropertyKey(name));
+ const ScopedValue result(scope, o->get(key));
+ imports[i] = engine->registerNativeModule(url, result);
+ }
+ }
}
- imports[i] = valuePtr;
}
+ const auto throwReferenceError = [&](const CompiledData::ExportEntry &entry, const QString &importName) {
+ QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference ");
+ referenceErrorMessage += importName;
+ engine->throwReferenceError(
+ referenceErrorMessage, fileName(),
+ entry.location.line(), entry.location.column());
+ };
+
for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this);
- if (!dependentModuleUnit)
- return nullptr;
-
+ auto dependentModule = engine->loadModule(urlAt(entry.moduleRequest), this);
ScopedString importName(scope, runtimeStrings[entry.importName]);
- if (!dependentModuleUnit->resolveExport(importName)) {
- QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference ");
- referenceErrorMessage += importName->toQString();
- engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column);
- return nullptr;
+ if (const auto dependentModuleUnit = dependentModule.compiled) {
+ if (!dependentModuleUnit->resolveExport(importName)) {
+ throwReferenceError(entry, importName->toQString());
+ return nullptr;
+ }
+ } else if (const auto native = dependentModule.native) {
+ ScopedObject o(scope, native);
+ const ScopedPropertyKey key(scope, scope.engine->identifierTable->asPropertyKey(importName));
+ const ScopedValue result(scope, o->get(key));
+ if (result->isUndefined()) {
+ throwReferenceError(entry, importName->toQString());
+ return nullptr;
+ }
}
}
@@ -532,6 +467,11 @@ const Value *ExecutableCompilationUnit::resolveExportRecursively(
if (exportName->toQString() == QLatin1String("*"))
return &module()->self;
+ const CompiledData::Unit *data = m_compilationUnit->data;
+
+ Q_ASSERT(data);
+ Q_ASSERT(engine);
+
Scope scope(engine);
if (auto localExport = lookupNameInExportTable(
@@ -547,13 +487,31 @@ const Value *ExecutableCompilationUnit::resolveExportRecursively(
if (auto indirectExport = lookupNameInExportTable(
data->indirectExportEntryTable(), data->indirectExportEntryTableSize, exportName)) {
- auto dependentModuleUnit = engine->loadModule(urlAt(indirectExport->moduleRequest), this);
- if (!dependentModuleUnit)
- return nullptr;
+ QUrl request = urlAt(indirectExport->moduleRequest);
+ auto dependentModule = engine->loadModule(request, this);
ScopedString importName(scope, runtimeStrings[indirectExport->importName]);
- return dependentModuleUnit->resolveExportRecursively(importName, resolveSet);
- }
+ if (dependentModule.compiled) {
+ return dependentModule.compiled->resolveExportRecursively(importName, resolveSet);
+ } else if (dependentModule.native) {
+ if (exportName->toQString() == QLatin1String("*"))
+ return dependentModule.native;
+ if (exportName->toQString() == QLatin1String("default"))
+ return nullptr;
+
+ request.setFragment(importName->toQString());
+ const auto fragment = engine->moduleForUrl(request);
+ if (fragment.native)
+ return fragment.native;
+ ScopedObject o(scope, dependentModule.native);
+ if (o)
+ return engine->registerNativeModule(request, o->get(importName));
+
+ return nullptr;
+ } else {
+ return nullptr;
+ }
+ }
if (exportName->toQString() == QLatin1String("default"))
return nullptr;
@@ -562,11 +520,28 @@ const Value *ExecutableCompilationUnit::resolveExportRecursively(
for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this);
- if (!dependentModuleUnit)
- return nullptr;
+ QUrl request = urlAt(entry.moduleRequest);
+ auto dependentModule = engine->loadModule(request, this);
+ const Value *resolution = nullptr;
+ if (dependentModule.compiled) {
+ resolution = dependentModule.compiled->resolveExportRecursively(
+ exportName, resolveSet);
+ } else if (dependentModule.native) {
+ if (exportName->toQString() == QLatin1String("*")) {
+ resolution = dependentModule.native;
+ } else if (exportName->toQString() != QLatin1String("default")) {
+ request.setFragment(exportName->toQString());
+ const auto fragment = engine->moduleForUrl(request);
+ if (fragment.native) {
+ resolution = fragment.native;
+ } else {
+ ScopedObject o(scope, dependentModule.native);
+ if (o)
+ resolution = engine->registerNativeModule(request, o->get(exportName));
+ }
+ }
+ }
- const Value *resolution = dependentModuleUnit->resolveExportRecursively(exportName, resolveSet);
// ### handle ambiguous
if (resolution) {
if (!starResolution) {
@@ -607,6 +582,11 @@ void ExecutableCompilationUnit::getExportedNamesRecursively(
names->append(name);
};
+ const CompiledData::Unit *data = m_compilationUnit->data;
+
+ Q_ASSERT(data);
+ Q_ASSERT(engine);
+
for (uint i = 0; i < data->localExportEntryTableSize; ++i) {
const CompiledData::ExportEntry &entry = data->localExportEntryTable()[i];
append(stringAt(entry.exportName));
@@ -619,15 +599,28 @@ void ExecutableCompilationUnit::getExportedNamesRecursively(
for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i];
- auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this);
- if (!dependentModuleUnit)
- return;
- dependentModuleUnit->getExportedNamesRecursively(names, exportNameSet, /*includeDefaultExport*/false);
+ auto dependentModule = engine->loadModule(urlAt(entry.moduleRequest), this);
+ if (dependentModule.compiled) {
+ dependentModule.compiled->getExportedNamesRecursively(
+ names, exportNameSet, /*includeDefaultExport*/false);
+ } else if (dependentModule.native) {
+ Scope scope(engine);
+ ScopedObject o(scope, dependentModule.native);
+ ObjectIterator iterator(scope, o, ObjectIterator::EnumerableOnly);
+ while (true) {
+ ScopedValue val(scope, iterator.nextPropertyNameAsString());
+ if (val->isNull())
+ break;
+ append(val->toQString());
+ }
+ }
}
}
void ExecutableCompilationUnit::evaluate()
{
+ Q_ASSERT(engine);
+
QV4::Scope scope(engine);
QV4::Scoped<Module> mod(scope, module());
mod->evaluate();
@@ -635,245 +628,81 @@ void ExecutableCompilationUnit::evaluate()
void ExecutableCompilationUnit::evaluateModuleRequests()
{
- for (const QString &request: moduleRequests()) {
- auto dependentModuleUnit = engine->loadModule(QUrl(request), this);
- if (engine->hasException)
- return;
- dependentModuleUnit->evaluate();
- if (engine->hasException)
- return;
- }
-}
-
-bool ExecutableCompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString)
-{
- if (!QQmlFile::isLocalFile(url)) {
- *errorString = QStringLiteral("File has to be a local file.");
- return false;
- }
-
- const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
+ Q_ASSERT(engine);
- const QStringList cachePaths = { sourcePath + QLatin1Char('c'), localCacheFilePath(url) };
- for (const QString &cachePath : cachePaths) {
- CompiledData::Unit *mappedUnit = cacheFile->open(cachePath, sourceTimeStamp, errorString);
- if (!mappedUnit)
+ const QStringList moduleRequests = m_compilationUnit->moduleRequests();
+ for (const QString &request: moduleRequests) {
+ auto dependentModule = engine->loadModule(QUrl(request), this);
+ if (dependentModule.native)
continue;
- const CompiledData::Unit * const oldDataPtr
- = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data
- : nullptr;
- const CompiledData::Unit *oldData = data;
- auto dataPtrRevert = qScopeGuard([this, oldData](){
- setUnitData(oldData);
- });
- setUnitData(mappedUnit);
-
- if (data->sourceFileIndex != 0
- && sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
- *errorString = QStringLiteral("QML source file has moved to a different location.");
- continue;
- }
-
- dataPtrRevert.dismiss();
- free(const_cast<CompiledData::Unit*>(oldDataPtr));
- backingFile.reset(cacheFile.take());
- return true;
- }
-
- return false;
-}
-
-bool ExecutableCompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
-{
- if (data->sourceTimeStamp == 0) {
- *errorString = QStringLiteral("Missing time stamp for source file");
- return false;
- }
-
- if (!QQmlFile::isLocalFile(unitUrl)) {
- *errorString = QStringLiteral("File has to be a local file.");
- return false;
- }
-
- return CompiledData::SaveableUnitPointer(unitData()).saveToDisk<char>(
- [&unitUrl, errorString](const char *data, quint32 size) {
- return CompiledData::SaveableUnitPointer::writeDataToFile(localCacheFilePath(unitUrl), data,
- size, errorString);
- });
-}
-
-/*!
-Returns the property cache, if one alread exists. The cache is not referenced.
-*/
-QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::propertyCache() const
-{
- if (type.isValid())
- return typePropertyCache;
- else
- return compilationUnit->rootPropertyCache();
-}
-
-/*!
-Returns the property cache, creating one if it doesn't already exist. The cache is not referenced.
-*/
-QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::createPropertyCache(QQmlEngine *engine)
-{
- if (typePropertyCache) {
- return typePropertyCache;
- } else if (type.isValid()) {
- typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type.metaObject(), minorVersion);
- return typePropertyCache;
- } else {
- return compilationUnit->rootPropertyCache();
- }
-}
-
-bool ResolvedTypeReference::addToHash(QCryptographicHash *hash, QQmlEngine *engine)
-{
- if (type.isValid()) {
- bool ok = false;
- hash->addData(createPropertyCache(engine)->checksum(&ok));
- return ok;
- }
- if (!compilationUnit)
- return false;
- hash->addData(compilationUnit->data->md5Checksum,
- sizeof(compilationUnit->data->md5Checksum));
- return true;
-}
-
-template <typename T>
-bool qtTypeInherits(const QMetaObject *mo) {
- while (mo) {
- if (mo == &T::staticMetaObject)
- return true;
- mo = mo->superClass();
- }
- return false;
-}
-
-void ResolvedTypeReference::doDynamicTypeCheck()
-{
- const QMetaObject *mo = nullptr;
- if (typePropertyCache)
- mo = typePropertyCache->firstCppMetaObject();
- else if (type.isValid())
- mo = type.metaObject();
- else if (compilationUnit)
- mo = compilationUnit->rootPropertyCache()->firstCppMetaObject();
- isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
-}
+ if (engine->hasException)
+ return;
-bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *engine) const
-{
- for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
- if (!it.value()->addToHash(hash, engine))
- return false;
+ Q_ASSERT(dependentModule.compiled);
+ dependentModule.compiled->evaluate();
+ if (engine->hasException)
+ return;
}
-
- return true;
}
QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Binding *binding) const
{
+#if QT_CONFIG(translation)
using namespace CompiledData;
- switch (binding->type) {
- case Binding::Type_Script:
- case Binding::Type_String:
- return stringAt(binding->stringIndex);
- case Binding::Type_Null:
- return QStringLiteral("null");
- case Binding::Type_Boolean:
- return binding->value.b ? QStringLiteral("true") : QStringLiteral("false");
- case Binding::Type_Number:
- return QString::number(bindingValueAsNumber(binding), 'g', QLocale::FloatingPointShortest);
- case Binding::Type_Invalid:
- return QString();
-#if !QT_CONFIG(translation)
+ bool byId = false;
+ switch (binding->type()) {
case Binding::Type_TranslationById:
- case Binding::Type_Translation:
- return stringAt(
- data->translations()[binding->value.translationDataIndex].stringIndex);
-#else
- case Binding::Type_TranslationById: {
- const TranslationData &translation
- = data->translations()[binding->value.translationDataIndex];
- QByteArray id = stringAt(translation.stringIndex).toUtf8();
- return qtTrId(id.constData(), translation.number);
- }
+ byId = true;
+ Q_FALLTHROUGH();
case Binding::Type_Translation: {
- const TranslationData &translation
- = data->translations()[binding->value.translationDataIndex];
- // This code must match that in the qsTr() implementation
- const QString &path = fileName();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- QStringRef context = (lastSlash > -1) ? path.midRef(lastSlash + 1, path.length() - lastSlash - 5)
- : QStringRef();
- QByteArray contextUtf8 = context.toUtf8();
- QByteArray comment = stringAt(translation.commentIndex).toUtf8();
- QByteArray text = stringAt(translation.stringIndex).toUtf8();
- return QCoreApplication::translate(contextUtf8.constData(), text.constData(),
- comment.constData(), translation.number);
+ return translateFrom({ binding->value.translationDataIndex, byId });
}
-#endif
default:
break;
}
- return QString();
-}
-
-QString ExecutableCompilationUnit::bindingValueAsScriptString(
- const CompiledData::Binding *binding) const
-{
- return (binding->type == CompiledData::Binding::Type_String)
- ? CompiledData::Binding::escapedString(stringAt(binding->stringIndex))
- : bindingValueAsString(binding);
+#endif
+ return m_compilationUnit->bindingValueAsString(binding);
}
-bool ExecutableCompilationUnit::verifyHeader(
- const CompiledData::Unit *unit, QDateTime expectedSourceTimeStamp, QString *errorString)
+QString ExecutableCompilationUnit::translateFrom(TranslationDataIndex index) const
{
- if (strncmp(unit->magic, CompiledData::magic_str, sizeof(unit->magic))) {
- *errorString = QStringLiteral("Magic bytes in the header do not match");
- return false;
- }
+#if !QT_CONFIG(translation)
+ return QString();
+#else
+ const CompiledData::TranslationData &translation = unitData()->translations()[index.index];
- if (unit->version != quint32(QV4_DATA_STRUCTURE_VERSION)) {
- *errorString = QString::fromUtf8("V4 data structure version mismatch. Found %1 expected %2")
- .arg(unit->version, 0, 16).arg(QV4_DATA_STRUCTURE_VERSION, 0, 16);
- return false;
+ if (index.byId) {
+ QByteArray id = stringAt(translation.stringIndex).toUtf8();
+ return qtTrId(id.constData(), translation.number);
}
- if (unit->qtVersion != quint32(QT_VERSION)) {
- *errorString = QString::fromUtf8("Qt version mismatch. Found %1 expected %2")
- .arg(unit->qtVersion, 0, 16).arg(QT_VERSION, 0, 16);
- return false;
- }
+ const auto fileContext = [this]() {
+ // This code must match that in the qsTr() implementation
+ const QString &path = fileName();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- if (unit->sourceTimeStamp) {
- // Files from the resource system do not have any time stamps, so fall back to the application
- // executable.
- if (!expectedSourceTimeStamp.isValid())
- expectedSourceTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified();
+ QStringView context = (lastSlash > -1)
+ ? QStringView{ path }.mid(lastSlash + 1, path.size() - lastSlash - 5)
+ : QStringView();
+ return context.toUtf8();
+ };
- if (expectedSourceTimeStamp.isValid()
- && expectedSourceTimeStamp.toMSecsSinceEpoch() != unit->sourceTimeStamp) {
- *errorString = QStringLiteral("QML source file has a different time stamp than cached file.");
- return false;
- }
+ const bool hasContext
+ = translation.contextIndex != QV4::CompiledData::TranslationData::NoContextIndex;
+ QByteArray context;
+ if (hasContext) {
+ context = stringAt(translation.contextIndex).toUtf8();
+ } else {
+ auto pragmaTranslationContext = unitData()->translationContextIndex();
+ context = stringAt(*pragmaTranslationContext).toUtf8();
+ context = context.isEmpty() ? fileContext() : context;
}
-#if defined(QML_COMPILE_HASH)
- if (qstrcmp(qml_compile_hash, unit->libraryVersionHash) != 0) {
- *errorString = QStringLiteral("QML library version mismatch. Expected compile hash does not match");
- return false;
- }
-#else
-#error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
+ QByteArray comment = stringAt(translation.commentIndex).toUtf8();
+ QByteArray text = stringAt(translation.stringIndex).toUtf8();
+ return QCoreApplication::translate(context, text, comment, translation.number);
#endif
- return true;
}
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h
index 6eef3b12c3..3f3335ef4e 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit_p.h
+++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4EXECUTABLECOMPILATIONUNIT_P_H
#define QV4EXECUTABLECOMPILATIONUNIT_P_H
@@ -51,173 +15,137 @@
// We mean it.
//
-#include <private/qv4compileddata_p.h>
-#include <private/qv4identifier_p.h>
-#include <private/qqmlrefcount_p.h>
#include <private/qintrusivelist_p.h>
+#include <private/qqmlmetatype_p.h>
+#include <private/qqmlnullablevalue_p.h>
#include <private/qqmlpropertycachevector_p.h>
+#include <private/qqmlrefcount_p.h>
#include <private/qqmltype_p.h>
-#include <private/qqmlnullablevalue_p.h>
+#include <private/qqmltypenamecache_p.h>
+#include <private/qv4compileddata_p.h>
+#include <private/qv4identifierhash_p.h>
+
+#include <memory>
QT_BEGIN_NAMESPACE
class QQmlScriptData;
class QQmlEnginePrivate;
-namespace QV4 {
-// index is per-object binding index
-typedef QVector<QQmlPropertyData*> BindingPropertyData;
+namespace QV4 {
class CompilationUnitMapper;
-struct ResolvedTypeReference;
-// map from name index
-// 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.
-struct ResolvedTypeReferenceMap: public QMap<int, ResolvedTypeReference*>
+
+struct CompilationUnitRuntimeData
{
- bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const;
+ Heap::String **runtimeStrings = nullptr; // Array
+
+ // pointers either to data->constants() or little-endian memory copy.
+ // We keep this member twice so that the JIT can access it via standard layout.
+ const StaticValue *constants = nullptr;
+
+ QV4::StaticValue *runtimeRegularExpressions = nullptr;
+ Heap::InternalClass **runtimeClasses = nullptr;
+ const StaticValue **imports = nullptr;
+
+ QV4::Lookup *runtimeLookups = nullptr;
+ QVector<QV4::Function *> runtimeFunctions;
+ QVector<QV4::Heap::InternalClass *> runtimeBlocks;
+ mutable QVector<QV4::Heap::Object *> templateObjects;
};
-class Q_QML_PRIVATE_EXPORT ExecutableCompilationUnit final: public CompiledData::CompilationUnit,
- public QQmlRefCount
+static_assert(std::is_standard_layout_v<CompilationUnitRuntimeData>);
+static_assert(offsetof(CompilationUnitRuntimeData, runtimeStrings) == 0);
+static_assert(offsetof(CompilationUnitRuntimeData, constants) == sizeof(QV4::Heap::String **));
+static_assert(offsetof(CompilationUnitRuntimeData, runtimeRegularExpressions) == offsetof(CompilationUnitRuntimeData, constants) + sizeof(const StaticValue *));
+static_assert(offsetof(CompilationUnitRuntimeData, runtimeClasses) == offsetof(CompilationUnitRuntimeData, runtimeRegularExpressions) + sizeof(const StaticValue *));
+static_assert(offsetof(CompilationUnitRuntimeData, imports) == offsetof(CompilationUnitRuntimeData, runtimeClasses) + sizeof(const StaticValue *));
+
+class Q_QML_EXPORT ExecutableCompilationUnit final
+ : public CompilationUnitRuntimeData,
+ public QQmlRefCounted<ExecutableCompilationUnit>
{
Q_DISABLE_COPY_MOVE(ExecutableCompilationUnit)
public:
+ friend class QQmlRefCounted<ExecutableCompilationUnit>;
friend class QQmlRefPointer<ExecutableCompilationUnit>;
+ friend struct ExecutionEngine;
- static QQmlRefPointer<ExecutableCompilationUnit> create(
- CompiledData::CompilationUnit &&compilationUnit)
+ ExecutionEngine *engine = nullptr;
+
+ QString finalUrlString() const { return m_compilationUnit->finalUrlString(); }
+ QString fileName() const { return m_compilationUnit->fileName(); }
+
+ QUrl url() const { return m_compilationUnit->url(); }
+ QUrl finalUrl() const { return m_compilationUnit->finalUrl(); }
+
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache() const
{
- return QQmlRefPointer<ExecutableCompilationUnit>(
- new ExecutableCompilationUnit(std::move(compilationUnit)),
- QQmlRefPointer<ExecutableCompilationUnit>::Adopt);
+ return m_compilationUnit->typeNameCache;
}
- static QQmlRefPointer<ExecutableCompilationUnit> create()
+ QQmlPropertyCacheVector *propertyCachesPtr()
{
- return QQmlRefPointer<ExecutableCompilationUnit>(
- new ExecutableCompilationUnit,
- QQmlRefPointer<ExecutableCompilationUnit>::Adopt);
+ return &m_compilationUnit->propertyCaches;
}
- QIntrusiveListNode nextCompilationUnit;
- ExecutionEngine *engine = nullptr;
- QQmlEnginePrivate *qmlEngine = nullptr; // only used in QML environment for composite types, not in plain QJSEngine case.
-
- // url() and fileName() shall be used to load the actual QML/JS code or to show errors or
- // warnings about that code. They include any potential URL interceptions and thus represent the
- // "physical" location of the code.
- //
- // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code
- // They are _not_ intercepted and thus represent the "logical" name for the code.
-
- QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
- QUrl finalUrl() const
+ QQmlPropertyCache::ConstPtr rootPropertyCache() const
{
- if (m_finalUrl.isNull)
- m_finalUrl = QUrl(finalUrlString());
- return m_finalUrl;
+ return m_compilationUnit->rootPropertyCache();
}
- QV4::Lookup *runtimeLookups = nullptr;
- QVector<QV4::Function *> runtimeFunctions;
- QVector<QV4::Heap::InternalClass *> runtimeBlocks;
- mutable QVector<QV4::Heap::Object *> templateObjects;
- mutable QQmlNullableValue<QUrl> m_url;
- mutable QQmlNullableValue<QUrl> m_finalUrl;
-
- // QML specific fields
- QQmlPropertyCacheVector propertyCaches;
- QQmlRefPointer<QQmlPropertyCache> rootPropertyCache() const { return propertyCaches.at(/*root object*/0); }
-
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
-
- // index is object index. This allows fast access to the
- // property data when initializing bindings, avoiding expensive
- // lookups by string (property name).
- 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
QHash<int, IdentifierHash> namedObjectsPerComponentCache;
inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex);
- void finalizeCompositeType(QQmlEnginePrivate *qmlEngine);
-
- int totalBindingsCount = 0; // Number of bindings used in this type
- int totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
- int totalObjectCount = 0; // Number of objects explicitly instantiated
-
- QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts;
- ResolvedTypeReferenceMap resolvedTypes;
- ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); }
-
- bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
+ int totalBindingsCount() const { return m_compilationUnit->totalBindingsCount(); }
+ int totalParserStatusCount() const { return m_compilationUnit->totalParserStatusCount(); }
+ int totalObjectCount() const { return m_compilationUnit->totalObjectCount(); }
- int metaTypeId = -1;
- int listMetaTypeId = -1;
- bool isRegisteredWithEngine = false;
-
- QScopedPointer<CompilationUnitMapper> backingFile;
-
- // --- interface for QQmlPropertyCacheCreator
- using CompiledObject = CompiledData::Object;
- using CompiledFunction = CompiledData::Function;
-
- int objectCount() const { return qmlData->nObjects; }
- const CompiledObject *objectAt(int index) const
+ ResolvedTypeReference *resolvedType(int id) const
{
- return qmlData->objectAt(index);
+ return m_compilationUnit->resolvedType(id);
}
- int importCount() const { return qmlData->nImports; }
- const CompiledData::Import *importAt(int index) const
+ QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const
{
- return qmlData->importAt(index);
+ return m_compilationUnit->qmlTypeForComponent(inlineComponentName);
}
- Heap::Object *templateObjectAt(int index) const;
-
- struct FunctionIterator
- {
- FunctionIterator(const CompiledData::Unit *unit, const CompiledObject *object, int index)
- : unit(unit), object(object), index(index) {}
- const CompiledData::Unit *unit;
- const CompiledObject *object;
- int index;
-
- const CompiledFunction *operator->() const
- {
- return unit->functionAt(object->functionOffsetTable()[index]);
- }
-
- void operator++() { ++index; }
- bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; }
- bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; }
- };
+ QMetaType metaType() const { return m_compilationUnit->qmlType.typeId(); }
- FunctionIterator objectFunctionsBegin(const CompiledObject *object) const
+ int inlineComponentId(const QString &inlineComponentName) const
{
- return FunctionIterator(data, object, 0);
+ return m_compilationUnit->inlineComponentId(inlineComponentName);
}
- FunctionIterator objectFunctionsEnd(const CompiledObject *object) const
- {
- return FunctionIterator(data, object, object->nFunctions);
- }
+ // --- interface for QQmlPropertyCacheCreator
+ using CompiledObject = CompiledData::CompilationUnit::CompiledObject;
+ using CompiledFunction = CompiledData::CompilationUnit::CompiledFunction;
+ using CompiledBinding = CompiledData::CompilationUnit::CompiledBinding;
+ using IdToObjectMap = CompiledData::CompilationUnit::IdToObjectMap;
- bool isESModule() const
+ bool nativeMethodsAcceptThisObjects() const
{
- return data->flags & CompiledData::Unit::IsESModule;
+ return m_compilationUnit->nativeMethodsAcceptThisObjects();
}
- bool isSharedLibrary() const
+ bool ignoresFunctionSignature() const { return m_compilationUnit->ignoresFunctionSignature(); }
+ bool valueTypesAreCopied() const { return m_compilationUnit->valueTypesAreCopied(); }
+ bool valueTypesAreAddressable() const { return m_compilationUnit->valueTypesAreAddressable(); }
+ bool componentsAreBound() const { return m_compilationUnit->componentsAreBound(); }
+ bool isESModule() const { return m_compilationUnit->isESModule(); }
+
+ int objectCount() const { return m_compilationUnit->objectCount(); }
+ const CompiledObject *objectAt(int index) const
{
- return data->flags & CompiledData::Unit::IsSharedLibrary;
+ return m_compilationUnit->objectAt(index);
}
- QStringList moduleRequests() const;
- Heap::Module *instantiate(ExecutionEngine *engine);
+ Heap::Object *templateObjectAt(int index) const;
+
+ Heap::Module *instantiate();
const Value *resolveExport(QV4::String *exportName)
{
QVector<ResolveSetEntry> resolveSet;
@@ -238,33 +166,74 @@ public:
void evaluate();
void evaluateModuleRequests();
- QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
- void unlink();
+ void mark(MarkStack *markStack) const { markObjects(markStack); }
+ void markObjects(MarkStack *markStack) const;
- void markObjects(MarkStack *markStack);
+ QString bindingValueAsString(const CompiledData::Binding *binding) const;
+ double bindingValueAsNumber(const CompiledData::Binding *binding) const
+ {
+ return m_compilationUnit->bindingValueAsNumber(binding);
+ }
+ QString bindingValueAsScriptString(const CompiledData::Binding *binding) const
+ {
+ return m_compilationUnit->bindingValueAsScriptString(binding);
+ }
- bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString);
+ struct TranslationDataIndex
+ {
+ uint index;
+ bool byId;
+ };
- static QString localCacheFilePath(const QUrl &url);
- bool saveToDisk(const QUrl &unitUrl, QString *errorString);
+ QString translateFrom(TranslationDataIndex index) const;
- QString bindingValueAsString(const CompiledData::Binding *binding) const;
- QString bindingValueAsScriptString(const CompiledData::Binding *binding) const;
- double bindingValueAsNumber(const CompiledData::Binding *binding) const
+ Heap::Module *module() const { return m_module; }
+ void setModule(Heap::Module *module) { m_module = module; }
+
+ const CompiledData::Unit *unitData() const { return m_compilationUnit->data; }
+
+ QString stringAt(uint index) const { return m_compilationUnit->stringAt(index); }
+
+ const QVector<QQmlRefPointer<QQmlScriptData>> *dependentScriptsPtr() const
+ {
+ return &m_compilationUnit->dependentScripts;
+ }
+
+ const CompiledData::BindingPropertyData *bindingPropertyDataPerObjectAt(
+ qsizetype objectIndex) const
+ {
+ return &m_compilationUnit->bindingPropertyDataPerObject.at(objectIndex);
+ }
+
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &baseCompilationUnit() const
+ {
+ return m_compilationUnit;
+ }
+
+ QV4::Function *rootFunction()
{
- if (binding->type != CompiledData::Binding::Type_Number)
- return 0.0;
- return constants[binding->value.constantValueIndex].doubleValue();
+ if (!runtimeStrings)
+ populate();
+
+ const auto *data = unitData();
+ return data->indexOfRootFunction != -1
+ ? runtimeFunctions[data->indexOfRootFunction]
+ : nullptr;
}
- static bool verifyHeader(const CompiledData::Unit *unit, QDateTime expectedSourceTimeStamp,
- QString *errorString);
+ void populate();
+ void clear();
protected:
quint32 totalStringCount() const
- { return data->stringTableSize; }
+ { return unitData()->stringTableSize; }
private:
+ friend struct ExecutionEngine;
+
+ QQmlRefPointer<CompiledData::CompilationUnit> m_compilationUnit;
+ Heap::Module *m_module = nullptr;
+
struct ResolveSetEntry
{
ResolveSetEntry() {}
@@ -275,9 +244,13 @@ private:
};
ExecutableCompilationUnit();
- ExecutableCompilationUnit(CompiledData::CompilationUnit &&compilationUnit);
+ ExecutableCompilationUnit(QQmlRefPointer<CompiledData::CompilationUnit> &&compilationUnit);
~ExecutableCompilationUnit();
+ static QQmlRefPointer<ExecutableCompilationUnit> create(
+ QQmlRefPointer<CompiledData::CompilationUnit> &&compilationUnit,
+ ExecutionEngine *engine);
+
const Value *resolveExportRecursively(QV4::String *exportName,
QVector<ResolveSetEntry> *resolveSet);
@@ -293,36 +266,12 @@ private:
bool includeDefaultExport = true) const;
};
-struct ResolvedTypeReference
-{
- ResolvedTypeReference()
- : majorVersion(0)
- , minorVersion(0)
- , isFullyDynamicType(false)
- {}
-
- QQmlType type;
- QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
-
- int majorVersion;
- int minorVersion;
- // Types such as QQmlPropertyMap can add properties dynamically at run-time and
- // therefore cannot have a property cache installed when instantiated.
- bool isFullyDynamicType;
-
- QQmlRefPointer<QQmlPropertyCache> propertyCache() const;
- QQmlRefPointer<QQmlPropertyCache> createPropertyCache(QQmlEngine *);
- bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
-
- void doDynamicTypeCheck();
-};
-
IdentifierHash ExecutableCompilationUnit::namedObjectsPerComponent(int componentObjectIndex)
{
- auto it = namedObjectsPerComponentCache.find(componentObjectIndex);
- if (Q_UNLIKELY(it == namedObjectsPerComponentCache.end()))
+ auto it = namedObjectsPerComponentCache.constFind(componentObjectIndex);
+ if (Q_UNLIKELY(it == namedObjectsPerComponentCache.cend()))
return createNamedObjectsPerComponent(componentObjectIndex);
+ Q_ASSERT(!it->isEmpty());
return *it;
}
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index aeb4835c40..ae36b563e0 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -1,82 +1,89 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qml/qqmlprivate.h"
#include "qv4function_p.h"
-#include "qv4functionobject_p.h"
#include "qv4managed_p.h"
#include "qv4string_p.h"
#include "qv4value_p.h"
#include "qv4engine_p.h"
-#include "qv4lookup_p.h"
#include <private/qv4mm_p.h>
#include <private/qv4identifiertable_p.h>
#include <private/qv4functiontable_p.h>
#include <assembler/MacroAssemblerCodeRef.h>
#include <private/qv4vme_moth_p.h>
#include <private/qqmlglobal_p.h>
+#include <private/qv4jscall_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
QT_BEGIN_NAMESPACE
-using namespace QV4;
+namespace QV4 {
+
+bool Function::call(QObject *thisObject, void **a, const QMetaType *types, int argc,
+ ExecutionContext *context)
+{
+ if (kind != AotCompiled) {
+ return QV4::convertAndCall(
+ context->engine(), thisObject, a, types, argc,
+ [this, context](const Value *thisObject, const Value *argv, int argc) {
+ return call(thisObject, argv, argc, context);
+ });
+ }
-ReturnedValue Function::call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context) {
ExecutionEngine *engine = context->engine();
- CppStackFrame frame;
- frame.init(engine, this, argv, argc);
- frame.setupJSFrame(engine->jsStackTop, Value::undefinedValue(), context->d(),
- thisObject ? *thisObject : Value::undefinedValue(),
- Value::undefinedValue());
+ MetaTypesStackFrame frame;
+ frame.init(this, thisObject, context, a, types, argc);
+ frame.push(engine);
+ Moth::VME::exec(&frame, engine);
+ frame.pop(engine);
+ return !frame.isReturnValueUndefined();
+}
- frame.push();
+static ReturnedValue doCall(
+ QV4::Function *self, const QV4::Value *thisObject, const QV4::Value *argv, int argc,
+ QV4::ExecutionContext *context)
+{
+ ExecutionEngine *engine = context->engine();
+ JSTypesStackFrame frame;
+ frame.init(self, argv, argc);
+ frame.setupJSFrame(engine->jsStackTop, Value::undefinedValue(), context->d(),
+ thisObject ? *thisObject : Value::undefinedValue());
engine->jsStackTop += frame.requiredJSStackFrameSize();
-
+ frame.push(engine);
ReturnedValue result = Moth::VME::exec(&frame, engine);
+ frame.pop(engine);
+ return result;
+}
- frame.pop();
+ReturnedValue Function::call(
+ const Value *thisObject, const Value *argv, int argc, ExecutionContext *context) {
+ switch (kind) {
+ case AotCompiled:
+ return QV4::convertAndCall(
+ context->engine(), &aotCompiledFunction, thisObject, argv, argc,
+ [this, context](
+ QObject *thisObject, void **a, const QMetaType *types, int argc) {
+ call(thisObject, a, types, argc, context);
+ });
+ case JsTyped:
+ return QV4::coerceAndCall(
+ context->engine(), &jsTypedFunction, compiledFunction, argv, argc,
+ [this, context, thisObject](const Value *argv, int argc) {
+ return doCall(this, thisObject, argv, argc, context);
+ });
+ default:
+ break;
+ }
- return result;
+ return doCall(this, thisObject, argv, argc, context);
}
Function *Function::create(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
- const CompiledData::Function *function)
+ const CompiledData::Function *function,
+ const QQmlPrivate::AOTCompiledFunction *aotFunction)
{
- return new Function(engine, unit, function);
+ return new Function(engine, unit, function, aotFunction);
}
void Function::destroy()
@@ -84,13 +91,24 @@ void Function::destroy()
delete this;
}
+void Function::mark(MarkStack *ms)
+{
+ if (internalClass)
+ internalClass->mark(ms);
+}
+
+static bool isSpecificType(const CompiledData::ParameterType &type)
+{
+ return type.typeNameIndexOrCommonType()
+ != (type.indexIsCommonType() ? quint32(CompiledData::CommonType::Invalid) : 0);
+}
+
Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
- const CompiledData::Function *function)
- : FunctionData(unit)
+ const CompiledData::Function *function,
+ const QQmlPrivate::AOTCompiledFunction *aotFunction)
+ : FunctionData(engine, unit)
, compiledFunction(function)
, codeData(function->code())
- , jittedCode(nullptr)
- , codeRef(nullptr)
{
Scope scope(engine);
Scoped<InternalClass> ic(scope, engine->internalClasses(EngineBase::Class_CallContext));
@@ -101,11 +119,59 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
const CompiledData::Parameter *formalsIndices = compiledFunction->formalsTable();
- for (quint32 i = 0; i < compiledFunction->nFormals; ++i)
+ bool enforceJsTypes = !unit->ignoresFunctionSignature();
+
+ for (quint32 i = 0; i < compiledFunction->nFormals; ++i) {
ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[formalsIndices[i].nameIndex]), Attr_NotConfigurable);
- internalClass = ic->d();
+ if (enforceJsTypes && !isSpecificType(formalsIndices[i].type))
+ enforceJsTypes = false;
+ }
+ internalClass.set(engine, ic->d());
nFormals = compiledFunction->nFormals;
+
+ if (!enforceJsTypes)
+ return;
+
+ if (aotFunction) {
+ aotCompiledCode = aotFunction->functionPtr;
+ new (&aotCompiledFunction) AOTCompiledFunction;
+ kind = AotCompiled;
+ aotCompiledFunction.types.resize(aotFunction->numArguments + 1);
+ aotFunction->signature(unit, aotCompiledFunction.types.data());
+ return;
+ }
+
+ // If a function has any typed arguments, but an untyped return value, the return value is void.
+ // If it doesn't have any arguments at all and the return value is untyped, the function is
+ // untyped. Users can specifically set the return type to "void" to have it enforced.
+ if (nFormals == 0 && !isSpecificType(compiledFunction->returnType))
+ return;
+
+ QQmlTypeLoader *typeLoader = engine->typeLoader();
+
+ auto findQmlType = [&](const CompiledData::ParameterType &param) {
+ const quint32 type = param.typeNameIndexOrCommonType();
+ if (param.indexIsCommonType()) {
+ return QQmlMetaType::qmlType(QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(
+ QV4::CompiledData::CommonType(type)));
+ }
+
+ if (type == 0 || !typeLoader)
+ return QQmlType();
+
+ const auto &base = unit->baseCompilationUnit();
+ const QQmlType qmltype = QQmlTypePrivate::compositeQmlType(
+ base, typeLoader, base->stringAt(type));
+ return qmltype.typeId().isValid() ? qmltype : QQmlType();
+ };
+
+ new (&jsTypedFunction) JSTypedFunction;
+ kind = JsTyped;
+ jsTypedFunction.types.reserve(nFormals + 1);
+ jsTypedFunction.types.append(findQmlType(compiledFunction->returnType));
+ for (quint16 i = 0; i < nFormals; ++i)
+ jsTypedFunction.types.append(findQmlType(formalsIndices[i].type));
}
Function::~Function()
@@ -114,6 +180,18 @@ Function::~Function()
destroyFunctionTable(this, codeRef);
delete codeRef;
}
+
+ switch (kind) {
+ case JsTyped:
+ jsTypedFunction.~JSTypedFunction();
+ break;
+ case AotCompiled:
+ aotCompiledFunction.~AOTCompiledFunction();
+ break;
+ case JsUntyped:
+ case Eval:
+ break;
+ }
}
void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters)
@@ -121,7 +199,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
QStringList parameterNames;
// Resolve duplicate parameter names:
- for (int i = 0, ei = parameters.count(); i != ei; ++i) {
+ for (int i = 0, ei = parameters.size(); i != ei; ++i) {
const QByteArray &param = parameters.at(i);
int duplicate = -1;
@@ -136,30 +214,31 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
if (duplicate == -1) {
parameterNames.append(QString::fromUtf8(param));
} else {
- const QString &dup = parameterNames[duplicate];
+ const QString dup = parameterNames[duplicate];
parameterNames.append(dup);
parameterNames[duplicate] =
- QString(0xfffe) + QString::number(duplicate) + dup;
+ QString(QChar(0xfffe)) + QString::number(duplicate) + dup;
}
}
- internalClass = engine->internalClasses(EngineBase::Class_CallContext);
+ Scope scope(engine);
+ Scoped<InternalClass> ic(scope, engine->internalClasses(EngineBase::Class_CallContext));
// first locals
const quint32_le *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i) {
- internalClass = internalClass->addMember(
+ ic = ic->addMember(
engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]),
Attr_NotConfigurable);
}
- Scope scope(engine);
ScopedString arg(scope);
for (const QString &parameterName : parameterNames) {
arg = engine->newIdentifier(parameterName);
- internalClass = internalClass->addMember(arg->propertyKey(), Attr_NotConfigurable);
+ ic = ic->addMember(arg->propertyKey(), Attr_NotConfigurable);
}
+ internalClass.set(engine, ic->d());
nFormals = parameters.size();
}
@@ -176,7 +255,15 @@ QString Function::prettyName(const Function *function, const void *code)
QQmlSourceLocation Function::sourceLocation() const
{
- return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column);
+ return QQmlSourceLocation(
+ sourceFile(), compiledFunction->location.line(), compiledFunction->location.column());
}
+FunctionData::FunctionData(EngineBase *engine, ExecutableCompilationUnit *compilationUnit_)
+{
+ compilationUnit.set(engine, compilationUnit_);
+}
+
+} // namespace QV4
+
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 51960863c4..7543dd3c4b 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4FUNCTION_H
#define QV4FUNCTION_H
@@ -50,6 +14,7 @@
// We mean it.
//
+#include <qqmlprivate.h>
#include "qv4global_p.h"
#include <private/qv4executablecompilationunit_p.h>
#include <private/qv4context_p.h>
@@ -65,33 +30,38 @@ struct QQmlSourceLocation;
namespace QV4 {
-struct Q_QML_EXPORT FunctionData {
- CompiledData::CompilationUnitBase *compilationUnit;
+struct Q_QML_EXPORT FunctionData
+{
+ WriteBarrier::HeapObjectWrapper<CompilationUnitRuntimeData, 1> compilationUnit;
// Intentionally require an ExecutableCompilationUnit but save only a pointer to
// CompilationUnitBase. This is so that we can take advantage of the standard layout
// of CompilationUnitBase in the JIT. Furthermore we can safely static_cast to
// ExecutableCompilationUnit where we need it.
- FunctionData(ExecutableCompilationUnit *compilationUnit)
- : compilationUnit(compilationUnit)
- {}
+ FunctionData(EngineBase *engine, ExecutableCompilationUnit *compilationUnit_);
};
// Make sure this class can be accessed through offsetof (done by the assemblers):
Q_STATIC_ASSERT(std::is_standard_layout< FunctionData >::value);
struct Q_QML_EXPORT Function : public FunctionData {
-private:
+protected:
Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
- const CompiledData::Function *function);
+ const CompiledData::Function *function, const QQmlPrivate::AOTCompiledFunction *aotFunction);
~Function();
public:
- const CompiledData::Function *compiledFunction;
+ struct JSTypedFunction {
+ QVarLengthArray<QQmlType, 4> types;
+ };
+
+ struct AOTCompiledFunction {
+ QVarLengthArray<QMetaType, 4> types;
+ };
QV4::ExecutableCompilationUnit *executableCompilationUnit() const
{
// This is safe: We require an ExecutableCompilationUnit in the ctor.
- return static_cast<QV4::ExecutableCompilationUnit *>(compilationUnit);
+ return static_cast<QV4::ExecutableCompilationUnit *>(compilationUnit.get());
}
QV4::Heap::String *runtimeString(uint i) const
@@ -99,24 +69,44 @@ public:
return compilationUnit->runtimeStrings[i];
}
- ReturnedValue call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context);
+ bool call(QObject *thisObject, void **a, const QMetaType *types, int argc,
+ ExecutionContext *context);
+ ReturnedValue call(const Value *thisObject, const Value *argv, int argc,
+ ExecutionContext *context);
- const char *codeData;
+ const CompiledData::Function *compiledFunction = nullptr;
+ const char *codeData = nullptr;
+ JSC::MacroAssemblerCodeRef *codeRef = nullptr;
typedef ReturnedValue (*JittedCode)(CppStackFrame *, ExecutionEngine *);
- JittedCode jittedCode;
- JSC::MacroAssemblerCodeRef *codeRef;
+ typedef void (*AotCompiledCode)(const QQmlPrivate::AOTCompiledContext *context, void **argv);
+
+ union {
+ void *noFunction = nullptr;
+ JSTypedFunction jsTypedFunction;
+ AOTCompiledFunction aotCompiledFunction;
+ };
+
+ union {
+ JittedCode jittedCode = nullptr;
+ AotCompiledCode aotCompiledCode;
+ };
// first nArguments names in internalClass are the actual arguments
- Heap::InternalClass *internalClass;
- uint nFormals;
+ QV4::WriteBarrier::Pointer<Heap::InternalClass> internalClass;
int interpreterCallCount = 0;
- bool isEval = false;
+ quint16 nFormals = 0;
+ enum Kind : quint8 { JsUntyped, JsTyped, AotCompiled, Eval };
+ Kind kind = JsUntyped;
+ bool detectedInjectedParameters = false;
static Function *create(ExecutionEngine *engine, ExecutableCompilationUnit *unit,
- const CompiledData::Function *function);
+ const CompiledData::Function *function,
+ const QQmlPrivate::AOTCompiledFunction *aotFunction);
void destroy();
+ void mark(QV4::MarkStack *ms);
+
// used when dynamically assigning signal handlers (QQmlConnection)
void updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> &parameters);
@@ -132,6 +122,7 @@ public:
inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; }
inline bool isArrowFunction() const { return compiledFunction->flags & CompiledData::Function::IsArrowFunction; }
inline bool isGenerator() const { return compiledFunction->flags & CompiledData::Function::IsGenerator; }
+ inline bool isClosureWrapper() const { return compiledFunction->flags & CompiledData::Function::IsClosureWrapper; }
QQmlSourceLocation sourceLocation() const;
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 6fb7946023..ab6a34435f 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -1,50 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4object_p.h"
-#include "qv4objectproto_p.h"
-#include "qv4stringobject_p.h"
#include "qv4function_p.h"
#include "qv4symbol_p.h"
#include <private/qv4mm_p.h>
-#include "qv4arrayobject_p.h"
#include "qv4scopedvalue_p.h"
#include "qv4argumentsobject_p.h"
@@ -63,16 +24,17 @@
#include <QtCore/QDebug>
#include <algorithm>
-#include "qv4profiling_p.h"
using namespace QV4;
DEFINE_OBJECT_VTABLE(FunctionObject);
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, VTable::Call call)
+void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name,
+ VTable::Call call, VTable::CallWithMetaTypes callWithMetaTypes)
{
jsCall = call;
+ jsCallWithMetaTypes = callWithMetaTypes;
jsConstruct = nullptr;
Object::init();
@@ -88,6 +50,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name)
ExecutionEngine *e = scope->engine();
jsCall = vtable()->call;
+ jsCallWithMetaTypes = vtable()->callWithMetaTypes;
jsConstruct = vtable()->callAsConstructor;
Object::init();
@@ -103,6 +66,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name)
void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n)
{
jsCall = vtable()->call;
+ jsCallWithMetaTypes = vtable()->callWithMetaTypes;
jsConstruct = vtable()->callAsConstructor;
Object::init();
@@ -125,6 +89,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const QString &nam
void Heap::FunctionObject::init()
{
jsCall = vtable()->call;
+ jsCallWithMetaTypes = vtable()->callWithMetaTypes;
jsConstruct = vtable()->callAsConstructor;
Object::init();
@@ -156,6 +121,19 @@ void FunctionObject::createDefaultPrototypeProperty(uint protoConstructorSlot)
defineDefaultProperty(s.engine->id_prototype(), proto, Attr_NotEnumerable|Attr_NotConfigurable);
}
+void FunctionObject::call(QObject *thisObject, void **a, const QMetaType *types, int argc)
+{
+ if (const auto callWithMetaTypes = d()->jsCallWithMetaTypes) {
+ callWithMetaTypes(this, thisObject, a, types, argc);
+ return;
+ }
+
+ QV4::convertAndCall(engine(), thisObject, a, types, argc,
+ [this](const Value *thisObject, const Value *argv, int argc) {
+ return call(thisObject, argv, argc);
+ });
+}
+
ReturnedValue FunctionObject::name() const
{
return get(scope()->internalClass->engine->id_name());
@@ -166,6 +144,11 @@ ReturnedValue FunctionObject::virtualCall(const FunctionObject *, const Value *,
return Encode::undefined();
}
+void FunctionObject::virtualCallWithMetaTypes(
+ const FunctionObject *, QObject *, void **, const QMetaType *, int)
+{
+}
+
Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function)
{
if (function->isArrowFunction())
@@ -198,7 +181,7 @@ Heap::FunctionObject *FunctionObject::createBuiltinFunction(ExecutionEngine *eng
Scope scope(engine);
ScopedString name(scope, nameOrSymbol);
if (!name)
- name = engine->newString(QChar::fromLatin1('[') + nameOrSymbol->toQString().midRef(1) + QChar::fromLatin1(']'));
+ name = engine->newString(QChar::fromLatin1('[') + QStringView{nameOrSymbol->toQString()}.mid(1) + QChar::fromLatin1(']'));
ScopedFunctionObject function(scope, engine->memoryManager->allocate<FunctionObject>(engine->rootContext(), name, code));
function->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(argumentCount));
@@ -273,7 +256,7 @@ QQmlRefPointer<ExecutableCompilationUnit> FunctionCtor::parse(ExecutionEngine *e
if (engine->hasException)
return nullptr;
- return ExecutableCompilationUnit::create(cg.generateCompilationUnit());
+ return engine->insertCompilationUnit(cg.generateCompilationUnit());
}
ReturnedValue FunctionCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -285,7 +268,7 @@ ReturnedValue FunctionCtor::virtualCallAsConstructor(const FunctionObject *f, co
if (engine->hasException)
return Encode::undefined();
- Function *vmf = compilationUnit->linkToEngine(engine);
+ Function *vmf = compilationUnit->rootFunction();
ExecutionContext *global = engine->scriptContext();
ReturnedValue o = Encode(FunctionObject::createScriptFunction(global, vmf));
@@ -358,47 +341,49 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons
return v4->throwTypeError();
thisObject = argc ? argv : nullptr;
if (argc < 2 || argv[1].isNullOrUndefined())
- return f->call(thisObject, argv, 0);
+ return checkedResult(v4, f->call(thisObject, argv, 0));
Object *arr = argv[1].objectValue();
if (!arr)
return v4->throwTypeError();
- uint len = arr->getLength();
-
Scope scope(v4);
+ const int len = v4->safeForAllocLength(arr->getLength());
+ CHECK_EXCEPTION();
+
Value *arguments = scope.alloc<Scope::Uninitialized>(len);
if (len) {
if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) {
QV4::ArgumentsObject *a = arr->cast<ArgumentsObject>();
- int l = qMin(len, (uint)a->d()->context->argc());
+ int l = qMin(len, a->d()->context->argc());
memcpy(arguments, a->d()->context->args(), l*sizeof(Value));
- for (quint32 i = l; i < len; ++i)
+ for (int i = l; i < len; ++i)
arguments[i] = Value::undefinedValue();
} else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) {
auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData());
- uint alen = sad ? sad->values.size : 0;
+ int alen = sad ? sad->values.size : 0;
if (alen > len)
alen = len;
- for (uint i = 0; i < alen; ++i)
+ for (int i = 0; i < alen; ++i)
arguments[i] = sad->data(i);
- for (quint32 i = alen; i < len; ++i)
+ for (int i = alen; i < len; ++i)
arguments[i] = Value::undefinedValue();
} else {
// need to init the arguments array, as the get() calls below can have side effects
memset(arguments, 0, len*sizeof(Value));
- for (quint32 i = 0; i < len; ++i)
+ for (int i = 0; i < len; ++i)
arguments[i] = arr->get(i);
}
}
- return f->call(thisObject, arguments, len);
+ return checkedResult(v4, f->call(thisObject, arguments, len));
}
ReturnedValue FunctionPrototype::method_call(const QV4::FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
+ QV4::ExecutionEngine *v4 = b->engine();
if (!thisObject->isFunctionObject())
- return b->engine()->throwTypeError();
+ return v4->throwTypeError();
const FunctionObject *f = static_cast<const FunctionObject *>(thisObject);
@@ -407,7 +392,7 @@ ReturnedValue FunctionPrototype::method_call(const QV4::FunctionObject *b, const
++argv;
--argc;
}
- return f->call(thisObject, argv, argc);
+ return checkedResult(v4, f->call(thisObject, argv, argc));
}
ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
@@ -443,8 +428,8 @@ ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Valu
}
ScopedContext ctx(scope, target->scope());
- Heap::BoundFunction *bound = BoundFunction::create(ctx, target, boundThis, boundArgs);
- bound->setFunction(target->function());
+ Scoped<BoundFunction> bound(scope, BoundFunction::create(ctx, target, boundThis, boundArgs));
+ bound->d()->setFunction(target->function());
return bound->asReturnedValue();
}
@@ -480,18 +465,18 @@ ReturnedValue ScriptFunction::virtualCallAsConstructor(const FunctionObject *fo,
}
ScopedValue thisObject(scope, v4->memoryManager->allocObject<Object>(ic));
- CppStackFrame frame;
- frame.init(v4, f->function(), argv, argc);
+ JSTypesStackFrame frame;
+ frame.init(f->function(), argv, argc);
frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
thisObject,
newTarget ? *newTarget : Value::undefinedValue());
- frame.push();
+ frame.push(v4);
v4->jsStackTop += frame.requiredJSStackFrameSize();
ReturnedValue result = Moth::VME::exec(&frame, v4);
- frame.pop();
+ frame.pop(v4);
if (Q_UNLIKELY(v4->hasException))
return Encode::undefined();
@@ -502,31 +487,75 @@ ReturnedValue ScriptFunction::virtualCallAsConstructor(const FunctionObject *fo,
DEFINE_OBJECT_VTABLE(ArrowFunction);
-ReturnedValue ArrowFunction::virtualCall(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc)
+void ArrowFunction::virtualCallWithMetaTypes(const FunctionObject *fo, QObject *thisObject,
+ void **a, const QMetaType *types, int argc)
+{
+ if (fo->function()->kind != Function::AotCompiled) {
+ QV4::convertAndCall(fo->engine(), thisObject, a, types, argc,
+ [fo](const Value *thisObject, const Value *argv, int argc) {
+ return ArrowFunction::virtualCall(fo, thisObject, argv, argc);
+ });
+ return;
+ }
+
+ QV4::Scope scope(fo->engine());
+ QV4::Scoped<ExecutionContext> context(scope, fo->scope());
+ MetaTypesStackFrame frame;
+ frame.init(fo->function(), thisObject, context, a, types, argc);
+ frame.push(scope.engine);
+ Moth::VME::exec(&frame, scope.engine);
+ frame.pop(scope.engine);
+}
+
+static ReturnedValue qfoDoCall(const QV4::FunctionObject *fo, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc)
{
ExecutionEngine *engine = fo->engine();
- CppStackFrame frame;
- frame.init(engine, fo->function(), argv, argc, true);
+ JSTypesStackFrame frame;
+ frame.init(fo->function(), argv, argc, true);
frame.setupJSFrame(engine->jsStackTop, *fo, fo->scope(),
- thisObject ? *thisObject : Value::undefinedValue(),
- Value::undefinedValue());
+ thisObject ? *thisObject : Value::undefinedValue());
- frame.push();
+ frame.push(engine);
engine->jsStackTop += frame.requiredJSStackFrameSize();
ReturnedValue result;
do {
- frame.pendingTailCall = false;
+ frame.setPendingTailCall(false);
result = Moth::VME::exec(&frame, engine);
- frame.isTailCalling = true;
- } while (frame.pendingTailCall);
+ frame.setTailCalling(true);
+ } while (frame.pendingTailCall());
- frame.pop();
+ frame.pop(engine);
return result;
}
+ReturnedValue ArrowFunction::virtualCall(const QV4::FunctionObject *fo, const Value *thisObject,
+ const QV4::Value *argv, int argc)
+{
+ Function *function = fo->function();
+ switch (function->kind) {
+ case Function::AotCompiled:
+ return QV4::convertAndCall(
+ fo->engine(), &function->aotCompiledFunction, thisObject, argv, argc,
+ [fo](QObject *thisObject, void **a, const QMetaType *types, int argc) {
+ ArrowFunction::virtualCallWithMetaTypes(fo, thisObject, a, types, argc);
+ });
+ case Function::JsTyped:
+ return QV4::coerceAndCall(
+ fo->engine(), &function->jsTypedFunction, function->compiledFunction, argv, argc,
+ [fo, thisObject](const Value *argv, int argc) {
+ return qfoDoCall(fo, thisObject, argv, argc);
+ });
+ default:
+ break;
+ }
+
+ return qfoDoCall(fo, thisObject, argv, argc);
+}
+
void Heap::ArrowFunction::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n)
{
FunctionObject::init();
@@ -583,19 +612,19 @@ ReturnedValue ConstructorFunction::virtualCallAsConstructor(const FunctionObject
ExecutionEngine *v4 = f->engine();
- CppStackFrame frame;
- frame.init(v4, f->function(), argv, argc);
+ JSTypesStackFrame frame;
+ frame.init(f->function(), argv, argc);
frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
Value::emptyValue(),
newTarget ? *newTarget : Value::undefinedValue());
- frame.push();
+ frame.push(v4);
v4->jsStackTop += frame.requiredJSStackFrameSize();
ReturnedValue result = Moth::VME::exec(&frame, v4);
ReturnedValue thisObject = frame.jsFrame->thisObject.asReturnedValue();
- frame.pop();
+ frame.pop(v4);
if (Q_UNLIKELY(v4->hasException))
return Encode::undefined();
@@ -637,20 +666,20 @@ ReturnedValue DefaultClassConstructorFunction::virtualCallAsConstructor(const Fu
ScopedFunctionObject super(scope, f->getPrototypeOf());
Q_ASSERT(super->isFunctionObject());
- CppStackFrame frame;
- frame.init(v4, nullptr, argv, argc);
+ JSTypesStackFrame frame;
+ frame.init(nullptr, argv, argc);
frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
Value::undefinedValue(),
newTarget ? *newTarget : Value::undefinedValue(), argc, argc);
- frame.push();
+ frame.push(v4);
v4->jsStackTop += frame.requiredJSStackFrameSize(argc);
// Do a super call
ReturnedValue result = super->callAsConstructor(argv, argc, newTarget);
ReturnedValue thisObject = frame.jsFrame->thisObject.asReturnedValue();
- frame.pop();
+ frame.pop(v4);
if (Q_UNLIKELY(v4->hasException))
return Encode::undefined();
@@ -707,23 +736,23 @@ void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject
ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *, const Value *argv, int argc)
{
- const BoundFunction *f = static_cast<const BoundFunction *>(fo);
- Scope scope(f->engine());
-
- if (scope.hasException())
+ QV4::ExecutionEngine *v4 = fo->engine();
+ if (v4->hasException)
return Encode::undefined();
+ const BoundFunction *f = static_cast<const BoundFunction *>(fo);
+ Scope scope(v4);
Scoped<MemberData> boundArgs(scope, f->boundArgs());
ScopedFunctionObject target(scope, f->target());
- JSCallData jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc);
- *jsCallData->thisObject = f->boundThis();
- Value *argp = jsCallData->args;
+ JSCallArguments jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc);
+ *jsCallData.thisObject = f->boundThis();
+ Value *argp = jsCallData.args;
if (boundArgs) {
memcpy(argp, boundArgs->data(), boundArgs->size()*sizeof(Value));
argp += boundArgs->size();
}
memcpy(argp, argv, argc*sizeof(Value));
- return target->call(jsCallData);
+ return checkedResult(v4, target->call(jsCallData));
}
ReturnedValue BoundFunction::virtualCallAsConstructor(const FunctionObject *fo, const Value *argv, int argc, const Value *)
@@ -736,8 +765,8 @@ ReturnedValue BoundFunction::virtualCallAsConstructor(const FunctionObject *fo,
Scoped<MemberData> boundArgs(scope, f->boundArgs());
ScopedFunctionObject target(scope, f->target());
- JSCallData jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc);
- Value *argp = jsCallData->args;
+ JSCallArguments jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc);
+ Value *argp = jsCallData.args;
if (boundArgs) {
memcpy(argp, boundArgs->data(), boundArgs->size()*sizeof(Value));
argp += boundArgs->size();
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index c99cad8e33..573848f62a 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4FUNCTIONOBJECT_H
#define QV4FUNCTIONOBJECT_H
@@ -72,10 +36,11 @@ namespace Heap {
Member(class, NoMark, Function *, function) \
Member(class, NoMark, VTable::Call, jsCall) \
Member(class, NoMark, VTable::CallAsConstructor, jsConstruct) \
+ Member(class, NoMark, VTable::CallWithMetaTypes, jsCallWithMetaTypes) \
Member(class, NoMark, bool, canBeTailCalled)
DECLARE_HEAP_OBJECT(FunctionObject, Object) {
- DECLARE_MARKOBJECTS(FunctionObject);
+ DECLARE_MARKOBJECTS(FunctionObject)
enum {
Index_ProtoConstructor = 0,
Index_Prototype = 0,
@@ -86,12 +51,14 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) {
return jsConstruct != nullptr;
}
- Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name, VTable::Call call);
- Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr);
- Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
- Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, const QString &name);
- Q_QML_PRIVATE_EXPORT void init();
- Q_QML_PRIVATE_EXPORT void destroy();
+ Q_QML_EXPORT void init(
+ QV4::ExecutionContext *scope, QV4::String *name,
+ VTable::Call call, VTable::CallWithMetaTypes callWithMetaTypes = nullptr);
+ Q_QML_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr);
+ Q_QML_EXPORT void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
+ Q_QML_EXPORT void init(QV4::ExecutionContext *scope, const QString &name);
+ Q_QML_EXPORT void init();
+ Q_QML_EXPORT void destroy();
void setFunction(Function *f);
@@ -107,9 +74,11 @@ struct FunctionPrototype : FunctionObject {
void init();
};
+// A function object with an additional index into a list.
+// Used by Models to refer to property roles.
struct IndexedBuiltinFunction : FunctionObject {
- inline void init(QV4::ExecutionContext *scope, uint index, VTable::Call call);
- uint index;
+ inline void init(QV4::ExecutionContext *scope, qsizetype index, VTable::Call call);
+ qsizetype index;
};
struct ArrowFunction : FunctionObject {
@@ -158,7 +127,7 @@ struct DefaultClassConstructorFunction : FunctionObject
Member(class, Pointer, MemberData *, boundArgs)
DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) {
- DECLARE_MARKOBJECTS(BoundFunction);
+ DECLARE_MARKOBJECTS(BoundFunction)
void init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs);
};
@@ -202,6 +171,9 @@ struct Q_QML_EXPORT FunctionObject: Object {
return d()->jsCall(this, thisObject, argv, argc);
}
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+ void call(QObject *thisObject, void **a, const QMetaType *types, int argc);
+ static void virtualCallWithMetaTypes(const FunctionObject *f, QObject *thisObject,
+ void **a, const QMetaType *types, int argc);
static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function);
static Heap::FunctionObject *createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor);
@@ -260,12 +232,13 @@ struct FunctionPrototype: FunctionObject
static ReturnedValue method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
-struct Q_QML_PRIVATE_EXPORT IndexedBuiltinFunction : FunctionObject
+struct Q_QML_EXPORT IndexedBuiltinFunction : FunctionObject
{
V4_OBJECT2(IndexedBuiltinFunction, FunctionObject)
};
-void Heap::IndexedBuiltinFunction::init(QV4::ExecutionContext *scope, uint index, VTable::Call call)
+void Heap::IndexedBuiltinFunction::init(
+ QV4::ExecutionContext *scope, qsizetype index, VTable::Call call)
{
Heap::FunctionObject::init(scope);
this->jsCall = call;
@@ -277,7 +250,10 @@ struct ArrowFunction : FunctionObject {
V4_INTERNALCLASS(ArrowFunction)
enum { NInlineProperties = 3 };
- static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+ static void virtualCallWithMetaTypes(const FunctionObject *f, QObject *thisObject,
+ void **a, const QMetaType *types, int argc);
+ static ReturnedValue virtualCall(const QV4::FunctionObject *f, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc);
};
struct ScriptFunction : ArrowFunction {
@@ -328,6 +304,10 @@ inline bool FunctionObject::isBoundFunction() const
return d()->vtable() == BoundFunction::staticVTable();
}
+inline ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result)
+{
+ return v4->hasException ? QV4::Encode::undefined() : result;
+}
}
diff --git a/src/qml/jsruntime/qv4functiontable_noop.cpp b/src/qml/jsruntime/qv4functiontable_noop.cpp
index 31c198eb00..8a72fa5469 100644
--- a/src/qml/jsruntime/qv4functiontable_noop.cpp
+++ b/src/qml/jsruntime/qv4functiontable_noop.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4functiontable_p.h"
diff --git a/src/qml/jsruntime/qv4functiontable_p.h b/src/qml/jsruntime/qv4functiontable_p.h
index 69e3d2bdd5..8937e2fe85 100644
--- a/src/qml/jsruntime/qv4functiontable_p.h
+++ b/src/qml/jsruntime/qv4functiontable_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4FUNCTIONTABLE_P_H
#define QV4FUNCTIONTABLE_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include "qv4global_p.h"
+#include <QtQml/private/qqmlglobal_p.h>
namespace JSC {
class MacroAssemblerCodeRef;
diff --git a/src/qml/jsruntime/qv4functiontable_unix.cpp b/src/qml/jsruntime/qv4functiontable_unix.cpp
index 25b5c27161..9561917777 100644
--- a/src/qml/jsruntime/qv4functiontable_unix.cpp
+++ b/src/qml/jsruntime/qv4functiontable_unix.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4functiontable_p.h"
#include "qv4function_p.h"
diff --git a/src/qml/jsruntime/qv4functiontable_win64.cpp b/src/qml/jsruntime/qv4functiontable_win64.cpp
index fc13dc2602..c21cdb790a 100644
--- a/src/qml/jsruntime/qv4functiontable_win64.cpp
+++ b/src/qml/jsruntime/qv4functiontable_win64.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4functiontable_p.h"
@@ -43,7 +7,7 @@
#include <QtCore/qdebug.h>
-#include <windows.h>
+#include <qt_windows.h>
QT_BEGIN_NAMESPACE
@@ -106,7 +70,7 @@ struct ExceptionHandlerRecord
void generateFunctionTable(Function *, JSC::MacroAssemblerCodeRef *codeRef)
{
ExceptionHandlerRecord *record = reinterpret_cast<ExceptionHandlerRecord *>(
- codeRef->executableMemory()->exceptionHandler());
+ codeRef->executableMemory()->exceptionHandlerStart());
record->info.Version = 1;
record->info.Flags = 0;
@@ -136,7 +100,7 @@ void generateFunctionTable(Function *, JSC::MacroAssemblerCodeRef *codeRef)
void destroyFunctionTable(Function *, JSC::MacroAssemblerCodeRef *codeRef)
{
ExceptionHandlerRecord *record = reinterpret_cast<ExceptionHandlerRecord *>(
- codeRef->executableMemory()->exceptionHandler());
+ codeRef->executableMemory()->exceptionHandlerStart());
if (!RtlDeleteFunctionTable(&record->handler)) {
const unsigned int errorCode = GetLastError();
qWarning() << "Failed to remove win64 unwind hook. Error code:" << errorCode;
diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp
index 4eee6f4338..e7a63ba185 100644
--- a/src/qml/jsruntime/qv4generatorobject.cpp
+++ b/src/qml/jsruntime/qv4generatorobject.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qv4generatorobject_p.h>
#include <qv4symbol_p.h>
@@ -62,7 +26,7 @@ ReturnedValue GeneratorFunctionCtor::virtualCallAsConstructor(const FunctionObje
if (engine->hasException)
return Encode::undefined();
- Function *vmf = compilationUnit->linkToEngine(engine);
+ Function *vmf = compilationUnit->rootFunction();
ExecutionContext *global = engine->scriptContext();
ReturnedValue o = Encode(GeneratorFunction::create(global, vmf));
@@ -97,33 +61,31 @@ ReturnedValue GeneratorFunction::virtualCall(const FunctionObject *f, const Valu
Function *function = gf->function();
ExecutionEngine *engine = gf->engine();
- // We need to set up a separate stack for the generator, as it's being re-entered
- uint stackSize = argc // space for the original arguments
- + CppStackFrame::requiredJSStackFrameSize(function); // space for the JS stack frame
-
- size_t requiredMemory = sizeof(GeneratorObject::Data) - sizeof(Value) + sizeof(Value) * stackSize;
-
Scope scope(gf);
- Scoped<GeneratorObject> g(scope, scope.engine->memoryManager->allocManaged<GeneratorObject>(requiredMemory, scope.engine->classes[EngineBase::Class_GeneratorObject]));
+ Scoped<GeneratorObject> g(scope, engine->memoryManager->allocManaged<GeneratorObject>(engine->classes[EngineBase::Class_GeneratorObject]));
g->setPrototypeOf(ScopedObject(scope, gf->get(scope.engine->id_prototype())));
+ // We need to set up a separate JSFrame for the generator, as it's being re-entered
Heap::GeneratorObject *gp = g->d();
- gp->stack.size = stackSize;
- gp->stack.alloc = stackSize;
+ gp->values.set(engine, engine->newArrayObject(argc));
+ gp->jsFrame.set(engine, engine->newArrayObject(
+ JSTypesStackFrame::requiredJSStackFrameSize(function)));
// copy original arguments
- memcpy(gp->stack.values, argv, argc*sizeof(Value));
- gp->cppFrame.init(engine, function, gp->stack.values, argc);
- gp->cppFrame.setupJSFrame(&gp->stack.values[argc], *gf, gf->scope(),
+ for (int i = 0; i < argc; i++)
+ gp->values->arrayData->setArrayData(engine, i, argv[i]);
+
+ gp->cppFrame.init(function, gp->values->arrayData->values.values, argc);
+ gp->cppFrame.setupJSFrame(gp->jsFrame->arrayData->values.values, *gf, gf->scope(),
thisObject ? *thisObject : Value::undefinedValue(),
Value::undefinedValue());
- gp->cppFrame.push();
+ gp->cppFrame.push(engine);
Moth::VME::interpret(&gp->cppFrame, engine, function->codeData);
gp->state = GeneratorState::SuspendedStart;
- gp->cppFrame.pop();
+ gp->cppFrame.pop(engine);
return g->asReturnedValue();
}
@@ -191,7 +153,7 @@ ReturnedValue GeneratorPrototype::method_return(const FunctionObject *f, const V
// a yield called with return()
engine->throwError(Value::emptyValue());
- return g->resume(engine, argc ? argv[0]: Value::undefinedValue());
+ return g->resume(engine, argc ? argv[0] : Value::undefinedValue());
}
ReturnedValue GeneratorPrototype::method_throw(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
@@ -203,7 +165,7 @@ ReturnedValue GeneratorPrototype::method_throw(const FunctionObject *f, const Va
Heap::GeneratorObject *gp = g->d();
- engine->throwError(argc ? argv[0]: Value::undefinedValue());
+ engine->throwError(argc ? argv[0] : Value::undefinedValue());
if (gp->state == GeneratorState::SuspendedStart || gp->state == GeneratorState::Completed) {
gp->state = GeneratorState::Completed;
@@ -217,25 +179,25 @@ ReturnedValue GeneratorObject::resume(ExecutionEngine *engine, const Value &arg)
{
Heap::GeneratorObject *gp = d();
gp->state = GeneratorState::Executing;
- gp->cppFrame.parent = engine->currentStackFrame;
+ gp->cppFrame.setParentFrame(engine->currentStackFrame);
engine->currentStackFrame = &gp->cppFrame;
- Q_ASSERT(gp->cppFrame.yield != nullptr);
- const char *code = gp->cppFrame.yield;
- gp->cppFrame.yield = nullptr;
+ Q_ASSERT(gp->cppFrame.yield() != nullptr);
+ const char *code = gp->cppFrame.yield();
+ gp->cppFrame.setYield(nullptr);
gp->cppFrame.jsFrame->accumulator = arg;
- gp->cppFrame.yieldIsIterator = false;
+ gp->cppFrame.setYieldIsIterator(false);
Scope scope(engine);
ScopedValue result(scope, Moth::VME::interpret(&gp->cppFrame, engine, code));
- engine->currentStackFrame = gp->cppFrame.parent;
+ engine->currentStackFrame = gp->cppFrame.parentFrame();
- bool done = (gp->cppFrame.yield == nullptr);
+ bool done = (gp->cppFrame.yield() == nullptr);
gp->state = done ? GeneratorState::Completed : GeneratorState::SuspendedYield;
if (engine->hasException)
return Encode::undefined();
- if (gp->cppFrame.yieldIsIterator)
+ if (gp->cppFrame.yieldIsIterator())
return result->asReturnedValue();
return IteratorPrototype::createIterResultObject(engine, result, done);
}
diff --git a/src/qml/jsruntime/qv4generatorobject_p.h b/src/qml/jsruntime/qv4generatorobject_p.h
index 366319723d..55ccc133aa 100644
--- a/src/qml/jsruntime/qv4generatorobject_p.h
+++ b/src/qml/jsruntime/qv4generatorobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4GENERATOROBJECT_P_H
#define QV4GENERATOROBJECT_P_H
@@ -87,13 +51,13 @@ struct GeneratorPrototype : FunctionObject {
#define GeneratorObjectMembers(class, Member) \
Member(class, Pointer, ExecutionContext *, context) \
- Member(class, Pointer, GeneratorFunction *, function) \
Member(class, NoMark, GeneratorState, state) \
- Member(class, NoMark, CppStackFrame, cppFrame) \
- Member(class, ValueArray, ValueArray, stack)
+ Member(class, NoMark, JSTypesStackFrame, cppFrame) \
+ Member(class, Pointer, ArrayObject *, values) \
+ Member(class, Pointer, ArrayObject *, jsFrame)
DECLARE_HEAP_OBJECT(GeneratorObject, Object) {
- DECLARE_MARKOBJECTS(GeneratorObject);
+ DECLARE_MARKOBJECTS(GeneratorObject)
};
}
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index c6a737b467..d15fb356c4 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4GLOBAL_H
#define QV4GLOBAL_H
@@ -55,30 +19,9 @@
#include <private/qv4compilerglobal_p.h>
#include <QString>
-#ifdef QT_NO_DEBUG
-#define QML_NEARLY_ALWAYS_INLINE Q_ALWAYS_INLINE
-#else
-#define QML_NEARLY_ALWAYS_INLINE inline
-#endif
-
#include <qtqmlglobal.h>
#include <private/qtqmlglobal_p.h>
-#if defined(Q_CC_MSVC)
-#include <float.h>
-#include <math.h>
-
-namespace std {
-
-inline bool isinf(double d) { return !_finite(d) && !_isnan(d); }
-inline bool isnan(double d) { return !!_isnan(d); }
-inline bool isfinite(double d) { return _finite(d); }
-
-} // namespace std
-
-inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
-#endif
-
// Do certain things depending on whether the JIT is enabled or disabled
#if QT_CONFIG(qml_jit)
@@ -141,6 +84,8 @@ namespace Heap {
struct ArgumentsObject;
struct QObjectWrapper;
struct RegExpObject;
+ struct UrlObject;
+ struct UrlSearchParamsObject;
struct RegExp;
struct EvalFunction;
@@ -159,6 +104,8 @@ namespace Heap {
}
struct CppStackFrame;
+struct JSTypesStackFrame;
+struct MetaTypesStackFrame;
class MemoryManager;
class ExecutableAllocator;
struct PropertyKey;
@@ -244,6 +191,8 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(PropertyFlags)
struct PropertyAttributes
{
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_MSVC(4201) // nonstandard extension used: nameless struct/union
union {
uchar m_all;
struct {
@@ -261,6 +210,7 @@ struct PropertyAttributes
uchar configurable_set : 1;
};
};
+ QT_WARNING_POP
enum Type {
Data = 0,
@@ -318,7 +268,6 @@ struct PropertyAttributes
void clear() { m_all = 0; }
bool isEmpty() const { return !m_all; }
- uint flags() const { return m_flags; }
uint all() const { return m_all; }
bool operator==(PropertyAttributes other) {
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index bb81fb52d4..37548ffc9f 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -1,65 +1,29 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4globalobject_p.h"
-#include <private/qv4mm_p.h>
-#include "qv4value_p.h"
-#include "qv4context_p.h"
-#include "qv4function_p.h"
-#include "qv4debugging_p.h"
-#include "qv4profiling_p.h"
-#include "qv4script_p.h"
-#include "qv4scopedvalue_p.h"
-#include "qv4string_p.h"
-#include "qv4jscall_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 <private/qv4codegen_p.h>
+#include <private/qv4context_p.h>
+#include <private/qv4function_p.h>
+#include <private/qv4mm_p.h>
+#include <private/qv4scopedvalue_p.h>
+#include <private/qv4script_p.h>
+#include <private/qv4stackframe_p.h>
+#include <private/qv4string_p.h>
+#include <private/qv4value_p.h>
#include <wtf/MathExtras.h>
+#include <QtCore/private/qlocale_tools_p.h>
+#include <QtCore/private/qtools_p.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qstring.h>
+
+#include <iostream>
+
using namespace QV4;
using QtMiscUtils::toHexUpper;
using QtMiscUtils::fromHex;
@@ -68,7 +32,7 @@ static QString escape(const QString &input)
{
QString output;
output.reserve(input.size() * 3);
- const int length = input.length();
+ const int length = input.size();
for (int i = 0; i < length; ++i) {
ushort uc = input.at(i).unicode();
if (uc < 0x100) {
@@ -80,13 +44,13 @@ static QString escape(const QString &input)
|| (uc == 0x5F)) {
output.append(QChar(uc));
} else {
- output.append('%');
+ output.append(u'%');
output.append(QLatin1Char(toHexUpper(uc >> 4)));
output.append(QLatin1Char(toHexUpper(uc)));
}
} else {
- output.append('%');
- output.append('u');
+ output.append(u'%');
+ output.append(u'u');
output.append(QLatin1Char(toHexUpper(uc >> 12)));
output.append(QLatin1Char(toHexUpper(uc >> 8)));
output.append(QLatin1Char(toHexUpper(uc >> 4)));
@@ -99,14 +63,14 @@ static QString escape(const QString &input)
static QString unescape(const QString &input)
{
QString result;
- result.reserve(input.length());
+ result.reserve(input.size());
int i = 0;
- const int length = input.length();
+ const int length = input.size();
while (i < length) {
QChar c = input.at(i++);
- if ((c == '%') && (i + 1 < length)) {
+ if ((c == u'%') && (i + 1 < length)) {
QChar a = input.at(i);
- if ((a == 'u') && (i + 4 < length)) {
+ if ((a == u'u') && (i + 4 < length)) {
int d3 = fromHex(input.at(i+1).unicode());
int d2 = fromHex(input.at(i+2).unicode());
int d1 = fromHex(input.at(i+3).unicode());
@@ -122,7 +86,7 @@ static QString unescape(const QString &input)
int d1 = fromHex(a.unicode());
int d0 = fromHex(input.at(i+1).unicode());
if ((d1 != -1) && (d0 != -1)) {
- c = (d1 << 4) | d0;
+ c = QChar((d1 << 4) | d0);
i += 2;
}
result.append(c);
@@ -149,7 +113,7 @@ static QString encode(const QString &input, const char *unescapedSet, bool *ok)
{
*ok = true;
QString output;
- const int length = input.length();
+ const int length = input.size();
int i = 0;
while (i < length) {
const QChar c = input.at(i);
@@ -223,8 +187,8 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok)
{
*ok = true;
QString output;
- output.reserve(input.length());
- const int length = input.length();
+ output.reserve(input.size());
+ const int length = input.size();
int i = 0;
const QChar percent = QLatin1Char('%');
while (i < length) {
@@ -304,7 +268,7 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok)
++r;
}
if (*r)
- output.append(input.midRef(start, i - start + 1));
+ output.append(QStringView{input}.mid(start, i - start + 1));
else
output.append(QChar(b));
} else {
@@ -367,17 +331,17 @@ ReturnedValue EvalFunction::evalCall(const Value *, const Value *argv, int argc,
Function *function = script.function();
if (!function)
return Encode::undefined();
- function->isEval = true;
+ function->kind = Function::Eval;
if (function->isStrict() || isStrict) {
ScopedFunctionObject e(scope, FunctionObject::createScriptFunction(ctx, function));
ScopedValue thisObject(scope, directCall ? scope.engine->currentStackFrame->thisObject() : scope.engine->globalObject->asReturnedValue());
- return e->call(thisObject, nullptr, 0);
+ return checkedResult(v4, e->call(thisObject, nullptr, 0));
}
ScopedValue thisObject(scope, scope.engine->currentStackFrame->thisObject());
- return function->call(thisObject, nullptr, 0, ctx);
+ return checkedResult(v4, function->call(thisObject, nullptr, 0, ctx));
}
@@ -417,7 +381,7 @@ ReturnedValue GlobalFunctions::method_parseInt(const FunctionObject *b, const Va
CHECK_EXCEPTION();
const QChar *pos = trimmed.constData();
- const QChar *end = pos + trimmed.length();
+ const QChar *end = pos + trimmed.size();
int sign = 1; // 3
if (pos != end) {
diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h
index 021b445955..71e06ef417 100644
--- a/src/qml/jsruntime/qv4globalobject_p.h
+++ b/src/qml/jsruntime/qv4globalobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4GLOBALOBJECT_H
#define QV4GLOBALOBJECT_H
@@ -50,7 +14,7 @@
// We mean it.
//
-#include "qv4global_p.h"
+#include <QtQml/private/qqmlglobal_p.h>
#include "qv4functionobject_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp
deleted file mode 100644
index c3d7165f71..0000000000
--- a/src/qml/jsruntime/qv4identifier.cpp
+++ /dev/null
@@ -1,207 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "qv4identifier_p.h"
-#include "qv4identifiertable_p.h"
-#include "qv4string_p.h"
-#include <private/qprimefornumbits_p.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-
-IdentifierHashData::IdentifierHashData(IdentifierTable *table, int numBits)
- : size(0)
- , numBits(numBits)
- , identifierTable(table)
-{
- refCount.storeRelaxed(1);
- alloc = qPrimeForNumBits(numBits);
- entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
- memset(entries, 0, alloc*sizeof(IdentifierHashEntry));
- identifierTable->addIdentifierHash(this);
-}
-
-IdentifierHashData::IdentifierHashData(IdentifierHashData *other)
- : size(other->size)
- , numBits(other->numBits)
- , identifierTable(other->identifierTable)
-{
- refCount.storeRelaxed(1);
- alloc = other->alloc;
- entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
- memcpy(entries, other->entries, alloc*sizeof(IdentifierHashEntry));
- identifierTable->addIdentifierHash(this);
-}
-
-IdentifierHashData::~IdentifierHashData() {
- free(entries);
- if (identifierTable)
- identifierTable->removeIdentifierHash(this);
-}
-
-IdentifierHash::IdentifierHash(ExecutionEngine *engine)
-{
- d = new IdentifierHashData(engine->identifierTable, 3);
-}
-
-void IdentifierHash::detach()
-{
- if (!d || d->refCount.loadAcquire() == 1)
- return;
- IdentifierHashData *newData = new IdentifierHashData(d);
- if (d && !d->refCount.deref())
- delete d;
- d = newData;
-}
-
-
-IdentifierHashEntry *IdentifierHash::addEntry(PropertyKey identifier)
-{
- Q_ASSERT(identifier.isStringOrSymbol());
-
- // fill up to max 50%
- bool grow = (d->alloc <= d->size*2);
-
- if (grow) {
- ++d->numBits;
- int newAlloc = qPrimeForNumBits(d->numBits);
- IdentifierHashEntry *newEntries = (IdentifierHashEntry *)malloc(newAlloc * sizeof(IdentifierHashEntry));
- memset(newEntries, 0, newAlloc*sizeof(IdentifierHashEntry));
- for (int i = 0; i < d->alloc; ++i) {
- const IdentifierHashEntry &e = d->entries[i];
- if (!e.identifier.isValid())
- continue;
- uint idx = e.identifier.id() % newAlloc;
- while (newEntries[idx].identifier.isValid()) {
- ++idx;
- idx %= newAlloc;
- }
- newEntries[idx] = e;
- }
- free(d->entries);
- d->entries = newEntries;
- d->alloc = newAlloc;
- }
-
- uint idx = identifier.id() % d->alloc;
- while (d->entries[idx].identifier.isValid()) {
- Q_ASSERT(d->entries[idx].identifier != identifier);
- ++idx;
- idx %= d->alloc;
- }
- d->entries[idx].identifier = identifier;
- ++d->size;
- return d->entries + idx;
-}
-
-const IdentifierHashEntry *IdentifierHash::lookup(PropertyKey identifier) const
-{
- if (!d || !identifier.isStringOrSymbol())
- return nullptr;
- Q_ASSERT(d->entries);
-
- uint idx = identifier.id() % d->alloc;
- while (1) {
- if (!d->entries[idx].identifier.isValid())
- return nullptr;
- if (d->entries[idx].identifier == identifier)
- return d->entries + idx;
- ++idx;
- idx %= d->alloc;
- }
-}
-
-const IdentifierHashEntry *IdentifierHash::lookup(const QString &str) const
-{
- if (!d)
- return nullptr;
-
- PropertyKey id = d->identifierTable->asPropertyKey(str);
- return lookup(id);
-}
-
-const IdentifierHashEntry *IdentifierHash::lookup(String *str) const
-{
- if (!d)
- return nullptr;
- PropertyKey id = d->identifierTable->asPropertyKey(str);
- if (id.isValid())
- return lookup(id);
- return lookup(str->toQString());
-}
-
-const PropertyKey IdentifierHash::toIdentifier(const QString &str) const
-{
- Q_ASSERT(d);
- return d->identifierTable->asPropertyKey(str);
-}
-
-const PropertyKey IdentifierHash::toIdentifier(Heap::String *str) const
-{
- Q_ASSERT(d);
- return d->identifierTable->asPropertyKey(str);
-}
-
-QString QV4::IdentifierHash::findId(int value) const
-{
- IdentifierHashEntry *e = d->entries;
- IdentifierHashEntry *end = e + d->alloc;
- while (e < end) {
- if (e->identifier.isValid() && e->value == value)
- return e->identifier.toQString();
- ++e;
- }
- return QString();
-}
-
-void IdentifierHashData::markObjects(MarkStack *markStack) const
-{
- IdentifierHashEntry *e = entries;
- IdentifierHashEntry *end = e + alloc;
- while (e < end) {
- if (Heap::Base *o = e->identifier.asStringOrSymbol())
- o->mark(markStack);
- ++e;
- }
-}
-
-
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4identifier_p.h b/src/qml/jsruntime/qv4identifier_p.h
deleted file mode 100644
index 32de8b7c8d..0000000000
--- a/src/qml/jsruntime/qv4identifier_p.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef QV4IDENTIFIER_H
-#define QV4IDENTIFIER_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 <qstring.h>
-#include <private/qv4global_p.h>
-#include <private/qv4propertykey_p.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QV4 {
-
-struct IdentifierHashEntry {
- PropertyKey identifier;
- int value;
-};
-
-struct IdentifierHashData
-{
- IdentifierHashData(IdentifierTable *table, int numBits);
- explicit IdentifierHashData(IdentifierHashData *other);
- ~IdentifierHashData();
- void markObjects(MarkStack *markStack) const;
-
- QBasicAtomicInt refCount;
- int alloc;
- int size;
- int numBits;
- IdentifierTable *identifierTable;
- IdentifierHashEntry *entries;
-};
-
-struct IdentifierHash
-{
-
- IdentifierHashData *d = nullptr;
-
- IdentifierHash() {}
- IdentifierHash(ExecutionEngine *engine);
- inline IdentifierHash(const IdentifierHash &other);
- inline ~IdentifierHash();
- inline IdentifierHash &operator=(const IdentifierHash &other);
-
- bool isEmpty() const { return !d; }
-
- inline int count() const;
-
- void detach();
-
- void add(const QString &str, int value);
- void add(Heap::String *str, int value);
-
- inline int value(const QString &str) const;
- inline int value(String *str) const;
- QString findId(int value) const;
-
-protected:
- IdentifierHashEntry *addEntry(PropertyKey i);
- const IdentifierHashEntry *lookup(PropertyKey identifier) const;
- const IdentifierHashEntry *lookup(const QString &str) const;
- const IdentifierHashEntry *lookup(String *str) const;
- const PropertyKey toIdentifier(const QString &str) const;
- const PropertyKey toIdentifier(Heap::String *str) const;
-};
-
-
-inline IdentifierHash::IdentifierHash(const IdentifierHash &other)
-{
- d = other.d;
- if (d)
- d->refCount.ref();
-}
-
-inline IdentifierHash::~IdentifierHash()
-{
- if (d && !d->refCount.deref())
- delete d;
-}
-
-IdentifierHash &IdentifierHash::operator=(const IdentifierHash &other)
-{
- if (other.d)
- other.d->refCount.ref();
- if (d && !d->refCount.deref())
- delete d;
- d = other.d;
- return *this;
-}
-
-inline int IdentifierHash::count() const
-{
- return d ? d->size : 0;
-}
-
-inline
-void IdentifierHash::add(const QString &str, int value)
-{
- IdentifierHashEntry *e = addEntry(toIdentifier(str));
- e->value = value;
-}
-
-inline
-void IdentifierHash::add(Heap::String *str, int value)
-{
- IdentifierHashEntry *e = addEntry(toIdentifier(str));
- e->value = value;
-}
-
-inline int IdentifierHash::value(const QString &str) const
-{
- const IdentifierHashEntry *e = lookup(str);
- return e ? e->value : -1;
-}
-
-inline int IdentifierHash::value(String *str) const
-{
- const IdentifierHashEntry *e = lookup(str);
- return e ? e->value : -1;
-}
-
-}
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/jsruntime/qv4identifierhash.cpp b/src/qml/jsruntime/qv4identifierhash.cpp
new file mode 100644
index 0000000000..48df2283f0
--- /dev/null
+++ b/src/qml/jsruntime/qv4identifierhash.cpp
@@ -0,0 +1,190 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qv4identifierhash_p.h>
+#include <private/qv4identifiertable_p.h>
+#include <private/qv4string_p.h>
+#include <private/qv4identifierhashdata_p.h>
+#include <private/qprimefornumbits_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+IdentifierHash::IdentifierHash(ExecutionEngine *engine)
+{
+ d = new IdentifierHashData(engine->identifierTable, 3);
+ Q_ASSERT(!isEmpty());
+}
+
+void IdentifierHash::detach()
+{
+ if (!d || d->refCount.loadAcquire() == 1)
+ return;
+ IdentifierHashData *newData = new IdentifierHashData(d);
+ if (d && !d->refCount.deref())
+ delete d;
+ d = newData;
+}
+
+inline
+IdentifierHashEntry *IdentifierHash::addEntry(PropertyKey identifier)
+{
+ Q_ASSERT(identifier.isStringOrSymbol());
+
+ // fill up to max 50%
+ bool grow = (d->alloc <= d->size*2);
+
+ if (grow) {
+ ++d->numBits;
+ int newAlloc = qPrimeForNumBits(d->numBits);
+ IdentifierHashEntry *newEntries = (IdentifierHashEntry *)malloc(newAlloc * sizeof(IdentifierHashEntry));
+ memset(newEntries, 0, newAlloc*sizeof(IdentifierHashEntry));
+ for (int i = 0; i < d->alloc; ++i) {
+ const IdentifierHashEntry &e = d->entries[i];
+ if (!e.identifier.isValid())
+ continue;
+ uint idx = e.identifier.id() % newAlloc;
+ while (newEntries[idx].identifier.isValid()) {
+ ++idx;
+ idx %= newAlloc;
+ }
+ newEntries[idx] = e;
+ }
+ free(d->entries);
+ d->entries = newEntries;
+ d->alloc = newAlloc;
+ }
+
+ uint idx = identifier.id() % d->alloc;
+ while (d->entries[idx].identifier.isValid()) {
+ Q_ASSERT(d->entries[idx].identifier != identifier);
+ ++idx;
+ idx %= d->alloc;
+ }
+ d->entries[idx].identifier = identifier;
+ ++d->size;
+ return d->entries + idx;
+}
+
+inline
+const IdentifierHashEntry *IdentifierHash::lookup(PropertyKey identifier) const
+{
+ if (!d || !identifier.isStringOrSymbol())
+ return nullptr;
+ Q_ASSERT(d->entries);
+
+ uint idx = identifier.id() % d->alloc;
+ while (1) {
+ if (!d->entries[idx].identifier.isValid())
+ return nullptr;
+ if (d->entries[idx].identifier == identifier)
+ return d->entries + idx;
+ ++idx;
+ idx %= d->alloc;
+ }
+}
+
+inline
+const IdentifierHashEntry *IdentifierHash::lookup(const QString &str) const
+{
+ if (!d)
+ return nullptr;
+
+ PropertyKey id = d->identifierTable->asPropertyKey(str, IdentifierTable::ForceConversionToId);
+ return lookup(id);
+}
+
+inline
+const IdentifierHashEntry *IdentifierHash::lookup(String *str) const
+{
+ if (!d)
+ return nullptr;
+ PropertyKey id = d->identifierTable->asPropertyKey(str);
+ if (id.isValid())
+ return lookup(id);
+ return lookup(str->toQString());
+}
+
+inline
+const PropertyKey IdentifierHash::toIdentifier(const QString &str) const
+{
+ Q_ASSERT(d);
+ return d->identifierTable->asPropertyKey(str, IdentifierTable::ForceConversionToId);
+}
+
+inline
+const PropertyKey IdentifierHash::toIdentifier(Heap::String *str) const
+{
+ Q_ASSERT(d);
+ return d->identifierTable->asPropertyKey(str);
+}
+
+QString QV4::IdentifierHash::findId(int value) const
+{
+ IdentifierHashEntry *e = d->entries;
+ IdentifierHashEntry *end = e + d->alloc;
+ while (e < end) {
+ if (e->identifier.isValid() && e->value == value)
+ return e->identifier.toQString();
+ ++e;
+ }
+ return QString();
+}
+
+QV4::IdentifierHash::IdentifierHash(const IdentifierHash &other)
+{
+ d = other.d;
+ if (d)
+ d->refCount.ref();
+}
+
+QV4::IdentifierHash::~IdentifierHash()
+{
+ if (d && !d->refCount.deref())
+ delete d;
+}
+
+IdentifierHash &QV4::IdentifierHash::operator=(const IdentifierHash &other)
+{
+ if (other.d)
+ other.d->refCount.ref();
+ if (d && !d->refCount.deref())
+ delete d;
+ d = other.d;
+ return *this;
+}
+
+int QV4::IdentifierHash::count() const
+{
+ return d ? d->size : 0;
+}
+
+void QV4::IdentifierHash::add(const QString &str, int value)
+{
+ IdentifierHashEntry *e = addEntry(toIdentifier(str));
+ e->value = value;
+}
+
+void QV4::IdentifierHash::add(Heap::String *str, int value)
+{
+ IdentifierHashEntry *e = addEntry(toIdentifier(str));
+ e->value = value;
+}
+
+int QV4::IdentifierHash::value(const QString &str) const
+{
+ const IdentifierHashEntry *e = lookup(str);
+ return e ? e->value : -1;
+}
+
+int QV4::IdentifierHash::value(String *str) const
+{
+ const IdentifierHashEntry *e = lookup(str);
+ return e ? e->value : -1;
+}
+
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4identifierhash_p.h b/src/qml/jsruntime/qv4identifierhash_p.h
new file mode 100644
index 0000000000..6c77a78f85
--- /dev/null
+++ b/src/qml/jsruntime/qv4identifierhash_p.h
@@ -0,0 +1,63 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QV4IDENTIFIERHASH_P_H
+#define QV4IDENTIFIERHASH_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 <qstring.h>
+#include <private/qv4global_p.h>
+#include <private/qv4propertykey_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct IdentifierHashEntry;
+struct IdentifierHashData;
+struct Q_QML_EXPORT IdentifierHash
+{
+ IdentifierHash() = default;
+ IdentifierHash(ExecutionEngine *engine);
+ IdentifierHash(const IdentifierHash &other);
+ ~IdentifierHash();
+ IdentifierHash &operator=(const IdentifierHash &other);
+
+ bool isEmpty() const { return !d; }
+
+ int count() const;
+
+ void detach();
+
+ void add(const QString &str, int value);
+ void add(Heap::String *str, int value);
+
+ int value(const QString &str) const;
+ int value(String *str) const;
+ QString findId(int value) const;
+
+private:
+ inline IdentifierHashEntry *addEntry(PropertyKey i);
+ inline const IdentifierHashEntry *lookup(PropertyKey identifier) const;
+ inline const IdentifierHashEntry *lookup(const QString &str) const;
+ inline const IdentifierHashEntry *lookup(String *str) const;
+ inline const PropertyKey toIdentifier(const QString &str) const;
+ inline const PropertyKey toIdentifier(Heap::String *str) const;
+
+ IdentifierHashData *d = nullptr;
+};
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4_IDENTIFIERHASH_P_H
diff --git a/src/qml/jsruntime/qv4identifierhashdata_p.h b/src/qml/jsruntime/qv4identifierhashdata_p.h
new file mode 100644
index 0000000000..664e8e803d
--- /dev/null
+++ b/src/qml/jsruntime/qv4identifierhashdata_p.h
@@ -0,0 +1,86 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QV4IDENTIFIERHASHDATA_H
+#define QV4IDENTIFIERHASHDATA_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/qv4global_p.h>
+#include <private/qv4propertykey_p.h>
+#include <private/qv4identifiertable_p.h>
+#include <QtCore/qatomic.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct IdentifierHashEntry {
+ PropertyKey identifier;
+ int value;
+};
+
+struct IdentifierHashData
+{
+ IdentifierHashData(IdentifierTable *table, int numBits)
+ : size(0)
+ , numBits(numBits)
+ , identifierTable(table)
+ {
+ refCount.storeRelaxed(1);
+ alloc = qPrimeForNumBits(numBits);
+ entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
+ memset(entries, 0, alloc*sizeof(IdentifierHashEntry));
+ identifierTable->addIdentifierHash(this);
+ }
+
+ explicit IdentifierHashData(IdentifierHashData *other)
+ : size(other->size)
+ , numBits(other->numBits)
+ , identifierTable(other->identifierTable)
+ {
+ refCount.storeRelaxed(1);
+ alloc = other->alloc;
+ entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
+ memcpy(entries, other->entries, alloc*sizeof(IdentifierHashEntry));
+ identifierTable->addIdentifierHash(this);
+ }
+
+ ~IdentifierHashData() {
+ free(entries);
+ if (identifierTable)
+ identifierTable->removeIdentifierHash(this);
+ }
+
+ void markObjects(MarkStack *markStack) const
+ {
+ IdentifierHashEntry *e = entries;
+ IdentifierHashEntry *end = e + alloc;
+ while (e < end) {
+ if (Heap::Base *o = e->identifier.asStringOrSymbol())
+ o->mark(markStack);
+ ++e;
+ }
+ }
+
+ QBasicAtomicInt refCount;
+ int alloc;
+ int size;
+ int numBits;
+ IdentifierTable *identifierTable;
+ IdentifierHashEntry *entries;
+};
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4IDENTIFIERHASHDATA_P_H
diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp
index 21b47c3909..4c915442f4 100644
--- a/src/qml/jsruntime/qv4identifiertable.cpp
+++ b/src/qml/jsruntime/qv4identifiertable.cpp
@@ -1,43 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4identifiertable_p.h"
#include "qv4symbol_p.h"
+#include <private/qv4identifierhashdata_p.h>
#include <private/qprimefornumbits_p.h>
QT_BEGIN_NAMESPACE
@@ -60,7 +25,7 @@ IdentifierTable::~IdentifierTable()
{
free(entriesByHash);
free(entriesById);
- for (const auto &h : qAsConst(idHashes))
+ for (const auto &h : std::as_const(idHashes))
h->identifierTable = nullptr;
}
@@ -71,7 +36,7 @@ void IdentifierTable::addEntry(Heap::StringOrSymbol *str)
if (str->subtype == Heap::String::StringType_ArrayIndex)
return;
- str->identifier = PropertyKey::fromStringOrSymbol(str);
+ str->identifier = PropertyKey::fromStringOrSymbol(engine, str);
bool grow = (alloc <= size*2);
@@ -135,13 +100,19 @@ void IdentifierTable::addEntry(Heap::StringOrSymbol *str)
Heap::String *IdentifierTable::insertString(const QString &s)
{
uint subtype;
- uint hash = String::createHashValue(s.constData(), s.length(), &subtype);
+ uint hash = String::createHashValue(s.constData(), s.size(), &subtype);
if (subtype == Heap::String::StringType_ArrayIndex) {
Heap::String *str = engine->newString(s);
str->stringHash = hash;
str->subtype = subtype;
+ str->identifier = PropertyKey::fromArrayIndex(hash);
return str;
}
+ return resolveStringEntry(s, hash, subtype);
+}
+
+Heap::String *IdentifierTable::resolveStringEntry(const QString &s, uint hash, uint subtype)
+{
uint idx = hash % alloc;
while (Heap::StringOrSymbol *e = entriesByHash[idx]) {
if (e->stringHash == hash && e->toQString() == s)
@@ -162,7 +133,7 @@ Heap::Symbol *IdentifierTable::insertSymbol(const QString &s)
Q_ASSERT(s.at(0) == QLatin1Char('@'));
uint subtype;
- uint hash = String::createHashValue(s.constData(), s.length(), &subtype);
+ uint hash = String::createHashValue(s.constData(), s.size(), &subtype);
uint idx = hash % alloc;
while (Heap::StringOrSymbol *e = entriesByHash[idx]) {
if (e->stringHash == hash && e->toQString() == s)
@@ -194,6 +165,9 @@ PropertyKey IdentifierTable::asPropertyKeyImpl(const Heap::String *str)
while (Heap::StringOrSymbol *e = entriesByHash[idx]) {
if (e->stringHash == hash && e->toQString() == str->toQString()) {
str->identifier = e->identifier;
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) {
+ e->identifier.asStringOrSymbol()->mark(stack);
+ });
return e->identifier;
}
++idx;
@@ -278,32 +252,18 @@ void IdentifierTable::sweep()
size -= freed;
}
-PropertyKey IdentifierTable::asPropertyKey(const QString &s)
-{
- return insertString(s)->identifier;
-}
-
-PropertyKey IdentifierTable::asPropertyKey(const char *s, int len)
+PropertyKey IdentifierTable::asPropertyKey(const QString &s,
+ IdentifierTable::KeyConversionBehavior conversionBehvior)
{
uint subtype;
- uint hash = String::createHashValue(s, len, &subtype);
- if (hash == UINT_MAX)
- return asPropertyKey(QString::fromUtf8(s, len));
-
- QLatin1String latin(s, len);
- uint idx = hash % alloc;
- while (Heap::StringOrSymbol *e = entriesByHash[idx]) {
- if (e->stringHash == hash && e->toQString() == latin)
- return e->identifier;
- ++idx;
- idx %= alloc;
+ uint hash = String::createHashValue(s.constData(), s.size(), &subtype);
+ if (subtype == Heap::String::StringType_ArrayIndex) {
+ if (Q_UNLIKELY(conversionBehvior == ForceConversionToId))
+ hash = String::createHashValueDisallowingArrayIndex(s.constData(), s.size(), &subtype);
+ else
+ return PropertyKey::fromArrayIndex(hash);
}
-
- Heap::String *str = engine->newString(QString::fromLatin1(s, len));
- str->stringHash = hash;
- str->subtype = subtype;
- addEntry(str);
- return str->identifier;
+ return resolveStringEntry(s, hash, subtype)->identifier;
}
}
diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h
index 78e2b6620e..2ecd4a7294 100644
--- a/src/qml/jsruntime/qv4identifiertable_p.h
+++ b/src/qml/jsruntime/qv4identifiertable_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4IDENTIFIERTABLE_H
#define QV4IDENTIFIERTABLE_H
@@ -50,7 +14,7 @@
// We mean it.
//
-#include "qv4identifier_p.h"
+#include "qv4identifierhash_p.h"
#include "qv4string_p.h"
#include "qv4engine_p.h"
#include <qset.h>
@@ -60,7 +24,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-struct Q_QML_PRIVATE_EXPORT IdentifierTable
+struct Q_QML_EXPORT IdentifierTable
{
ExecutionEngine *engine;
@@ -91,8 +55,8 @@ public:
return asPropertyKey(str->d());
}
- PropertyKey asPropertyKey(const QString &s);
- PropertyKey asPropertyKey(const char *s, int len);
+ enum KeyConversionBehavior { Default, ForceConversionToId };
+ PropertyKey asPropertyKey(const QString &s, KeyConversionBehavior conversionBehavior = Default);
PropertyKey asPropertyKeyImpl(const Heap::String *str);
@@ -109,6 +73,9 @@ public:
void removeIdentifierHash(IdentifierHashData *h) {
idHashes.remove(h);
}
+
+private:
+ Heap::String *resolveStringEntry(const QString &s, uint hash, uint subtype);
};
}
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index 92face6f94..76545ba692 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4include_p.h"
#include "qv4scopedvalue_p.h"
@@ -59,20 +23,21 @@ QT_BEGIN_NAMESPACE
QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine,
QV4::QmlContext *qmlContext, const QV4::Value &callback)
- : v4(engine), m_url(url)
+ : QObject(engine->jsEngine())
+ , v4(engine), m_url(url)
#if QT_CONFIG(qml_network)
- , m_redirectCount(0), m_network(nullptr) , m_reply(nullptr)
+ , m_network(nullptr) , m_reply(nullptr)
#endif
{
if (qmlContext)
- m_qmlContext.set(engine, *qmlContext);
+ m_qmlContext.set(v4, *qmlContext);
if (callback.as<QV4::FunctionObject>())
- m_callbackFunction.set(engine, callback);
+ m_callbackFunction.set(v4, callback);
m_resultObject.set(v4, resultValue(v4));
#if QT_CONFIG(qml_network)
- if (QQmlEngine *qmlEngine = engine->qmlEngine()) {
+ if (QQmlEngine *qmlEngine = v4->qmlEngine()) {
m_network = qmlEngine->networkAccessManager();
QNetworkRequest request;
@@ -126,9 +91,9 @@ void QV4Include::callback(const QV4::Value &callback, const QV4::Value &status)
if (!f)
return;
- QV4::JSCallData jsCallData(scope, 1);
- *jsCallData->thisObject = v4->globalObject->asReturnedValue();
- jsCallData->args[0] = status;
+ QV4::JSCallArguments jsCallData(scope, 1);
+ *jsCallData.thisObject = v4->globalObject->asReturnedValue();
+ jsCallData.args[0] = status;
f->call(jsCallData);
if (scope.hasException())
scope.engine->catchException();
@@ -139,27 +104,9 @@ QV4::ReturnedValue QV4Include::result()
return m_resultObject.value();
}
-#define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
void QV4Include::finished()
{
#if QT_CONFIG(qml_network)
- m_redirectCount++;
-
- if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) {
- QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
- if (redirect.isValid()) {
- m_url = m_url.resolved(redirect.toUrl());
- delete m_reply;
-
- QNetworkRequest request;
- request.setUrl(m_url);
-
- m_reply = m_network->get(request);
- QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
- return;
- }
- }
-
QV4::Scope scope(v4);
QV4::ScopedObject resultObj(scope, m_resultObject.value());
QV4::ScopedString status(scope, v4->newString(QStringLiteral("status")));
@@ -172,9 +119,9 @@ void QV4Include::finished()
QV4::Script script(v4, qml, /*parse as QML binding*/false, code, m_url.toString());
script.parse();
- if (!scope.engine->hasException)
+ if (!scope.hasException())
script.run();
- if (scope.engine->hasException) {
+ if (scope.hasException()) {
QV4::ScopedValue ex(scope, scope.engine->catchException());
resultObj->put(status, QV4::ScopedValue(scope, QV4::Value::fromInt32(Exception)));
QV4::ScopedString exception(scope, v4->newString(QStringLiteral("exception")));
@@ -202,37 +149,40 @@ void QV4Include::finished()
/*
Documented in qv4engine.cpp
*/
-QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *argv, int argc)
+QJSValue QV4Include::method_include(QV4::ExecutionEngine *engine, const QUrl &url,
+ const QJSValue &callbackFunction)
{
- QV4::Scope scope(b);
- if (!argc)
- RETURN_UNDEFINED();
+ QQmlRefPointer<QQmlContextData> context = engine->callingQmlContext();
- QQmlContextData *context = scope.engine->callingQmlContext();
-
- if ((!context || !context->isJSContext) && scope.engine->qmlEngine())
- RETURN_RESULT(scope.engine->throwError(QString::fromUtf8("Qt.include(): Can only be called from JavaScript files")));
+ if ((!context || !context->isJSContext()) && engine->qmlEngine()) {
+ return QJSValuePrivate::fromReturnedValue(
+ engine->throwError(
+ QString::fromUtf8(
+ "Qt.include(): Can only be called from JavaScript files")));
+ }
- QV4::ScopedValue callbackFunction(scope, QV4::Value::undefinedValue());
- if (argc >= 2 && argv[1].as<QV4::FunctionObject>())
- callbackFunction = argv[1];
- QUrl url(scope.engine->resolvedUrl(argv[0].toQStringNoThrow()));
- if (scope.engine->qmlEngine() && scope.engine->qmlEngine()->urlInterceptor())
- url = scope.engine->qmlEngine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::JavaScriptFile);
+ QV4::Scope scope(engine);
+ QV4::ScopedValue scopedCallbackFunction(scope, QV4::Value::undefinedValue());
+ if (auto function = QJSValuePrivate::asManagedType<QV4::FunctionObject>(&callbackFunction))
+ scopedCallbackFunction = *function;
- QString localFile = QQmlFile::urlToLocalFileOrQrc(url);
+ const QQmlEngine *qmlEngine = engine->qmlEngine();
+ const QUrl intercepted = qmlEngine
+ ? qmlEngine->interceptUrl(url, QQmlAbstractUrlInterceptor::JavaScriptFile)
+ : url;
+ QString localFile = QQmlFile::urlToLocalFileOrQrc(intercepted);
QV4::ScopedValue result(scope);
QV4::Scoped<QV4::QmlContext> qmlcontext(scope, scope.engine->qmlContext());
if (localFile.isEmpty()) {
#if QT_CONFIG(qml_network)
- QV4Include *i = new QV4Include(url, scope.engine, qmlcontext, callbackFunction);
+ QV4Include *i = new QV4Include(url, engine, qmlcontext, scopedCallbackFunction);
result = i->result();
#else
result = resultValue(scope.engine, NetworkError);
- callback(callbackFunction, result);
+ callback(scopedCallbackFunction, result);
#endif
} else {
QScopedPointer<QV4::Script> script;
@@ -241,9 +191,9 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons
if (!script.isNull()) {
script->parse();
- if (!scope.engine->hasException)
+ if (!scope.hasException())
script->run();
- if (scope.engine->hasException) {
+ if (scope.hasException()) {
QV4::ScopedValue ex(scope, scope.engine->catchException());
result = resultValue(scope.engine, Exception);
QV4::ScopedString exception(scope, scope.engine->newString(QStringLiteral("exception")));
@@ -255,10 +205,10 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons
result = resultValue(scope.engine, NetworkError, error);
}
- callback(callbackFunction, result);
+ callback(scopedCallbackFunction, result);
}
- return result->asReturnedValue();
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h
index 70ccfbf223..c6ac98c761 100644
--- a/src/qml/jsruntime/qv4include_p.h
+++ b/src/qml/jsruntime/qv4include_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4INCLUDE_P_H
#define QV4INCLUDE_P_H
@@ -53,15 +17,16 @@
#include <QtCore/qobject.h>
#include <QtCore/qurl.h>
-
-#include <private/qqmlcontext_p.h>
+#include <QtCore/qpointer.h>
#include <private/qv4value_p.h>
#include <private/qv4context_p.h>
+#include <private/qv4persistent_p.h>
QT_BEGIN_NAMESPACE
-class QQmlEngine;
+class QJSEngine;
+class QJSValue;
#if QT_CONFIG(qml_network)
class QNetworkAccessManager;
#endif
@@ -77,13 +42,15 @@ public:
Exception = 3
};
- static QV4::ReturnedValue method_include(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QJSValue method_include(QV4::ExecutionEngine *engine, const QUrl &url,
+ const QJSValue &callbackFunction);
private Q_SLOTS:
void finished();
private:
- QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &callback);
+ QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext,
+ const QV4::Value &callback);
~QV4Include();
QV4::ReturnedValue result();
@@ -96,7 +63,6 @@ private:
QUrl m_url;
#if QT_CONFIG(qml_network)
- int m_redirectCount;
QNetworkAccessManager *m_network;
QPointer<QNetworkReply> m_reply;
#endif
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 70849775cb..228a6bcd36 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -1,48 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qv4internalclass_p.h>
#include <qv4string_p.h>
#include <qv4engine_p.h>
-#include <qv4identifier_p.h>
+#include <qv4identifierhash_p.h>
#include "qv4object_p.h"
-#include "qv4identifiertable_p.h"
#include "qv4value_p.h"
#include "qv4mm_p.h"
#include <private/qprimefornumbits_p.h>
@@ -78,34 +41,6 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
++d->size;
}
-int PropertyHash::removeIdentifier(PropertyKey identifier, int classSize)
-{
- int val = -1;
- PropertyHashData *dd = new PropertyHashData(d->numBits);
- for (int i = 0; i < d->alloc; ++i) {
- const Entry &e = d->entries[i];
- if (!e.identifier.isValid() || e.index >= static_cast<unsigned>(classSize))
- continue;
- if (e.identifier == identifier) {
- val = e.index;
- continue;
- }
- uint idx = e.identifier.id() % dd->alloc;
- while (dd->entries[idx].identifier.isValid()) {
- ++idx;
- idx %= dd->alloc;
- }
- dd->entries[idx] = e;
- }
- dd->size = classSize;
- if (!--d->refCount)
- delete d;
- d = dd;
-
- Q_ASSERT(val != -1);
- return val;
-}
-
void PropertyHash::detach(bool grow, int classSize)
{
if (d->refCount == 1 && !grow)
@@ -132,12 +67,11 @@ void PropertyHash::detach(bool grow, int classSize)
SharedInternalClassDataPrivate<PropertyKey>::SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate<PropertyKey> &other)
: refcount(1),
- engine(other.engine),
- data(nullptr)
+ engine(other.engine)
{
if (other.alloc()) {
const uint s = other.size();
- data = MemberData::allocate(engine, other.alloc(), other.data);
+ data.set(engine, MemberData::allocate(engine, other.alloc(), other.data));
setSize(s);
}
}
@@ -147,7 +81,7 @@ SharedInternalClassDataPrivate<PropertyKey>::SharedInternalClassDataPrivate(cons
: refcount(1),
engine(other.engine)
{
- data = MemberData::allocate(engine, other.alloc(), nullptr);
+ data.set(engine, MemberData::allocate(engine, other.alloc(), nullptr));
memcpy(data, other.data, sizeof(Heap::MemberData) - sizeof(Value) + pos*sizeof(Value));
data->values.size = pos + 1;
data->values.set(engine, pos, Value::fromReturnedValue(value.id()));
@@ -157,7 +91,7 @@ void SharedInternalClassDataPrivate<PropertyKey>::grow()
{
const uint a = alloc() * 2;
const uint s = size();
- data = MemberData::allocate(engine, a, data);
+ data.set(engine, MemberData::allocate(engine, a, data));
setSize(s);
Q_ASSERT(alloc() >= a);
}
@@ -178,7 +112,7 @@ void SharedInternalClassDataPrivate<PropertyKey>::setSize(uint s)
data->values.size = s;
}
-PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i)
+PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i) const
{
Q_ASSERT(data && i < size());
return PropertyKey::fromId(data->values.values[i].rawValue());
@@ -187,6 +121,11 @@ PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i)
void SharedInternalClassDataPrivate<PropertyKey>::set(uint i, PropertyKey t)
{
Q_ASSERT(data && i < size());
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) {
+ if constexpr (QV4::WriteBarrier::isInsertionBarrier)
+ if (auto string = t.asStringOrSymbol())
+ string->mark(stack);
+ });
data->values.values[i].rawValueRef() = t.id();
}
@@ -205,11 +144,20 @@ SharedInternalClassDataPrivate<PropertyAttributes>::SharedInternalClassDataPriva
m_engine(other.m_engine)
{
Q_ASSERT(m_size <= m_alloc);
+ Q_ASSERT(m_alloc > 0);
+
m_engine->memoryManager->changeUnmanagedHeapSizeUsage(m_alloc * sizeof(PropertyAttributes));
- data = new PropertyAttributes[m_alloc];
- if (other.data)
- memcpy(data, other.data, (m_size - 1) * sizeof(PropertyAttributes));
- data[pos] = value;
+ const PropertyAttributes *source = other.m_alloc > NumAttributesInPointer
+ ? other.m_data
+ : other.m_inlineData;
+ PropertyAttributes *target;
+ if (m_alloc > NumAttributesInPointer)
+ m_data = target = new PropertyAttributes[m_alloc];
+ else
+ target = m_inlineData;
+
+ memcpy(target, source, (m_size - 1) * sizeof(PropertyAttributes));
+ target[pos] = value;
}
SharedInternalClassDataPrivate<PropertyAttributes>::SharedInternalClassDataPrivate(
@@ -219,12 +167,14 @@ SharedInternalClassDataPrivate<PropertyAttributes>::SharedInternalClassDataPriva
m_size(other.m_size),
m_engine(other.m_engine)
{
- if (m_alloc) {
- m_engine->memoryManager->changeUnmanagedHeapSizeUsage(m_alloc * sizeof(PropertyAttributes));
- data = new PropertyAttributes[m_alloc];
- memcpy(data, other.data, m_size*sizeof(PropertyAttributes));
+ m_engine->memoryManager->changeUnmanagedHeapSizeUsage(m_alloc * sizeof(PropertyAttributes));
+ if (m_alloc > NumAttributesInPointer) {
+ m_data = new PropertyAttributes[m_alloc];
+ memcpy(m_data, other.m_data, m_size*sizeof(PropertyAttributes));
+ } else if (m_alloc > 0) {
+ memcpy(m_inlineData, other.m_inlineData, m_alloc * sizeof(PropertyAttributes));
} else {
- data = nullptr;
+ m_data = nullptr;
}
}
@@ -232,13 +182,14 @@ SharedInternalClassDataPrivate<PropertyAttributes>::~SharedInternalClassDataPriv
{
m_engine->memoryManager->changeUnmanagedHeapSizeUsage(
-qptrdiff(m_alloc * sizeof(PropertyAttributes)));
- delete [] data;
+ if (m_alloc > NumAttributesInPointer)
+ delete [] m_data;
}
void SharedInternalClassDataPrivate<PropertyAttributes>::grow() {
uint alloc;
if (!m_alloc) {
- alloc = 8;
+ alloc = NumAttributesInPointer;
m_engine->memoryManager->changeUnmanagedHeapSizeUsage(alloc * sizeof(PropertyAttributes));
} else {
// yes, signed. We don't want to deal with stuff > 2G
@@ -252,12 +203,16 @@ void SharedInternalClassDataPrivate<PropertyAttributes>::grow() {
(alloc - m_alloc) * sizeof(PropertyAttributes));
}
- auto *n = new PropertyAttributes[alloc];
- if (data) {
- memcpy(n, data, m_alloc*sizeof(PropertyAttributes));
- delete [] data;
+ if (alloc > NumAttributesInPointer) {
+ auto *n = new PropertyAttributes[alloc];
+ if (m_alloc > NumAttributesInPointer) {
+ memcpy(n, m_data, m_alloc * sizeof(PropertyAttributes));
+ delete [] m_data;
+ } else if (m_alloc > 0) {
+ memcpy(n, m_inlineData, m_alloc * sizeof(PropertyAttributes));
+ }
+ m_data = n;
}
- data = n;
m_alloc = alloc;
}
@@ -265,21 +220,21 @@ namespace Heap {
void InternalClass::init(ExecutionEngine *engine)
{
+// InternalClass is automatically zeroed during allocation:
+// prototype = nullptr;
+// parent = nullptr;
+// size = 0;
+// numRedundantTransitions = 0;
+// flags = 0;
+
Base::init();
new (&propertyTable) PropertyHash();
new (&nameMap) SharedInternalClassData<PropertyKey>(engine);
new (&propertyData) SharedInternalClassData<PropertyAttributes>(engine);
- new (&transitions) std::vector<Transition>();
+ new (&transitions) QVarLengthArray<Transition, 1>();
this->engine = engine;
vtable = QV4::InternalClass::staticVTable();
-// prototype = nullptr;
-// parent = nullptr;
-// size = 0;
- extensible = true;
- isFrozen = false;
- isSealed = false;
- isUsedAsProto = false;
protoId = engine->newProtoId();
// Also internal classes need an internal class pointer. Simply make it point to itself
@@ -293,20 +248,23 @@ void InternalClass::init(Heap::InternalClass *other)
new (&propertyTable) PropertyHash(other->propertyTable);
new (&nameMap) SharedInternalClassData<PropertyKey>(other->nameMap);
new (&propertyData) SharedInternalClassData<PropertyAttributes>(other->propertyData);
- new (&transitions) std::vector<Transition>();
+ new (&transitions) QVarLengthArray<Transition, 1>();
engine = other->engine;
vtable = other->vtable;
prototype = other->prototype;
parent = other;
size = other->size;
- extensible = other->extensible;
- isSealed = other->isSealed;
- isFrozen = other->isFrozen;
- isUsedAsProto = other->isUsedAsProto;
+ numRedundantTransitions = other->numRedundantTransitions;
+ flags = other->flags;
protoId = engine->newProtoId();
internalClass.set(engine, other->internalClass);
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) {
+ if constexpr (QV4::WriteBarrier::isInsertionBarrier) {
+ other->mark(stack);
+ }
+ });
}
void InternalClass::destroy()
@@ -326,14 +284,20 @@ void InternalClass::destroy()
propertyTable.~PropertyHash();
nameMap.~SharedInternalClassData<PropertyKey>();
propertyData.~SharedInternalClassData<PropertyAttributes>();
- transitions.~vector<Transition>();
+ transitions.~QVarLengthArray<Transition, 1>();
engine = nullptr;
Base::destroy();
}
-QString InternalClass::keyAt(uint index) const
+ReturnedValue InternalClass::keyAt(uint index) const
{
- return nameMap.at(index).toQString();
+ PropertyKey key = nameMap.at(index);
+ if (!key.isValid())
+ return Encode::undefined();
+ if (key.isArrayIndex())
+ return Encode(key.asArrayIndex());
+ Q_ASSERT(key.isStringOrSymbol());
+ return key.asStringOrSymbol()->asReturnedValue();
}
void InternalClass::changeMember(QV4::Object *object, PropertyKey id, PropertyAttributes data, InternalClassEntry *entry)
@@ -347,7 +311,7 @@ void InternalClass::changeMember(QV4::Object *object, PropertyKey id, PropertyAt
InternalClassTransition &InternalClass::lookupOrInsertTransition(const InternalClassTransition &t)
{
- std::vector<Transition>::iterator it = std::lower_bound(transitions.begin(), transitions.end(), t);
+ QVarLengthArray<Transition, 1>::iterator it = std::lower_bound(transitions.begin(), transitions.end(), t);
if (it != transitions.end() && *it == t) {
return *it;
} else {
@@ -365,7 +329,102 @@ static void addDummyEntry(InternalClass *newClass, PropertyHash::Entry e)
++newClass->size;
}
-Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry)
+static PropertyAttributes attributesFromFlags(int flags)
+{
+ PropertyAttributes attributes;
+ attributes.m_all = uchar(flags);
+ return attributes;
+}
+
+static Heap::InternalClass *cleanInternalClass(Heap::InternalClass *orig)
+{
+ if (++orig->numRedundantTransitions < Heap::InternalClass::MaxRedundantTransitions)
+ return orig;
+
+ // We will generally add quite a few transitions here. We have 255 redundant ones.
+ // We can expect at least as many significant ones in addition.
+ QVarLengthArray<InternalClassTransition, 1> transitions;
+
+ Scope scope(orig->engine);
+ Scoped<QV4::InternalClass> child(scope, orig);
+
+ {
+ quint8 remainingRedundantTransitions = orig->numRedundantTransitions;
+ QSet<PropertyKey> properties;
+ int structureChanges = 0;
+
+ Scoped<QV4::InternalClass> parent(scope, orig->parent);
+ while (parent && remainingRedundantTransitions > 0) {
+ Q_ASSERT(child->d() != scope.engine->classes[ExecutionEngine::Class_Empty]);
+ const auto it = std::find_if(
+ parent->d()->transitions.begin(), parent->d()->transitions.end(),
+ [&child](const InternalClassTransition &t) {
+ return child->d() == t.lookup;
+ });
+ Q_ASSERT(it != parent->d()->transitions.end());
+
+ if (it->flags & InternalClassTransition::StructureChange) {
+ // A structural change. Each kind of structural change has to be recorded only once.
+ if ((structureChanges & it->flags) != it->flags) {
+ transitions.push_back(*it);
+ structureChanges |= it->flags;
+ } else {
+ --remainingRedundantTransitions;
+ }
+ } else if (!properties.contains(it->id)) {
+ // We only need the final state of the property.
+ properties.insert(it->id);
+
+ // Property removal creates _two_ redundant transitions.
+ // We don't have to replay either, but numRedundantTransitions only records one.
+ if (it->flags != 0)
+ transitions.push_back(*it);
+ } else {
+ --remainingRedundantTransitions;
+ }
+
+ child = parent->d();
+ parent = child->d()->parent;
+ Q_ASSERT(child->d() != parent->d());
+ }
+ }
+
+ for (auto it = transitions.rbegin(); it != transitions.rend(); ++it) {
+ switch (it->flags) {
+ case InternalClassTransition::NotExtensible:
+ child = child->d()->nonExtensible();
+ continue;
+ case InternalClassTransition::VTableChange:
+ child = child->d()->changeVTable(it->vtable);
+ continue;
+ case InternalClassTransition::PrototypeChange:
+ child = child->d()->changePrototype(it->prototype);
+ continue;
+ case InternalClassTransition::ProtoClass:
+ child = child->d()->asProtoClass();
+ continue;
+ case InternalClassTransition::Sealed:
+ child = child->d()->sealed();
+ continue;
+ case InternalClassTransition::Frozen:
+ child = child->d()->frozen();
+ continue;
+ case InternalClassTransition::Locked:
+ child = child->d()->locked();
+ continue;
+ default:
+ Q_ASSERT(it->flags != 0);
+ Q_ASSERT(it->flags < InternalClassTransition::StructureChange);
+ child = child->addMember(it->id, attributesFromFlags(it->flags));
+ continue;
+ }
+ }
+
+ return child->d();
+}
+
+Heap::InternalClass *InternalClass::changeMember(
+ PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry)
{
if (!data.isEmpty())
data.resolve();
@@ -381,7 +440,7 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert
}
if (data == propertyData.at(idx))
- return static_cast<Heap::InternalClass *>(this);
+ return this;
Transition temp = { { identifier }, nullptr, int(data.all()) };
Transition &t = lookupOrInsertTransition(temp);
@@ -394,7 +453,8 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert
Q_ASSERT(!propertyData.at(idx).isAccessor());
// add a dummy entry for the accessor
- entry->setterIndex = newClass->size;
+ if (entry)
+ entry->setterIndex = newClass->size;
e->setterIndex = newClass->size;
addDummyEntry(newClass, *e);
}
@@ -403,7 +463,8 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert
t.lookup = newClass;
Q_ASSERT(t.lookup);
- return newClass;
+
+ return cleanInternalClass(newClass);
}
Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
@@ -413,7 +474,7 @@ Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
if (proto)
proto->setUsedAsProto();
Q_ASSERT(prototype != proto);
- Q_ASSERT(!proto || proto->internalClass->isUsedAsProto);
+ Q_ASSERT(!proto || proto->internalClass->isUsedAsProto());
Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::PrototypeChange };
temp.prototype = proto;
@@ -424,11 +485,14 @@ Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
// create a new class and add it to the tree
Heap::InternalClass *newClass = engine->newClass(this);
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) {
+ if (proto && QV4::WriteBarrier::isInsertionBarrier)
+ proto->mark(stack);
+ });
newClass->prototype = proto;
t.lookup = newClass;
-
- return newClass;
+ return prototype ? cleanInternalClass(newClass) : newClass;
}
Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
@@ -449,12 +513,14 @@ Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
t.lookup = newClass;
Q_ASSERT(t.lookup);
Q_ASSERT(newClass->vtable);
- return newClass;
+ return vtable == QV4::InternalClass::staticVTable()
+ ? newClass
+ : cleanInternalClass(newClass);
}
Heap::InternalClass *InternalClass::nonExtensible()
{
- if (!extensible)
+ if (!isExtensible())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::NotExtensible};
@@ -463,7 +529,25 @@ Heap::InternalClass *InternalClass::nonExtensible()
return t.lookup;
Heap::InternalClass *newClass = engine->newClass(this);
- newClass->extensible = false;
+ newClass->flags |= NotExtensible;
+
+ t.lookup = newClass;
+ Q_ASSERT(t.lookup);
+ return newClass;
+}
+
+InternalClass *InternalClass::locked()
+{
+ if (isLocked())
+ return this;
+
+ Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::Locked};
+ Transition &t = lookupOrInsertTransition(temp);
+ if (t.lookup)
+ return t.lookup;
+
+ Heap::InternalClass *newClass = engine->newClass(this);
+ newClass->flags |= Locked;
t.lookup = newClass;
Q_ASSERT(t.lookup);
@@ -500,7 +584,7 @@ Heap::InternalClass *InternalClass::addMember(PropertyKey identifier, PropertyAt
Heap::InternalClass *InternalClass::addMemberImpl(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry)
{
- Transition temp = { { identifier }, nullptr, (int)data.flags() };
+ Transition temp = { { identifier }, nullptr, int(data.all()) };
Transition &t = lookupOrInsertTransition(temp);
if (entry) {
@@ -553,21 +637,23 @@ void InternalClass::removeMember(QV4::Object *object, PropertyKey identifier)
changeMember(object, identifier, Attr_Invalid);
#ifndef QT_NO_DEBUG
- // we didn't remove the data slot, just made it inaccessible
- Q_ASSERT(object->internalClass()->size == oldClass->size);
+ // We didn't remove the data slot, just made it inaccessible.
+ // ... unless we've rebuilt the whole class. Then all the deleted properties are gone.
+ Q_ASSERT(object->internalClass()->numRedundantTransitions == 0
+ || object->internalClass()->size == oldClass->size);
#endif
}
Heap::InternalClass *InternalClass::sealed()
{
- if (isSealed)
+ if (isSealed())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Sealed };
Transition &t = lookupOrInsertTransition(temp);
if (t.lookup) {
- Q_ASSERT(t.lookup && t.lookup->isSealed);
+ Q_ASSERT(t.lookup && t.lookup->isSealed());
return t.lookup;
}
@@ -575,7 +661,7 @@ Heap::InternalClass *InternalClass::sealed()
Scoped<QV4::InternalClass> ic(scope, engine->newClass(this));
Heap::InternalClass *s = ic->d();
- if (!isFrozen) { // freezing also makes all properties non-configurable
+ if (!isFrozen()) { // freezing also makes all properties non-configurable
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
if (attrs.isEmpty())
@@ -584,7 +670,7 @@ Heap::InternalClass *InternalClass::sealed()
s->propertyData.set(i, attrs);
}
}
- s->isSealed = true;
+ s->flags |= Sealed;
t.lookup = s;
return s;
@@ -592,14 +678,14 @@ Heap::InternalClass *InternalClass::sealed()
Heap::InternalClass *InternalClass::frozen()
{
- if (isFrozen)
+ if (isFrozen())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Frozen };
Transition &t = lookupOrInsertTransition(temp);
if (t.lookup) {
- Q_ASSERT(t.lookup && t.lookup->isFrozen);
+ Q_ASSERT(t.lookup && t.lookup->isFrozen());
return t.lookup;
}
@@ -616,7 +702,7 @@ Heap::InternalClass *InternalClass::frozen()
attrs.setConfigurable(false);
f->propertyData.set(i, attrs);
}
- f->isFrozen = true;
+ f->flags |= Frozen;
t.lookup = f;
return f;
@@ -640,7 +726,7 @@ InternalClass *InternalClass::cryopreserved()
bool InternalClass::isImplicitlyFrozen() const
{
- if (isFrozen)
+ if (isFrozen())
return true;
for (uint i = 0; i < size; ++i) {
@@ -656,7 +742,7 @@ bool InternalClass::isImplicitlyFrozen() const
Heap::InternalClass *InternalClass::asProtoClass()
{
- if (isUsedAsProto)
+ if (isUsedAsProto())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::ProtoClass };
@@ -665,7 +751,7 @@ Heap::InternalClass *InternalClass::asProtoClass()
return t.lookup;
Heap::InternalClass *newClass = engine->newClass(this);
- newClass->isUsedAsProto = true;
+ newClass->flags |= UsedAsProto;
t.lookup = newClass;
Q_ASSERT(t.lookup);
@@ -685,7 +771,7 @@ static void updateProtoUsage(Heap::Object *o, Heap::InternalClass *ic)
void InternalClass::updateProtoUsage(Heap::Object *o)
{
- Q_ASSERT(isUsedAsProto);
+ Q_ASSERT(isUsedAsProto());
Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_Empty);
Q_ASSERT(!ic->prototype);
@@ -698,6 +784,9 @@ void InternalClass::markObjects(Heap::Base *b, MarkStack *stack)
if (ic->prototype)
ic->prototype->mark(stack);
+ if (ic->parent)
+ ic->parent->mark(stack);
+
ic->nameMap.mark(stack);
}
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index 403702ae55..56ce787859 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4INTERNALCLASS_H
#define QV4INTERNALCLASS_H
@@ -53,6 +17,8 @@
#include "qv4global_p.h"
#include <QHash>
+#include <QVarLengthArray>
+#include <climits> // for UINT_MAX
#include <private/qv4propertykey_p.h>
#include <private/qv4heap_p.h>
@@ -88,7 +54,6 @@ struct PropertyHash
void addEntry(const Entry &entry, int classSize);
Entry *lookup(PropertyKey identifier) const;
- int removeIdentifier(PropertyKey identifier, int classSize);
void detach(bool grow, int classSize);
};
@@ -158,7 +123,7 @@ struct SharedInternalClassDataPrivate<PropertyAttributes> {
: refcount(1),
m_alloc(0),
m_size(0),
- data(nullptr),
+ m_data(nullptr),
m_engine(engine)
{ }
SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate<PropertyAttributes> &other);
@@ -168,12 +133,14 @@ struct SharedInternalClassDataPrivate<PropertyAttributes> {
void grow();
+ void markIfNecessary(const PropertyAttributes &) {}
+
uint alloc() const { return m_alloc; }
uint size() const { return m_size; }
void setSize(uint s) { m_size = s; }
- PropertyAttributes at(uint i) { Q_ASSERT(data && i < m_alloc); return data[i]; }
- void set(uint i, PropertyAttributes t) { Q_ASSERT(data && i < m_alloc); data[i] = t; }
+ PropertyAttributes at(uint i) const { Q_ASSERT(i < m_alloc); return data(i); }
+ void set(uint i, PropertyAttributes t) { Q_ASSERT(i < m_alloc); setData(i, t); }
void mark(MarkStack *) {}
@@ -181,23 +148,49 @@ struct SharedInternalClassDataPrivate<PropertyAttributes> {
private:
uint m_alloc;
uint m_size;
- PropertyAttributes *data;
+
+ enum {
+ SizeOfAttributesPointer = sizeof(PropertyAttributes *),
+ SizeOfAttributes = sizeof(PropertyAttributes),
+ NumAttributesInPointer = SizeOfAttributesPointer / SizeOfAttributes,
+ };
+
+ static_assert(NumAttributesInPointer > 0);
+
+ PropertyAttributes data(uint i) const {
+ return m_alloc > NumAttributesInPointer ? m_data[i] : m_inlineData[i];
+ }
+
+ void setData(uint i, PropertyAttributes t) {
+ if (m_alloc > NumAttributesInPointer)
+ m_data[i] = t;
+ else
+ m_inlineData[i] = t;
+ }
+
+ union {
+ PropertyAttributes *m_data;
+ PropertyAttributes m_inlineData[NumAttributesInPointer];
+ };
ExecutionEngine *m_engine;
};
template<>
struct SharedInternalClassDataPrivate<PropertyKey> {
- SharedInternalClassDataPrivate(ExecutionEngine *e) : refcount(1), engine(e), data(nullptr) {}
+ SharedInternalClassDataPrivate(ExecutionEngine *e) : refcount(1), engine(e) {}
SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate &other);
SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate &other, uint pos, PropertyKey value);
~SharedInternalClassDataPrivate() {}
+ template<typename StringOrSymbol = Heap::StringOrSymbol>
+ void markIfNecessary(const PropertyKey &value);
+
void grow();
uint alloc() const;
uint size() const;
void setSize(uint s);
- PropertyKey at(uint i);
+ PropertyKey at(uint i) const;
void set(uint i, PropertyKey t);
void mark(MarkStack *s);
@@ -205,9 +198,20 @@ struct SharedInternalClassDataPrivate<PropertyKey> {
int refcount = 1;
private:
ExecutionEngine *engine;
- Heap::MemberData *data;
+ WriteBarrier::Pointer<Heap::MemberData> data;
};
+template<typename StringOrSymbol>
+void QV4::SharedInternalClassDataPrivate<PropertyKey>::markIfNecessary(const PropertyKey &value)
+{
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) {
+ if constexpr (QV4::WriteBarrier::isInsertionBarrier) {
+ if (auto s = value.asStringOrSymbol<StringOrSymbol>())
+ s->mark(stack);
+ }
+ });
+}
+
template <typename T>
struct SharedInternalClassData {
using Private = SharedInternalClassDataPrivate<T>;
@@ -235,12 +239,12 @@ struct SharedInternalClassData {
}
void add(uint pos, T value) {
+ d->markIfNecessary(value);
if (pos < d->size()) {
Q_ASSERT(d->refcount > 1);
// need to detach
Private *dd = new Private(*d, pos, value);
- if (!--d->refcount)
- delete d;
+ --d->refcount;
d = dd;
return;
}
@@ -257,11 +261,11 @@ struct SharedInternalClassData {
void set(uint pos, T value) {
Q_ASSERT(pos < d->size());
+ d->markIfNecessary(value);
if (d->refcount > 1) {
// need to detach
Private *dd = new Private(*d);
- if (!--d->refcount)
- delete d;
+ --d->refcount;
d = dd;
}
d->set(pos, value);
@@ -290,24 +294,35 @@ struct InternalClassTransition
int flags;
enum {
// range 0-0xff is reserved for attribute changes
- NotExtensible = 0x100,
- VTableChange = 0x200,
- PrototypeChange = 0x201,
- ProtoClass = 0x202,
- Sealed = 0x203,
- Frozen = 0x204
+ StructureChange = 0x100,
+ NotExtensible = StructureChange | (1 << 0),
+ VTableChange = StructureChange | (1 << 1),
+ PrototypeChange = StructureChange | (1 << 2),
+ ProtoClass = StructureChange | (1 << 3),
+ Sealed = StructureChange | (1 << 4),
+ Frozen = StructureChange | (1 << 5),
+ Locked = StructureChange | (1 << 6),
};
bool operator==(const InternalClassTransition &other) const
{ return id == other.id && flags == other.flags; }
bool operator<(const InternalClassTransition &other) const
- { return id < other.id || (id == other.id && flags < other.flags); }
+ { return flags < other.flags || (flags == other.flags && id < other.id); }
};
namespace Heap {
struct InternalClass : Base {
+ enum Flag {
+ NotExtensible = 1 << 0,
+ Sealed = 1 << 1,
+ Frozen = 1 << 2,
+ UsedAsProto = 1 << 3,
+ Locked = 1 << 4,
+ };
+ enum { MaxRedundantTransitions = 255 };
+
ExecutionEngine *engine;
const VTable *vtable;
quintptr protoId; // unique across the engine, gets changed whenever the proto chain changes
@@ -319,21 +334,26 @@ struct InternalClass : Base {
SharedInternalClassData<PropertyAttributes> propertyData;
typedef InternalClassTransition Transition;
- std::vector<Transition> transitions;
+ QVarLengthArray<Transition, 1> transitions;
InternalClassTransition &lookupOrInsertTransition(const InternalClassTransition &t);
uint size;
- bool extensible;
- bool isSealed;
- bool isFrozen;
- bool isUsedAsProto;
+ quint8 numRedundantTransitions;
+ quint8 flags;
+
+ bool isExtensible() const { return !(flags & NotExtensible); }
+ bool isSealed() const { return flags & Sealed; }
+ bool isFrozen() const { return flags & Frozen; }
+ bool isUsedAsProto() const { return flags & UsedAsProto; }
+ bool isLocked() const { return flags & Locked; }
void init(ExecutionEngine *engine);
void init(InternalClass *other);
void destroy();
- Q_QML_PRIVATE_EXPORT QString keyAt(uint index) const;
+ Q_QML_EXPORT ReturnedValue keyAt(uint index) const;
Q_REQUIRED_RESULT InternalClass *nonExtensible();
+ Q_REQUIRED_RESULT InternalClass *locked();
static void addMember(QV4::Object *object, PropertyKey id, PropertyAttributes data, InternalClassEntry *entry);
Q_REQUIRED_RESULT InternalClass *addMember(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry = nullptr);
diff --git a/src/qml/jsruntime/qv4iterator.cpp b/src/qml/jsruntime/qv4iterator.cpp
index a543565b37..617037ecdc 100644
--- a/src/qml/jsruntime/qv4iterator.cpp
+++ b/src/qml/jsruntime/qv4iterator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qv4iterator_p.h>
#include <qv4symbol_p.h>
#include <qv4engine_p.h>
diff --git a/src/qml/jsruntime/qv4iterator_p.h b/src/qml/jsruntime/qv4iterator_p.h
index 28e337d21b..46e48864ed 100644
--- a/src/qml/jsruntime/qv4iterator_p.h
+++ b/src/qml/jsruntime/qv4iterator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4ITERATOR_P_H
#define QV4ITERATOR_P_H
@@ -52,7 +16,6 @@
//
#include "qv4object_p.h"
-#include "qv4arraydata_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4jscall.cpp b/src/qml/jsruntime/qv4jscall.cpp
new file mode 100644
index 0000000000..513ae59145
--- /dev/null
+++ b/src/qml/jsruntime/qv4jscall.cpp
@@ -0,0 +1,46 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qv4jscall_p.h"
+
+#include <QtQml/qqmlinfo.h>
+
+#include <private/qqmlengine_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*! \internal
+
+ Sets the arguments of JSCallData from type erased \a args based on type
+ information provided by \a types
+ */
+void QV4::populateJSCallArguments(ExecutionEngine *v4, JSCallArguments &jsCall,
+ int argc, void **args, const QMetaType *types)
+{
+ for (int ii = 0; ii < argc; ++ii)
+ jsCall.args[ii] = v4->metaTypeToJS(types[ii], args[ii + 1]);
+}
+
+void QV4::warnAboutCoercionToVoid(
+ ExecutionEngine *engine, const Value &value, CoercionProblem problem)
+{
+ auto log = qCritical().nospace().noquote();
+ if (const CppStackFrame *frame = engine->currentStackFrame)
+ log << frame->source() << ':' << frame->lineNumber() << ": ";
+ log << value.toQStringNoThrow()
+ << " should be coerced to void because";
+ switch (problem) {
+ case InsufficientAnnotation:
+ log << " the function called is insufficiently annotated.";
+ break;
+ case InvalidListType:
+ log << " the target type, a list of unknown elements, cannot be resolved.";
+ break;
+ }
+
+ log << " The original value is retained. This will change in a future version of Qt.";
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h
index 31689b1ba1..ed1ca983ad 100644
--- a/src/qml/jsruntime/qv4jscall_p.h
+++ b/src/qml/jsruntime/qv4jscall_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4JSCALL_H
#define QV4JSCALL_H
@@ -50,54 +14,86 @@
// We mean it.
//
-#include "qv4object_p.h"
-#include "qv4function_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4context_p.h"
-#include "qv4scopedvalue_p.h"
-#include "qv4stackframe_p.h"
+#include <private/qqmlengine_p.h>
+#include <private/qqmllistwrapper_p.h>
+#include <private/qqmlvaluetype_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qv4alloca_p.h>
+#include <private/qv4context_p.h>
+#include <private/qv4dateobject_p.h>
+#include <private/qv4function_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4regexpobject_p.h>
+#include <private/qv4scopedvalue_p.h>
+#include <private/qv4stackframe_p.h>
+#include <private/qv4urlobject_p.h>
+#include <private/qv4variantobject_p.h>
+
+#if QT_CONFIG(regularexpression)
+#include <QtCore/qregularexpression.h>
+#endif
QT_BEGIN_NAMESPACE
namespace QV4 {
-struct JSCallData {
- JSCallData(const Scope &scope, int argc = 0, const Value *argv = nullptr, const Value *thisObject = nullptr)
- : scope(scope), argc(argc)
+template<typename Args>
+CallData *callDatafromJS(const Scope &scope, const Args *args, const FunctionObject *f = nullptr)
+{
+ int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + args->argc;
+ CallData *ptr = reinterpret_cast<CallData *>(scope.alloc<Scope::Uninitialized>(size));
+ ptr->function = Encode::undefined();
+ ptr->context = Encode::undefined();
+ ptr->accumulator = Encode::undefined();
+ ptr->thisObject = args->thisObject ? args->thisObject->asReturnedValue() : Encode::undefined();
+ ptr->newTarget = Encode::undefined();
+ ptr->setArgc(args->argc);
+ if (args->argc)
+ memcpy(ptr->args, args->args, args->argc*sizeof(Value));
+ if (f)
+ ptr->function = f->asReturnedValue();
+ return ptr;
+}
+
+struct JSCallArguments
+{
+ JSCallArguments(const Scope &scope, int argc = 0)
+ : thisObject(scope.alloc()), args(scope.alloc(argc)), argc(argc)
{
- if (thisObject)
- this->thisObject = const_cast<Value *>(thisObject);
- else
- this->thisObject = scope.alloc();
- if (argv)
- this->args = const_cast<Value *>(argv);
- else
- this->args = scope.alloc(argc);
- }
-
- JSCallData *operator->() {
- return this;
- }
-
- CallData *callData(const FunctionObject *f = nullptr) const {
- int size = int(offsetof(QV4::CallData, args)/sizeof(QV4::Value)) + argc;
- CallData *ptr = reinterpret_cast<CallData *>(scope.alloc<Scope::Uninitialized>(size));
- ptr->function = Encode::undefined();
- ptr->context = Encode::undefined();
- ptr->accumulator = Encode::undefined();
- ptr->thisObject = thisObject->asReturnedValue();
- ptr->newTarget = Encode::undefined();
- ptr->setArgc(argc);
- if (argc)
- memcpy(ptr->args, args, argc*sizeof(Value));
- if (f)
- ptr->function = f->asReturnedValue();
- return ptr;
- }
- const Scope &scope;
- int argc;
- Value *args;
+ }
+
+ CallData *callData(const Scope &scope, const FunctionObject *f = nullptr) const
+ {
+ return callDatafromJS(scope, this, f);
+ }
+
Value *thisObject;
+ Value *args;
+ const int argc;
+};
+
+struct JSCallData
+{
+ JSCallData(const Value *thisObject, const Value *argv, int argc)
+ : thisObject(thisObject), args(argv), argc(argc)
+ {
+ }
+
+ Q_IMPLICIT JSCallData(const JSCallArguments &args)
+ : thisObject(args.thisObject), args(args.args), argc(args.argc)
+ {
+ }
+
+ CallData *callData(const Scope &scope, const FunctionObject *f = nullptr) const
+ {
+ return callDatafromJS(scope, this, f);
+ }
+
+ const Value *thisObject;
+ const Value *args;
+ const int argc;
};
inline
@@ -112,29 +108,483 @@ ReturnedValue FunctionObject::call(const JSCallData &data) const
return call(data.thisObject, data.args, data.argc);
}
+void populateJSCallArguments(ExecutionEngine *v4, JSCallArguments &jsCall, int argc,
+ void **args, const QMetaType *types);
+
+template<typename Callable>
+ReturnedValue convertAndCall(
+ ExecutionEngine *engine, const Function::AOTCompiledFunction *aotFunction,
+ const Value *thisObject, const Value *argv, int argc, Callable call)
+{
+ const qsizetype numFunctionArguments = aotFunction->types.length() - 1;
+ Q_ALLOCA_VAR(void *, values, (numFunctionArguments + 1) * sizeof(void *));
+ Q_ALLOCA_VAR(QMetaType, types, (numFunctionArguments + 1) * sizeof(QMetaType));
-struct ScopedStackFrame {
- Scope &scope;
- CppStackFrame frame;
+ for (qsizetype i = 0; i < numFunctionArguments; ++i) {
+ const QMetaType argumentType = aotFunction->types[i + 1];
+ types[i + 1] = argumentType;
+ if (const qsizetype argumentSize = argumentType.sizeOf()) {
+ Q_ALLOCA_VAR(void, argument, argumentSize);
+ if (argumentType.flags() & QMetaType::NeedsConstruction) {
+ argumentType.construct(argument);
+ if (i < argc)
+ ExecutionEngine::metaTypeFromJS(argv[i], argumentType, argument);
+ } else if (i >= argc
+ || !ExecutionEngine::metaTypeFromJS(argv[i], argumentType, argument)) {
+ // If we can't convert the argument, we need to default-construct it even if it
+ // doesn't formally need construction.
+ // E.g. an int doesn't need construction, but we still want it to be 0.
+ argumentType.construct(argument);
+ }
- ScopedStackFrame(Scope &scope, Heap::ExecutionContext *context)
- : scope(scope)
- {
- frame.parent = scope.engine->currentStackFrame;
- if (!context)
- return;
- frame.jsFrame = reinterpret_cast<CallData *>(scope.alloc(sizeof(CallData)/sizeof(Value)));
- frame.jsFrame->context = context;
- frame.v4Function = frame.parent ? frame.parent->v4Function : nullptr;
- scope.engine->currentStackFrame = &frame;
+ values[i + 1] = argument;
+ } else {
+ values[i + 1] = nullptr;
+ }
+ }
+
+ Q_ALLOCA_DECLARE(void, returnValue);
+ types[0] = aotFunction->types[0];
+ if (const qsizetype returnSize = types[0].sizeOf()) {
+ Q_ALLOCA_ASSIGN(void, returnValue, returnSize);
+ values[0] = returnValue;
+ if (types[0].flags() & QMetaType::NeedsConstruction)
+ types[0].construct(returnValue);
+ } else {
+ values[0] = nullptr;
+ }
+
+ if (const QV4::QObjectWrapper *cppThisObject = thisObject
+ ? thisObject->as<QV4::QObjectWrapper>()
+ : nullptr) {
+ call(cppThisObject->object(), values, types, argc);
+ } else {
+ call(nullptr, values, types, argc);
}
- ~ScopedStackFrame() {
- scope.engine->currentStackFrame = frame.parent;
+
+ ReturnedValue result;
+ if (values[0]) {
+ result = engine->metaTypeToJS(types[0], values[0]);
+ if (types[0].flags() & QMetaType::NeedsDestruction)
+ types[0].destruct(values[0]);
+ } else {
+ result = Encode::undefined();
+ }
+
+ for (qsizetype i = 1, end = numFunctionArguments + 1; i < end; ++i) {
+ if (types[i].flags() & QMetaType::NeedsDestruction)
+ types[i].destruct(values[i]);
}
+
+ return result;
+}
+
+template<typename Callable>
+bool convertAndCall(ExecutionEngine *engine, QObject *thisObject,
+ void **a, const QMetaType *types, int argc, Callable call)
+{
+ Scope scope(engine);
+ QV4::JSCallArguments jsCallData(scope, argc);
+
+ for (int ii = 0; ii < argc; ++ii)
+ jsCallData.args[ii] = engine->metaTypeToJS(types[ii + 1], a[ii + 1]);
+
+ ScopedObject jsThisObject(scope);
+ if (thisObject) {
+ // The result of wrap() can only be null, undefined, or an object.
+ jsThisObject = QV4::QObjectWrapper::wrap(engine, thisObject);
+ if (!jsThisObject)
+ jsThisObject = engine->globalObject;
+ } else {
+ jsThisObject = engine->globalObject;
+ }
+
+ ScopedValue jsResult(scope, call(jsThisObject, jsCallData.args, argc));
+ void *result = a[0];
+ if (!result)
+ return !jsResult->isUndefined();
+
+ const QMetaType resultType = types[0];
+ if (scope.hasException()) {
+ // Clear the return value
+ resultType.destruct(result);
+ resultType.construct(result);
+ } else if (resultType == QMetaType::fromType<QVariant>()) {
+ // When the return type is QVariant, JS objects are to be returned as
+ // QJSValue wrapped in QVariant. metaTypeFromJS unwraps them, unfortunately.
+ *static_cast<QVariant *>(result) = ExecutionEngine::toVariant(jsResult, QMetaType {});
+ } else if (!ExecutionEngine::metaTypeFromJS(jsResult, resultType, result)) {
+ // If we cannot convert, also clear the return value.
+ // The caller may have given us an uninitialized QObject*, expecting it to be overwritten.
+ resultType.destruct(result);
+ resultType.construct(result);
+ }
+ return !jsResult->isUndefined();
+}
+
+inline ReturnedValue coerce(
+ ExecutionEngine *engine, const Value &value, const QQmlType &qmlType, bool isList);
+
+inline QObject *coerceQObject(const Value &value, const QQmlType &qmlType)
+{
+ QObject *o;
+ if (const QV4::QObjectWrapper *wrapper = value.as<QV4::QObjectWrapper>())
+ o = wrapper->object();
+ else if (const QV4::QQmlTypeWrapper *wrapper = value.as<QQmlTypeWrapper>())
+ o = wrapper->object();
+ else
+ return nullptr;
+
+ return (o && qmlobject_can_qml_cast(o, qmlType)) ? o : nullptr;
+}
+
+enum CoercionProblem
+{
+ InsufficientAnnotation,
+ InvalidListType
};
+Q_QML_EXPORT void warnAboutCoercionToVoid(
+ ExecutionEngine *engine, const Value &value, CoercionProblem problem);
+
+inline ReturnedValue coerceListType(
+ ExecutionEngine *engine, const Value &value, const QQmlType &qmlType)
+{
+ QMetaType type = qmlType.qListTypeId();
+ const auto metaSequence = [&]() {
+ // TODO: We should really add the metasequence to the same QQmlType that holds
+ // all the other type information. Then we can get rid of the extra
+ // QQmlMetaType::qmlListType() here.
+ return qmlType.isSequentialContainer()
+ ? qmlType.listMetaSequence()
+ : QQmlMetaType::qmlListType(type).listMetaSequence();
+ };
+
+ if (const QV4::Sequence *sequence = value.as<QV4::Sequence>()) {
+ if (sequence->d()->listType() == type)
+ return value.asReturnedValue();
+ }
+
+ if (const QmlListWrapper *list = value.as<QmlListWrapper>()) {
+ if (list->d()->propertyType() == type)
+ return value.asReturnedValue();
+ }
+
+ QMetaType listValueType = qmlType.typeId();
+ if (!listValueType.isValid()) {
+ warnAboutCoercionToVoid(engine, value, InvalidListType);
+ return value.asReturnedValue();
+ }
+
+ QV4::Scope scope(engine);
+
+ const ArrayObject *array = value.as<ArrayObject>();
+ if (!array) {
+ return (listValueType.flags() & QMetaType::PointerToQObject)
+ ? QmlListWrapper::create(engine, listValueType)
+ : SequencePrototype::fromData(engine, type, metaSequence(), nullptr);
+ }
+
+ if (listValueType.flags() & QMetaType::PointerToQObject) {
+ QV4::Scoped<QmlListWrapper> newList(scope, QmlListWrapper::create(engine, type));
+ QQmlListProperty<QObject> *listProperty = newList->d()->property();
+
+ const qsizetype length = array->getLength();
+ qsizetype i = 0;
+ for (; i < length; ++i) {
+ ScopedValue v(scope, array->get(i));
+ listProperty->append(listProperty, coerceQObject(v, qmlType));
+ }
+
+ return newList->asReturnedValue();
+ }
+
+ QV4::Scoped<Sequence> sequence(
+ scope, SequencePrototype::fromData(engine, type, metaSequence(), nullptr));
+ const qsizetype length = array->getLength();
+ for (qsizetype i = 0; i < length; ++i)
+ sequence->containerPutIndexed(i, array->get(i));
+ return sequence->asReturnedValue();
}
+inline ReturnedValue coerce(
+ ExecutionEngine *engine, const Value &value, const QQmlType &qmlType, bool isList)
+{
+ // These are all the named non-list, non-QObject builtins. Only those need special handling.
+ // Some of them may be wrapped in VariantObject because that is how they are stored in VME
+ // properties.
+ if (isList)
+ return coerceListType(engine, value, qmlType);
+
+ const QMetaType metaType = qmlType.typeId();
+ if (!metaType.isValid()) {
+ if (!value.isUndefined())
+ warnAboutCoercionToVoid(engine, value, InsufficientAnnotation);
+ return value.asReturnedValue();
+ }
+
+ switch (metaType.id()) {
+ case QMetaType::Void:
+ return Encode::undefined();
+ case QMetaType::QVariant:
+ return value.asReturnedValue();
+ case QMetaType::Int:
+ return Encode(value.toInt32());
+ case QMetaType::Double:
+ return value.convertedToNumber();
+ case QMetaType::QString:
+ return value.toString(engine)->asReturnedValue();
+ case QMetaType::Bool:
+ return Encode(value.toBoolean());
+ case QMetaType::QDateTime:
+ if (value.as<DateObject>())
+ return value.asReturnedValue();
+ if (const VariantObject *varObject = value.as<VariantObject>()) {
+ const QVariant &var = varObject->d()->data();
+ switch (var.metaType().id()) {
+ case QMetaType::QDateTime:
+ return engine->newDateObject(var.value<QDateTime>())->asReturnedValue();
+ case QMetaType::QTime:
+ return engine->newDateObject(var.value<QTime>(), nullptr, -1, 0)->asReturnedValue();
+ case QMetaType::QDate:
+ return engine->newDateObject(var.value<QDate>(), nullptr, -1, 0)->asReturnedValue();
+ default:
+ break;
+ }
+ }
+ return engine->newDateObject(QDateTime())->asReturnedValue();
+ case QMetaType::QUrl:
+ if (value.as<UrlObject>())
+ return value.asReturnedValue();
+ if (const VariantObject *varObject = value.as<VariantObject>()) {
+ const QVariant &var = varObject->d()->data();
+ return var.metaType() == QMetaType::fromType<QUrl>()
+ ? engine->newUrlObject(var.value<QUrl>())->asReturnedValue()
+ : engine->newUrlObject()->asReturnedValue();
+ }
+ // Since URL properties are stored as string, we need to support the string conversion here.
+ if (const String *string = value.stringValue())
+ return engine->newUrlObject(QUrl(string->toQString()))->asReturnedValue();
+ return engine->newUrlObject()->asReturnedValue();
+#if QT_CONFIG(regularexpression)
+ case QMetaType::QRegularExpression:
+ if (value.as<RegExpObject>())
+ return value.asReturnedValue();
+ if (const VariantObject *varObject = value.as<VariantObject>()) {
+ const QVariant &var = varObject->d()->data();
+ if (var.metaType() == QMetaType::fromType<QRegularExpression>())
+ return engine->newRegExpObject(var.value<QRegularExpression>())->asReturnedValue();
+ }
+ return engine->newRegExpObject(QString(), 0)->asReturnedValue();
+#endif
+ default:
+ break;
+ }
+
+ if (metaType.flags() & QMetaType::PointerToQObject) {
+ return coerceQObject(value, qmlType)
+ ? value.asReturnedValue()
+ : Encode::null();
+ }
+
+ if (const QQmlValueTypeWrapper *wrapper = value.as<QQmlValueTypeWrapper>()) {
+ if (wrapper->type() == metaType)
+ return value.asReturnedValue();
+ }
+
+ if (void *target = QQmlValueTypeProvider::heapCreateValueType(qmlType, value)) {
+ Heap::QQmlValueTypeWrapper *wrapper = engine->memoryManager->allocate<QQmlValueTypeWrapper>(
+ nullptr, metaType, qmlType.metaObjectForValueType(),
+ nullptr, -1, Heap::ReferenceObject::NoFlag);
+ Q_ASSERT(!wrapper->gadgetPtr());
+ wrapper->setGadgetPtr(target);
+ return wrapper->asReturnedValue();
+ }
+
+ return Encode::undefined();
+}
+
+template<typename Callable>
+ReturnedValue coerceAndCall(
+ ExecutionEngine *engine,
+ const Function::JSTypedFunction *typedFunction, const CompiledData::Function *compiledFunction,
+ const Value *argv, int argc, Callable call)
+{
+ Scope scope(engine);
+
+ QV4::JSCallArguments jsCallData(scope, typedFunction->types.size() - 1);
+ const CompiledData::Parameter *formals = compiledFunction->formalsTable();
+ for (qsizetype i = 0; i < jsCallData.argc; ++i) {
+ jsCallData.args[i] = coerce(
+ engine, i < argc ? argv[i] : Encode::undefined(),
+ typedFunction->types[i + 1], formals[i].type.isList());
+ }
+
+ ScopedValue result(scope, call(jsCallData.args, jsCallData.argc));
+ return coerce(engine, result, typedFunction->types[0], compiledFunction->returnType.isList());
+}
+
+// Note: \a to is unininitialized here! This is in contrast to most other related functions.
+inline void coerce(
+ ExecutionEngine *engine, QMetaType fromType, const void *from, QMetaType toType, void *to)
+{
+ if ((fromType.flags() & QMetaType::PointerToQObject)
+ && (toType.flags() & QMetaType::PointerToQObject)) {
+ QObject *fromObj = *static_cast<QObject * const*>(from);
+ *static_cast<QObject **>(to)
+ = (fromObj && fromObj->metaObject()->inherits(toType.metaObject()))
+ ? fromObj
+ : nullptr;
+ return;
+ }
+
+ if (toType == QMetaType::fromType<QVariant>()) {
+ new (to) QVariant(fromType, from);
+ return;
+ }
+
+ if (toType == QMetaType::fromType<QJSPrimitiveValue>()) {
+ new (to) QJSPrimitiveValue(fromType, from);
+ return;
+ }
+
+ if (fromType == QMetaType::fromType<QVariant>()) {
+ const QVariant *fromVariant = static_cast<const QVariant *>(from);
+ if (fromVariant->metaType() == toType)
+ toType.construct(to, fromVariant->data());
+ else
+ coerce(engine, fromVariant->metaType(), fromVariant->data(), toType, to);
+ return;
+ }
+
+ if (fromType == QMetaType::fromType<QJSPrimitiveValue>()) {
+ const QJSPrimitiveValue *fromPrimitive = static_cast<const QJSPrimitiveValue *>(from);
+ if (fromPrimitive->metaType() == toType)
+ toType.construct(to, fromPrimitive->data());
+ else
+ coerce(engine, fromPrimitive->metaType(), fromPrimitive->data(), toType, to);
+ return;
+ }
+
+ // TODO: This is expensive. We might establish a direct C++-to-C++ type coercion, like we have
+ // for JS-to-JS. However, we shouldn't need this very often. Most of the time the compiler
+ // will generate code that passes the right arguments.
+ if (toType.flags() & QMetaType::NeedsConstruction)
+ toType.construct(to);
+ QV4::Scope scope(engine);
+ QV4::ScopedValue value(scope, engine->fromData(fromType, from));
+ if (!ExecutionEngine::metaTypeFromJS(value, toType, to))
+ QMetaType::convert(fromType, from, toType, to);
+}
+
+template<typename TypedFunction, typename Callable>
+void coerceAndCall(
+ ExecutionEngine *engine, const TypedFunction *typedFunction,
+ void **argv, const QMetaType *types, int argc, Callable call)
+{
+ const qsizetype numFunctionArguments = typedFunction->parameterCount();
+
+ Q_ALLOCA_DECLARE(void *, transformedArguments);
+ Q_ALLOCA_DECLARE(void, transformedResult);
+
+ const QMetaType returnType = typedFunction->returnMetaType();
+ const QMetaType frameReturn = types[0];
+ bool returnsQVariantWrapper = false;
+ if (argv[0] && returnType != frameReturn) {
+ Q_ALLOCA_ASSIGN(void *, transformedArguments, (numFunctionArguments + 1) * sizeof(void *));
+ memcpy(transformedArguments, argv, (argc + 1) * sizeof(void *));
+
+ if (frameReturn == QMetaType::fromType<QVariant>()) {
+ QVariant *returnValue = static_cast<QVariant *>(argv[0]);
+ *returnValue = QVariant(returnType);
+ transformedResult = transformedArguments[0] = returnValue->data();
+ returnsQVariantWrapper = true;
+ } else if (returnType.sizeOf() > 0) {
+ Q_ALLOCA_ASSIGN(void, transformedResult, returnType.sizeOf());
+ transformedArguments[0] = transformedResult;
+ if (returnType.flags() & QMetaType::NeedsConstruction)
+ returnType.construct(transformedResult);
+ } else {
+ transformedResult = transformedArguments[0] = &argc; // Some non-null marker value
+ }
+ }
+
+ for (qsizetype i = 0; i < numFunctionArguments; ++i) {
+ const bool isValid = argc > i;
+ const QMetaType frameType = isValid ? types[i + 1] : QMetaType();
+
+ const QMetaType argumentType = typedFunction->parameterMetaType(i);
+ if (isValid && argumentType == frameType)
+ continue;
+
+ if (transformedArguments == nullptr) {
+ Q_ALLOCA_ASSIGN(void *, transformedArguments, (numFunctionArguments + 1) * sizeof(void *));
+ memcpy(transformedArguments, argv, (argc + 1) * sizeof(void *));
+ }
+
+ if (argumentType.sizeOf() == 0) {
+ transformedArguments[i + 1] = nullptr;
+ continue;
+ }
+
+ void *frameVal = isValid ? argv[i + 1] : nullptr;
+ if (isValid && frameType == QMetaType::fromType<QVariant>()) {
+ QVariant *variant = static_cast<QVariant *>(frameVal);
+
+ const QMetaType variantType = variant->metaType();
+ if (variantType == argumentType) {
+ // Slightly nasty, but we're allowed to do this.
+ // We don't want to destruct() the QVariant's data() below.
+ transformedArguments[i + 1] = argv[i + 1] = variant->data();
+ } else {
+ Q_ALLOCA_VAR(void, arg, argumentType.sizeOf());
+ coerce(engine, variantType, variant->constData(), argumentType, arg);
+ transformedArguments[i + 1] = arg;
+ }
+ continue;
+ }
+
+ Q_ALLOCA_VAR(void, arg, argumentType.sizeOf());
+
+ if (isValid)
+ coerce(engine, frameType, frameVal, argumentType, arg);
+ else
+ argumentType.construct(arg);
+
+ transformedArguments[i + 1] = arg;
+ }
+
+ if (!transformedArguments) {
+ call(argv, numFunctionArguments);
+ return;
+ }
+
+ call(transformedArguments, numFunctionArguments);
+
+ if (transformedResult && !returnsQVariantWrapper) {
+ if (frameReturn.sizeOf() > 0) {
+ if (frameReturn.flags() & QMetaType::NeedsDestruction)
+ frameReturn.destruct(argv[0]);
+ coerce(engine, returnType, transformedResult, frameReturn, argv[0]);
+ }
+ if (returnType.flags() & QMetaType::NeedsDestruction)
+ returnType.destruct(transformedResult);
+ }
+
+ for (qsizetype i = 0; i < numFunctionArguments; ++i) {
+ void *arg = transformedArguments[i + 1];
+ if (arg == nullptr)
+ continue;
+ if (i >= argc || arg != argv[i + 1]) {
+ const QMetaType argumentType = typedFunction->parameterMetaType(i);
+ if (argumentType.flags() & QMetaType::NeedsDestruction)
+ argumentType.destruct(arg);
+ }
+ }
+}
+
+} // namespace QV4
+
QT_END_NAMESPACE
#endif // QV4JSCALL_H
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 936c032fad..d78d09113a 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qv4jsonobject_p.h>
#include <qv4objectproto_p.h>
#include <qv4numberobject_p.h>
@@ -45,7 +9,6 @@
#include <qv4scopedvalue_p.h>
#include <qv4runtime_p.h>
#include <qv4variantobject_p.h>
-#include "qv4string_p.h"
#include "qv4jscall_p.h"
#include <qv4symbol_p.h>
@@ -125,12 +88,13 @@ enum {
bool JsonParser::eatSpace()
{
while (json < end) {
- if (*json > Space)
+ const char16_t ch = json->unicode();
+ if (ch > Space)
break;
- if (*json != Space &&
- *json != Tab &&
- *json != LineFeed &&
- *json != Return)
+ if (ch != Space &&
+ ch != Tab &&
+ ch != LineFeed &&
+ ch != Return)
break;
++json;
}
@@ -140,7 +104,7 @@ bool JsonParser::eatSpace()
QChar JsonParser::nextToken()
{
if (!eatSpace())
- return 0;
+ return u'\0';
QChar token = *json++;
switch (token.unicode()) {
case BeginArray:
@@ -150,10 +114,11 @@ QChar JsonParser::nextToken()
case EndArray:
case EndObject:
eatSpace();
+ break;
case Quote:
break;
default:
- token = 0;
+ token = u'\0';
break;
}
return token;
@@ -216,21 +181,21 @@ ReturnedValue JsonParser::parseObject()
ScopedObject o(scope, engine->newObject());
QChar token = nextToken();
- while (token == Quote) {
+ while (token.unicode() == Quote) {
if (!parseMember(o))
return Encode::undefined();
token = nextToken();
- if (token != ValueSeparator)
+ if (token.unicode() != ValueSeparator)
break;
token = nextToken();
- if (token == EndObject) {
+ if (token.unicode() == EndObject) {
lastError = QJsonParseError::MissingObject;
return Encode::undefined();
}
}
DEBUG << "end token=" << token;
- if (token != EndObject) {
+ if (token.unicode() != EndObject) {
lastError = QJsonParseError::UnterminatedObject;
return Encode::undefined();
}
@@ -253,7 +218,7 @@ bool JsonParser::parseMember(Object *o)
if (!parseString(&key))
return false;
QChar token = nextToken();
- if (token != NameSeparator) {
+ if (token.unicode() != NameSeparator) {
lastError = QJsonParseError::MissingNameSeparator;
return false;
}
@@ -292,7 +257,7 @@ ReturnedValue JsonParser::parseArray()
lastError = QJsonParseError::UnterminatedArray;
return Encode::undefined();
}
- if (*json == EndArray) {
+ if (json->unicode() == EndArray) {
nextToken();
} else {
uint index = 0;
@@ -302,9 +267,9 @@ ReturnedValue JsonParser::parseArray()
return Encode::undefined();
array->arraySet(index, val);
QChar token = nextToken();
- if (token == EndArray)
+ if (token.unicode() == EndArray)
break;
- else if (token != ValueSeparator) {
+ else if (token.unicode() != ValueSeparator) {
if (!eatSpace())
lastError = QJsonParseError::UnterminatedArray;
else
@@ -332,14 +297,14 @@ bool JsonParser::parseValue(Value *val)
BEGIN << "parse Value" << *json;
switch ((json++)->unicode()) {
- case 'n':
+ case u'n':
if (end - json < 3) {
lastError = QJsonParseError::IllegalValue;
return false;
}
- if (*json++ == 'u' &&
- *json++ == 'l' &&
- *json++ == 'l') {
+ if (*json++ == u'u' &&
+ *json++ == u'l' &&
+ *json++ == u'l') {
*val = Value::nullValue();
DEBUG << "value: null";
END;
@@ -347,14 +312,14 @@ bool JsonParser::parseValue(Value *val)
}
lastError = QJsonParseError::IllegalValue;
return false;
- case 't':
+ case u't':
if (end - json < 3) {
lastError = QJsonParseError::IllegalValue;
return false;
}
- if (*json++ == 'r' &&
- *json++ == 'u' &&
- *json++ == 'e') {
+ if (*json++ == u'r' &&
+ *json++ == u'u' &&
+ *json++ == u'e') {
*val = Value::fromBoolean(true);
DEBUG << "value: true";
END;
@@ -362,15 +327,15 @@ bool JsonParser::parseValue(Value *val)
}
lastError = QJsonParseError::IllegalValue;
return false;
- case 'f':
+ case u'f':
if (end - json < 4) {
lastError = QJsonParseError::IllegalValue;
return false;
}
- if (*json++ == 'a' &&
- *json++ == 'l' &&
- *json++ == 's' &&
- *json++ == 'e') {
+ if (*json++ == u'a' &&
+ *json++ == u'l' &&
+ *json++ == u's' &&
+ *json++ == u'e') {
*val = Value::fromBoolean(false);
DEBUG << "value: false";
END;
@@ -443,32 +408,32 @@ bool JsonParser::parseNumber(Value *val)
bool isInt = true;
// minus
- if (json < end && *json == '-')
+ if (json < end && *json == u'-')
++json;
// int = zero / ( digit1-9 *DIGIT )
- if (json < end && *json == '0') {
+ if (json < end && *json == u'0') {
++json;
} else {
- while (json < end && *json >= '0' && *json <= '9')
+ while (json < end && *json >= u'0' && *json <= u'9')
++json;
}
// frac = decimal-point 1*DIGIT
- if (json < end && *json == '.') {
+ if (json < end && *json == u'.') {
isInt = false;
++json;
- while (json < end && *json >= '0' && *json <= '9')
+ while (json < end && *json >= u'0' && *json <= u'9')
++json;
}
// exp = e [ minus / plus ] 1*DIGIT
- if (json < end && (*json == 'e' || *json == 'E')) {
+ if (json < end && (*json == u'e' || *json == u'E')) {
isInt = false;
++json;
- if (json < end && (*json == '-' || *json == '+'))
+ if (json < end && (*json == u'-' || *json == u'+'))
++json;
- while (json < end && *json >= '0' && *json <= '9')
+ while (json < end && *json >= u'0' && *json <= u'9')
++json;
}
@@ -526,12 +491,12 @@ static inline bool addHexDigit(QChar digit, uint *result)
{
ushort d = digit.unicode();
*result <<= 4;
- if (d >= '0' && d <= '9')
- *result |= (d - '0');
- else if (d >= 'a' && d <= 'f')
- *result |= (d - 'a') + 10;
- else if (d >= 'A' && d <= 'F')
- *result |= (d - 'A') + 10;
+ if (d >= u'0' && d <= u'9')
+ *result |= (d - u'0');
+ else if (d >= u'a' && d <= u'f')
+ *result |= (d - u'a') + 10;
+ else if (d >= u'A' && d <= u'F')
+ *result |= (d - u'A') + 10;
else
return false;
return true;
@@ -546,23 +511,23 @@ static inline bool scanEscapeSequence(const QChar *&json, const QChar *end, uint
DEBUG << "scan escape";
uint escaped = (json++)->unicode();
switch (escaped) {
- case '"':
+ case u'"':
*ch = '"'; break;
- case '\\':
+ case u'\\':
*ch = '\\'; break;
- case '/':
+ case u'/':
*ch = '/'; break;
- case 'b':
+ case u'b':
*ch = 0x8; break;
- case 'f':
+ case u'f':
*ch = 0xc; break;
- case 'n':
+ case u'n':
*ch = 0xa; break;
- case 'r':
+ case u'r':
*ch = 0xd; break;
- case 't':
+ case u't':
*ch = 0x9; break;
- case 'u': {
+ case u'u': {
*ch = 0;
if (json > end - 4)
return false;
@@ -585,9 +550,9 @@ bool JsonParser::parseString(QString *string)
BEGIN << "parse string stringPos=" << json;
while (json < end) {
- if (*json == '"')
+ if (*json == u'"')
break;
- else if (*json == '\\') {
+ else if (*json == u'\\') {
uint ch = 0;
if (!scanEscapeSequence(json, end, &ch)) {
lastError = QJsonParseError::IllegalEscapeSequence;
@@ -645,47 +610,69 @@ struct Stringify
QString makeMember(const QString &key, const Value &v);
};
+class [[nodiscard]] CallDepthAndCycleChecker
+{
+ Q_DISABLE_COPY_MOVE(CallDepthAndCycleChecker);
+
+public:
+ CallDepthAndCycleChecker(Stringify *stringify, Object *o)
+ : m_callDepthRecorder(stringify->v4)
+ {
+ if (stringify->stackContains(o)) {
+ stringify->v4->throwTypeError(
+ QStringLiteral("Cannot convert circular structure to JSON"));
+ }
+
+ stringify->v4->checkStackLimits();
+ }
+
+ bool foundProblem() const { return m_callDepthRecorder.ee->hasException; }
+
+private:
+ ExecutionEngineCallDepthRecorder<1> m_callDepthRecorder;
+};
+
static QString quote(const QString &str)
{
QString product;
- const int length = str.length();
+ const int length = str.size();
product.reserve(length + 2);
- product += QLatin1Char('"');
+ product += u'"';
for (int i = 0; i < length; ++i) {
QChar c = str.at(i);
switch (c.unicode()) {
- case '"':
+ case u'"':
product += QLatin1String("\\\"");
break;
- case '\\':
+ case u'\\':
product += QLatin1String("\\\\");
break;
- case '\b':
+ case u'\b':
product += QLatin1String("\\b");
break;
- case '\f':
+ case u'\f':
product += QLatin1String("\\f");
break;
- case '\n':
+ case u'\n':
product += QLatin1String("\\n");
break;
- case '\r':
+ case u'\r':
product += QLatin1String("\\r");
break;
- case '\t':
+ case u'\t':
product += QLatin1String("\\t");
break;
default:
if (c.unicode() <= 0x1f) {
product += QLatin1String("\\u00");
- product += (c.unicode() > 0xf ? QLatin1Char('1') : QLatin1Char('0')) +
+ product += (c.unicode() > 0xf ? u'1' : u'0') +
QLatin1Char("0123456789abcdef"[c.unicode() & 0xf]);
} else {
product += c;
}
}
}
- product += QLatin1Char('"');
+ product += u'"';
return product;
}
@@ -699,21 +686,31 @@ QString Stringify::Str(const QString &key, const Value &v)
ScopedString s(scope, v4->newString(QStringLiteral("toJSON")));
ScopedFunctionObject toJSON(scope, o->get(s));
if (!!toJSON) {
- JSCallData jsCallData(scope, 1);
- *jsCallData->thisObject = value;
- jsCallData->args[0] = v4->newString(key);
+ JSCallArguments jsCallData(scope, 1);
+ *jsCallData.thisObject = value;
+ jsCallData.args[0] = v4->newString(key);
value = toJSON->call(jsCallData);
+ if (v4->hasException)
+ return QString();
}
}
if (replacerFunction) {
- ScopedObject holder(scope, v4->newObject());
- holder->put(scope.engine->id_empty(), value);
- JSCallData jsCallData(scope, 2);
- jsCallData->args[0] = v4->newString(key);
- jsCallData->args[1] = value;
- *jsCallData->thisObject = holder;
+ JSCallArguments jsCallData(scope, 2);
+ jsCallData.args[0] = v4->newString(key);
+ jsCallData.args[1] = value;
+
+ if (stack.isEmpty()) {
+ ScopedObject holder(scope, v4->newObject());
+ holder->put(scope.engine->id_empty(), v);
+ *jsCallData.thisObject = holder;
+ } else {
+ *jsCallData.thisObject = stack.top();
+ }
+
value = replacerFunction->call(jsCallData);
+ if (v4->hasException)
+ return QString();
}
o = value->asReturnedValue();
@@ -760,9 +757,9 @@ QString Stringify::makeMember(const QString &key, const Value &v)
{
QString strP = Str(key, v);
if (!strP.isEmpty()) {
- QString member = quote(key) + QLatin1Char(':');
+ QString member = quote(key) + u':';
if (!gap.isEmpty())
- member += QLatin1Char(' ');
+ member += u' ';
member += strP;
return member;
}
@@ -771,10 +768,9 @@ QString Stringify::makeMember(const QString &key, const Value &v)
QString Stringify::JO(Object *o)
{
- if (stackContains(o)) {
- v4->throwTypeError();
+ CallDepthAndCycleChecker check(this, o);
+ if (check.foundProblem())
return QString();
- }
Scope scope(v4);
@@ -817,11 +813,11 @@ QString Stringify::JO(Object *o)
if (partial.isEmpty()) {
result = QStringLiteral("{}");
} else if (gap.isEmpty()) {
- result = QLatin1Char('{') + partial.join(QLatin1Char(',')) + QLatin1Char('}');
+ result = u'{' + partial.join(u',') + u'}';
} else {
QString separator = QLatin1String(",\n") + indent;
- result = QLatin1String("{\n") + indent + partial.join(separator) + QLatin1Char('\n')
- + stepback + QLatin1Char('}');
+ result = QLatin1String("{\n") + indent + partial.join(separator) + u'\n'
+ + stepback + u'}';
}
indent = stepback;
@@ -831,10 +827,9 @@ QString Stringify::JO(Object *o)
QString Stringify::JA(Object *a)
{
- if (stackContains(a)) {
- v4->throwTypeError();
+ CallDepthAndCycleChecker check(this, a);
+ if (check.foundProblem())
return QString();
- }
Scope scope(a->engine());
@@ -863,10 +858,10 @@ QString Stringify::JA(Object *a)
if (partial.isEmpty()) {
result = QStringLiteral("[]");
} else if (gap.isEmpty()) {
- result = QLatin1Char('[') + partial.join(QLatin1Char(',')) + QLatin1Char(']');
+ result = u'[' + partial.join(u',') + u']';
} else {
QString separator = QLatin1String(",\n") + indent;
- result = QLatin1String("[\n") + indent + partial.join(separator) + QLatin1Char('\n') + stepback + QLatin1Char(']');
+ result = QLatin1String("[\n") + indent + partial.join(separator) + u'\n' + stepback + u']';
}
indent = stepback;
@@ -896,7 +891,7 @@ ReturnedValue JsonObject::method_parse(const FunctionObject *b, const Value *, c
jtext = argv[0].toQString();
DEBUG << "parsing source = " << jtext;
- JsonParser parser(v4, jtext.constData(), jtext.length());
+ JsonParser parser(v4, jtext.constData(), jtext.size());
QJsonParseError error;
ReturnedValue result = parser.parse(&error);
if (error.error != QJsonParseError::NoError) {
@@ -916,9 +911,10 @@ ReturnedValue JsonObject::method_stringify(const FunctionObject *b, const Value
if (o) {
stringify.replacerFunction = o->as<FunctionObject>();
if (o->isArrayObject()) {
- uint arrayLen = o->getLength();
+ int arrayLen = scope.engine->safeForAllocLength(o->getLength());
+ CHECK_EXCEPTION();
stringify.propertyList = static_cast<QV4::String *>(scope.alloc(arrayLen));
- for (uint i = 0; i < arrayLen; ++i) {
+ for (int i = 0; i < arrayLen; ++i) {
Value *v = stringify.propertyList + i;
*v = o->get(i);
if (v->as<NumberObject>() || v->as<StringObject>() || v->isNumber())
@@ -926,7 +922,7 @@ ReturnedValue JsonObject::method_stringify(const FunctionObject *b, const Value
if (!v->isString()) {
v->setM(nullptr);
} else {
- for (uint j = 0; j <i; ++j) {
+ for (int j = 0; j <i; ++j) {
if (stringify.propertyList[j].m() == v->m()) {
v->setM(nullptr);
break;
@@ -944,7 +940,7 @@ ReturnedValue JsonObject::method_stringify(const FunctionObject *b, const Value
s = so->d()->string;
if (s->isNumber()) {
- stringify.gap = QString(qMin(10, (int)s->toInteger()), ' ');
+ stringify.gap = QString(qMin(10, (int)s->toInteger()), u' ');
} else if (String *str = s->stringValue()) {
stringify.gap = str->toQString().left(10);
}
@@ -952,7 +948,7 @@ ReturnedValue JsonObject::method_stringify(const FunctionObject *b, const Value
ScopedValue arg0(scope, argc ? argv[0] : Value::undefinedValue());
QString result = stringify.Str(QString(), arg0);
- if (result.isEmpty() || scope.engine->hasException)
+ if (result.isEmpty() || scope.hasException())
RETURN_UNDEFINED();
return Encode(scope.engine->newString(result));
}
@@ -992,12 +988,16 @@ QJsonValue JsonObject::toJsonValue(const Value &value, V4ObjectSet &visitedObjec
Q_ASSERT(value.isObject());
Scope scope(value.as<Object>()->engine());
- ScopedArrayObject a(scope, value);
- if (a)
+ if (ScopedArrayObject a{ scope, value }) {
return toJsonArray(a, visitedObjects);
- ScopedObject o(scope, value);
- if (o)
+ } else if (Scoped<QV4::Sequence> a{ scope, value }) {
+ return toJsonArray(a, visitedObjects);
+ } else if (Scoped<QmlListWrapper> lw{ scope, value }) {
+ return toJsonArray(lw, visitedObjects);
+ } else if (ScopedObject o{ scope, value }) {
return toJsonObject(o, visitedObjects);
+ }
+
return QJsonValue(value.toQString());
}
@@ -1062,7 +1062,7 @@ QV4::ReturnedValue JsonObject::fromJsonArray(ExecutionEngine *engine, const QJso
return a.asReturnedValue();
}
-QJsonArray JsonObject::toJsonArray(const ArrayObject *a, V4ObjectSet &visitedObjects)
+QJsonArray JsonObject::toJsonArray(const Object *a, V4ObjectSet &visitedObjects)
{
QJsonArray result;
if (!a)
diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h
index 7d9f204910..f6f63d7eb3 100644
--- a/src/qml/jsruntime/qv4jsonobject_p.h
+++ b/src/qml/jsruntime/qv4jsonobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4JSONOBJECT_H
#define QV4JSONOBJECT_H
@@ -77,7 +41,7 @@ struct ObjectItem {
inline bool operator ==(const ObjectItem &a, const ObjectItem &b)
{ return a.o->d() == b.o->d(); }
-inline int qHash(const ObjectItem &i, uint seed = 0)
+inline size_t qHash(const ObjectItem &i, size_t seed = 0)
{ return ::qHash((void *)i.o->d(), seed); }
struct JsonObject : Object {
@@ -99,14 +63,13 @@ public:
{ V4ObjectSet visitedObjects; return toJsonValue(value, visitedObjects); }
static inline QJsonObject toJsonObject(const QV4::Object *o)
{ V4ObjectSet visitedObjects; return toJsonObject(o, visitedObjects); }
- static inline QJsonArray toJsonArray(const QV4::ArrayObject *a)
- { V4ObjectSet visitedObjects; return toJsonArray(a, visitedObjects); }
+ static inline QJsonArray toJsonArray(const QV4::Object *o)
+ { V4ObjectSet visitedObjects; return toJsonArray(o, visitedObjects); }
private:
static QJsonValue toJsonValue(const QV4::Value &value, V4ObjectSet &visitedObjects);
static QJsonObject toJsonObject(const Object *o, V4ObjectSet &visitedObjects);
- static QJsonArray toJsonArray(const ArrayObject *a, V4ObjectSet &visitedObjects);
-
+ static QJsonArray toJsonArray(const Object *o, V4ObjectSet &visitedObjects);
};
class JsonParser
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 0cda6b864a..654275a709 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -1,46 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "qv4lookup_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4jscall_p.h"
-#include "qv4string_p.h"
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qv4functionobject_p.h>
#include <private/qv4identifiertable_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4runtime_p.h>
+#include <private/qv4stackframe_p.h>
QT_BEGIN_NAMESPACE
@@ -74,6 +40,9 @@ ReturnedValue Lookup::resolveGetter(ExecutionEngine *engine, const Object *objec
ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Value &object)
{
+ // Otherwise we cannot trust the protoIds
+ Q_ASSERT(engine->isInitialized);
+
primitiveLookup.type = object.type();
switch (primitiveLookup.type) {
case Value::Undefined_Type:
@@ -85,12 +54,12 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu
return engine->throwTypeError(message);
}
case Value::Boolean_Type:
- primitiveLookup.proto = engine->booleanPrototype()->d();
+ primitiveLookup.proto.set(engine, engine->booleanPrototype()->d());
break;
case Value::Managed_Type: {
// ### Should move this over to the Object path, as strings also have an internalClass
Q_ASSERT(object.isStringOrSymbol());
- primitiveLookup.proto = static_cast<const Managed &>(object).internalClass()->prototype;
+ primitiveLookup.proto.set(engine, static_cast<const Managed &>(object).internalClass()->prototype);
Q_ASSERT(primitiveLookup.proto);
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
@@ -103,7 +72,7 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu
}
case Value::Integer_Type:
default: // Number
- primitiveLookup.proto = engine->numberPrototype()->d();
+ primitiveLookup.proto.set(engine, engine->numberPrototype()->d());
}
PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
@@ -119,6 +88,9 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu
ReturnedValue Lookup::resolveGlobalGetter(ExecutionEngine *engine)
{
+ // Otherwise we cannot trust the protoIds
+ Q_ASSERT(engine->isInitialized);
+
Object *o = engine->globalObject;
PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
protoLookup.protoId = o->internalClass()->protoId;
@@ -144,47 +116,78 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va
return l->resolvePrimitiveGetter(engine, object);
}
+static inline void setupObjectLookupTwoClasses(Lookup *l, const Lookup &first, const Lookup &second)
+{
+ Heap::InternalClass *ic1 = first.objectLookup.ic;
+ const uint offset1 = first.objectLookup.offset;
+ Heap::InternalClass *ic2 = second.objectLookup.ic;
+ const uint offset2 = second.objectLookup.offset;
+ auto engine = ic1->engine;
+
+ l->objectLookupTwoClasses.ic.set(engine, ic1);
+ l->objectLookupTwoClasses.ic2.set(engine, ic2);
+ l->objectLookupTwoClasses.offset = offset1;
+ l->objectLookupTwoClasses.offset2 = offset2;
+}
+
+static inline void setupProtoLookupTwoClasses(Lookup *l, const Lookup &first, const Lookup &second)
+{
+ const quintptr protoId1 = first.protoLookup.protoId;
+ const Value *data1 = first.protoLookup.data;
+ const quintptr protoId2 = second.protoLookup.protoId;
+ const Value *data2 = second.protoLookup.data;
+
+ l->protoLookupTwoClasses.protoId = protoId1;
+ l->protoLookupTwoClasses.protoId2 = protoId2;
+ l->protoLookupTwoClasses.data = data1;
+ l->protoLookupTwoClasses.data2 = data2;
+}
+
ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object)
{
if (const Object *o = object.as<Object>()) {
- Lookup first = *l;
- Lookup second = *l;
-
- ReturnedValue result = second.resolveGetter(engine, o);
- if (first.getter == getter0Inline && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
- l->objectLookupTwoClasses.ic = first.objectLookup.ic;
- l->objectLookupTwoClasses.ic2 = second.objectLookup.ic;
- l->objectLookupTwoClasses.offset = first.objectLookup.offset;
- l->objectLookupTwoClasses.offset2 = second.objectLookup.offset;
- l->getter = second.getter == getter0Inline ? getter0Inlinegetter0Inline : getter0Inlinegetter0MemberData;
+ // Do the resolution on a second lookup, then merge.
+ Lookup second;
+ memset(&second, 0, sizeof(Lookup));
+ second.nameIndex = l->nameIndex;
+ second.forCall = l->forCall;
+ second.getter = getterGeneric;
+ const ReturnedValue result = second.resolveGetter(engine, o);
+
+ if (l->getter == getter0Inline
+ && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
+ setupObjectLookupTwoClasses(l, *l, second);
+ l->getter = (second.getter == getter0Inline)
+ ? getter0Inlinegetter0Inline
+ : getter0Inlinegetter0MemberData;
return result;
}
- if (first.getter == getter0MemberData && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
- l->objectLookupTwoClasses.ic = second.objectLookup.ic;
- l->objectLookupTwoClasses.ic2 = first.objectLookup.ic;
- l->objectLookupTwoClasses.offset = second.objectLookup.offset;
- l->objectLookupTwoClasses.offset2 = first.objectLookup.offset;
- l->getter = second.getter == getter0Inline ? getter0Inlinegetter0MemberData : getter0MemberDatagetter0MemberData;
+
+ if (l->getter == getter0MemberData
+ && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
+ setupObjectLookupTwoClasses(l, second, *l);
+ l->getter = (second.getter == getter0Inline)
+ ? getter0Inlinegetter0MemberData
+ : getter0MemberDatagetter0MemberData;
return result;
}
- if (first.getter == getterProto && second.getter == getterProto) {
- l->protoLookupTwoClasses.protoId = first.protoLookup.protoId;
- l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId;
- l->protoLookupTwoClasses.data = first.protoLookup.data;
- l->protoLookupTwoClasses.data2 = second.protoLookup.data;
+
+
+ if (l->getter == getterProto && second.getter == getterProto) {
+ setupProtoLookupTwoClasses(l, *l, second);
l->getter = getterProtoTwoClasses;
return result;
}
- if (first.getter == getterProtoAccessor && second.getter == getterProtoAccessor) {
- l->protoLookupTwoClasses.protoId = first.protoLookup.protoId;
- l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId;
- l->protoLookupTwoClasses.data = first.protoLookup.data;
- l->protoLookupTwoClasses.data2 = second.protoLookup.data;
+
+ if (l->getter == getterProtoAccessor && second.getter == getterProtoAccessor) {
+ setupProtoLookupTwoClasses(l, *l, second);
l->getter = getterProtoAccessorTwoClasses;
return result;
}
+ // If any of the above options were true, the propertyCache was inactive.
+ second.releasePropertyCache();
}
l->getter = getterFallback;
@@ -201,6 +204,21 @@ ReturnedValue Lookup::getterFallback(Lookup *l, ExecutionEngine *engine, const V
return o->get(name);
}
+ReturnedValue Lookup::getterFallbackAsVariant(
+ Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ if (&Lookup::getterFallback == &Lookup::getterFallbackAsVariant) {
+ // Certain compilers, e.g. MSVC, will "helpfully" deduplicate methods that are completely
+ // equal. As a result, the pointers are the same, which wreaks havoc on the logic that
+ // decides how to retrieve the property.
+ qFatal("Your C++ compiler is broken.");
+ }
+
+ // This getter just marks the presence of a fallback lookup with variant conversion.
+ // It only does anything with it when running AOT-compiled code.
+ return getterFallback(l, engine, object);
+}
+
ReturnedValue Lookup::getter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object)
{
// we can safely cast to a QV4::Object here. If object is actually a string,
@@ -227,6 +245,9 @@ ReturnedValue Lookup::getter0Inline(Lookup *l, ExecutionEngine *engine, const Va
ReturnedValue Lookup::getterProto(Lookup *l, ExecutionEngine *engine, const Value &object)
{
+ // Otherwise we cannot trust the protoIds
+ Q_ASSERT(engine->isInitialized);
+
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
@@ -284,6 +305,9 @@ ReturnedValue Lookup::getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEng
ReturnedValue Lookup::getterProtoTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object)
{
+ // Otherwise we cannot trust the protoIds
+ Q_ASSERT(engine->isInitialized);
+
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
@@ -309,7 +333,8 @@ ReturnedValue Lookup::getterAccessor(Lookup *l, ExecutionEngine *engine, const V
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ &object, nullptr, 0));
}
}
l->getter = getterFallback;
@@ -318,6 +343,9 @@ ReturnedValue Lookup::getterAccessor(Lookup *l, ExecutionEngine *engine, const V
ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, const Value &object)
{
+ // Otherwise we cannot trust the protoIds
+ Q_ASSERT(engine->isInitialized);
+
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
@@ -326,13 +354,17 @@ ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, co
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ &object, nullptr, 0));
}
return getterTwoClasses(l, engine, object);
}
ReturnedValue Lookup::getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object)
{
+ // Otherwise we cannot trust the protoIds
+ Q_ASSERT(engine->isInitialized);
+
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
@@ -346,7 +378,8 @@ ReturnedValue Lookup::getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ &object, nullptr, 0));
}
}
l->getter = getterFallback;
@@ -368,11 +401,60 @@ ReturnedValue Lookup::getterIndexed(Lookup *l, ExecutionEngine *engine, const Va
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
+}
+
+ReturnedValue Lookup::getterQObject(Lookup *lookup, ExecutionEngine *engine, const Value &object)
+{
+ const auto revertLookup = [lookup, engine, &object]() {
+ lookup->qobjectLookup.propertyCache->release();
+ lookup->qobjectLookup.propertyCache = nullptr;
+ lookup->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(lookup, engine, object);
+ };
+
+ const QObjectWrapper::Flags flags = lookup->forCall
+ ? QObjectWrapper::AllowOverride
+ : (QObjectWrapper::AllowOverride | QObjectWrapper::AttachMethods);
+ return QObjectWrapper::lookupPropertyGetterImpl(lookup, engine, object, flags, revertLookup);
+}
+
+ReturnedValue Lookup::getterQObjectAsVariant(
+ Lookup *lookup, ExecutionEngine *engine, const Value &object)
+{
+ if (&Lookup::getterQObject == &Lookup::getterQObjectAsVariant) {
+ // Certain compilers, e.g. MSVC, will "helpfully" deduplicate methods that are completely
+ // equal. As a result, the pointers are the same, which wreaks havoc on the logic that
+ // decides how to retrieve the property.
+ qFatal("Your C++ compiler is broken.");
+ }
+
+ // This getter marks the presence of a qobjectlookup with variant conversion.
+ // It only does anything with it when running AOT-compiled code.
+ return getterQObject(lookup, engine, object);
+}
+
+ReturnedValue Lookup::getterQObjectMethod(Lookup *lookup, ExecutionEngine *engine, const Value &object)
+{
+ const auto revertLookup = [lookup, engine, &object]() {
+ lookup->qobjectMethodLookup.propertyCache->release();
+ lookup->qobjectMethodLookup.propertyCache = nullptr;
+ lookup->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(lookup, engine, object);
+ };
+
+ const QObjectWrapper::Flags flags = lookup->forCall
+ ? QObjectWrapper::AllowOverride
+ : (QObjectWrapper::AllowOverride | QObjectWrapper::AttachMethods);
+
+ return QObjectWrapper::lookupMethodGetterImpl(lookup, engine, object, flags, revertLookup);
}
ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object)
{
+ // Otherwise we cannot trust the protoIds
+ Q_ASSERT(engine->isInitialized);
+
if (object.type() == l->primitiveLookup.type && !object.isObject()) {
Heap::Object *o = l->primitiveLookup.proto;
if (l->primitiveLookup.protoId == o->internalClass->protoId)
@@ -384,6 +466,9 @@ ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, c
ReturnedValue Lookup::primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object)
{
+ // Otherwise we cannot trust the protoIds
+ Q_ASSERT(engine->isInitialized);
+
if (object.type() == l->primitiveLookup.type && !object.isObject()) {
Heap::Object *o = l->primitiveLookup.proto;
if (l->primitiveLookup.protoId == o->internalClass->protoId) {
@@ -391,7 +476,8 @@ ReturnedValue Lookup::primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ &object, nullptr, 0));
}
}
l->getter = getterGeneric;
@@ -414,6 +500,9 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine)
ReturnedValue Lookup::globalGetterProto(Lookup *l, ExecutionEngine *engine)
{
+ // Otherwise we cannot trust the protoIds
+ Q_ASSERT(engine->isInitialized);
+
Heap::Object *o = engine->globalObject->d();
if (l->protoLookup.protoId == o->internalClass->protoId)
return l->protoLookup.data->asReturnedValue();
@@ -423,13 +512,17 @@ ReturnedValue Lookup::globalGetterProto(Lookup *l, ExecutionEngine *engine)
ReturnedValue Lookup::globalGetterProtoAccessor(Lookup *l, ExecutionEngine *engine)
{
+ // Otherwise we cannot trust the protoIds
+ Q_ASSERT(engine->isInitialized);
+
Heap::Object *o = engine->globalObject->d();
if (l->protoLookup.protoId == o->internalClass->protoId) {
const Value *getter = l->protoLookup.data;
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(engine->globalObject, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ engine->globalObject, nullptr, 0));
}
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
@@ -458,23 +551,31 @@ bool Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, co
bool Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
- Lookup first = *l;
- Lookup second = *l;
+ // A precondition of this method is that l->objectLookup is the active variant of the union.
+ Q_ASSERT(l->setter == setter0MemberData || l->setter == setter0Inline);
if (object.isObject()) {
+
+ // As l->objectLookup is active, we can stash some members here, before resolving.
+ Heap::InternalClass *ic = l->objectLookup.ic;
+ const uint index = l->objectLookup.index;
+
if (!l->resolveSetter(engine, static_cast<Object *>(&object), value)) {
l->setter = setterFallback;
return false;
}
if (l->setter == Lookup::setter0MemberData || l->setter == Lookup::setter0Inline) {
- l->objectLookupTwoClasses.ic = first.objectLookup.ic;
- l->objectLookupTwoClasses.ic2 = second.objectLookup.ic;
- l->objectLookupTwoClasses.offset = first.objectLookup.index;
- l->objectLookupTwoClasses.offset2 = second.objectLookup.index;
+ auto engine = ic->engine;
+ l->objectLookupTwoClasses.ic.set(engine, ic);
+ l->objectLookupTwoClasses.ic2.set(engine, ic);
+ l->objectLookupTwoClasses.offset = index;
+ l->objectLookupTwoClasses.offset2 = index;
l->setter = setter0setter0;
return true;
}
+
+ l->releasePropertyCache();
}
l->setter = setterFallback;
@@ -492,6 +593,21 @@ bool Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, c
return o->put(name, value);
}
+bool Lookup::setterFallbackAsVariant(
+ Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+{
+ if (&Lookup::setterFallback == &Lookup::setterFallbackAsVariant) {
+ // Certain compilers, e.g. MSVC, will "helpfully" deduplicate methods that are completely
+ // equal. As a result, the pointers are the same, which wreaks havoc on the logic that
+ // decides how to retrieve the property.
+ qFatal("Your C++ compiler is broken.");
+ }
+
+ // This setter just marks the presence of a fallback lookup with QVariant conversion.
+ // It only does anything with it when running AOT-compiled code.
+ return setterFallback(l, engine, object, value);
+}
+
bool Lookup::setter0MemberData(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
@@ -534,6 +650,9 @@ bool Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, c
bool Lookup::setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
+ // Otherwise we cannot trust the protoIds
+ Q_ASSERT(engine->isInitialized);
+
Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass()->protoId == l->insertionLookup.protoId) {
o->setInternalClass(l->insertionLookup.newClass);
@@ -545,6 +664,29 @@ bool Lookup::setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, con
return setterFallback(l, engine, object, value);
}
+bool Lookup::setterQObject(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v)
+{
+ // This setter just marks the presence of a qobjectlookup. It only does anything with it when
+ // running AOT-compiled code, though.
+ return setterFallback(l, engine, object, v);
+}
+
+bool Lookup::setterQObjectAsVariant(
+ Lookup *l, ExecutionEngine *engine, Value &object, const Value &v)
+{
+ if (&Lookup::setterQObject == &Lookup::setterQObjectAsVariant) {
+ // Certain compilers, e.g. MSVC, will "helpfully" deduplicate methods that are completely
+ // equal. As a result, the pointers are the same, which wreaks havoc on the logic that
+ // decides how to retrieve the property.
+ qFatal("Your C++ compiler is broken.");
+ }
+
+ // This setter marks the presence of a qobjectlookup with QVariant conversion.
+ // It only does anything with it when running AOT-compiled code.
+ return setterQObject(l, engine, object, v);
+}
+
+
bool Lookup::arrayLengthSetter(Lookup *, ExecutionEngine *engine, Value &object, const Value &value)
{
Q_ASSERT(object.isObject() && static_cast<Object &>(object).isArrayObject());
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 31c90b31f6..258184cd37 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4LOOKUP_H
#define QV4LOOKUP_H
@@ -50,18 +14,28 @@
// We mean it.
//
-#include "qv4global_p.h"
-#include "qv4runtime_p.h"
#include "qv4engine_p.h"
-#include "qv4context_p.h"
#include "qv4object_p.h"
#include "qv4internalclass_p.h"
+#include "qv4qmlcontext_p.h"
+#include <private/qqmltypewrapper_p.h>
+#include <private/qv4mm_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-struct Q_QML_PRIVATE_EXPORT Lookup {
+namespace Heap {
+ struct QObjectMethod;
+}
+
+template <typename T, int PhantomTag>
+using HeapObjectWrapper = WriteBarrier::HeapObjectWrapper<T, PhantomTag>;
+
+// Note: We cannot hide the copy ctor and assignment operator of this class because it needs to
+// be trivially copyable. But you should never ever copy it. There are refcounted members
+// in there.
+struct Q_QML_EXPORT Lookup {
union {
ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object);
ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine);
@@ -69,6 +43,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
bool (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v);
};
// NOTE: gc assumes the first two entries in the struct are pointers to heap objects or null
+ // or that the least significant bit is 1 (see the Lookup::markObjects function)
union {
struct {
Heap::Base *h1;
@@ -77,7 +52,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
quintptr unused2;
} markDef;
struct {
- Heap::InternalClass *ic;
+ HeapObjectWrapper<Heap::InternalClass, 0> ic;
quintptr unused;
uint index;
uint offset;
@@ -88,8 +63,8 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
const Value *data;
} protoLookup;
struct {
- Heap::InternalClass *ic;
- Heap::InternalClass *ic2;
+ HeapObjectWrapper<Heap::InternalClass, 1> ic;
+ HeapObjectWrapper<Heap::InternalClass, 2> ic2;
uint offset;
uint offset2;
} objectLookupTwoClasses;
@@ -102,12 +77,12 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
struct {
// Make sure the next two values are in sync with protoLookup
quintptr protoId;
- Heap::Object *proto;
+ HeapObjectWrapper<Heap::Object, 3> proto;
const Value *data;
quintptr type;
} primitiveLookup;
struct {
- Heap::InternalClass *newClass;
+ HeapObjectWrapper<Heap::InternalClass, 4> newClass;
quintptr protoId;
uint offset;
uint unused;
@@ -119,16 +94,30 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
uint unused;
} indexedLookup;
struct {
- Heap::InternalClass *ic;
- Heap::InternalClass *qmlTypeIc; // only used when lookup goes through QQmlTypeWrapper
- QQmlPropertyCache *propertyCache;
- QQmlPropertyData *propertyData;
+ HeapObjectWrapper<Heap::InternalClass, 5> ic;
+ HeapObjectWrapper<Heap::InternalClass, 6> qmlTypeIc; // only used when lookup goes through QQmlTypeWrapper
+ const QQmlPropertyCache *propertyCache;
+ const QQmlPropertyData *propertyData;
} qobjectLookup;
struct {
- Heap::InternalClass *ic;
- quintptr unused;
- QQmlPropertyCache *propertyCache;
- QQmlPropertyData *propertyData;
+ HeapObjectWrapper<Heap::InternalClass, 7> ic;
+ HeapObjectWrapper<Heap::QObjectMethod, 8> method;
+ const QQmlPropertyCache *propertyCache;
+ const QQmlPropertyData *propertyData;
+ } qobjectMethodLookup;
+ struct {
+ quintptr isConstant; // This is a bool, encoded as 0 or 1. Both values are ignored by gc
+ quintptr metaObject; // a (const QMetaObject* & 1) or nullptr
+ int coreIndex;
+ int notifyIndex;
+ } qobjectFallbackLookup;
+ struct {
+ HeapObjectWrapper<Heap::InternalClass, 9> ic;
+ quintptr metaObject; // a (const QMetaObject* & 1) or nullptr
+ const QtPrivate::QMetaTypeInterface *metaType; // cannot use QMetaType; class must be trivial
+ quint16 coreIndex;
+ bool isFunction;
+ bool isEnum;
} qgadgetLookup;
struct {
quintptr unused1;
@@ -136,8 +125,9 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
int scriptIndex;
} qmlContextScriptLookup;
struct {
- Heap::Object *singleton;
- quintptr unused;
+ HeapObjectWrapper<Heap::Base, 10> singletonObject;
+ quintptr unused2;
+ QV4::ReturnedValue singletonValue;
} qmlContextSingletonLookup;
struct {
quintptr unused1;
@@ -152,20 +142,24 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
ReturnedValue (*getterTrampoline)(Lookup *l, ExecutionEngine *engine);
} qmlContextGlobalLookup;
struct {
- Heap::Object *qmlTypeWrapper;
+ HeapObjectWrapper<Heap::Base, 11> qmlTypeWrapper;
quintptr unused2;
} qmlTypeLookup;
struct {
- Heap::InternalClass *ic;
+ HeapObjectWrapper<Heap::InternalClass, 12> ic;
quintptr unused;
ReturnedValue encodedEnumValue;
+ const QtPrivate::QMetaTypeInterface *metaType;
} qmlEnumValueLookup;
struct {
- Heap::InternalClass *ic;
- Heap::Object *qmlScopedEnumWrapper;
+ HeapObjectWrapper<Heap::InternalClass, 13> ic;
+ HeapObjectWrapper<Heap::Object, 14> qmlScopedEnumWrapper;
} qmlScopedEnumWrapperLookup;
};
- uint nameIndex;
+
+ uint nameIndex: 28; // Same number of bits we store in the compilation unit for name indices
+ uint forCall: 1; // Whether we are looking up a value in order to call it right away
+ uint reserved: 3;
ReturnedValue resolveGetter(ExecutionEngine *engine, const Object *object);
ReturnedValue resolvePrimitiveGetter(ExecutionEngine *engine, const Value &object);
@@ -175,6 +169,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
static ReturnedValue getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterFallback(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getterFallbackAsVariant(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -187,6 +182,9 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
static ReturnedValue getterProtoAccessor(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterIndexed(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getterQObject(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getterQObjectAsVariant(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getterQObjectMethod(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -200,10 +198,13 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
static bool setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
Q_NEVER_INLINE static bool setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setterFallbackAsVariant(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setter0MemberData(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setterQObject(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setterQObjectAsVariant(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool arrayLengthSetter(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
void markObjects(MarkStack *stack) {
@@ -213,8 +214,24 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
markDef.h2->mark(stack);
}
- void clear() {
- memset(&markDef, 0, sizeof(markDef));
+ void releasePropertyCache()
+ {
+ if (getter == getterQObject
+ || getter == QQmlTypeWrapper::lookupSingletonProperty
+ || setter == setterQObject
+ || qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty
+ || qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty
+ || getter == getterQObjectAsVariant
+ || setter == setterQObjectAsVariant) {
+ if (const QQmlPropertyCache *pc = qobjectLookup.propertyCache)
+ pc->release();
+ } else if (getter == getterQObjectMethod
+ || getter == QQmlTypeWrapper::lookupSingletonMethod
+ || qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectMethod
+ || qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectMethod) {
+ if (const QQmlPropertyCache *pc = qobjectMethodLookup.propertyCache)
+ pc->release();
+ }
}
};
@@ -223,6 +240,57 @@ Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value);
// across 32-bit and 64-bit (matters when cross-compiling).
Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0);
+inline void setupQObjectLookup(
+ Lookup *lookup, const QQmlData *ddata, const QQmlPropertyData *propertyData)
+{
+ lookup->releasePropertyCache();
+ Q_ASSERT(!ddata->propertyCache.isNull());
+ lookup->qobjectLookup.propertyCache = ddata->propertyCache.data();
+ lookup->qobjectLookup.propertyCache->addref();
+ lookup->qobjectLookup.propertyData = propertyData;
+}
+
+inline void setupQObjectLookup(
+ Lookup *lookup, const QQmlData *ddata, const QQmlPropertyData *propertyData,
+ const Object *self)
+{
+ setupQObjectLookup(lookup, ddata, propertyData);
+ lookup->qobjectLookup.ic.set(self->engine(), self->internalClass());
+}
+
+
+inline void setupQObjectLookup(
+ Lookup *lookup, const QQmlData *ddata, const QQmlPropertyData *propertyData,
+ const Object *self, const Object *qmlType)
+{
+ setupQObjectLookup(lookup, ddata, propertyData, self);
+ lookup->qobjectLookup.qmlTypeIc.set(self->engine(), qmlType->internalClass());
+}
+
+// template parameter is an ugly trick to avoid pulling in the QObjectMethod header here
+template<typename QObjectMethod = Heap::QObjectMethod>
+inline void setupQObjectMethodLookup(
+ Lookup *lookup, const QQmlData *ddata, const QQmlPropertyData *propertyData,
+ const Object *self, QObjectMethod *method)
+{
+ lookup->releasePropertyCache();
+ Q_ASSERT(!ddata->propertyCache.isNull());
+ auto engine = self->engine();
+ lookup->qobjectMethodLookup.method.set(engine, method);
+ lookup->qobjectMethodLookup.ic.set(engine, self->internalClass());
+ lookup->qobjectMethodLookup.propertyCache = ddata->propertyCache.data();
+ lookup->qobjectMethodLookup.propertyCache->addref();
+ lookup->qobjectMethodLookup.propertyData = propertyData;
+}
+
+inline bool qualifiesForMethodLookup(const QQmlPropertyData *propertyData)
+{
+ return propertyData->isFunction()
+ && !propertyData->isSignalHandler() // TODO: Optimize SignalHandler, too
+ && !propertyData->isVMEFunction() // Handled by QObjectLookup
+ && !propertyData->isVarProperty();
+}
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index d51b03d90b..3524a1adcb 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -1,45 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4managed_p.h"
#include <private/qv4mm_p.h>
-#include "qv4errorobject_p.h"
using namespace QV4;
@@ -105,6 +68,12 @@ QString Managed::className() const
case Type_MathObject:
s = "Math";
break;
+ case Type_UrlObject:
+ s = "URL";
+ break;
+ case Type_UrlSearchParamsObject:
+ s = "URLSearchParams";
+ break;
case Type_ExecutionContext:
s = "__ExecutionContext";
@@ -131,8 +100,11 @@ QString Managed::className() const
s = "__RegExp";
break;
- case Type_QmlSequence:
- s = "QmlSequence";
+ case Type_V4Sequence:
+ s = "V4Sequence";
+ break;
+ case Type_QmlListProperty:
+ s = "QML List";
break;
}
return QString::fromLatin1(s);
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 4f22dc7330..c5f5fbff8e 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMLJS_MANAGED_H
#define QMLJS_MANAGED_H
@@ -92,10 +56,10 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
#define V4_MANAGED(DataClass, superClass) \
private: \
- DataClass() Q_DECL_EQ_DELETE; \
+ DataClass() = delete; \
Q_DISABLE_COPY(DataClass) \
V4_MANAGED_ITSELF(DataClass, superClass) \
- Q_STATIC_ASSERT(std::is_trivial< QV4::Heap::DataClass >::value);
+ Q_STATIC_ASSERT(std::is_trivial_v<QV4::Heap::DataClass>);
#define Q_MANAGED_TYPE(type) \
public: \
@@ -105,7 +69,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
static Heap::InternalClass *defaultInternalClass(QV4::EngineBase *e) \
{ return e->internalClasses(QV4::EngineBase::Class_##c); }
-struct Q_QML_PRIVATE_EXPORT Managed : Value, VTableBase
+struct Q_QML_EXPORT Managed : Value, VTableBase
{
V4_MANAGED_ITSELF(Base, Managed)
enum {
@@ -119,7 +83,7 @@ struct Q_QML_PRIVATE_EXPORT Managed : Value, VTableBase
};
private:
void *operator new(size_t);
- Managed() Q_DECL_EQ_DELETE;
+ Managed() = delete;
Q_DISABLE_COPY(Managed)
public:
@@ -144,6 +108,8 @@ public:
Type_JsonObject,
Type_MathObject,
Type_ProxyObject,
+ Type_UrlObject,
+ Type_UrlSearchParamsObject,
Type_ExecutionContext,
Type_InternalClass,
@@ -154,7 +120,9 @@ public:
Type_ForInIterator,
Type_RegExp,
- Type_QmlSequence
+ Type_V4Sequence,
+ Type_QmlListProperty,
+
};
Q_MANAGED_TYPE(Invalid)
@@ -162,8 +130,9 @@ public:
const VTable *vtable() const { return d()->internalClass->vtable; }
inline ExecutionEngine *engine() const { return internalClass()->engine; }
- bool isListType() const { return d()->internalClass->vtable->type == Type_QmlSequence; }
- bool isArrayLike() const { return isArrayObject() || isListType(); }
+ bool isV4SequenceType() const { return d()->internalClass->vtable->type == Type_V4Sequence; }
+ bool isQmlListPropertyType() const { return d()->internalClass->vtable->type == Type_QmlListProperty; }
+ bool isArrayLike() const { return isArrayObject() || isV4SequenceType() || isQmlListPropertyType(); }
bool isArrayObject() const { return d()->internalClass->vtable->type == Type_ArrayObject; }
bool isStringObject() const { return d()->internalClass->vtable->type == Type_StringObject; }
diff --git a/src/qml/jsruntime/qv4mapiterator.cpp b/src/qml/jsruntime/qv4mapiterator.cpp
index cd5fbb8e63..494ee94865 100644
--- a/src/qml/jsruntime/qv4mapiterator.cpp
+++ b/src/qml/jsruntime/qv4mapiterator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Crimson AS <info@crimson.no>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Crimson AS <info@crimson.no>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qv4iterator_p.h>
#include <private/qv4estable_p.h>
diff --git a/src/qml/jsruntime/qv4mapiterator_p.h b/src/qml/jsruntime/qv4mapiterator_p.h
index 836ba14663..97a72db85c 100644
--- a/src/qml/jsruntime/qv4mapiterator_p.h
+++ b/src/qml/jsruntime/qv4mapiterator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Crimson AS <info@crimson.no>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Crimson AS <info@crimson.no>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4MAPITERATOR_P_H
#define QV4MAPITERATOR_P_H
@@ -66,7 +30,7 @@ namespace Heap {
Member(class, NoMark, quint32, mapNextIndex)
DECLARE_HEAP_OBJECT(MapIteratorObject, Object) {
- DECLARE_MARKOBJECTS(MapIteratorObject);
+ DECLARE_MARKOBJECTS(MapIteratorObject)
void init(Object *obj, QV4::ExecutionEngine *engine)
{
Object::init();
diff --git a/src/qml/jsruntime/qv4mapobject.cpp b/src/qml/jsruntime/qv4mapobject.cpp
index 90e1908a84..4bb9617b93 100644
--- a/src/qml/jsruntime/qv4mapobject.cpp
+++ b/src/qml/jsruntime/qv4mapobject.cpp
@@ -1,43 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Crimson AS <info@crimson.no>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** 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 "qv4setobject_p.h" // ### temporary
+// Copyright (C) 2018 Crimson AS <info@crimson.no>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
#include "qv4mapobject_p.h"
#include "qv4mapiterator_p.h"
#include "qv4estable_p.h"
@@ -111,8 +74,7 @@ ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv,
if (scope.hasException())
break;
}
- ScopedValue falsey(scope, Encode(false));
- return Runtime::IteratorClose::call(scope.engine, iter, falsey);
+ return Runtime::IteratorClose::call(scope.engine, iter);
}
}
return a->asReturnedValue();
diff --git a/src/qml/jsruntime/qv4mapobject_p.h b/src/qml/jsruntime/qv4mapobject_p.h
index a0fae2a14a..68bc7ceed8 100644
--- a/src/qml/jsruntime/qv4mapobject_p.h
+++ b/src/qml/jsruntime/qv4mapobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Crimson AS <info@crimson.no>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Crimson AS <info@crimson.no>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4MAPOBJECT_P_H
#define QV4MAPOBJECT_P_H
@@ -52,9 +16,7 @@
//
#include "qv4object_p.h"
-#include "qv4objectproto_p.h"
#include "qv4functionobject_p.h"
-#include "qv4string_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4math_p.h b/src/qml/jsruntime/qv4math_p.h
index 6632d69c27..b12990700d 100644
--- a/src/qml/jsruntime/qv4math_p.h
+++ b/src/qml/jsruntime/qv4math_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMLJS_MATH_H
#define QMLJS_MATH_H
@@ -70,7 +34,7 @@ namespace QV4 {
static inline QMLJS_READONLY ReturnedValue add_int32(int a, int b)
{
int result;
- if (Q_UNLIKELY(add_overflow(a, b, &result)))
+ if (Q_UNLIKELY(qAddOverflow(a, b, &result)))
return StaticValue::fromDouble(static_cast<double>(a) + b).asReturnedValue();
return StaticValue::fromInt32(result).asReturnedValue();
}
@@ -78,7 +42,7 @@ static inline QMLJS_READONLY ReturnedValue add_int32(int a, int b)
static inline QMLJS_READONLY ReturnedValue sub_int32(int a, int b)
{
int result;
- if (Q_UNLIKELY(sub_overflow(a, b, &result)))
+ if (Q_UNLIKELY(qSubOverflow(a, b, &result)))
return StaticValue::fromDouble(static_cast<double>(a) - b).asReturnedValue();
return StaticValue::fromInt32(result).asReturnedValue();
}
@@ -86,8 +50,11 @@ static inline QMLJS_READONLY ReturnedValue sub_int32(int a, int b)
static inline QMLJS_READONLY ReturnedValue mul_int32(int a, int b)
{
int result;
- if (Q_UNLIKELY(mul_overflow(a, b, &result)))
+ if (Q_UNLIKELY(qMulOverflow(a, b, &result)))
return StaticValue::fromDouble(static_cast<double>(a) * b).asReturnedValue();
+ // need to handle the case where one number is negative and the other 0 ==> -0
+ if (((a < 0) xor (b < 0)) && (result == 0))
+ return StaticValue::fromDouble(-0.0).asReturnedValue();
return StaticValue::fromInt32(result).asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index 07440047d4..71ff6ec0f8 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -1,44 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4mathobject_p.h"
-#include "qv4objectproto_p.h"
#include "qv4symbol_p.h"
#include <QtCore/qdatetime.h>
@@ -47,7 +10,6 @@
#include <QtCore/private/qnumeric_p.h>
#include <QtCore/qthreadstorage.h>
-#include <math.h>
#include <cmath>
using namespace QV4;
@@ -146,11 +108,12 @@ ReturnedValue MathObject::method_acosh(const FunctionObject *, const Value *, co
if (v < 1)
RETURN_RESULT(Encode(qt_qnan()));
-#ifdef Q_OS_ANDROID // incomplete std :-(
- RETURN_RESULT(Encode(std::log(v +std::sqrt(v + 1) * std::sqrt(v - 1))));
-#else
- RETURN_RESULT(Encode(std::acosh(v)));
+#ifdef Q_CC_MINGW
+ // Mingw has a broken std::acosh(). It returns NaN when passed Infinity.
+ if (std::isinf(v))
+ RETURN_RESULT(Encode(v));
#endif
+ RETURN_RESULT(Encode(std::acosh(v)));
}
ReturnedValue MathObject::method_asin(const FunctionObject *, const Value *, const Value *argv, int argc)
@@ -167,12 +130,7 @@ ReturnedValue MathObject::method_asinh(const FunctionObject *, const Value *, co
double v = argc ? argv[0].toNumber() : 2;
if (v == 0.0)
RETURN_RESULT(Encode(v));
-
-#ifdef Q_OS_ANDROID // incomplete std :-(
- RETURN_RESULT(Encode(std::log(v +std::sqrt(1 + v * v))));
-#else
RETURN_RESULT(Encode(std::asinh(v)));
-#endif
}
ReturnedValue MathObject::method_atan(const FunctionObject *, const Value *, const Value *argv, int argc)
@@ -190,17 +148,7 @@ ReturnedValue MathObject::method_atanh(const FunctionObject *, const Value *, co
if (v == 0.0)
RETURN_RESULT(Encode(v));
-#ifdef Q_OS_ANDROID // incomplete std :-(
- if (-1 < v && v < 1)
- RETURN_RESULT(Encode(0.5 * (std::log(v + 1) - std::log(v - 1))));
-
- if (v > 1 || v < -1)
- RETURN_RESULT(Encode(qt_qnan()));
-
- RETURN_RESULT(Encode(copySign(qt_inf(), v)));
-#else
RETURN_RESULT(Encode(std::atanh(v)));
-#endif
}
ReturnedValue MathObject::method_atan2(const FunctionObject *, const Value *, const Value *argv, int argc)
@@ -224,11 +172,7 @@ ReturnedValue MathObject::method_atan2(const FunctionObject *, const Value *, co
ReturnedValue MathObject::method_cbrt(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double v = argc ? argv[0].toNumber() : qt_qnan();
-#ifdef Q_OS_ANDROID // incomplete std :-(
- RETURN_RESULT(Encode(copySign(std::exp(std::log(std::abs(v)) / 3), v)));
-#else
RETURN_RESULT(Encode(std::cbrt(v))); // cube root
-#endif
}
ReturnedValue MathObject::method_ceil(const FunctionObject *, const Value *, const Value *argv, int argc)
@@ -282,11 +226,7 @@ ReturnedValue MathObject::method_expm1(const FunctionObject *, const Value *, co
else
RETURN_RESULT(Encode(qt_inf()));
} else {
-#ifdef Q_OS_ANDROID // incomplete std :-(
- RETURN_RESULT(Encode(std::exp(v) - 1));
-#else
RETURN_RESULT(Encode(std::expm1(v)));
-#endif
}
}
@@ -311,29 +251,14 @@ ReturnedValue MathObject::method_hypot(const FunctionObject *, const Value *, co
{
// ES6 Math.hypot(v1, ..., vn) -> sqrt(sum(vi**2)) but "should take care to
// avoid the loss of precision from overflows and underflows" (as std::hypot does).
- double v = argc ? argv[0].toNumber() : 0;
+ double v = 0;
// Spec mandates +0 on no args; and says nothing about what to do if toNumber() signals ...
-#ifdef Q_OS_ANDROID // incomplete std :-(
- bool big = qt_is_inf(v), bad = std::isnan(v);
- v *= v;
- for (int i = 1; !big && i < argc; i++) {
- double u = argv[i].toNumber();
- if (qt_is_inf(u))
- big = true;
- if (std::isnan(u))
- bad = true;
- v += u * u;
+ if (argc > 0) {
+ QtPrivate::QHypotHelper<double> h(argv[0].toNumber());
+ for (int i = 1; i < argc; i++)
+ h = h.add(argv[i].toNumber());
+ v = h.result();
}
- if (big)
- RETURN_RESULT(Encode(qt_inf()));
- if (bad)
- RETURN_RESULT(Encode(qt_qnan()));
- // Should actually check for {und,ov}erflow, but too fiddly !
- RETURN_RESULT(Value::fromDouble(sqrt(v)));
-#else
- for (int i = 1; i < argc; i++)
- v = std::hypot(v, argv[i].toNumber());
-#endif
RETURN_RESULT(Value::fromDouble(v));
}
@@ -381,13 +306,7 @@ ReturnedValue MathObject::method_log2(const FunctionObject *, const Value *, con
if (v < 0) {
RETURN_RESULT(Encode(qt_qnan()));
} else {
-#ifdef Q_OS_ANDROID // incomplete std :-(
- // Android ndk r10e doesn't have std::log2, so fall back.
- const double ln2 = std::log(2.0);
- RETURN_RESULT(Encode(std::log(v) / ln2));
-#else
RETURN_RESULT(Encode(std::log2(v)));
-#endif
}
}
@@ -422,49 +341,7 @@ ReturnedValue MathObject::method_pow(const FunctionObject *, const Value *, cons
double x = argc > 0 ? argv[0].toNumber() : qt_qnan();
double y = argc > 1 ? argv[1].toNumber() : qt_qnan();
- if (std::isnan(y))
- RETURN_RESULT(Encode(qt_qnan()));
-
- if (y == 0) {
- RETURN_RESULT(Encode(1));
- } else if (((x == 1) || (x == -1)) && std::isinf(y)) {
- RETURN_RESULT(Encode(qt_qnan()));
- } else if (((x == 0) && copySign(1.0, x) == 1.0) && (y < 0)) {
- RETURN_RESULT(Encode(qInf()));
- } else if ((x == 0) && copySign(1.0, x) == -1.0) {
- if (y < 0) {
- if (std::fmod(-y, 2.0) == 1.0)
- RETURN_RESULT(Encode(-qt_inf()));
- else
- RETURN_RESULT(Encode(qt_inf()));
- } else if (y > 0) {
- if (std::fmod(y, 2.0) == 1.0)
- RETURN_RESULT(Encode(copySign(0, -1.0)));
- else
- RETURN_RESULT(Encode(0));
- }
- }
-
-#ifdef Q_OS_AIX
- else if (qt_is_inf(x) && copySign(1.0, x) == -1.0) {
- if (y > 0) {
- if (std::fmod(y, 2.0) == 1.0)
- RETURN_RESULT(Encode(-qt_inf()));
- else
- RETURN_RESULT(Encode(qt_inf()));
- } else if (y < 0) {
- if (std::fmod(-y, 2.0) == 1.0)
- RETURN_RESULT(Encode(copySign(0, -1.0)));
- else
- RETURN_RESULT(Encode(0));
- }
- }
-#endif
- else {
- RETURN_RESULT(Encode(std::pow(x, y)));
- }
- // ###
- RETURN_RESULT(Encode(qt_qnan()));
+ RETURN_RESULT(Encode(QQmlPrivate::jsExponentiate(x, y)));
}
ReturnedValue MathObject::method_random(const FunctionObject *, const Value *, const Value *, int)
@@ -475,11 +352,14 @@ ReturnedValue MathObject::method_random(const FunctionObject *, const Value *, c
ReturnedValue MathObject::method_round(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double v = argc ? argv[0].toNumber() : qt_qnan();
- if (std::isnan(v) || qt_is_inf(v) || qIsNull(v))
+ if (!std::isfinite(v))
RETURN_RESULT(Encode(v));
- v = copySign(std::floor(v + 0.5), v);
- RETURN_RESULT(Encode(v));
+ if (v < 0.5 && v >= -0.5)
+ v = std::copysign(0.0, v);
+ else
+ v = std::floor(v + 0.5);
+ RETURN_RESULT(Encode(v));
}
ReturnedValue MathObject::method_sign(const FunctionObject *, const Value *, const Value *argv, int argc)
@@ -540,13 +420,5 @@ ReturnedValue MathObject::method_tanh(const FunctionObject *, const Value *, con
ReturnedValue MathObject::method_trunc(const FunctionObject *, const Value *, const Value *argv, int argc)
{
double v = argc ? argv[0].toNumber() : qt_qnan();
-#ifdef Q_OS_ANDROID // incomplete std :-(
- if (std::isnan(v) || qt_is_inf(v) || qIsNull(v))
- RETURN_RESULT(Encode(v));
- // Nearest integer not greater in magnitude:
- quint64 whole = std::abs(v);
- RETURN_RESULT(Encode(copySign(whole, v)));
-#else
RETURN_RESULT(Encode(std::trunc(v)));
-#endif
}
diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h
index 2658e25438..5547cbab61 100644
--- a/src/qml/jsruntime/qv4mathobject_p.h
+++ b/src/qml/jsruntime/qv4mathobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4MATHOBJECT_H
#define QV4MATHOBJECT_H
diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp
index 34b0c38ae6..0231641609 100644
--- a/src/qml/jsruntime/qv4memberdata.cpp
+++ b/src/qml/jsruntime/qv4memberdata.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4memberdata_p.h"
#include <private/qv4mm_p.h>
@@ -82,7 +46,7 @@ Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberD
if (oldSize > alloc)
alloc = oldSize;
m = e->memoryManager->allocManaged<MemberData>(alloc);
- // no write barrier required here
+ // no write barrier required here, as m gets marked later when member data is set
memcpy(m, old, oldSize);
} else {
m = e->memoryManager->allocManaged<MemberData>(alloc);
diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h
index 186083b83a..672b058fef 100644
--- a/src/qml/jsruntime/qv4memberdata_p.h
+++ b/src/qml/jsruntime/qv4memberdata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4MEMBERDATA_H
#define QV4MEMBERDATA_H
@@ -63,9 +27,9 @@ namespace Heap {
Member(class, ValueArray, ValueArray, values)
DECLARE_HEAP_OBJECT(MemberData, Base) {
- DECLARE_MARKOBJECTS(MemberData);
+ DECLARE_MARKOBJECTS(MemberData)
};
-Q_STATIC_ASSERT(std::is_trivial< MemberData >::value);
+Q_STATIC_ASSERT(std::is_trivial_v<MemberData>);
}
diff --git a/src/qml/jsruntime/qv4module.cpp b/src/qml/jsruntime/qv4module.cpp
index 08a1900383..f701529096 100644
--- a/src/qml/jsruntime/qv4module.cpp
+++ b/src/qml/jsruntime/qv4module.cpp
@@ -1,52 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4module_p.h"
-#include <private/qv4mm_p.h>
-#include <private/qv4vme_moth_p.h>
#include <private/qv4context_p.h>
-#include <private/qv4symbol_p.h>
#include <private/qv4identifiertable_p.h>
+#include <private/qv4mm_p.h>
+#include <private/qv4stackframe_p.h>
+#include <private/qv4symbol_p.h>
+#include <private/qv4vme_moth_p.h>
-#include <QScopeGuard>
+#include <QtCore/qscopeguard.h>
using namespace QV4;
@@ -86,8 +51,8 @@ void Heap::Module::init(ExecutionEngine *engine, ExecutableCompilationUnit *modu
{
Scoped<QV4::InternalClass> ic(valueScope, scope->internalClass);
- for (uint i = 0; i < unit->data->importEntryTableSize; ++i) {
- const CompiledData::ImportEntry &import = unit->data->importEntryTable()[i];
+ for (uint i = 0; i < unit->unitData()->importEntryTableSize; ++i) {
+ const CompiledData::ImportEntry &import = unit->unitData()->importEntryTable()[i];
ic = ic->addMember(engine->identifierTable->asPropertyKey(unit->runtimeStrings[import.localName]), Attr_NotConfigurable);
}
scope->internalClass.set(engine, ic->d());
@@ -111,16 +76,16 @@ void Module::evaluate()
unit->evaluateModuleRequests();
ExecutionEngine *v4 = engine();
- Function *moduleFunction = unit->runtimeFunctions[unit->data->indexOfRootFunction];
- CppStackFrame frame;
- frame.init(v4, moduleFunction, nullptr, 0);
+ Function *moduleFunction = unit->runtimeFunctions[unit->unitData()->indexOfRootFunction];
+ JSTypesStackFrame frame;
+ frame.init(moduleFunction, nullptr, 0);
frame.setupJSFrame(v4->jsStackTop, Value::undefinedValue(), d()->scope,
Value::undefinedValue(), Value::undefinedValue());
- frame.push();
+ frame.push(v4);
v4->jsStackTop += frame.requiredJSStackFrameSize();
- auto frameCleanup = qScopeGuard([&frame]() {
- frame.pop();
+ auto frameCleanup = qScopeGuard([&frame, v4]() {
+ frame.pop(v4);
});
Moth::VME::exec(&frame, v4);
}
@@ -231,7 +196,7 @@ struct ModuleNamespaceIterator : ObjectOwnPropertyKeyIterator
PropertyKey ModuleNamespaceIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs)
{
const Module *module = static_cast<const Module *>(o);
- if (exportIndex < exportedNames.count()) {
+ if (exportIndex < exportedNames.size()) {
if (attrs)
*attrs = Attr_Data;
Scope scope(module->engine());
@@ -258,9 +223,12 @@ OwnPropertyKeyIterator *Module::virtualOwnPropertyKeys(const Object *o, Value *t
if (module->d()->unit->isESModule()) {
names = module->d()->unit->exportedNames();
} else {
- Heap::InternalClass *scopeClass = module->d()->scope->internalClass;
- for (uint i = 0; i < scopeClass->size; ++i)
- names << scopeClass->keyAt(i);
+ QV4::Scope scope(module->engine());
+ QV4::Scoped<InternalClass> scopeClass(scope, module->d()->scope->internalClass);
+ for (uint i = 0, end = scopeClass->d()->size; i < end; ++i) {
+ QV4::ScopedValue key(scope, scopeClass->d()->keyAt(i));
+ names << key->toQString();
+ }
}
return new ModuleNamespaceIterator(names);
diff --git a/src/qml/jsruntime/qv4module_p.h b/src/qml/jsruntime/qv4module_p.h
index aabb2e005e..43cd995b06 100644
--- a/src/qml/jsruntime/qv4module_p.h
+++ b/src/qml/jsruntime/qv4module_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4MODULE
#define QV4MODULE
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index 13f6912371..d744e569f5 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -1,45 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4numberobject_p.h"
#include "qv4runtime_p.h"
-#include "qv4string_p.h"
#include <QtCore/qnumeric.h>
#include <QtCore/qmath.h>
@@ -196,7 +159,7 @@ ReturnedValue NumberPrototype::method_isSafeInteger(const FunctionObject *, cons
return Encode(false);
double iv = v.toInteger();
- return Encode(dv == iv && std::fabs(iv) <= (2^53)-1);
+ return Encode(dv == iv && std::fabs(iv) <= (1LL << 53) - 1);
}
ReturnedValue NumberPrototype::method_isNaN(const FunctionObject *, const Value *, const Value *argv, int argc)
@@ -306,7 +269,7 @@ ReturnedValue NumberPrototype::method_toPrecision(const FunctionObject *b, const
{
Scope scope(b);
ScopedValue v(scope, thisNumberValue(scope.engine, thisObject));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
double d = v->asDouble();
@@ -314,7 +277,7 @@ ReturnedValue NumberPrototype::method_toPrecision(const FunctionObject *b, const
return Encode(v->toString(scope.engine));
int precision = argv[0].toInt32();
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
if (std::isnan(d))
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index 576817cf36..8ac2bd1f79 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4NUMBEROBJECT_H
#define QV4NUMBEROBJECT_H
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 89161433ed..1ad5e063e8 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -1,77 +1,84 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4object_p.h"
-#include "qv4objectproto_p.h"
-#include "qv4stringobject_p.h"
-#include "qv4argumentsobject_p.h"
+
+#include <private/qv4argumentsobject_p.h>
+#include <private/qv4identifiertable_p.h>
+#include <private/qv4jscall_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4memberdata_p.h>
#include <private/qv4mm_p.h>
-#include "qv4lookup_p.h"
-#include "qv4scopedvalue_p.h"
-#include "qv4memberdata_p.h"
-#include "qv4objectiterator_p.h"
-#include "qv4identifier_p.h"
-#include "qv4string_p.h"
-#include "qv4identifiertable_p.h"
-#include "qv4jscall_p.h"
-#include "qv4symbol_p.h"
-#include "qv4proxy_p.h"
+#include <private/qv4proxy_p.h>
+#include <private/qv4scopedvalue_p.h>
+#include <private/qv4stackframe_p.h>
+#include <private/qv4stringobject_p.h>
+#include <private/qv4symbol_p.h>
+
+#include <QtCore/qloggingcategory.h>
#include <stdint.h>
using namespace QV4;
+using namespace Qt::Literals::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcJavaScriptGlobals, "qt.qml.js.globals")
DEFINE_OBJECT_VTABLE(Object);
void Object::setInternalClass(Heap::InternalClass *ic)
{
- d()->internalClass.set(engine(), ic);
- if (ic->isUsedAsProto)
- ic->updateProtoUsage(d());
Q_ASSERT(ic && ic->vtable);
- uint nInline = d()->vtable()->nInlineProperties;
- if (ic->size <= nInline)
- return;
- bool hasMD = d()->memberData != nullptr;
- uint requiredSize = ic->size - nInline;
- if (!(hasMD && requiredSize) || (hasMD && d()->memberData->values.size < requiredSize))
- d()->memberData.set(ic->engine, MemberData::allocate(ic->engine, requiredSize, d()->memberData));
+ Heap::Object *p = d();
+
+ if (ic->numRedundantTransitions < p->internalClass.get()->numRedundantTransitions) {
+ // IC was rebuilt. The indices are different now. We need to move everything.
+
+ Scope scope(engine());
+
+ // We allocate before setting the new IC. Protect it from GC.
+ Scoped<InternalClass> newIC(scope, ic);
+
+ // Pick the members of the old IC that are still valid in the new IC.
+ // Order them by index in memberData (or inline data).
+ Scoped<MemberData> newMembers(scope, MemberData::allocate(scope.engine, ic->size));
+ for (uint i = 0; i < ic->size; ++i) {
+ // Note that some members might have been deleted. The key may be invalid.
+ const PropertyKey key = ic->nameMap.at(i);
+ newMembers->set(scope.engine, i, key.isValid() ? get(key) : Encode::undefined());
+ }
+
+ p->internalClass.set(scope.engine, ic);
+ const uint nInline = p->vtable()->nInlineProperties;
+
+ if (ic->size > nInline)
+ p->memberData.set(scope.engine, MemberData::allocate(ic->engine, ic->size - nInline));
+ else
+ p->memberData.set(scope.engine, nullptr);
+
+ const auto &memberValues = newMembers->d()->values;
+ for (uint i = 0; i < ic->size; ++i)
+ setProperty(i, memberValues[i]);
+ } else {
+ // The old indices are still the same. No need to move any values.
+ // We may need to re-allocate, though.
+
+ p->internalClass.set(ic->engine, ic);
+ const uint nInline = p->vtable()->nInlineProperties;
+ if (ic->size > nInline) {
+ const uint requiredSize = ic->size - nInline;
+ if ((p->memberData ? p->memberData->values.size : 0) < requiredSize) {
+ p->memberData.set(ic->engine, MemberData::allocate(
+ ic->engine, requiredSize, p->memberData));
+ }
+ }
+ }
+
+ // Before the engine is done initializing, we cannot have any lookups.
+ // Therefore, there is no point in updating the proto IDs.
+ if (ic->engine->isInitialized && ic->isUsedAsProto())
+ ic->updateProtoUsage(p);
+
}
void Object::getProperty(const InternalClassEntry &entry, Property *p) const
@@ -102,10 +109,10 @@ ReturnedValue Object::getValueAccessor(const Value *thisObject, const Value &v,
return Encode::undefined();
Scope scope(f->engine());
- JSCallData jsCallData(scope);
+ JSCallArguments jsCallData(scope);
if (thisObject)
- *jsCallData->thisObject = *thisObject;
- return f->call(jsCallData);
+ *jsCallData.thisObject = *thisObject;
+ return checkedResult(scope.engine, f->call(jsCallData));
}
bool Object::putValue(uint memberIndex, PropertyAttributes attrs, const Value &value)
@@ -119,9 +126,9 @@ bool Object::putValue(uint memberIndex, PropertyAttributes attrs, const Value &v
if (set) {
Scope scope(ic->engine);
ScopedFunctionObject setter(scope, set);
- JSCallData jsCallData(scope, 1);
- jsCallData->args[0] = value;
- *jsCallData->thisObject = this;
+ JSCallArguments jsCallData(scope, 1);
+ jsCallData.args[0] = value;
+ *jsCallData.thisObject = this;
setter->call(jsCallData);
return !ic->engine->hasException;
}
@@ -176,16 +183,16 @@ void Object::defineAccessorProperty(StringOrSymbol *name, VTable::Call getter, V
QV4::Scope scope(v4);
ScopedProperty p(scope);
QString n = name->toQString();
- if (n.at(0) == QLatin1Char('@'))
- n = QChar::fromLatin1('[') + n.midRef(1) + QChar::fromLatin1(']');
+ if (!n.isEmpty() && n.at(0) == '@'_L1)
+ n = '['_L1 + QStringView{n}.mid(1) + ']'_L1;
if (getter) {
- ScopedString getName(scope, v4->newString(QString::fromLatin1("get ") + n));
+ ScopedString getName(scope, v4->newString("get "_L1 + n));
p->setGetter(ScopedFunctionObject(scope, FunctionObject::createBuiltinFunction(v4, getName, getter, 0)));
} else {
p->setGetter(nullptr);
}
if (setter) {
- ScopedString setName(scope, v4->newString(QString::fromLatin1("set ") + n));
+ ScopedString setName(scope, v4->newString("set "_L1 + n));
p->setSetter(ScopedFunctionObject(scope, FunctionObject::createBuiltinFunction(v4, setName, setter, 0)));
} else {
p->setSetter(nullptr);
@@ -460,7 +467,7 @@ ReturnedValue Object::internalGet(PropertyKey id, const Value *receiver, bool *h
bool Object::internalPut(PropertyKey id, const Value &value, Value *receiver)
{
Scope scope(this);
- if (scope.engine->hasException)
+ if (scope.hasException())
return false;
Object *r = receiver->objectValue();
@@ -519,11 +526,11 @@ bool Object::internalPut(PropertyKey id, const Value &value, Value *receiver)
ScopedFunctionObject setter(scope, p->setter());
if (!setter)
return false;
- JSCallData jsCallData(scope, 1);
- jsCallData->args[0] = value;
- *jsCallData->thisObject = *receiver;
+ JSCallArguments jsCallData(scope, 1);
+ jsCallData.args[0] = value;
+ *jsCallData.thisObject = *receiver;
setter->call(jsCallData);
- return !scope.engine->hasException;
+ return !scope.hasException();
}
// Data property
@@ -566,7 +573,7 @@ bool Object::internalDeleteProperty(PropertyKey id)
if (id.isArrayIndex()) {
uint index = id.asArrayIndex();
Scope scope(engine());
- if (scope.engine->hasException)
+ if (scope.hasException())
return false;
Scoped<ArrayData> ad(scope, arrayData());
@@ -735,6 +742,9 @@ ReturnedValue Object::virtualInstanceOf(const Object *typeObject, const Value &v
ReturnedValue Object::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
{
+ // Otherwise we cannot trust the protoIds
+ Q_ASSERT(engine->isInitialized);
+
Heap::Object *obj = object->d();
PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);
if (name.isArrayIndex()) {
@@ -758,7 +768,7 @@ ReturnedValue Object::virtualResolveLookupGetter(const Object *object, Execution
} else {
lookup->getter = Lookup::getterAccessor;
}
- lookup->objectLookup.ic = obj->internalClass;
+ lookup->objectLookup.ic.set(engine, obj->internalClass.get());
lookup->objectLookup.offset = index.index;
return lookup->getter(lookup, engine, *object);
}
@@ -770,6 +780,9 @@ ReturnedValue Object::virtualResolveLookupGetter(const Object *object, Execution
bool Object::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value)
{
+ // Otherwise we cannot trust the protoIds
+ Q_ASSERT(engine->isInitialized);
+
Scope scope(engine);
ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);
@@ -782,7 +795,7 @@ bool Object::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine,
lookup->setter = Lookup::arrayLengthSetter;
return lookup->setter(lookup, engine, *object, value);
} else if (idx.attrs.isData() && idx.attrs.isWritable()) {
- lookup->objectLookup.ic = object->internalClass();
+ lookup->objectLookup.ic.set(engine, object->internalClass());
lookup->objectLookup.index = idx.index;
const auto nInline = object->d()->vtable()->nInlineProperties;
if (idx.index < nInline) {
@@ -816,12 +829,37 @@ bool Object::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine,
lookup->setter = Lookup::setterFallback;
return false;
}
- lookup->insertionLookup.newClass = object->internalClass();
+ lookup->insertionLookup.newClass.set(engine, object->internalClass());
lookup->insertionLookup.offset = idx.index;
lookup->setter = Lookup::setterInsert;
return true;
}
+/*!
+ * \internal
+ *
+ * This method is modeled after \l{QMetaObject::metacall}. It takes a JavaScript
+ * \a object and performs \a call on it, using \a index as identifier for the
+ * property/method/etc to be used and \a a as arguments. Like
+ * \l{QMetaObject::metacall} this method is overly generic in order to reduce the
+ * API surface. On a plain Object it does nothing and returns 0. Specific
+ * objects can override it and do some meaningful work. If the metacall succeeds
+ * they should return a non-0 value. Otherwise they should return 0.
+ *
+ * Most prominently, \l QMetaObject::ReadProperty and \l QMetaObject::WriteProperty
+ * calls can be used to manipulate properties of QObjects and Q_GADGETs wrapped
+ * by QV4::QObjectWrapper, QV4::QQmlTypeWrapper and QV4::QQmlValueTypeWrapper.
+ * They can also be used to manipulate elements in QV4::Sequence.
+ */
+int Object::virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a)
+{
+ Q_UNUSED(object);
+ Q_UNUSED(call);
+ Q_UNUSED(index);
+ Q_UNUSED(a);
+ return 0;
+}
+
ReturnedValue Object::checkedInstanceOf(ExecutionEngine *engine, const FunctionObject *f, const Value &var)
{
Scope scope(engine);
@@ -939,12 +977,29 @@ bool Object::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property
return o->internalDefineOwnProperty(scope.engine, index, nullptr, p, attrs);
}
- auto memberIndex = o->internalClass()->find(id);
+ Scoped<InternalClass> ic(scope, o->internalClass());
+ auto memberIndex = ic->d()->find(id);
if (!memberIndex.isValid()) {
if (!o->isExtensible())
return false;
+ // If the IC is locked, you're not allowed to shadow any unconfigurable properties.
+ if (ic->d()->isLocked()) {
+ while (Heap::Object *prototype = ic->d()->prototype) {
+ ic = prototype->internalClass;
+ const auto entry = ic->d()->find(id);
+ if (entry.isValid()) {
+ if (entry.attributes.isConfigurable())
+ break;
+ qCWarning(lcJavaScriptGlobals).noquote()
+ << QStringLiteral("You cannot shadow the locked property "
+ "'%1' in QML.").arg(id.toQString());
+ return false;
+ }
+ }
+ }
+
Scoped<StringOrSymbol> name(scope, id.asStringOrSymbol());
ScopedProperty pd(scope);
pd->copy(p, attrs);
@@ -958,7 +1013,7 @@ bool Object::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property
bool Object::virtualIsExtensible(const Managed *m)
{
- return m->d()->internalClass->extensible;
+ return m->d()->internalClass->isExtensible();
}
bool Object::virtualPreventExtensions(Managed *m)
@@ -978,11 +1033,12 @@ bool Object::virtualSetPrototypeOf(Managed *m, const Object *proto)
{
Q_ASSERT(m->isObject());
Object *o = static_cast<Object *>(m);
- Heap::Object *current = o->internalClass()->prototype;
+ Heap::InternalClass *ic = o->internalClass();
+ Heap::Object *current = ic->prototype;
Heap::Object *protod = proto ? proto->d() : nullptr;
if (current == protod)
return true;
- if (!o->internalClass()->extensible)
+ if (!ic->isExtensible() || ic->isLocked())
return false;
Heap::Object *p = protod;
while (p) {
@@ -992,7 +1048,7 @@ bool Object::virtualSetPrototypeOf(Managed *m, const Object *proto)
break;
p = p->prototype();
}
- o->setInternalClass(o->internalClass()->changePrototype(protod));
+ o->setInternalClass(ic->changePrototype(protod));
return true;
}
@@ -1013,6 +1069,8 @@ bool Object::setArrayLength(uint newLen)
} else {
if (newLen >= 0x100000)
initSparseArray();
+ else
+ ArrayData::realloc(this, arrayType(), newLen, false);
}
setArrayLengthUnchecked(newLen);
return ok;
@@ -1103,7 +1161,7 @@ void Heap::ArrayObject::init(const QStringList &list)
// The result is a new Array object with length equal to the length
// of the QStringList, and the elements being the QStringList's
// elements converted to JS Strings.
- int len = list.count();
+ int len = list.size();
a->arrayReserve(len);
ScopedValue v(scope);
for (int ii = 0; ii < len; ++ii)
@@ -1126,6 +1184,7 @@ QStringList ArrayObject::toQStringList() const
ScopedValue v(scope);
uint length = getLength();
+ result.reserve(length);
for (uint i = 0; i < length; ++i) {
v = const_cast<ArrayObject *>(this)->get(i);
result.append(v->toQStringNoThrow());
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index f3375929a3..55d18fad52 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4_OBJECT_H
#define QV4_OBJECT_H
@@ -57,7 +21,6 @@
#include "qv4scopedvalue_p.h"
#include "qv4value_p.h"
#include "qv4internalclass_p.h"
-#include "qv4string_p.h"
QT_BEGIN_NAMESPACE
@@ -157,7 +120,7 @@ struct Q_QML_EXPORT Object: Managed {
const Value *propertyData(uint index) const { return d()->propertyData(index); }
Heap::ArrayData *arrayData() const { return d()->arrayData; }
- void setArrayData(ArrayData *a) { d()->arrayData.set(engine(), a->d()); }
+ void setArrayData(ArrayData *a) { d()->arrayData.set(engine(), a ? a->d() : nullptr); }
void getProperty(const InternalClassEntry &entry, Property *p) const;
void setProperty(const InternalClassEntry &entry, const Property *p);
@@ -380,6 +343,9 @@ public:
ReturnedValue resolveLookupSetter(ExecutionEngine *engine, Lookup *lookup, const Value &value)
{ return vtable()->resolveLookupSetter(this, engine, lookup, value); }
+ int metacall(QMetaObject::Call call, int index, void **a)
+ { return vtable()->metacall(this, call, index, a); }
+
protected:
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver,bool *hasProperty);
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
@@ -396,6 +362,7 @@ protected:
static ReturnedValue virtualInstanceOf(const Object *typeObject, const Value &var);
static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
+ static int virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a);
public:
// qv4runtime uses this directly
static ReturnedValue checkedInstanceOf(ExecutionEngine *engine, const FunctionObject *typeObject, const Value &var);
@@ -410,7 +377,7 @@ private:
friend struct ObjectPrototype;
};
-struct Q_QML_PRIVATE_EXPORT ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator
+struct Q_QML_EXPORT ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator
{
uint arrayIndex = 0;
uint memberIndex = 0;
@@ -504,7 +471,12 @@ inline void Object::push_back(const Value &v)
{
arrayCreate();
- uint idx = getLength();
+ const auto length = getLength();
+ if (Q_UNLIKELY(length == std::numeric_limits<uint>::max())) {
+ engine()->throwRangeError(QLatin1String("Too many elements."));
+ return;
+ }
+ uint idx = uint(length);
arrayReserve(idx + 1);
arrayPut(idx, v);
setArrayLengthUnchecked(idx + 1);
diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index e529b8e86b..90eb326d65 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -1,49 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4objectiterator_p.h"
#include "qv4object_p.h"
-#include "qv4stringobject_p.h"
-#include "qv4identifier_p.h"
-#include "qv4argumentsobject_p.h"
-#include "qv4string_p.h"
#include "qv4iterator_p.h"
#include "qv4propertykey_p.h"
+#include <QtQml/private/qv4functionobject_p.h>
using namespace QV4;
@@ -182,7 +143,7 @@ PropertyKey ForInIteratorObject::nextProperty() const
if (d()->current != d()->object) {
o = d()->object;
bool shadowed = false;
- while (o->d() != c->heapObject()) {
+ while (o && o->d() != c->heapObject()) {
if (o->getOwnProperty(key) != Attr_Invalid) {
shadowed = true;
break;
diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h
index a20ce9cb88..7f06faf9d5 100644
--- a/src/qml/jsruntime/qv4objectiterator_p.h
+++ b/src/qml/jsruntime/qv4objectiterator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4OBJECTITERATOR_H
#define QV4OBJECTITERATOR_H
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 3d3b3f413f..e7f96a12ba 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -1,52 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Crimson AS <info@crimson.no>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 Crimson AS <info@crimson.no>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4objectproto_p.h"
#include "qv4argumentsobject_p.h"
#include <private/qv4mm_p.h>
#include "qv4scopedvalue_p.h"
-#include "qv4runtime_p.h"
#include "qv4objectiterator_p.h"
-#include "qv4string_p.h"
-#include "qv4jscall_p.h"
#include "qv4symbol_p.h"
#include "qv4propertykey_p.h"
@@ -137,7 +98,7 @@ ReturnedValue ObjectPrototype::method_getPrototypeOf(const FunctionObject *b, co
return scope.engine->throwTypeError();
ScopedObject o(scope, argv[0].toObject(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
ScopedObject p(scope, o->getPrototypeOf());
@@ -160,7 +121,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(const FunctionObj
return scope.engine->throwTypeError();
ScopedObject O(scope, argv[0].toObject(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
if (ArgumentsObject::isNonStrictArgumentsObject(O))
@@ -168,7 +129,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(const FunctionObj
ScopedValue v(scope, argc > 1 ? argv[1] : Value::undefinedValue());
ScopedPropertyKey name(scope, v->toPropertyKey(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
ScopedProperty desc(scope);
@@ -183,7 +144,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptors(const FunctionOb
return scope.engine->throwTypeError();
ScopedObject o(scope, argv[0].toObject(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
ScopedObject descriptors(scope, scope.engine->newObject());
@@ -212,7 +173,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyNames(const FunctionObject *
return scope.engine->throwTypeError();
ScopedObject O(scope, argv[0].toObject(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
return Encode(getOwnPropertyNames(scope.engine, argv[0]));
@@ -252,7 +213,7 @@ ReturnedValue ObjectPrototype::method_assign(const FunctionObject *b, const Valu
return scope.engine->throwTypeError();
ScopedObject to(scope, argv[0].toObject(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
if (argc == 1)
@@ -263,7 +224,7 @@ ReturnedValue ObjectPrototype::method_assign(const FunctionObject *b, const Valu
continue;
ScopedObject from(scope, argv[i].toObject(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
QV4::ScopedArrayObject keys(scope, QV4::ObjectPrototype::getOwnPropertyNames(scope.engine, from));
quint32 length = keys->getLength();
@@ -284,7 +245,7 @@ ReturnedValue ObjectPrototype::method_assign(const FunctionObject *b, const Valu
propValue = from->get(nextKey);
to->set(nextKey, propValue, Object::DoThrowOnRejection);
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
}
}
@@ -322,14 +283,14 @@ ReturnedValue ObjectPrototype::method_defineProperty(const FunctionObject *b, co
ScopedObject O(scope, argv[0]);
ScopedPropertyKey name(scope, (argc > 1 ? argv[1] : Value::undefinedValue()).toPropertyKey(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
ScopedValue attributes(scope, argc > 2 ? argv[2] : Value::undefinedValue());
ScopedProperty pd(scope);
PropertyAttributes attrs;
toPropertyDescriptor(scope.engine, attributes, pd, &attrs);
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
if (!O->defineOwnProperty(name, pd, attrs))
@@ -347,7 +308,7 @@ ReturnedValue ObjectPrototype::method_defineProperties(const FunctionObject *b,
ScopedObject O(scope, argv[0]);
ScopedObject o(scope, argv[1].toObject(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
ScopedValue val(scope);
@@ -364,7 +325,7 @@ ReturnedValue ObjectPrototype::method_defineProperties(const FunctionObject *b,
PropertyAttributes nattrs;
val = o->getValue(pd->value, attrs);
toPropertyDescriptor(scope.engine, val, n, &nattrs);
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
bool ok = O->defineOwnProperty(key, n, nattrs);
if (!ok)
@@ -381,7 +342,7 @@ ReturnedValue ObjectPrototype::method_entries(const FunctionObject *f, const Val
return scope.engine->throwTypeError();
ScopedObject o(scope, argv[0].toObject(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
ScopedArrayObject a(scope, scope.engine->newArrayObject());
@@ -405,7 +366,7 @@ ReturnedValue ObjectPrototype::method_entries(const FunctionObject *f, const Val
entry = a->get(PropertyKey::fromArrayIndex(i));
name = entry->get(PropertyKey::fromArrayIndex(0));
value = o->get(name->toPropertyKey());
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
entry->push_back(value);
}
@@ -560,7 +521,7 @@ ReturnedValue ObjectPrototype::method_keys(const FunctionObject *b, const Value
return scope.engine->throwTypeError();
ScopedObject o(scope, argv[0].toObject(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
ScopedArrayObject a(scope, scope.engine->newArrayObject());
@@ -602,7 +563,7 @@ ReturnedValue ObjectPrototype::method_values(const FunctionObject *f, const Valu
return scope.engine->throwTypeError();
ScopedObject o(scope, argv[0].toObject(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
ScopedArrayObject a(scope, scope.engine->newArrayObject());
@@ -658,6 +619,7 @@ ReturnedValue ObjectPrototype::method_toString(const FunctionObject *b, const Va
ReturnedValue ObjectPrototype::method_toLocaleString(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(b);
+ CHECK_STACK_LIMITS(scope.engine)
ScopedObject o(scope, thisObject->toObject(scope.engine));
if (!o)
RETURN_UNDEFINED();
@@ -666,7 +628,7 @@ ReturnedValue ObjectPrototype::method_toLocaleString(const FunctionObject *b, co
if (!f)
THROW_TYPE_ERROR();
- return f->call(thisObject, argv, argc);
+ return checkedResult(scope.engine, f->call(thisObject, argv, argc));
}
ReturnedValue ObjectPrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int)
@@ -678,10 +640,10 @@ ReturnedValue ObjectPrototype::method_hasOwnProperty(const FunctionObject *b, co
{
Scope scope(b);
ScopedPropertyKey P(scope, (argc ? argv[0] : Value::undefinedValue()).toPropertyKey(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
ScopedObject O(scope, thisObject->toObject(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
bool r = O->getOwnProperty(P) != Attr_Invalid;
return Encode(r);
@@ -695,7 +657,7 @@ ReturnedValue ObjectPrototype::method_isPrototypeOf(const FunctionObject *b, con
ScopedObject V(scope, argv[0]);
ScopedObject O(scope, thisObject->toObject(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
ScopedObject proto(scope, V->getPrototypeOf());
while (proto) {
@@ -710,11 +672,11 @@ ReturnedValue ObjectPrototype::method_propertyIsEnumerable(const FunctionObject
{
Scope scope(b);
ScopedPropertyKey p(scope, (argc ? argv[0] : Value::undefinedValue()).toPropertyKey(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
ScopedObject o(scope, thisObject->toObject(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
PropertyAttributes attrs = o->getOwnProperty(p);
return Encode(attrs.isEnumerable());
@@ -731,7 +693,7 @@ ReturnedValue ObjectPrototype::method_defineGetter(const FunctionObject *b, cons
THROW_TYPE_ERROR();
ScopedString prop(scope, argv[0], ScopedString::Convert);
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
ScopedObject o(scope, thisObject);
@@ -761,7 +723,7 @@ ReturnedValue ObjectPrototype::method_defineSetter(const FunctionObject *b, cons
THROW_TYPE_ERROR();
ScopedString prop(scope, argv[0], ScopedString::Convert);
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
ScopedObject o(scope, thisObject);
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index 8707305dc2..d152bfd175 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4ECMAOBJECTS_P_H
#define QV4ECMAOBJECTS_P_H
@@ -74,7 +38,7 @@ struct ObjectCtor: FunctionObject
static ReturnedValue virtualCall(const FunctionObject *m, const Value *thisObject, const Value *argv, int argc);
};
-struct Q_QML_PRIVATE_EXPORT ObjectPrototype: Object
+struct Q_QML_EXPORT ObjectPrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp
index 79c372348f..4f11d0a2ad 100644
--- a/src/qml/jsruntime/qv4persistent.cpp
+++ b/src/qml/jsruntime/qv4persistent.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4persistent_p.h"
#include <private/qv4mm_p.h>
@@ -64,7 +28,7 @@ struct Page {
Value values[1]; // Really kEntriesPerPage, but keep the compiler happy
};
-Page *getPage(Value *val) {
+Page *getPage(const Value *val) {
return reinterpret_cast<Page *>(reinterpret_cast<quintptr>(val) & ~((quintptr)(WTF::pageSize() - 1)));
}
@@ -178,6 +142,7 @@ PersistentValueStorage::PersistentValueStorage(ExecutionEngine *engine)
PersistentValueStorage::~PersistentValueStorage()
{
+ clearFreePageHint();
Page *p = static_cast<Page *>(firstPage);
while (p) {
for (int i = 0; i < kEntriesPerPage; ++i) {
@@ -195,7 +160,9 @@ PersistentValueStorage::~PersistentValueStorage()
Value *PersistentValueStorage::allocate()
{
- Page *p = static_cast<Page *>(firstPage);
+ Page *p = static_cast<Page *>(freePageHint);
+ if (p && p->header.freeList == -1)
+ p = static_cast<Page *>(firstPage);
while (p) {
if (p->header.freeList != -1)
break;
@@ -207,9 +174,15 @@ Value *PersistentValueStorage::allocate()
Value *v = p->values + p->header.freeList;
p->header.freeList = v->int_32();
- if (p->header.freeList != -1 && p != firstPage) {
- unlink(p);
- insertInFront(this, p);
+ if (p->header.freeList != -1 && p != freePageHint) {
+ if (auto oldHint = static_cast<Page *>(freePageHint)) {
+ oldHint->header.refCount--;
+ // no need to free - if the old page were unused,
+ // we would have used it to serve the allocation
+ Q_ASSERT(oldHint->header.refCount);
+ }
+ freePageHint = p;
+ p->header.refCount++;
}
++p->header.refCount;
@@ -219,11 +192,9 @@ Value *PersistentValueStorage::allocate()
return v;
}
-void PersistentValueStorage::free(Value *v)
+void PersistentValueStorage::freeUnchecked(Value *v)
{
- if (!v)
- return;
-
+ Q_ASSERT(v);
Page *p = getPage(v);
*v = Encode(p->header.freeList);
@@ -240,13 +211,23 @@ void PersistentValueStorage::mark(MarkStack *markStack)
if (Managed *m = p->values[i].as<Managed>())
m->mark(markStack);
}
- markStack->drain();
p = p->header.next;
}
}
-ExecutionEngine *PersistentValueStorage::getEngine(Value *v)
+void PersistentValueStorage::clearFreePageHint()
+{
+ if (!freePageHint)
+ return;
+ auto page = static_cast<Page *>(freePageHint);
+ if (!--page->header.refCount)
+ freePage(page);
+ freePageHint = nullptr;
+
+}
+
+ExecutionEngine *PersistentValueStorage::getEngine(const Value *v)
{
return getPage(v)->header.engine;
}
@@ -262,22 +243,18 @@ void PersistentValueStorage::freePage(void *page)
PersistentValue::PersistentValue(const PersistentValue &other)
: val(nullptr)
{
- if (other.val) {
- val = other.engine()->memoryManager->m_persistentValues->allocate();
- *val = *other.val;
- }
+ if (other.val)
+ set(other.engine(), *other.val);
}
PersistentValue::PersistentValue(ExecutionEngine *engine, const Value &value)
{
- val = engine->memoryManager->m_persistentValues->allocate();
- *val = value;
+ set(engine, value);
}
PersistentValue::PersistentValue(ExecutionEngine *engine, ReturnedValue value)
{
- val = engine->memoryManager->m_persistentValues->allocate();
- *val = value;
+ set(engine, value);
}
PersistentValue::PersistentValue(ExecutionEngine *engine, Object *object)
@@ -285,14 +262,7 @@ PersistentValue::PersistentValue(ExecutionEngine *engine, Object *object)
{
if (!object)
return;
-
- val = engine->memoryManager->m_persistentValues->allocate();
- *val = object;
-}
-
-PersistentValue::~PersistentValue()
-{
- PersistentValueStorage::free(val);
+ set(engine, *object);
}
PersistentValue &PersistentValue::operator=(const PersistentValue &other)
@@ -315,19 +285,16 @@ PersistentValue &PersistentValue::operator=(const PersistentValue &other)
PersistentValue &PersistentValue::operator=(const WeakValue &other)
{
- if (!val) {
- if (!other.valueRef())
- return *this;
- val = other.engine()->memoryManager->m_persistentValues->allocate();
- }
+ if (!val && !other.valueRef())
+ return *this;
if (!other.valueRef()) {
*val = Encode::undefined();
return *this;
}
- Q_ASSERT(engine() == other.engine());
+ Q_ASSERT(!engine() || engine() == other.engine());
- *val = *other.valueRef();
+ set(other.engine(), *other.valueRef());
return *this;
}
@@ -337,10 +304,7 @@ PersistentValue &PersistentValue::operator=(Object *object)
PersistentValueStorage::free(val);
return *this;
}
- if (!val)
- val = object->engine()->memoryManager->m_persistentValues->allocate();
-
- *val = object;
+ set(object->engine(), *object);
return *this;
}
@@ -348,6 +312,10 @@ void PersistentValue::set(ExecutionEngine *engine, const Value &value)
{
if (!val)
val = engine->memoryManager->m_persistentValues->allocate();
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack){
+ if (QV4::WriteBarrier::isInsertionBarrier && value.isManaged())
+ value.heapObject()->mark(stack);
+ });
*val = value;
}
@@ -355,6 +323,13 @@ void PersistentValue::set(ExecutionEngine *engine, ReturnedValue value)
{
if (!val)
val = engine->memoryManager->m_persistentValues->allocate();
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack){
+ if constexpr (!QV4::WriteBarrier::isInsertionBarrier)
+ return;
+ auto val = Value::fromReturnedValue(value);
+ if (val.isManaged())
+ val.heapObject()->mark(stack);
+ });
*val = value;
}
@@ -362,6 +337,11 @@ void PersistentValue::set(ExecutionEngine *engine, Heap::Base *obj)
{
if (!val)
val = engine->memoryManager->m_persistentValues->allocate();
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack){
+ if constexpr (QV4::WriteBarrier::isInsertionBarrier)
+ obj->mark(stack);
+ });
+
*val = obj;
}
@@ -403,6 +383,56 @@ WeakValue::~WeakValue()
free();
}
+/*
+ WeakValue::set shold normally not mark objects, after all a weak value
+ is not supposed to keep an object alive.
+ However, if we are past GCState::HandleQObjectWrappers, nothing will
+ reset weak values referencing unmarked values, but those values will
+ still be swept.
+ That lead to stale pointers, and potentially to crashes. To avoid this,
+ we mark the objects here (they might still get collected in the next gc
+ run).
+ This is especially important due to the way we handle QObjectWrappers.
+ */
+void WeakValue::set(ExecutionEngine *engine, const Value &value)
+{
+ if (!val)
+ allocVal(engine);
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *ms) {
+ if (engine->memoryManager->gcStateMachine->state <= GCState::HandleQObjectWrappers)
+ return;
+ if (auto *h = value.heapObject())
+ h->mark(ms);
+ });
+ *val = value;
+}
+
+void WeakValue::set(ExecutionEngine *engine, ReturnedValue value)
+{
+ if (!val)
+ allocVal(engine);
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *ms) {
+ if (engine->memoryManager->gcStateMachine->state <= GCState::HandleQObjectWrappers)
+ return;
+ if (auto *h = QV4::Value::fromReturnedValue(value).heapObject())
+ h->mark(ms);
+ });
+
+ *val = value;
+}
+
+void WeakValue::set(ExecutionEngine *engine, Heap::Base *obj)
+{
+ if (!val)
+ allocVal(engine);
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *ms) {
+ if (engine->memoryManager->gcStateMachine->state <= GCState::HandleQObjectWrappers)
+ return;
+ obj->mark(ms);
+ });
+ *val = obj;
+}
+
void WeakValue::allocVal(ExecutionEngine *engine)
{
val = engine->memoryManager->m_weakValues->allocate();
diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h
index 55e8eefcb7..d0e29a166e 100644
--- a/src/qml/jsruntime/qv4persistent_p.h
+++ b/src/qml/jsruntime/qv4persistent_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4PERSISTENT_H
#define QV4PERSISTENT_H
@@ -63,7 +27,11 @@ struct Q_QML_EXPORT PersistentValueStorage
~PersistentValueStorage();
Value *allocate();
- static void free(Value *e);
+ static void free(Value *v)
+ {
+ if (v)
+ freeUnchecked(v);
+ }
void mark(MarkStack *markStack);
@@ -83,23 +51,32 @@ struct Q_QML_EXPORT PersistentValueStorage
Iterator begin() { return Iterator(firstPage, 0); }
Iterator end() { return Iterator(nullptr, 0); }
- static ExecutionEngine *getEngine(Value *v);
+ void clearFreePageHint();
+
+ static ExecutionEngine *getEngine(const Value *v);
ExecutionEngine *engine;
void *firstPage;
+ void *freePageHint = nullptr;
private:
+ static void freeUnchecked(Value *v);
static void freePage(void *page);
};
class Q_QML_EXPORT PersistentValue
{
public:
- PersistentValue() {}
+ constexpr PersistentValue() noexcept = default;
PersistentValue(const PersistentValue &other);
PersistentValue &operator=(const PersistentValue &other);
+
+ PersistentValue(PersistentValue &&other) noexcept : val(std::exchange(other.val, nullptr)) {}
+ void swap(PersistentValue &other) noexcept { qt_ptr_swap(val, other.val); }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(PersistentValue)
+ ~PersistentValue() { PersistentValueStorage::free(val); }
+
PersistentValue &operator=(const WeakValue &other);
PersistentValue &operator=(Object *object);
- ~PersistentValue();
PersistentValue(ExecutionEngine *engine, const Value &value);
PersistentValue(ExecutionEngine *engine, ReturnedValue value);
@@ -154,26 +131,11 @@ public:
WeakValue &operator=(const WeakValue &other);
~WeakValue();
- void set(ExecutionEngine *engine, const Value &value)
- {
- if (!val)
- allocVal(engine);
- *val = value;
- }
+ void set(ExecutionEngine *engine, const Value &value);
- void set(ExecutionEngine *engine, ReturnedValue value)
- {
- if (!val)
- allocVal(engine);
- *val = value;
- }
+ void set(ExecutionEngine *engine, ReturnedValue value);
- void set(ExecutionEngine *engine, Heap::Base *obj)
- {
- if (!val)
- allocVal(engine);
- *val = obj;
- }
+ void set(ExecutionEngine *engine, Heap::Base *obj);
ReturnedValue value() const {
return (val ? val->asReturnedValue() : Encode::undefined());
diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp
index 26e1074fe3..df63d4bdf7 100644
--- a/src/qml/jsruntime/qv4profiling.cpp
+++ b/src/qml/jsruntime/qv4profiling.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4profiling_p.h"
#include <private/qv4mm_p.h>
@@ -50,8 +14,8 @@ FunctionLocation FunctionCall::resolveLocation() const
{
return FunctionLocation(m_function->name()->toQString(),
m_function->executableCompilationUnit()->fileName(),
- m_function->compiledFunction->location.line,
- m_function->compiledFunction->location.column);
+ m_function->compiledFunction->location.line(),
+ m_function->compiledFunction->location.column());
}
FunctionCallProperties FunctionCall::properties() const
@@ -96,9 +60,10 @@ void Profiler::reportData()
FunctionLocationHash locations;
properties.reserve(m_data.size());
- for (const FunctionCall &call : qAsConst(m_data)) {
+ for (const FunctionCall &call : std::as_const(m_data)) {
properties.append(call.properties());
Function *function = call.function();
+ Q_ASSERT(function);
SentMarker &marker = m_sentLocations[reinterpret_cast<quintptr>(function)];
if (!marker.isValid()) {
FunctionLocation &location = locations[properties.constLast().id];
@@ -123,10 +88,10 @@ void Profiler::startProfiling(quint64 features)
(qint64)m_engine->memoryManager->getLargeItemsMem(),
HeapPage};
m_memory_data.append(heap);
- MemoryAllocationProperties small = {timestamp,
+ MemoryAllocationProperties smallP = {timestamp,
(qint64)m_engine->memoryManager->getUsedMem(),
SmallItem};
- m_memory_data.append(small);
+ m_memory_data.append(smallP);
MemoryAllocationProperties large = {timestamp,
(qint64)m_engine->memoryManager->getLargeItemsMem(),
LargeItem};
diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h
index ccf7c9210d..d1e8e34ba3 100644
--- a/src/qml/jsruntime/qv4profiling_p.h
+++ b/src/qml/jsruntime/qv4profiling_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4PROFILING_H
#define QV4PROFILING_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include "qv4global_p.h"
+#include <QtQml/private/qv4global_p.h>
#include "qv4engine_p.h"
#include "qv4function_p.h"
@@ -59,8 +23,8 @@
#if !QT_CONFIG(qml_debug)
-#define Q_V4_PROFILE_ALLOC(engine, size, type) (!engine)
-#define Q_V4_PROFILE_DEALLOC(engine, size, type) (!engine)
+#define Q_V4_PROFILE_ALLOC(engine, size, type) Q_UNUSED(engine)
+#define Q_V4_PROFILE_DEALLOC(engine, size, type) Q_UNUSED(engine)
QT_BEGIN_NAMESPACE
@@ -138,9 +102,7 @@ struct MemoryAllocationProperties {
class FunctionCall {
public:
-
- FunctionCall() : m_function(nullptr), m_start(0), m_end(0)
- { Q_ASSERT_X(false, Q_FUNC_INFO, "Cannot construct a function call without function"); }
+ FunctionCall() : m_function(nullptr), m_start(0), m_end(0) {}
FunctionCall(Function *function, qint64 start, qint64 end) :
m_function(function), m_start(start), m_end(end)
@@ -150,13 +112,24 @@ public:
m_function(other.m_function), m_start(other.m_start), m_end(other.m_end)
{ m_function->executableCompilationUnit()->addref(); }
+ FunctionCall(FunctionCall &&other) noexcept
+ : m_function(std::exchange(other.m_function, nullptr))
+ , m_start(std::exchange(other.m_start, 0))
+ , m_end(std::exchange(other.m_end, 0))
+ {}
+
~FunctionCall()
- { m_function->executableCompilationUnit()->release(); }
+ {
+ if (m_function)
+ m_function->executableCompilationUnit()->release();
+ }
FunctionCall &operator=(const FunctionCall &other) {
if (&other != this) {
- other.m_function->executableCompilationUnit()->addref();
- m_function->executableCompilationUnit()->release();
+ if (other.m_function)
+ other.m_function->executableCompilationUnit()->addref();
+ if (m_function)
+ m_function->executableCompilationUnit()->release();
m_function = other.m_function;
m_start = other.m_start;
m_end = other.m_end;
@@ -164,6 +137,15 @@ public:
return *this;
}
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(FunctionCall)
+
+ void swap(FunctionCall &other) noexcept
+ {
+ qt_ptr_swap(m_function, other.m_function);
+ std::swap(m_start, other.m_start);
+ std::swap(m_end, other.m_end);
+ }
+
Function *function() const
{
return m_function;
@@ -254,7 +236,7 @@ public:
void reportData();
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
-signals:
+Q_SIGNALS:
void dataReady(const QV4::Profiling::FunctionLocationHash &,
const QVector<QV4::Profiling::FunctionCallProperties> &,
const QVector<QV4::Profiling::MemoryAllocationProperties> &);
@@ -276,7 +258,6 @@ public:
// It's enough to ref() the function in the destructor as it will probably not disappear while
// it's executing ...
FunctionCallProfiler(ExecutionEngine *engine, Function *f)
- : profiler(nullptr)
{
Profiler *p = engine->profiler();
if (Q_UNLIKELY(p) && (p->featuresEnabled & (1 << Profiling::FeatureFunctionCall))) {
@@ -292,20 +273,20 @@ public:
profiler->m_data.append(FunctionCall(function, startTime, profiler->m_timer.nsecsElapsed()));
}
- Profiler *profiler;
- Function *function;
- qint64 startTime;
+ Profiler *profiler = nullptr;
+ Function *function = nullptr;
+ qint64 startTime = 0;
};
} // namespace Profiling
} // namespace QV4
-Q_DECLARE_TYPEINFO(QV4::Profiling::MemoryAllocationProperties, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionLocation, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(QV4::Profiling::Profiler::SentMarker, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QV4::Profiling::MemoryAllocationProperties, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionLocation, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QV4::Profiling::Profiler::SentMarker, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QV4::Profiling::FunctionLocationHash)
diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp
index 17d218a6eb..16cffea124 100644
--- a/src/qml/jsruntime/qv4promiseobject.cpp
+++ b/src/qml/jsruntime/qv4promiseobject.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QCoreApplication>
#include <private/qv4promiseobject_p.h>
#include <private/qv4symbol_p.h>
#include "qv4jscall_p.h"
+QT_BEGIN_NAMESPACE
+
using namespace QV4;
using namespace QV4::Promise;
@@ -81,7 +47,6 @@ void dropException(QV4::ExecutionEngine* e)
}
}
-QT_BEGIN_NAMESPACE
namespace QV4 {
namespace Promise {
@@ -114,7 +79,6 @@ struct ResolveThenableEvent : public QEvent
} // namespace Promise
} // namespace QV4
-QT_END_NAMESPACE
ReactionHandler::ReactionHandler(QObject *parent)
: QObject(parent)
@@ -227,17 +191,17 @@ public:
void ReactionHandler::executeResolveThenable(ResolveThenableEvent *event)
{
Scope scope(event->then.engine());
- JSCallData jsCallData(scope, 2);
+ JSCallArguments jsCallData(scope, 2);
PromiseObject *promise = event->promise.as<PromiseObject>();
ScopedFunctionObject resolve {scope, FunctionBuilder::makeResolveFunction(scope.engine, promise->d())};
ScopedFunctionObject reject {scope, FunctionBuilder::makeRejectFunction(scope.engine, promise->d())};
- jsCallData->args[0] = resolve;
+ jsCallData.args[0] = resolve;
jsCallData.args[1] = reject;
- jsCallData->thisObject = event->thenable.as<QV4::Object>();
+ jsCallData.thisObject = event->thenable.as<QV4::Object>();
event->then.as<const FunctionObject>()->call(jsCallData);
- if (scope.engine->hasException) {
- JSCallData rejectCallData(scope, 1);
- rejectCallData->args[0] = scope.engine->catchException();
+ if (scope.hasException()) {
+ JSCallArguments rejectCallData(scope, 1);
+ rejectCallData.args[0] = scope.engine->catchException();
Scoped<RejectWrapper> reject {scope, scope.engine->memoryManager->allocate<QV4::RejectWrapper>()};
reject->call(rejectCallData);
}
@@ -428,7 +392,7 @@ ReturnedValue PromiseCtor::virtualCallAsConstructor(const FunctionObject *f, con
THROW_TYPE_ERROR(); // throw a TypeError exception
Scoped<PromiseObject> a(scope, scope.engine->newPromiseObject());
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
a->d()->state = Heap::PromiseObject::Pending; //4. Set promise.[[PromiseState]] to "pending"
@@ -440,16 +404,16 @@ ReturnedValue PromiseCtor::virtualCallAsConstructor(const FunctionObject *f, con
ScopedFunctionObject resolve(scope, FunctionBuilder::makeResolveFunction(scope.engine, a->d()));
ScopedFunctionObject reject(scope, FunctionBuilder::makeRejectFunction(scope.engine, a->d()));
- JSCallData jsCallData(scope, 2);
- jsCallData->args[0] = resolve;
- jsCallData->args[1] = reject;
- //jsCallData->thisObject = a; VERIFY corretness, but this should be undefined (see below)
+ JSCallArguments jsCallData(scope, 2);
+ jsCallData.args[0] = resolve;
+ jsCallData.args[1] = reject;
+ //jsCallData.thisObject = a; VERIFY corretness, but this should be undefined (see below)
executor->call(jsCallData); // 9. Let completion be Call(executor, undefined, « resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]] »).
- if (scope.engine->hasException) {
+ if (scope.hasException()) {
ScopedValue exception {scope, scope.engine->catchException()};
- JSCallData callData {scope, 1};
+ JSCallArguments callData {scope, 1};
callData.args[0] = exception;
reject->call(callData);
}
@@ -611,15 +575,17 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
}
if (!doneValue->toBoolean())
- completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(e, iteratorObject);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
}
ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
- if (!nextPromise || scope.hasException()) {
- ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue));
+ if (scope.hasException() || !nextPromise) {
+ ScopedValue completion(scope, doneValue->toBoolean()
+ ? Encode::undefined()
+ : Runtime::IteratorClose::call(e, iteratorObject));
if (scope.hasException()) {
completion = e->exceptionValue->asReturnedValue();
dropException(e);
@@ -641,7 +607,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
}
if (!doneValue->toBoolean())
- completion = Runtime::IteratorClose::call(scope.engine, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(scope.engine, iteratorObject);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -649,10 +615,10 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
ScopedFunctionObject resolveElement(scope, FunctionBuilder::makeResolveElementFunction(e, index, executionState->d()));
- JSCallData jsCallData(scope, 2);
- jsCallData->args[0] = resolveElement;
- jsCallData->args[1] = reject;
- jsCallData->thisObject = nextPromise;
+ JSCallArguments jsCallData(scope, 2);
+ jsCallData.args[0] = resolveElement;
+ jsCallData.args[1] = reject;
+ jsCallData.thisObject = nextPromise;
then->call(jsCallData);
if (scope.hasException()) {
@@ -660,7 +626,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
dropException(e);
if (!doneValue->toBoolean())
- completion = Runtime::IteratorClose::call(scope.engine, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(scope.engine, iteratorObject);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -722,7 +688,9 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
doneValue = Value::fromReturnedValue(Runtime::IteratorNext::call(e, iteratorObject, nextValue));
if (scope.hasException()) {
- ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue));
+ ScopedValue completion(scope, doneValue->toBoolean()
+ ? Encode::undefined()
+ : Runtime::IteratorClose::call(e, iteratorObject));
if (scope.hasException()) {
completion = e->exceptionValue->asReturnedValue();
dropException(e);
@@ -757,15 +725,17 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
}
if (!doneValue->toBoolean())
- completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(e, iteratorObject);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
}
ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
- if (!nextPromise || scope.hasException()) {
- ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue));
+ if (scope.hasException() || !nextPromise) {
+ ScopedValue completion(scope, doneValue->toBoolean()
+ ? Encode::undefined()
+ : Runtime::IteratorClose::call(e, iteratorObject));
if (scope.hasException()) {
completion = e->exceptionValue->asReturnedValue();
dropException(e);
@@ -785,7 +755,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
}
if (!doneValue->toBoolean())
- completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(e, iteratorObject);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -793,10 +763,10 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
ScopedFunctionObject resolveOriginalPromise(scope, capability->d()->resolve);
- JSCallData jsCallData(scope, 2);
- jsCallData->args[0] = resolveOriginalPromise;
- jsCallData->args[1] = reject;
- jsCallData->thisObject = nextPromise;
+ JSCallArguments jsCallData(scope, 2);
+ jsCallData.args[0] = resolveOriginalPromise;
+ jsCallData.args[1] = reject;
+ jsCallData.thisObject = nextPromise;
then->call(jsCallData);
if (scope.hasException()) {
@@ -804,7 +774,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
dropException(e);
if (!doneValue->toBoolean())
- completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue);
+ completion = Runtime::IteratorClose::call(e, iteratorObject);
reject->call(newPromise, completion, 1);
return newPromise.asReturnedValue();
@@ -927,10 +897,10 @@ ReturnedValue PromisePrototype::method_catch(const FunctionObject *f, const Valu
onRejected = argv[0];
}
- JSCallData jsCallData(scope, 2);
- jsCallData->args[0] = Encode::undefined();
- jsCallData->args[1] = onRejected;
- jsCallData->thisObject = promise;
+ JSCallArguments jsCallData(scope, 2);
+ jsCallData.args[0] = Encode::undefined();
+ jsCallData.args[1] = onRejected;
+ jsCallData.thisObject = promise;
ScopedString thenName(scope, scope.engine->newIdentifier(QStringLiteral("then")));
ScopedFunctionObject then(scope, promise->get(thenName));
@@ -1032,7 +1002,7 @@ ReturnedValue ResolveWrapper::virtualCall(const FunctionObject *f, const Value *
// 8. Let then be Get(resolution, then)
ScopedFunctionObject thenAction { scope, resolutionObject->get(thenName)};
// 9. If then is an abrupt completion, then
- if (scope.engine->hasException) {
+ if (scope.hasException()) {
// Return RecjectPromise(promise, then.[[Value]]
ScopedValue thenValue {scope, scope.engine->catchException()};
promise->d()->setState(Heap::PromiseObject::Rejected);
@@ -1084,13 +1054,17 @@ ReturnedValue RejectWrapper::virtualCall(const FunctionObject *f, const Value *t
ScopedString thenName(scope, scope.engine->newIdentifier(QStringLiteral("catch")));
ScopedFunctionObject then(scope, promise->get(thenName));
- JSCallData jsCallData(scope, 2);
- jsCallData->args[0] = *f;
- jsCallData->args[1] = Encode::undefined();
- jsCallData->thisObject = value;
+ JSCallArguments jsCallData(scope, 2);
+ jsCallData.args[0] = *f;
+ jsCallData.args[1] = Encode::undefined();
+ jsCallData.thisObject = value;
then->call(jsCallData);
}
return Encode::undefined();
}
+
+QT_END_NAMESPACE
+
+#include "moc_qv4promiseobject_p.cpp"
diff --git a/src/qml/jsruntime/qv4promiseobject_p.h b/src/qml/jsruntime/qv4promiseobject_p.h
index 8a3724e07d..ca31f00881 100644
--- a/src/qml/jsruntime/qv4promiseobject_p.h
+++ b/src/qml/jsruntime/qv4promiseobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4PROMISEOBJECT_H
#define QV4PROMISEOBJECT_H
@@ -70,7 +34,7 @@ class ReactionHandler : public QObject
public:
ReactionHandler(QObject *parent = nullptr);
- virtual ~ReactionHandler() override;
+ ~ReactionHandler() override;
void addReaction(ExecutionEngine *e, const Value *reaction, const Value *value);
void addResolveThenable(ExecutionEngine *e, const PromiseObject *promise, const Object *thenable, const FunctionObject *then);
@@ -217,7 +181,7 @@ struct PromiseExecutionState : Object
V4_OBJECT2(PromiseExecutionState, Object)
};
-struct Q_QML_PRIVATE_EXPORT PromiseObject : Object
+struct Q_QML_EXPORT PromiseObject : Object
{
V4_OBJECT2(PromiseObject, Object)
V4_NEEDS_DESTROY
diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h
index 555f323737..e7ad6b58d6 100644
--- a/src/qml/jsruntime/qv4property_p.h
+++ b/src/qml/jsruntime/qv4property_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4PROPERTYDESCRIPTOR_H
#define QV4PROPERTYDESCRIPTOR_H
@@ -209,8 +173,6 @@ struct PropertyIndex {
}
-Q_DECLARE_TYPEINFO(QV4::Property, Q_MOVABLE_TYPE);
-
QT_END_NAMESPACE
#endif
diff --git a/src/qml/jsruntime/qv4propertykey.cpp b/src/qml/jsruntime/qv4propertykey.cpp
index 064d030b83..65dd7e7fc1 100644
--- a/src/qml/jsruntime/qv4propertykey.cpp
+++ b/src/qml/jsruntime/qv4propertykey.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4propertykey_p.h"
@@ -43,12 +7,15 @@
#include <qv4string_p.h>
#include <qv4engine_p.h>
#include <qv4scopedvalue_p.h>
+#include <private/qv4mm_p.h>
+
+using namespace Qt::Literals::StringLiterals;
QV4::Heap::StringOrSymbol *QV4::PropertyKey::toStringOrSymbol(QV4::ExecutionEngine *e)
{
if (isArrayIndex())
return Value::fromUInt32(asArrayIndex()).toString(e);
- return static_cast<Heap::StringOrSymbol *>(asStringOrSymbol());
+ return asStringOrSymbol();
}
bool QV4::PropertyKey::isString() const {
@@ -57,7 +24,7 @@ bool QV4::PropertyKey::isString() const {
}
bool QV4::PropertyKey::isSymbol() const {
- Heap::Base *s = asStringOrSymbol();
+ Heap::StringOrSymbol *s = asStringOrSymbol();
return s && !s->internalClass->vtable->isString && s->internalClass->vtable->isStringOrSymbol;
}
@@ -92,9 +59,9 @@ QV4::Heap::String *QV4::PropertyKey::asFunctionName(ExecutionEngine *engine, Fun
{
QString n;
if (prefix == Getter)
- n = QStringLiteral("get ");
+ n += "get "_L1;
else if (prefix == Setter)
- n = QStringLiteral("set ");
+ n += "set "_L1;
if (isArrayIndex())
n += QString::number(asArrayIndex());
else {
@@ -102,8 +69,8 @@ QV4::Heap::String *QV4::PropertyKey::asFunctionName(ExecutionEngine *engine, Fun
QString str = s->toQString();
if (s->internalClass->vtable->isString)
n += s->toQString();
- else if (str.length() > 1)
- n += QChar::fromLatin1('[') + str.midRef(1) + QChar::fromLatin1(']');
+ else if (str.size() > 1)
+ n += QChar::fromLatin1('[') + QStringView{str}.mid(1) + QChar::fromLatin1(']');
}
return engine->newString(n);
}
diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h
index b2a2ec3dea..f3b05ee0d8 100644
--- a/src/qml/jsruntime/qv4propertykey_p.h
+++ b/src/qml/jsruntime/qv4propertykey_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4PROPERTYKEY_H
#define QV4PROPERTYKEY_H
@@ -50,7 +14,10 @@
// We mean it.
//
+#include <private/qv4writebarrier_p.h>
#include <private/qv4global_p.h>
+#include <private/qv4staticvalue_p.h>
+#include <QtCore/qhashfunctions.h>
QT_BEGIN_NAMESPACE
@@ -71,68 +38,74 @@ private:
// * If the key is a Symbol it simply points to the referenced symbol object
// * if the key is an array index (a uint < UINT_MAX), it's encoded as an
// integer value
- quint64 val;
+ QV4::StaticValue val;
- // Important: Always keep this in sync with the definitions for Integers and heap objects in Value
- static const quint64 ArrayIndexMask = 0x3800000000000ull;
- enum {
- IsManagedOrUndefined_Shift = 64-15,
- };
- inline bool isManaged() const { return (val >> IsManagedOrUndefined_Shift) == 0; }
- inline quint32 value() const { return val & quint64(~quint32(0)); }
+ inline bool isManaged() const { return val.isManaged(); }
+ inline quint32 value() const { return val.value(); }
-#if QT_POINTER_SIZE == 8
- QML_NEARLY_ALWAYS_INLINE Heap::StringOrSymbol *m() const
+public:
+ static PropertyKey invalid()
{
- Heap::StringOrSymbol *b;
- memcpy(&b, &val, 8);
- return b;
+ PropertyKey key;
+ key.val = StaticValue::undefinedValue();
+ return key;
}
- QML_NEARLY_ALWAYS_INLINE void setM(Heap::StringOrSymbol *b)
+
+ static PropertyKey fromArrayIndex(uint idx)
{
- memcpy(&val, &b, 8);
+ PropertyKey key;
+ key.val.setInt_32(idx);
+ return key;
}
-#elif QT_POINTER_SIZE == 4
- QML_NEARLY_ALWAYS_INLINE Heap::StringOrSymbol *m() const
+
+ bool isStringOrSymbol() const { return isManaged(); }
+ uint asArrayIndex() const
{
- Q_STATIC_ASSERT(sizeof(Heap::StringOrSymbol*) == sizeof(quint32));
- Heap::StringOrSymbol *b;
- quint32 v = value();
- memcpy(&b, &v, 4);
- return b;
+ Q_ASSERT(isArrayIndex());
+ return value();
}
- QML_NEARLY_ALWAYS_INLINE void setM(Heap::StringOrSymbol *b)
+
+ bool isArrayIndex() const { return val.isInteger(); }
+ bool isValid() const { return !val.isUndefined(); }
+
+ // We cannot #include the declaration of Heap::StringOrSymbol here.
+ // Therefore we do some gymnastics to enforce the type safety.
+
+ template<typename StringOrSymbol = Heap::StringOrSymbol, typename Engine = QV4::EngineBase>
+ static PropertyKey fromStringOrSymbol(Engine *engine, StringOrSymbol *b)
{
- quint32 v;
- memcpy(&v, &b, 4);
- val = v;
+ static_assert(std::is_base_of_v<Heap::StringOrSymbol, StringOrSymbol>);
+ PropertyKey key;
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) {
+ if constexpr (QV4::WriteBarrier::isInsertionBarrier) {
+ // treat this as an insertion - the StringOrSymbol becomes reachable
+ // via the propertykey, so we consequently need to mark it durnig gc
+ b->mark(stack);
+ }
+ });
+ key.val.setM(b);
+ Q_ASSERT(key.isManaged());
+ return key;
}
-#endif
-public:
- static PropertyKey invalid() { PropertyKey key; key.val = 0; return key; }
- static PropertyKey fromArrayIndex(uint idx) { PropertyKey key; key.val = ArrayIndexMask | static_cast<quint64>(idx); return key; }
- bool isStringOrSymbol() const { return isManaged() && val != 0; }
- uint asArrayIndex() const { Q_ASSERT(isArrayIndex()); return static_cast<uint>(val & 0xffffffff); }
- uint isArrayIndex() const { return !isManaged() && val != 0; }
- bool isValid() const { return val != 0; }
- static PropertyKey fromStringOrSymbol(Heap::StringOrSymbol *b)
- { PropertyKey key; key.setM(b); return key; }
- Heap::StringOrSymbol *asStringOrSymbol() const {
+ template<typename StringOrSymbol = Heap::StringOrSymbol>
+ StringOrSymbol *asStringOrSymbol() const
+ {
+ static_assert(std::is_base_of_v<Heap::StringOrSymbol, StringOrSymbol>);
if (!isManaged())
return nullptr;
- return m();
+ return static_cast<StringOrSymbol *>(val.m());
}
Q_QML_EXPORT bool isString() const;
- bool isSymbol() const;
+ Q_QML_EXPORT bool isSymbol() const;
bool isCanonicalNumericIndexString() const;
Q_QML_EXPORT QString toQString() const;
Heap::StringOrSymbol *toStringOrSymbol(ExecutionEngine *e);
- quint64 id() const { return val; }
+ quint64 id() const { return val._val; }
static PropertyKey fromId(quint64 id) {
- PropertyKey key; key.val = id; return key;
+ PropertyKey key; key.val._val = id; return key;
}
enum FunctionNamePrefix {
@@ -142,9 +115,10 @@ public:
};
Heap::String *asFunctionName(ExecutionEngine *e, FunctionNamePrefix prefix) const;
- bool operator ==(const PropertyKey &other) const { return val == other.val; }
- bool operator !=(const PropertyKey &other) const { return val != other.val; }
- bool operator <(const PropertyKey &other) const { return val < other.val; }
+ bool operator ==(const PropertyKey &other) const { return val._val == other.val._val; }
+ bool operator !=(const PropertyKey &other) const { return val._val != other.val._val; }
+ bool operator <(const PropertyKey &other) const { return val._val < other.val._val; }
+ friend size_t qHash(const PropertyKey &key, size_t seed = 0) { return qHash(key.val._val, seed); }
};
}
diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp
index 9325e2e53b..109ab61059 100644
--- a/src/qml/jsruntime/qv4proxy.cpp
+++ b/src/qml/jsruntime/qv4proxy.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4proxy_p.h"
@@ -90,12 +54,15 @@ ReturnedValue ProxyObject::virtualGet(const Managed *m, PropertyKey id, const Va
if (hasProperty)
*hasProperty = true;
- JSCallData cdata(scope, 3, nullptr, handler);
- cdata.args[0] = target;
- cdata.args[1] = id.toStringOrSymbol(scope.engine);
- cdata.args[2] = *receiver;
+ Value *args = scope.alloc(3);
+ args[0] = target;
+ args[1] = id.toStringOrSymbol(scope.engine);
+ args[2] = *receiver;
+ JSCallData cdata(handler, args, 3);
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.hasException())
+ return Encode::undefined();
ScopedProperty targetDesc(scope);
PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
if (attributes != Attr_Invalid && !attributes.isConfigurable()) {
@@ -129,14 +96,15 @@ bool ProxyObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Val
if (!trap->isFunctionObject())
return scope.engine->throwTypeError();
- JSCallData cdata(scope, 4, nullptr, handler);
- cdata.args[0] = target;
- cdata.args[1] = id.toStringOrSymbol(scope.engine);
- cdata.args[2] = value;
- cdata.args[3] = *receiver;
+ Value *args = scope.alloc(4);
+ args[0] = target;
+ args[1] = id.toStringOrSymbol(scope.engine);
+ args[2] = value;
+ args[3] = *receiver;
+ JSCallData cdata(handler, args, 4);
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
- if (!trapResult->toBoolean())
+ if (scope.hasException() || !trapResult->toBoolean())
return false;
ScopedProperty targetDesc(scope);
PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
@@ -170,13 +138,14 @@ bool ProxyObject::virtualDeleteProperty(Managed *m, PropertyKey id)
if (!trap->isFunctionObject())
return scope.engine->throwTypeError();
- JSCallData cdata(scope, 3, nullptr, handler);
- cdata.args[0] = target;
- cdata.args[1] = id.toStringOrSymbol(scope.engine);
- cdata.args[2] = o->d(); // ### fix receiver handling
+ Value *args = scope.alloc(3);
+ args[0] = target;
+ args[1] = id.toStringOrSymbol(scope.engine);
+ args[2] = o->d(); // ### fix receiver handling
+ JSCallData cdata(handler, args, 3);
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
- if (!trapResult->toBoolean())
+ if (scope.hasException() || !trapResult->toBoolean())
return false;
ScopedProperty targetDesc(scope);
PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
@@ -206,11 +175,14 @@ bool ProxyObject::virtualHasProperty(const Managed *m, PropertyKey id)
if (!trap->isFunctionObject())
return scope.engine->throwTypeError();
- JSCallData cdata(scope, 2, nullptr, handler);
- cdata.args[0] = target;
- cdata.args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
+ Value *args = scope.alloc(2);
+ args[0] = target;
+ args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
+ JSCallData cdata(handler, args, 2);
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.hasException())
+ return false;
bool result = trapResult->toBoolean();
if (!result) {
ScopedProperty targetDesc(scope);
@@ -246,11 +218,14 @@ PropertyAttributes ProxyObject::virtualGetOwnProperty(const Managed *m, Property
return Attr_Invalid;
}
- JSCallData cdata(scope, 2, nullptr, handler);
- cdata.args[0] = target;
- cdata.args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
+ Value *args = scope.alloc(2);
+ args[0] = target;
+ args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
+ JSCallData cdata(handler, args, 2);
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.hasException())
+ return Attr_Invalid;
if (!trapResult->isObject() && !trapResult->isUndefined()) {
scope.engine->throwTypeError();
return Attr_Invalid;
@@ -259,9 +234,9 @@ PropertyAttributes ProxyObject::virtualGetOwnProperty(const Managed *m, Property
ScopedProperty targetDesc(scope);
PropertyAttributes targetAttributes = target->getOwnProperty(id, targetDesc);
if (trapResult->isUndefined()) {
- p->value = Encode::undefined();
- if (targetAttributes == Attr_Invalid) {
+ if (p)
p->value = Encode::undefined();
+ if (targetAttributes == Attr_Invalid) {
return Attr_Invalid;
}
if (!targetAttributes.isConfigurable() || !target->isExtensible()) {
@@ -289,8 +264,10 @@ PropertyAttributes ProxyObject::virtualGetOwnProperty(const Managed *m, Property
}
}
- p->value = resultDesc->value;
- p->set = resultDesc->set;
+ if (p) {
+ p->value = resultDesc->value;
+ p->set = resultDesc->set;
+ }
return resultAttributes;
}
@@ -317,13 +294,14 @@ bool ProxyObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Pro
return false;
}
- JSCallData cdata(scope, 3, nullptr, handler);
- cdata.args[0] = target;
- cdata.args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
- cdata.args[2] = ObjectPrototype::fromPropertyDescriptor(scope.engine, p, attrs);
+ Value *args = scope.alloc(3);
+ args[0] = target;
+ args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
+ args[2] = ObjectPrototype::fromPropertyDescriptor(scope.engine, p, attrs);
+ JSCallData cdata(handler, args, 3);
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
- bool result = trapResult->toBoolean();
+ bool result = !scope.hasException() && trapResult->toBoolean();
if (!result)
return false;
@@ -369,10 +347,13 @@ bool ProxyObject::virtualIsExtensible(const Managed *m)
if (!trap->isFunctionObject())
return scope.engine->throwTypeError();
- JSCallData cdata(scope, 1, nullptr, handler);
- cdata.args[0] = target;
+ Value *args = scope.alloc(1);
+ args[0] = target;
+ JSCallData cdata(handler, args, 1);
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.hasException())
+ return false;
bool result = trapResult->toBoolean();
if (result != target->isExtensible()) {
scope.engine->throwTypeError();
@@ -400,10 +381,13 @@ bool ProxyObject::virtualPreventExtensions(Managed *m)
if (!trap->isFunctionObject())
return scope.engine->throwTypeError();
- JSCallData cdata(scope, 1, nullptr, handler);
- cdata.args[0] = target;
+ Value *args = scope.alloc(1);
+ args[0] = target;
+ JSCallData cdata(handler, args, 1);
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.hasException())
+ return false;
bool result = trapResult->toBoolean();
if (result && target->isExtensible()) {
scope.engine->throwTypeError();
@@ -435,10 +419,13 @@ Heap::Object *ProxyObject::virtualGetPrototypeOf(const Managed *m)
return nullptr;
}
- JSCallData cdata(scope, 1, nullptr, handler);
- cdata.args[0] = target;
+ Value *args = scope.alloc(1);
+ args[0] = target;
+ JSCallData cdata(handler, args, 1);
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.hasException())
+ return nullptr;
if (!trapResult->isNull() && !trapResult->isObject()) {
scope.engine->throwTypeError();
return nullptr;
@@ -477,12 +464,13 @@ bool ProxyObject::virtualSetPrototypeOf(Managed *m, const Object *p)
return false;
}
- JSCallData cdata(scope, 2, nullptr, handler);
- cdata.args[0] = target;
- cdata.args[1] = p ? p->asReturnedValue() : Encode::null();
+ Value *args = scope.alloc(2);
+ args[0] = target;
+ args[1] = p ? p->asReturnedValue() : Encode::null();
+ JSCallData cdata(handler, args, 2);
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
- bool result = trapResult->toBoolean();
+ bool result = !scope.hasException() && trapResult->toBoolean();
if (!result)
return false;
if (!target->isExtensible()) {
@@ -515,7 +503,7 @@ ProxyObjectOwnPropertyKeyIterator::ProxyObjectOwnPropertyKeyIterator(ArrayObject
PropertyKey ProxyObjectOwnPropertyKeyIterator::next(const Object *m, Property *pd, PropertyAttributes *attrs)
{
- if (index >= len)
+ if (index >= len || m == nullptr)
return PropertyKey::invalid();
Scope scope(m);
@@ -570,9 +558,12 @@ OwnPropertyKeyIterator *ProxyObject::virtualOwnPropertyKeys(const Object *m, Val
return nullptr;
}
- JSCallData cdata(scope, 1, nullptr, handler);
- cdata.args[0] = target;
+ Value *args = scope.alloc(1);
+ args[0] = target;
+ JSCallData cdata(handler, args, 1);
ScopedObject trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.hasException())
+ return nullptr;
if (!trapResult) {
scope.engine->throwTypeError();
return nullptr;
@@ -583,7 +574,7 @@ OwnPropertyKeyIterator *ProxyObject::virtualOwnPropertyKeys(const Object *m, Val
ScopedStringOrSymbol key(scope);
for (uint i = 0; i < len; ++i) {
key = trapResult->get(i);
- if (scope.engine->hasException)
+ if (scope.hasException())
return nullptr;
if (!key) {
scope.engine->throwTypeError();
@@ -608,8 +599,10 @@ OwnPropertyKeyIterator *ProxyObject::virtualOwnPropertyKeys(const Object *m, Val
else
targetNonConfigurableKeys->push_back(keyAsValue);
}
- if (target->isExtensible() && targetNonConfigurableKeys->getLength() == 0)
+ if (target->isExtensible() && targetNonConfigurableKeys->getLength() == 0) {
+ *iteratorTarget = *m;
return new ProxyObjectOwnPropertyKeyIterator(trapKeys);
+ }
ScopedArrayObject uncheckedResultKeys(scope, scope.engine->newArrayObject());
uncheckedResultKeys->copyArrayData(trapKeys);
@@ -623,8 +616,10 @@ OwnPropertyKeyIterator *ProxyObject::virtualOwnPropertyKeys(const Object *m, Val
}
}
- if (target->isExtensible())
+ if (target->isExtensible()) {
+ *iteratorTarget = *m;
return new ProxyObjectOwnPropertyKeyIterator(trapKeys);
+ }
len = targetConfigurableKeys->getLength();
for (uint i = 0; i < len; ++i) {
@@ -699,7 +694,7 @@ ReturnedValue ProxyFunctionObject::virtualCall(const FunctionObject *f, const Va
if (scope.hasException())
return Encode::undefined();
if (trap->isNullOrUndefined())
- return target->call(thisObject, argv, argc);
+ return checkedResult(scope.engine, target->call(thisObject, argv, argc));
if (!trap->isFunctionObject())
return scope.engine->throwTypeError();
diff --git a/src/qml/jsruntime/qv4proxy_p.h b/src/qml/jsruntime/qv4proxy_p.h
index 2ccb50ece6..b3be05a11b 100644
--- a/src/qml/jsruntime/qv4proxy_p.h
+++ b/src/qml/jsruntime/qv4proxy_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4PROXY_P_H
#define QV4PROXY_P_H
diff --git a/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp b/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp
new file mode 100644
index 0000000000..13d93c7122
--- /dev/null
+++ b/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp
@@ -0,0 +1,126 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qv4qmetaobjectwrapper_p.h"
+
+#include <private/qqmlobjectorgadget_p.h>
+#include <private/qv4jscall_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+namespace QV4 {
+
+void Heap::QMetaObjectWrapper::init(const QMetaObject *metaObject)
+{
+ FunctionObject::init();
+ this->metaObject = metaObject;
+ constructors = nullptr;
+ constructorCount = 0;
+}
+
+void Heap::QMetaObjectWrapper::destroy()
+{
+ delete[] constructors;
+}
+
+void Heap::QMetaObjectWrapper::ensureConstructorsCache() {
+
+ const int count = metaObject->constructorCount();
+ if (constructorCount != count) {
+ delete[] constructors;
+ constructorCount = count;
+ if (count == 0) {
+ constructors = nullptr;
+ return;
+ }
+ constructors = new QQmlPropertyData[count];
+
+ for (int i = 0; i < count; ++i) {
+ QMetaMethod method = metaObject->constructor(i);
+ QQmlPropertyData &d = constructors[i];
+ d.load(method);
+ d.setCoreIndex(i);
+ }
+ }
+}
+
+
+ReturnedValue QMetaObjectWrapper::create(ExecutionEngine *engine, const QMetaObject* metaObject) {
+
+ Scope scope(engine);
+ Scoped<QMetaObjectWrapper> mo(scope, engine->memoryManager->allocate<QMetaObjectWrapper>(metaObject)->asReturnedValue());
+ mo->init(engine);
+ return mo->asReturnedValue();
+}
+
+void QMetaObjectWrapper::init(ExecutionEngine *) {
+ const QMetaObject & mo = *d()->metaObject;
+
+ for (int i = 0; i < mo.enumeratorCount(); i++) {
+ QMetaEnum Enum = mo.enumerator(i);
+ for (int k = 0; k < Enum.keyCount(); k++) {
+ const char* key = Enum.key(k);
+ const int value = Enum.value(k);
+ defineReadonlyProperty(QLatin1String(key), Value::fromInt32(value));
+ }
+ }
+}
+
+ReturnedValue QMetaObjectWrapper::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *)
+{
+ const QMetaObjectWrapper *This = static_cast<const QMetaObjectWrapper*>(f);
+ return This->constructInternal(argv, argc);
+}
+
+ReturnedValue QMetaObjectWrapper::constructInternal(const Value *argv, int argc) const
+{
+
+ d()->ensureConstructorsCache();
+
+ ExecutionEngine *v4 = engine();
+ const QMetaObject* mo = d()->metaObject;
+ if (d()->constructorCount == 0) {
+ return v4->throwTypeError(QLatin1String(mo->className())
+ + QLatin1String(" has no invokable constructor"));
+ }
+
+ Scope scope(v4);
+ Scoped<QObjectWrapper> object(scope);
+ JSCallData cData(nullptr, argv, argc);
+ CallData *callData = cData.callData(scope);
+
+ const QQmlObjectOrGadget objectOrGadget(mo);
+
+ if (d()->constructorCount == 1) {
+ object = QObjectMethod::callPrecise(
+ objectOrGadget, d()->constructors[0], v4, callData, QMetaObject::CreateInstance);
+ } else if (const QQmlPropertyData *ctor = QObjectMethod::resolveOverloaded(
+ objectOrGadget, d()->constructors, d()->constructorCount, v4, callData)) {
+ object = QObjectMethod::callPrecise(
+ objectOrGadget, *ctor, v4, callData, QMetaObject::CreateInstance);
+ }
+ if (object) {
+ Scoped<QMetaObjectWrapper> metaObject(scope, this);
+ object->defineDefaultProperty(v4->id_constructor(), metaObject);
+ object->setPrototypeOf(const_cast<QMetaObjectWrapper*>(this));
+ }
+
+ return object.asReturnedValue();
+}
+
+bool QMetaObjectWrapper::virtualIsEqualTo(Managed *a, Managed *b)
+{
+ const QMetaObjectWrapper *aMetaObject = a->as<QMetaObjectWrapper>();
+ Q_ASSERT(aMetaObject);
+ const QMetaObjectWrapper *bMetaObject = b->as<QMetaObjectWrapper>();
+ return bMetaObject && aMetaObject->metaObject() == bMetaObject->metaObject();
+}
+
+DEFINE_OBJECT_VTABLE(QMetaObjectWrapper);
+
+} // namespace QV4
+
+QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h b/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h
new file mode 100644
index 0000000000..063bc089e7
--- /dev/null
+++ b/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h
@@ -0,0 +1,66 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QV4QMETAOBJECTWRAPPER_P_H
+#define QV4QMETAOBJECTWRAPPER_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/qv4functionobject_p.h>
+#include <private/qv4value_p.h>
+
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlPropertyData;
+
+namespace QV4 {
+namespace Heap {
+
+struct QMetaObjectWrapper : FunctionObject {
+ const QMetaObject* metaObject;
+ QQmlPropertyData *constructors;
+ int constructorCount;
+
+ void init(const QMetaObject* metaObject);
+ void destroy();
+ void ensureConstructorsCache();
+};
+
+} // namespace Heap
+
+struct Q_QML_EXPORT QMetaObjectWrapper : public FunctionObject
+{
+ V4_OBJECT2(QMetaObjectWrapper, FunctionObject)
+ V4_NEEDS_DESTROY
+
+ static ReturnedValue create(ExecutionEngine *engine, const QMetaObject* metaObject);
+ const QMetaObject *metaObject() const { return d()->metaObject; }
+
+protected:
+ static ReturnedValue virtualCallAsConstructor(
+ const FunctionObject *, const Value *argv, int argc, const Value *);
+ static bool virtualIsEqualTo(Managed *a, Managed *b);
+
+private:
+ void init(ExecutionEngine *engine);
+ ReturnedValue constructInternal(const Value *argv, int argc) const;
+};
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4QMETAOBJECTWRAPPER_P_H
+
+
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index e2d3b98ff6..53444cddb7 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -1,97 +1,64 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4qmlcontext_p.h"
-#include <private/qqmlengine_p.h>
+#include <private/qjsvalue_p.h>
#include <private/qqmlcontext_p.h>
-
+#include <private/qqmlengine_p.h>
+#include <private/qqmlglobal_p.h>
+#include <private/qqmljavascriptexpression_p.h>
+#include <private/qqmllistwrapper_p.h>
+#include <private/qqmltypewrapper_p.h>
+#include <private/qv4compileddata_p.h>
#include <private/qv4engine_p.h>
-#include <private/qv4value_p.h>
-#include <private/qv4objectproto_p.h>
-#include <private/qv4mm_p.h>
#include <private/qv4function_p.h>
-#include <private/qv4compileddata_p.h>
-#include <private/qqmltypewrapper_p.h>
-#include <private/qqmllistwrapper_p.h>
-#include <private/qqmljavascriptexpression_p.h>
-#include <private/qjsvalue_p.h>
-#include <private/qv4qobjectwrapper_p.h>
-#include <private/qv4module_p.h>
-#include <private/qv4lookup_p.h>
#include <private/qv4identifiertable_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4mm_p.h>
+#include <private/qv4module_p.h>
+#include <private/qv4objectproto_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4stackframe_p.h>
+#include <private/qv4value_p.h>
+
+#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQmlContext, "qt.qml.context");
+
using namespace QV4;
DEFINE_OBJECT_VTABLE(QQmlContextWrapper);
DEFINE_MANAGED_VTABLE(QmlContext);
-void Heap::QQmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject)
+void Heap::QQmlContextWrapper::init(QQmlRefPointer<QQmlContextData> context, QObject *scopeObject)
{
Object::init();
- this->context = new QQmlContextDataRef(context);
+ this->context = context.take();
this->scopeObject.init(scopeObject);
}
void Heap::QQmlContextWrapper::destroy()
{
- delete context;
+ context->release();
+ context = nullptr;
scopeObject.destroy();
Object::destroy();
}
-static OptionalReturnedValue searchContextProperties(QV4::ExecutionEngine *v4, QQmlContextData *context, String *name,
- bool *hasProperty, Value *base, QV4::Lookup *lookup,
- QV4::Lookup *originalLookup, QQmlEnginePrivate *ep)
+static OptionalReturnedValue searchContextProperties(
+ QV4::ExecutionEngine *v4, const QQmlRefPointer<QQmlContextData> &context, String *name,
+ bool *hasProperty, Value *base, QV4::Lookup *lookup, QV4::Lookup *originalLookup,
+ QQmlEnginePrivate *ep)
{
- const QV4::IdentifierHash &properties = context->propertyNames();
- if (properties.count() == 0)
- return OptionalReturnedValue();
-
- const int propertyIdx = properties.value(name);
+ const int propertyIdx = context->propertyIndex(name);
if (propertyIdx == -1)
return OptionalReturnedValue();
- if (propertyIdx < context->idValueCount) {
+ if (propertyIdx < context->numIdValues()) {
if (hasProperty)
*hasProperty = true;
@@ -104,25 +71,44 @@ static OptionalReturnedValue searchContextProperties(QV4::ExecutionEngine *v4, Q
}
if (ep->propertyCapture)
- ep->propertyCapture->captureProperty(&context->idValues[propertyIdx].bindings);
- return OptionalReturnedValue(QV4::QObjectWrapper::wrap(v4, context->idValues[propertyIdx]));
+ ep->propertyCapture->captureProperty(context->idValueBindings(propertyIdx));
+ return OptionalReturnedValue(QV4::QObjectWrapper::wrap(v4, context->idValue(propertyIdx)));
}
QQmlContextPrivate *cp = context->asQQmlContextPrivate();
if (ep->propertyCapture)
- ep->propertyCapture->captureProperty(context->asQQmlContext(), -1, propertyIdx + cp->notifyIndex);
+ ep->propertyCapture->captureProperty(context->asQQmlContext(), -1, propertyIdx + cp->notifyIndex());
- const QVariant &value = cp->propertyValues.at(propertyIdx);
+ const QVariant &value = cp->propertyValue(propertyIdx);
if (hasProperty)
*hasProperty = true;
if (value.userType() == qMetaTypeId<QList<QObject*> >()) {
QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*) qintptr(propertyIdx),
QQmlContextPrivate::context_count,
QQmlContextPrivate::context_at);
- return OptionalReturnedValue(QmlListWrapper::create(v4, prop, qMetaTypeId<QQmlListProperty<QObject> >()));
+ return OptionalReturnedValue(QmlListWrapper::create(v4, prop, QMetaType::fromType<QQmlListProperty<QObject> >()));
+ }
+ return OptionalReturnedValue(v4->fromVariant(cp->propertyValue(propertyIdx)));
+}
+
+template<typename Lookup>
+bool performLookup(ScopedValue *result, bool *hasProperty, const Lookup &lookup) {
+ bool hasProp = false;
+ *result = lookup(&hasProp);
+ if (hasProp) {
+ if (hasProperty)
+ *hasProperty = hasProp;
+ return true;
}
- return OptionalReturnedValue(v4->fromVariant(cp->propertyValues.at(propertyIdx)));
+ return false;
+}
+
+static QV4::QObjectWrapper::Flags getQmlPropertyFlags(const Lookup *l)
+{
+ return (l && l->forCall)
+ ? QV4::QObjectWrapper::CheckRevision
+ : (QV4::QObjectWrapper::CheckRevision | QV4::QObjectWrapper::AttachMethods);
}
ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *resource, PropertyKey id, const Value *receiver, bool *hasProperty, Value *base, Lookup *lookup)
@@ -133,7 +119,7 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
QV4::ExecutionEngine *v4 = resource->engine();
QV4::Scope scope(v4);
- if (v4->callingQmlContext() != *resource->d()->context) {
+ if (v4->callingQmlContext().data() != resource->d()->context) {
if (resource->d()->module) {
Scoped<Module> module(scope, resource->d()->module);
bool hasProp = false;
@@ -148,18 +134,12 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
return Object::virtualGet(resource, id, receiver, hasProperty);
}
- bool hasProp = false;
- ScopedValue result(scope, Object::virtualGet(resource, id, receiver, &hasProp));
- if (hasProp) {
- if (hasProperty)
- *hasProperty = hasProp;
- return result->asReturnedValue();
- }
+ ScopedValue result(scope);
// It's possible we could delay the calculation of the "actual" context (in the case
// of sub contexts) until it is definitely needed.
- QQmlContextData *context = resource->getContext();
- QQmlContextData *expressionContext = context;
+ QQmlRefPointer<QQmlContextData> context = resource->getContext();
+ QQmlRefPointer<QQmlContextData> expressionContext = context;
if (!context) {
if (hasProperty)
@@ -179,17 +159,20 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
ScopedString name(scope, id.asStringOrSymbol());
- const auto performGobalLookUp = [&result, v4, &name, hasProperty]() {
- bool hasProp = false;
- result = v4->globalObject->get(name, &hasProp);
- if (hasProp) {
- if (hasProperty)
- *hasProperty = hasProp;
- return true;
- }
- return false;
+ const auto globalLookup = [v4, &name](bool *hasProp) {
+ return v4->globalObject->get(name, hasProp);
+ };
+
+ const auto jsLookup = [resource, &id, receiver](bool *hasProp) {
+ return Object::virtualGet(resource, id, receiver, hasProp);
};
+ const bool isJSContext = context->isJSContext();
+
+ // Do the generic JS lookup early in case of a JavaScript context.
+ if (isJSContext && performLookup(&result, hasProperty, jsLookup))
+ return result->asReturnedValue();
+
// If the scope object is a QAbstractDynamicMetaObject, then QMetaObject::indexOfProperty
// will call createProperty() on the QADMO and implicitly create the property. While that
// is questionable behavior, there are two use-cases that we support in the light of this:
@@ -204,16 +187,21 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
//
// Note: The scope object is only a QADMO for example when somebody registers a QQmlPropertyMap
// sub-class as QML type and then instantiates it in .qml.
- if (scopeObject && QQmlPropertyCache::isDynamicMetaObject(scopeObject->metaObject())) {
+ const QMetaObjectPrivate *metaObjectPrivate = scopeObject
+ ? reinterpret_cast<const QMetaObjectPrivate *>(scopeObject->metaObject()->d.data)
+ : nullptr;
+ if (metaObjectPrivate && metaObjectPrivate->flags & DynamicMetaObject) {
// all bets are off, so don't try to optimize any lookups
lookup = nullptr;
- if (performGobalLookUp())
+ if (performLookup(&result, hasProperty, globalLookup))
return result->asReturnedValue();
}
- if (context->imports && name->startsWithUpper()) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(v4->qmlEngine());
+ if (context->imports() && (name->startsWithUpper() || context->valueTypesAreAddressable())) {
// Search for attached properties, enums and imported scripts
- QQmlTypeNameCache::Result r = context->imports->query(name, QQmlImport::AllowRecursion);
+ QQmlTypeNameCache::Result r = context->imports()->query<QQmlImport::AllowRecursion>(
+ name, QQmlTypeLoader::get(ep));
if (r.isValid()) {
if (hasProperty)
@@ -224,36 +212,46 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupScript;
return lookup->qmlContextPropertyGetter(lookup, v4, base);
}
- QV4::ScopedObject scripts(scope, context->importedScripts.valueRef());
+ QV4::ScopedObject scripts(scope, context->importedScripts().valueRef());
if (scripts)
return scripts->get(r.scriptIndex);
return QV4::Encode::null();
} else if (r.type.isValid()) {
if (lookup) {
+ bool isValueSingleton = false;
if (r.type.isSingleton()) {
QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine());
if (r.type.isQObjectSingleton() || r.type.isCompositeSingleton()) {
e->singletonInstance<QObject*>(r.type);
- lookup->qmlContextSingletonLookup.singleton =
- static_cast<Heap::Object*>(
+ lookup->qmlContextSingletonLookup.singletonObject.set(v4,
Value::fromReturnedValue(
QQmlTypeWrapper::create(v4, nullptr, r.type)
).heapObject());
} else {
QJSValue singleton = e->singletonInstance<QJSValue>(r.type);
- QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, singleton));
- lookup->qmlContextSingletonLookup.singleton = o->d();
+
+ // QSrting values should already have been put on the engine heap at this point
+ // to manage their memory. We later assume this has already happened.
+ Q_ASSERT(!QJSValuePrivate::asQString(&singleton));
+
+ if (QV4::Value *val = QJSValuePrivate::takeManagedValue(&singleton)) {
+ lookup->qmlContextSingletonLookup.singletonObject.set(v4, val->heapObject());
+ } else {
+ lookup->qmlContextSingletonLookup.singletonValue = QJSValuePrivate::asReturnedValue(&singleton);
+ isValueSingleton = true;
+ }
}
- lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupSingleton;
+ lookup->qmlContextPropertyGetter = isValueSingleton ? QQmlContextWrapper::lookupValueSingleton
+ : QQmlContextWrapper::lookupSingleton;
return lookup->qmlContextPropertyGetter(lookup, v4, base);
}
}
result = QQmlTypeWrapper::create(v4, scopeObject, r.type);
} else if (r.importNamespace) {
- result = QQmlTypeWrapper::create(v4, scopeObject, context->imports, r.importNamespace);
+ result = QQmlTypeWrapper::create(v4, scopeObject, context->imports(), r.importNamespace);
}
if (lookup) {
- lookup->qmlTypeLookup.qmlTypeWrapper = static_cast<Heap::Object*>(result->heapObject());
+ lookup->qmlTypeLookup.qmlTypeWrapper.set(v4, result->heapObject());
lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupType;
}
return result->asReturnedValue();
@@ -262,44 +260,79 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
// Fall through
}
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(v4->qmlEngine());
Lookup * const originalLookup = lookup;
decltype(lookup->qmlContextPropertyGetter) contextGetterFunction = QQmlContextWrapper::lookupContextObjectProperty;
// minor optimization so we don't potentially try two property lookups on the same object
- if (scopeObject == context->contextObject) {
+ if (scopeObject == context->contextObject()) {
scopeObject = nullptr;
contextGetterFunction = QQmlContextWrapper::lookupScopeObjectProperty;
}
+ QQmlRefPointer<QQmlContextData> outer = context;
while (context) {
- if (auto property = searchContextProperties(v4, context, name, hasProperty, base, lookup, originalLookup, ep))
- return *property;
+ if (outer == context) {
+ if (auto property = searchContextProperties(
+ v4, context, name, hasProperty, base, lookup, originalLookup, ep)) {
+ return *property;
+ }
+
+ outer = outer->parent();
+
+ if (const auto cu = context->typeCompilationUnit(); cu && cu->componentsAreBound()) {
+ // If components are bound in this CU, we can search the whole context hierarchy
+ // of the file. Bound components' contexts override their local properties.
+ // You also can't instantiate bound components outside of their creation
+ // context. Therefore this is safe.
+
+ for (;
+ outer && outer->typeCompilationUnit() == cu;
+ outer = outer->parent()) {
+ if (auto property = searchContextProperties(
+ v4, outer, name, hasProperty, base,
+ nullptr, originalLookup, ep)) {
+ return *property;
+ }
+ }
+ }
+ }
// Search scope object
if (scopeObject) {
bool hasProp = false;
- QQmlPropertyData *propertyData = nullptr;
- QV4::ScopedValue result(scope, QV4::QObjectWrapper::getQmlProperty(v4, context, scopeObject,
- name, QV4::QObjectWrapper::CheckRevision, &hasProp, &propertyData));
+ const QQmlPropertyData *propertyData = nullptr;
+
+ QV4::ScopedObject wrapper(scope, QV4::QObjectWrapper::wrap(v4, scopeObject));
+ QV4::ScopedValue result(scope, QV4::QObjectWrapper::getQmlProperty(
+ v4, context, wrapper->d(), scopeObject, name,
+ getQmlPropertyFlags(lookup), &hasProp, &propertyData));
if (hasProp) {
if (hasProperty)
*hasProperty = true;
if (base)
- *base = QV4::QObjectWrapper::wrap(v4, scopeObject);
+ *base = wrapper;
if (lookup && propertyData) {
QQmlData *ddata = QQmlData::get(scopeObject, false);
if (ddata && ddata->propertyCache) {
- ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, scopeObject)));
- const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue());
- lookup->qobjectLookup.ic = That->internalClass();
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = propertyData;
- lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupScopeObjectProperty;
+ ScopedValue val(
+ scope,
+ base ? *base : Value::fromReturnedValue(
+ QV4::QObjectWrapper::wrap(v4, scopeObject)));
+ if (QObjectMethod *method = result->as<QObjectMethod>()) {
+ QV4::setupQObjectMethodLookup(
+ lookup, ddata, propertyData, val->objectValue(),
+ method->d());
+ lookup->qmlContextPropertyGetter
+ = QQmlContextWrapper::lookupScopeObjectMethod;
+ } else {
+ QV4::setupQObjectLookup(
+ lookup, ddata, propertyData, val->objectValue());
+ lookup->qmlContextPropertyGetter
+ = QQmlContextWrapper::lookupScopeObjectProperty;
+ }
}
}
@@ -310,28 +343,41 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
// Search context object
- if (context->contextObject) {
+ if (QObject *contextObject = context->contextObject()) {
bool hasProp = false;
- QQmlPropertyData *propertyData = nullptr;
- result = QV4::QObjectWrapper::getQmlProperty(v4, context, context->contextObject,
- name, QV4::QObjectWrapper::CheckRevision, &hasProp, &propertyData);
+ const QQmlPropertyData *propertyData = nullptr;
+ QV4::ScopedObject wrapper(scope, QV4::QObjectWrapper::wrap(v4, contextObject));
+ result = QV4::QObjectWrapper::getQmlProperty(
+ v4, context, wrapper->d(), contextObject, name, getQmlPropertyFlags(lookup),
+ &hasProp, &propertyData);
if (hasProp) {
if (hasProperty)
*hasProperty = true;
if (base)
- *base = QV4::QObjectWrapper::wrap(v4, context->contextObject);
+ *base = wrapper;
if (propertyData) {
if (lookup) {
- QQmlData *ddata = QQmlData::get(context->contextObject, false);
- if (ddata && ddata->propertyCache) {
- ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject)));
- const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue());
- lookup->qobjectLookup.ic = That->internalClass();
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = propertyData;
- lookup->qmlContextPropertyGetter = contextGetterFunction;
+ QQmlData *ddata = QQmlData::get(contextObject, false);
+ if (ddata && ddata->propertyCache
+ && lookup->qmlContextPropertyGetter != contextGetterFunction) {
+ ScopedValue val(
+ scope,
+ base ? *base : Value::fromReturnedValue(
+ QV4::QObjectWrapper::wrap(v4, contextObject)));
+ if (QObjectMethod *method = result->as<QObjectMethod>()) {
+ setupQObjectMethodLookup(
+ lookup, ddata, propertyData, val->objectValue(),
+ method->d());
+ if (contextGetterFunction == lookupScopeObjectProperty)
+ lookup->qmlContextPropertyGetter = lookupScopeObjectMethod;
+ else
+ lookup->qmlContextPropertyGetter = lookupContextObjectMethod;
+ } else {
+ setupQObjectLookup(
+ lookup, ddata, propertyData, val->objectValue());
+ lookup->qmlContextPropertyGetter = contextGetterFunction;
+ }
}
} else if (originalLookup) {
originalLookup->qmlContextPropertyGetter = lookupInParentContextHierarchy;
@@ -342,13 +388,18 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
}
}
- context = context->parent;
+ context = context->parent();
// As the hierarchy of contexts is not stable, we can't do accelerated lookups beyond
// the immediate QML context (of the .qml file).
lookup = nullptr;
}
+ // Do the generic JS lookup late in case of a non-JavaScript context.
+ // The scope, context, types etc should be able to override it.
+ if (!isJSContext && performLookup(&result, hasProperty, jsLookup))
+ return result->asReturnedValue();
+
// Do a lookup in the global object here to avoid expressionContext->unresolvedNames becoming
// true if we access properties of the global object.
if (originalLookup) {
@@ -366,11 +417,11 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
}
lookup->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
} else {
- if (performGobalLookUp())
+ if (performLookup(&result, hasProperty, globalLookup))
return result->asReturnedValue();
}
- expressionContext->unresolvedNames = true;
+ expressionContext->setUnresolvedNames(true);
return Encode::undefined();
}
@@ -402,8 +453,8 @@ bool QQmlContextWrapper::virtualPut(Managed *m, PropertyKey id, const Value &val
// It's possible we could delay the calculation of the "actual" context (in the case
// of sub contexts) until it is definitely needed.
- QQmlContextData *context = wrapper->getContext();
- QQmlContextData *expressionContext = context;
+ QQmlRefPointer<QQmlContextData> context = wrapper->getContext();
+ QQmlRefPointer<QQmlContextData> expressionContext = context;
if (!context)
return false;
@@ -414,17 +465,13 @@ bool QQmlContextWrapper::virtualPut(Managed *m, PropertyKey id, const Value &val
ScopedString name(scope, id.asStringOrSymbol());
while (context) {
- const QV4::IdentifierHash &properties = context->propertyNames();
// Search context properties
- if (properties.count()) {
- const int propertyIndex = properties.value(name);
- if (propertyIndex != -1) {
- if (propertyIndex < context->idValueCount) {
- v4->throwError(QLatin1String("left-hand side of assignment operator is not an lvalue"));
- return false;
- }
+ if (const int propertyIndex = context->propertyIndex(name); propertyIndex != -1) {
+ if (propertyIndex < context->numIdValues()) {
+ v4->throwError(QLatin1String("left-hand side of assignment operator is not an lvalue"));
return false;
}
+ return false;
}
// Search scope object
@@ -434,14 +481,15 @@ bool QQmlContextWrapper::virtualPut(Managed *m, PropertyKey id, const Value &val
scopeObject = nullptr;
// Search context object
- if (context->contextObject &&
- QV4::QObjectWrapper::setQmlProperty(v4, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, value))
+ if (context->contextObject() &&
+ QV4::QObjectWrapper::setQmlProperty(v4, context, context->contextObject(), name,
+ QV4::QObjectWrapper::CheckRevision, value))
return true;
- context = context->parent;
+ context = context->parent();
}
- expressionContext->unresolvedNames = true;
+ expressionContext->setUnresolvedNames(true);
QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
QLatin1Char('"');
@@ -452,8 +500,9 @@ bool QQmlContextWrapper::virtualPut(Managed *m, PropertyKey id, const Value &val
ReturnedValue QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(Lookup *l, ExecutionEngine *engine, Value *base)
{
Scope scope(engine);
- PropertyKey name =engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->
- runtimeStrings[l->nameIndex]);
+ auto *func = engine->currentStackFrame->v4Function;
+ ScopedPropertyKey name(scope, engine->identifierTable->asPropertyKey(
+ func->compilationUnit->runtimeStrings[l->nameIndex]));
// Special hack for bounded signal expressions, where the parameters of signals are injected
// into the handler expression through the locals of the call context. So for onClicked: { ... }
@@ -462,13 +511,26 @@ ReturnedValue QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(Lookup *
for (Heap::ExecutionContext *ctx = engine->currentContext()->d(); ctx; ctx = ctx->outer) {
if (ctx->type == Heap::ExecutionContext::Type_CallContext) {
const uint index = ctx->internalClass->indexOfValueOrGetter(name);
- if (index < std::numeric_limits<uint>::max())
+ if (index < std::numeric_limits<uint>::max()) {
+ if (!func->detectedInjectedParameters) {
+ const auto location = func->sourceLocation();
+ qCWarning(lcQmlContext).nospace().noquote()
+ << location.sourceFile << ":" << location.line << ":" << location.column
+ << " Parameter \"" << name->toQString() << "\" is not declared."
+ << " Injection of parameters into signal handlers is deprecated."
+ << " Use JavaScript functions with formal parameters instead.";
+
+ // Don't warn over and over for the same function
+ func->detectedInjectedParameters = true;
+ }
+
return static_cast<Heap::CallContext *>(ctx)->locals[index].asReturnedValue();
+ }
}
- // Skip only block contexts within the current call context.
+ // Skip only block and call contexts.
// Other contexts need a regular QML property lookup. See below.
- if (ctx->type != Heap::ExecutionContext::Type_BlockContext)
+ if (ctx->type != Heap::ExecutionContext::Type_BlockContext && ctx->type != Heap::ExecutionContext::Type_CallContext)
break;
}
@@ -478,8 +540,8 @@ ReturnedValue QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(Lookup *
Scoped<QmlContext> callingQmlContext(scope, engine->qmlContext());
if (callingQmlContext) {
Scoped<QQmlContextWrapper> qmlContextWrapper(scope, callingQmlContext->d()->qml());
- result = QQmlContextWrapper::getPropertyAndBase(qmlContextWrapper, name, /*receiver*/nullptr, &hasProperty,
- base, l);
+ result = QQmlContextWrapper::getPropertyAndBase(
+ qmlContextWrapper, name, /*receiver*/nullptr, &hasProperty, base, l);
} else {
// Code path typical to worker scripts, compiled with lookups but no qml context.
result = l->resolveGlobalGetter(engine);
@@ -490,23 +552,23 @@ ReturnedValue QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(Lookup *
}
}
if (!hasProperty)
- return engine->throwReferenceError(name.toQString());
+ return engine->throwReferenceError(name->toQString());
return result->asReturnedValue();
}
ReturnedValue QQmlContextWrapper::lookupScript(Lookup *l, ExecutionEngine *engine, Value *base)
{
- Q_UNUSED(base)
+ Q_UNUSED(base);
Scope scope(engine);
Scoped<QmlContext> qmlContext(scope, engine->qmlContext());
if (!qmlContext)
return QV4::Encode::null();
- QQmlContextData *context = qmlContext->qmlContext();
+ QQmlRefPointer<QQmlContextData> context = qmlContext->qmlContext();
if (!context)
return QV4::Encode::null();
- QV4::ScopedObject scripts(scope, context->importedScripts.valueRef());
+ QV4::ScopedObject scripts(scope, context->importedScripts().valueRef());
if (!scripts)
return QV4::Encode::null();
return scripts->get(l->qmlContextScriptLookup.scriptIndex);
@@ -514,20 +576,30 @@ ReturnedValue QQmlContextWrapper::lookupScript(Lookup *l, ExecutionEngine *engin
ReturnedValue QQmlContextWrapper::lookupSingleton(Lookup *l, ExecutionEngine *engine, Value *base)
{
- Q_UNUSED(engine)
- Q_UNUSED(base)
- return Value::fromHeapObject(l->qmlContextSingletonLookup.singleton).asReturnedValue();
+ Q_UNUSED(engine);
+ Q_UNUSED(base);
+
+ return l->qmlContextSingletonLookup.singletonObject->asReturnedValue();
+}
+
+ReturnedValue QQmlContextWrapper::lookupValueSingleton(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(base);
+
+ Q_ASSERT(l->qmlContextSingletonLookup.singletonObject == nullptr);
+ return l->qmlContextSingletonLookup.singletonValue;
}
ReturnedValue QQmlContextWrapper::lookupIdObject(Lookup *l, ExecutionEngine *engine, Value *base)
{
- Q_UNUSED(base)
+ Q_UNUSED(base);
Scope scope(engine);
Scoped<QmlContext> qmlContext(scope, engine->qmlContext());
if (!qmlContext)
return QV4::Encode::null();
- QQmlContextData *context = qmlContext->qmlContext();
+ QQmlRefPointer<QQmlContextData> context = qmlContext->qmlContext();
if (!context)
return QV4::Encode::null();
@@ -535,12 +607,35 @@ ReturnedValue QQmlContextWrapper::lookupIdObject(Lookup *l, ExecutionEngine *eng
const int objectId = l->qmlContextIdObjectLookup.objectId;
if (qmlEngine->propertyCapture)
- qmlEngine->propertyCapture->captureProperty(&context->idValues[objectId].bindings);
+ qmlEngine->propertyCapture->captureProperty(context->idValueBindings(objectId));
- return QV4::QObjectWrapper::wrap(engine, context->idValues[objectId]);
+ return QV4::QObjectWrapper::wrap(engine, context->idValue(objectId));
}
-ReturnedValue QQmlContextWrapper::lookupScopeObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base)
+ReturnedValue QQmlContextWrapper::lookupIdObjectInParentContext(
+ Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ return QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(l, engine, base);
+}
+
+static ReturnedValue revertObjectPropertyLookup(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ l->qobjectLookup.propertyCache->release();
+ l->qobjectLookup.propertyCache = nullptr;
+ l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
+ return QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(l, engine, base);
+}
+
+static ReturnedValue revertObjectMethodLookup(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ l->qobjectMethodLookup.propertyCache->release();
+ l->qobjectMethodLookup.propertyCache = nullptr;
+ l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
+ return QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(l, engine, base);
+}
+
+template<typename Call>
+ReturnedValue callWithScopeObject(ExecutionEngine *engine, Value *base, Call c)
{
Scope scope(engine);
Scoped<QmlContext> qmlContext(scope, engine->qmlContext());
@@ -554,52 +649,94 @@ ReturnedValue QQmlContextWrapper::lookupScopeObjectProperty(Lookup *l, Execution
if (QQmlData::wasDeleted(scopeObject))
return QV4::Encode::undefined();
- const auto revertLookup = [l, engine, base]() {
- l->qobjectLookup.propertyCache->release();
- l->qobjectLookup.propertyCache = nullptr;
- l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
- return QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(l, engine, base);
- };
-
ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, scopeObject));
if (base)
*base = obj;
- return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup);
+ return c(obj);
}
-ReturnedValue QQmlContextWrapper::lookupContextObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base)
+ReturnedValue QQmlContextWrapper::lookupScopeObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ return callWithScopeObject(engine, base, [l, engine, base](const Value &obj) {
+ const QObjectWrapper::Flags flags = l->forCall
+ ? QObjectWrapper::NoFlag
+ : QObjectWrapper::AttachMethods;
+ return QObjectWrapper::lookupPropertyGetterImpl(l, engine, obj, flags, [l, engine, base]() {
+ return revertObjectPropertyLookup(l, engine, base);
+ });
+ });
+}
+
+ReturnedValue QQmlContextWrapper::lookupScopeObjectMethod(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ return callWithScopeObject(engine, base, [l, engine, base](const Value &obj) {
+ const QObjectWrapper::Flags flags = l->forCall
+ ? QObjectWrapper::NoFlag
+ : QObjectWrapper::AttachMethods;
+ return QObjectWrapper::lookupMethodGetterImpl(l, engine, obj, flags, [l, engine, base]() {
+ return revertObjectMethodLookup(l, engine, base);
+ });
+ });
+}
+
+template<typename Call>
+ReturnedValue callWithContextObject(ExecutionEngine *engine, Value *base, Call c)
{
Scope scope(engine);
Scoped<QmlContext> qmlContext(scope, engine->qmlContext());
if (!qmlContext)
return QV4::Encode::undefined();
- QQmlContextData *context = qmlContext->qmlContext();
+ QQmlRefPointer<QQmlContextData> context = qmlContext->qmlContext();
if (!context)
return QV4::Encode::undefined();
- QObject *contextObject = context->contextObject;
+ QObject *contextObject = context->contextObject();
if (!contextObject)
return QV4::Encode::undefined();
if (QQmlData::wasDeleted(contextObject))
return QV4::Encode::undefined();
- const auto revertLookup = [l, engine, base]() {
- l->qobjectLookup.propertyCache->release();
- l->qobjectLookup.propertyCache = nullptr;
- l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
- return QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(l, engine, base);
- };
-
ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, contextObject));
if (base)
*base = obj;
- return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup);
+ return c(obj);
+}
+
+ReturnedValue QQmlContextWrapper::lookupContextObjectProperty(
+ Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ return callWithContextObject(engine, base, [l, engine, base](const Value &obj) {
+ const QObjectWrapper::Flags flags = l->forCall
+ ? QObjectWrapper::NoFlag
+ : QObjectWrapper::AttachMethods;
+ return QObjectWrapper::lookupPropertyGetterImpl(l, engine, obj, flags, [l, engine, base]() {
+ return revertObjectPropertyLookup(l, engine, base);
+ });
+ });
+}
+
+ReturnedValue QQmlContextWrapper::lookupContextObjectMethod(
+ Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ return callWithContextObject(engine, base, [l, engine, base](const Value &obj) {
+ const QObjectWrapper::Flags flags = l->forCall
+ ? QObjectWrapper::NoFlag
+ : QObjectWrapper::AttachMethods;
+ return QObjectWrapper::lookupMethodGetterImpl(l, engine, obj, flags, [l, engine, base]() {
+ return revertObjectMethodLookup(l, engine, base);
+ });
+ });
+}
+
+ReturnedValue QQmlContextWrapper::lookupScopeFallbackProperty(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ return resolveQmlContextPropertyLookupGetter(l, engine, base);
}
ReturnedValue QQmlContextWrapper::lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base)
@@ -621,11 +758,11 @@ ReturnedValue QQmlContextWrapper::lookupInParentContextHierarchy(Lookup *l, Exec
if (!qmlContext)
return QV4::Encode::undefined();
- QQmlContextData *context = qmlContext->qmlContext();
+ QQmlRefPointer<QQmlContextData> context = qmlContext->qmlContext();
if (!context)
return QV4::Encode::undefined();
- QQmlContextData *expressionContext = context;
+ QQmlRefPointer<QQmlContextData> expressionContext = context;
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->qmlEngine());
@@ -635,18 +772,20 @@ ReturnedValue QQmlContextWrapper::lookupInParentContextHierarchy(Lookup *l, Exec
ScopedValue result(scope);
- for (context = context->parent; context; context = context->parent) {
+ for (context = context->parent(); context; context = context->parent()) {
if (auto property = searchContextProperties(engine, context, name, nullptr, base, nullptr, nullptr, ep))
return *property;
// Search context object
- if (context->contextObject) {
+ if (QObject *contextObject = context->contextObject()) {
bool hasProp = false;
- result = QV4::QObjectWrapper::getQmlProperty(engine, context, context->contextObject,
- name, QV4::QObjectWrapper::CheckRevision, &hasProp);
+ QV4::ScopedObject wrapper(scope, QV4::QObjectWrapper::wrap(engine, contextObject));
+ result = QV4::QObjectWrapper::getQmlProperty(
+ engine, context, wrapper->d(), contextObject, name, getQmlPropertyFlags(l),
+ &hasProp);
if (hasProp) {
if (base)
- *base = QV4::QObjectWrapper::wrap(engine, context->contextObject);
+ *base = wrapper;
return result->asReturnedValue();
}
@@ -658,7 +797,7 @@ ReturnedValue QQmlContextWrapper::lookupInParentContextHierarchy(Lookup *l, Exec
if (hasProp)
return result->asReturnedValue();
- expressionContext->unresolvedNames = true;
+ expressionContext->setUnresolvedNames(true);
return Encode::undefined();
}
@@ -674,9 +813,9 @@ ReturnedValue QQmlContextWrapper::lookupType(Lookup *l, ExecutionEngine *engine,
if (scopeObject && QQmlData::wasDeleted(scopeObject))
return QV4::Encode::undefined();
- Heap::Object *heapObject = l->qmlTypeLookup.qmlTypeWrapper;
+ Heap::Base *heapObject = l->qmlTypeLookup.qmlTypeWrapper;
if (static_cast<Heap::QQmlTypeWrapper *>(heapObject)->object != scopeObject) {
- l->qmlTypeLookup.qmlTypeWrapper = nullptr;
+ l->qmlTypeLookup.qmlTypeWrapper.clear();
l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
return QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(l, engine, base);
}
@@ -692,11 +831,15 @@ void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContex
this->activation.set(internalClass->engine, qml->d());
}
-Heap::QmlContext *QmlContext::create(ExecutionContext *parent, QQmlContextData *context, QObject *scopeObject)
+Heap::QmlContext *QmlContext::create(
+ ExecutionContext *parent, QQmlRefPointer<QQmlContextData> context,
+ QObject *scopeObject)
{
Scope scope(parent);
- Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocate<QQmlContextWrapper>(context, scopeObject));
+ Scoped<QQmlContextWrapper> qml(
+ scope, scope.engine->memoryManager->allocate<QQmlContextWrapper>(
+ std::move(context), scopeObject));
Heap::QmlContext *c = scope.engine->memoryManager->alloc<QmlContext>(parent, qml);
Q_ASSERT(c->vtable() == staticVTable());
return c;
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index e3e7239fe5..1b337d4c0e 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4QMLCONTEXT_P_H
#define QV4QMLCONTEXT_P_H
@@ -51,12 +15,12 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <private/qqmlcontextdata_p.h>
#include <private/qtqmlglobal_p.h>
-
-#include <private/qv4object_p.h>
#include <private/qv4context_p.h>
-#include <private/qqmlcontext_p.h>
+#include <private/qv4object_p.h>
+
+#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
@@ -70,19 +34,20 @@ namespace Heap {
Member(class, Pointer, Module *, module)
DECLARE_HEAP_OBJECT(QQmlContextWrapper, Object) {
- DECLARE_MARKOBJECTS(QQmlContextWrapper);
+ DECLARE_MARKOBJECTS(QQmlContextWrapper)
- void init(QQmlContextData *context, QObject *scopeObject);
+ void init(QQmlRefPointer<QQmlContextData> context, QObject *scopeObject);
void destroy();
- QQmlContextDataRef *context;
- QQmlQPointer<QObject> scopeObject;
+ // This has to be a plain pointer because object needs to be a POD type.
+ QQmlContextData *context;
+ QV4QPointer<QObject> scopeObject;
};
#define QmlContextMembers(class, Member)
DECLARE_HEAP_OBJECT(QmlContext, ExecutionContext) {
- DECLARE_MARKOBJECTS(QmlContext);
+ DECLARE_MARKOBJECTS(QmlContext)
QQmlContextWrapper *qml() { return static_cast<QQmlContextWrapper *>(activation.get()); }
void init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml);
@@ -97,7 +62,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object
V4_INTERNALCLASS(QmlContextWrapper)
inline QObject *getScopeObject() const { return d()->scopeObject; }
- inline QQmlContextData *getContext() const { return *d()->context; }
+ inline QQmlRefPointer<QQmlContextData> getContext() const { return d()->context; }
static ReturnedValue getPropertyAndBase(const QQmlContextWrapper *resource, PropertyKey id, const Value *receiver,
bool *hasProperty, Value *base, Lookup *lookup = nullptr);
@@ -107,9 +72,14 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object
static ReturnedValue resolveQmlContextPropertyLookupGetter(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupScript(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupSingleton(Lookup *l, ExecutionEngine *engine, Value *base);
+ static ReturnedValue lookupValueSingleton(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupIdObject(Lookup *l, ExecutionEngine *engine, Value *base);
+ static ReturnedValue lookupIdObjectInParentContext(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupScopeObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base);
+ static ReturnedValue lookupScopeObjectMethod(Lookup *l, ExecutionEngine *engine, Value *base);
+ static ReturnedValue lookupScopeFallbackProperty(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupContextObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base);
+ static ReturnedValue lookupContextObjectMethod(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupInParentContextHierarchy(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupType(Lookup *l, ExecutionEngine *engine, Value *base);
@@ -120,13 +90,16 @@ struct Q_QML_EXPORT QmlContext : public ExecutionContext
V4_MANAGED(QmlContext, ExecutionContext)
V4_INTERNALCLASS(QmlContext)
- static Heap::QmlContext *create(QV4::ExecutionContext *parent, QQmlContextData *context, QObject *scopeObject);
+ static Heap::QmlContext *create(
+ QV4::ExecutionContext *parent, QQmlRefPointer<QQmlContextData> context,
+ QObject *scopeObject);
QObject *qmlScope() const {
return d()->qml()->scopeObject;
}
- QQmlContextData *qmlContext() const {
- return *d()->qml()->context;
+
+ QQmlRefPointer<QQmlContextData> qmlContext() const {
+ return d()->qml()->context;
}
};
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 2b5e8bd2b9..5f85aae89e 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1,45 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4qobjectwrapper_p.h"
-#include <private/qqmlstaticmetaobject_p.h>
+#include <private/qqmlobjectorgadget_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlbinding_p.h>
@@ -50,6 +14,9 @@
#include <private/qqmlvaluetypewrapper_p.h>
#include <private/qqmllistwrapper_p.h>
#include <private/qqmlbuiltinfunctions_p.h>
+#if QT_CONFIG(qml_locale)
+#include <private/qqmllocale_p.h>
+#endif
#include <private/qv4arraybuffer_p.h>
#include <private/qv4functionobject_p.h>
@@ -58,11 +25,7 @@
#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>
-#endif
-
#include <private/qv4objectproto_p.h>
#include <private/qv4jsonobject_p.h>
#include <private/qv4regexpobject_p.h>
@@ -72,6 +35,9 @@
#include <private/qv4mm_p.h>
#include <private/qqmlscriptstring_p.h>
#include <private/qv4compileddata_p.h>
+#include <private/qqmlpropertybinding_p.h>
+#include <private/qqmlpropertycachemethodarguments_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <QtQml/qjsvalue.h>
#include <QtCore/qjsonarray.h>
@@ -85,24 +51,32 @@
#include <QtCore/qabstractitemmodel.h>
#endif
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qqueue.h>
+#include <QtCore/qtypes.h>
#include <vector>
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
+Q_LOGGING_CATEGORY(lcObjectConnect, "qt.qml.object.connect", QtWarningMsg)
+Q_LOGGING_CATEGORY(lcOverloadResolution, "qt.qml.overloadresolution", QtWarningMsg)
+Q_LOGGING_CATEGORY(lcMethodBehavior, "qt.qml.method.behavior")
+Q_LOGGING_CATEGORY(lcSignalHandler, "qt.qml.signalhandler")
// The code in this file does not violate strict aliasing, but GCC thinks it does
// so turn off the warnings for us to have a clean build
QT_WARNING_DISABLE_GCC("-Wstrict-aliasing")
-using namespace QV4;
+using namespace Qt::StringLiterals;
+
+namespace QV4 {
-QPair<QObject *, int> QObjectMethod::extractQtMethod(const QV4::FunctionObject *function)
+QPair<QObject *, int> QObjectMethod::extractQtMethod(const FunctionObject *function)
{
- QV4::ExecutionEngine *v4 = function->engine();
+ ExecutionEngine *v4 = function->engine();
if (v4) {
- QV4::Scope scope(v4);
- QV4::Scoped<QObjectMethod> method(scope, function->as<QObjectMethod>());
+ Scope scope(v4);
+ Scoped<QObjectMethod> method(scope, function->as<QObjectMethod>());
if (method)
return qMakePair(method->object(), method->methodIndex());
}
@@ -110,16 +84,16 @@ QPair<QObject *, int> QObjectMethod::extractQtMethod(const QV4::FunctionObject *
return qMakePair((QObject *)nullptr, -1);
}
-static QPair<QObject *, int> extractQtSignal(const QV4::Value &value)
+static QPair<QObject *, int> extractQtSignal(const Value &value)
{
if (value.isObject()) {
- QV4::ExecutionEngine *v4 = value.as<QV4::Object>()->engine();
- QV4::Scope scope(v4);
- QV4::ScopedFunctionObject function(scope, value);
+ ExecutionEngine *v4 = value.as<Object>()->engine();
+ Scope scope(v4);
+ ScopedFunctionObject function(scope, value);
if (function)
return QObjectMethod::extractQtMethod(function);
- QV4::Scoped<QV4::QmlSignalHandler> handler(scope, value);
+ Scoped<QmlSignalHandler> handler(scope, value);
if (handler)
return qMakePair(handler->object(), handler->signalIndex());
}
@@ -127,83 +101,223 @@ static QPair<QObject *, int> extractQtSignal(const QV4::Value &value)
return qMakePair((QObject *)nullptr, -1);
}
-static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object,
- const QQmlPropertyData &property)
+static Heap::ReferenceObject::Flags referenceFlags(
+ ExecutionEngine *v4,
+ const QQmlPropertyData &property)
+{
+ Heap::ReferenceObject::Flags flags = Heap::ReferenceObject::NoFlag;
+ if (CppStackFrame *stackFrame = v4->currentStackFrame) {
+ if (stackFrame->v4Function->executableCompilationUnit()->valueTypesAreCopied())
+ flags |= Heap::ReferenceObject::EnforcesLocation;
+ }
+
+ if (property.isWritable())
+ flags |= Heap::ReferenceObject::CanWriteBack;
+
+ return flags;
+}
+
+static ReturnedValue loadProperty(
+ ExecutionEngine *v4, Heap::Object *wrapper,
+ QObject *object, const QQmlPropertyData &property)
{
Q_ASSERT(!property.isFunction());
- QV4::Scope scope(v4);
+ Scope scope(v4);
+ const QMetaType propMetaType = property.propType();
if (property.isQObject()) {
QObject *rv = nullptr;
property.readProperty(object, &rv);
- return QV4::QObjectWrapper::wrap(v4, rv);
- } else if (property.isQList()) {
- return QmlListWrapper::create(v4, object, property.coreIndex(), property.propType());
- } else if (property.propType() == QMetaType::QReal) {
- qreal v = 0;
+ if (propMetaType.flags().testFlag(QMetaType::IsConst))
+ return QObjectWrapper::wrapConst(v4, rv);
+ else
+ return QObjectWrapper::wrap(v4, rv);
+ }
+
+ if (property.isQList() && propMetaType.flags().testFlag(QMetaType::IsQmlList))
+ return QmlListWrapper::create(v4, object, property.coreIndex(), propMetaType);
+
+ const auto encodeSimple = [&](auto v) {
+ property.readProperty(object, &v);
+ return Encode(v);
+ };
+
+ const auto encodeInt = [&](auto v) {
property.readProperty(object, &v);
- return QV4::Encode(v);
- } else if (property.propType() == QMetaType::Int || property.isEnum()) {
- int v = 0;
+ return Encode(int(v));
+ };
+
+ const auto encodeDouble = [&](auto v) {
property.readProperty(object, &v);
- return QV4::Encode(v);
- } else if (property.propType() == QMetaType::Bool) {
- bool v = false;
+ return Encode(double(v));
+ };
+
+ const auto encodeDate = [&](auto v) {
property.readProperty(object, &v);
- return QV4::Encode(v);
- } else if (property.propType() == QMetaType::QString) {
- QString v;
+ return Encode(v4->newDateObject(
+ v, wrapper, property.coreIndex(), referenceFlags(scope.engine, property)));
+ };
+
+ const auto encodeString = [&](auto v) {
property.readProperty(object, &v);
return v4->newString(v)->asReturnedValue();
- } else if (property.propType() == QMetaType::UInt) {
- uint v = 0;
+ };
+
+ const auto encodeSequence = [&](QMetaSequence metaSequence) {
+ // Pass nullptr as data. It's lazy-loaded.
+ return QV4::SequencePrototype::newSequence(
+ v4, propMetaType, metaSequence, nullptr,
+ wrapper, property.coreIndex(), referenceFlags(scope.engine, property));
+ };
+
+
+ switch (property.isEnum() ? propMetaType.underlyingType().id() : propMetaType.id()) {
+ case QMetaType::UnknownType:
+ case QMetaType::Void:
+ return Encode::undefined();
+ case QMetaType::Nullptr:
+ case QMetaType::VoidStar:
+ return Encode::null();
+ case QMetaType::Int:
+ return encodeSimple(int());
+ case QMetaType::Bool:
+ return encodeSimple(bool());
+ case QMetaType::QString:
+ return encodeString(QString());
+ case QMetaType::QByteArray: {
+ QByteArray v;
property.readProperty(object, &v);
- return QV4::Encode(v);
- } else if (property.propType() == QMetaType::Float) {
- float v = 0;
+ return v4->newArrayBuffer(v)->asReturnedValue();
+ }
+ case QMetaType::QChar:
+ return encodeString(QChar());
+ case QMetaType::Char16:
+ return encodeString(char16_t());
+ case QMetaType::UInt:
+ return encodeSimple(uint());
+ case QMetaType::Float:
+ return encodeSimple(float());
+ case QMetaType::Double:
+ return encodeSimple(double());
+ case QMetaType::Short:
+ return encodeInt(short());
+ case QMetaType::UShort:
+ return encodeInt(ushort());
+ case QMetaType::Char:
+ return encodeInt(char());
+ case QMetaType::UChar:
+ return encodeInt(uchar());
+ case QMetaType::SChar:
+ return encodeInt(qint8());
+ case QMetaType::Long:
+ return encodeDouble(long());
+ case QMetaType::ULong:
+ return encodeDouble(ulong());
+ case QMetaType::LongLong:
+ return encodeDouble(qlonglong());
+ case QMetaType::ULongLong:
+ return encodeDouble(qulonglong());
+ case QMetaType::QDateTime:
+ return encodeDate(QDateTime());
+ case QMetaType::QDate:
+ return encodeDate(QDate());
+ case QMetaType::QTime:
+ return encodeDate(QTime());
+#if QT_CONFIG(regularexpression)
+ case QMetaType::QRegularExpression: {
+ QRegularExpression v;
property.readProperty(object, &v);
- return QV4::Encode(v);
- } else if (property.propType() == QMetaType::Double) {
- double v = 0;
+ return Encode(v4->newRegExpObject(v));
+ }
+#endif
+ case QMetaType::QVariantMap: {
+ QVariantMap v;
property.readProperty(object, &v);
- return QV4::Encode(v);
- } else if (property.propType() == qMetaTypeId<QJSValue>()) {
- QJSValue v;
+ return scope.engine->fromData(
+ propMetaType, &v, wrapper, property.coreIndex(), referenceFlags(v4, property));
+ }
+ case QMetaType::QJsonValue: {
+ QJsonValue v;
property.readProperty(object, &v);
- return QJSValuePrivate::convertedToValue(v4, v);
- } else if (property.isQVariant()) {
- QVariant v;
+ return QV4::JsonObject::fromJsonValue(v4, v);
+ }
+ case QMetaType::QJsonObject: {
+ QJsonObject v;
+ property.readProperty(object, &v);
+ return QV4::JsonObject::fromJsonObject(v4, v);
+ }
+ case QMetaType::QJsonArray: {
+ QJsonArray v;
+ property.readProperty(object, &v);
+ return QV4::JsonObject::fromJsonArray(v4, v);
+ }
+ case QMetaType::QStringList:
+ return encodeSequence(QMetaSequence::fromContainer<QStringList>());
+ case QMetaType::QVariantList:
+ return encodeSequence(QMetaSequence::fromContainer<QVariantList>());
+ case QMetaType::QUrl: {
+ // ### Qt7: We really want this to be a JS URL object, but that would break things.
+ QUrl v;
property.readProperty(object, &v);
+ return Encode(v4->newVariantObject(propMetaType, &v));
+ }
+ case QMetaType::QPixmap:
+ case QMetaType::QImage: {
+ // Scarce value types
+ QVariant v(propMetaType);
+ property.readProperty(object, v.data());
+ return Encode(v4->newVariantObject(propMetaType, v.constData()));
+ }
+ default:
+ break;
+ }
- if (QQmlValueTypeFactory::isValueType(v.userType())) {
- if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(v.userType()))
- return QV4::QQmlValueTypeWrapper::create(v4, object, property.coreIndex(), valueTypeMetaObject, v.userType()); // VariantReference value-type.
- }
+ if (propMetaType == QMetaType::fromType<QJSValue>()) {
+ QJSValue v;
+ property.readProperty(object, &v);
+ return QJSValuePrivate::convertToReturnedValue(v4, v);
+ }
- return scope.engine->fromVariant(v);
- } else if (QQmlValueTypeFactory::isValueType(property.propType())) {
- if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property.propType()))
- return QV4::QQmlValueTypeWrapper::create(v4, object, property.coreIndex(), valueTypeMetaObject, property.propType());
- } else {
-#if QT_CONFIG(qml_sequence_object)
- // see if it's a sequence type
- bool succeeded = false;
- QV4::ScopedValue retn(scope, QV4::SequencePrototype::newSequence(v4, property.propType(), object, property.coreIndex(), !property.isWritable(), &succeeded));
- if (succeeded)
- return retn->asReturnedValue();
-#endif
+ if (property.isQVariant()) {
+ // We have to read the property even if it's a lazy-loaded reference object.
+ // Without reading it, we wouldn't know its inner type.
+ QVariant v;
+ property.readProperty(object, &v);
+ return scope.engine->fromVariant(
+ v, wrapper, property.coreIndex(),
+ referenceFlags(scope.engine, property) | Heap::ReferenceObject::IsVariant);
}
- if (property.propType() == QMetaType::UnknownType) {
+ if (!propMetaType.isValid()) {
QMetaProperty p = object->metaObject()->property(property.coreIndex());
qWarning("QMetaProperty::read: Unable to handle unregistered datatype '%s' for property "
"'%s::%s'", p.typeName(), object->metaObject()->className(), p.name());
- return QV4::Encode::undefined();
- } else {
- QVariant v(property.propType(), (void *)nullptr);
- property.readProperty(object, v.data());
- return scope.engine->fromVariant(v);
+ return Encode::undefined();
+ }
+
+ // TODO: For historical reasons we don't enforce locations for reference objects here.
+ // Once we do, we can eager load and use the fromVariant() below.
+ // Then the extra checks for value types and sequences can be dropped.
+
+ if (QQmlMetaType::isValueType(propMetaType)) {
+ if (const QMetaObject *valueTypeMetaObject
+ = QQmlMetaType::metaObjectForValueType(propMetaType)) {
+ // Lazy loaded value type reference. Pass nullptr as data.
+ return QQmlValueTypeWrapper::create(
+ v4, nullptr, valueTypeMetaObject, propMetaType, wrapper,
+ property.coreIndex(), referenceFlags(scope.engine, property));
+ }
}
+
+ // See if it's a sequence type.
+ const QQmlType qmlType = QQmlMetaType::qmlListType(propMetaType);
+ if (qmlType.isSequentialContainer())
+ return encodeSequence(qmlType.listMetaSequence());
+
+ QVariant v(propMetaType);
+ property.readProperty(object, v.data());
+ return scope.engine->fromVariant(
+ v, wrapper, property.coreIndex(), referenceFlags(scope.engine, property));
}
void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
@@ -212,28 +326,33 @@ void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
engine->functionPrototype()->defineDefaultProperty(QStringLiteral("disconnect"), method_disconnect);
}
-QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const
+const QQmlPropertyData *QObjectWrapper::findProperty(
+ const QQmlRefPointer<QQmlContextData> &qmlContext, String *name,
+ Flags flags, QQmlPropertyData *local) const
{
- QObject *o = d()->object();
- return findProperty(engine, o, qmlContext, name, revisionMode, local);
+ return findProperty(d()->object(), qmlContext, name, flags, local);
}
-QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QObject *o, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local)
+const QQmlPropertyData *QObjectWrapper::findProperty(
+ QObject *o, const QQmlRefPointer<QQmlContextData> &qmlContext,
+ String *name, Flags flags, QQmlPropertyData *local)
{
- Q_UNUSED(revisionMode);
+ Q_UNUSED(flags);
QQmlData *ddata = QQmlData::get(o, false);
- QQmlPropertyData *result = nullptr;
+ const QQmlPropertyData *result = nullptr;
if (ddata && ddata->propertyCache)
result = ddata->propertyCache->property(name, o, qmlContext);
else
- result = QQmlPropertyCache::property(engine->jsEngine(), o, name, qmlContext, *local);
+ result = QQmlPropertyCache::property(o, name, qmlContext, local);
return result;
}
-ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property)
+ReturnedValue QObjectWrapper::getProperty(
+ ExecutionEngine *engine, Heap::Object *wrapper, QObject *object,
+ const QQmlPropertyData *property, Flags flags)
{
- QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex()));
+ QQmlData::flushPendingBinding(object, property->coreIndex());
if (property->isFunction() && !property->isVarProperty()) {
if (property->isVMEFunction()) {
@@ -245,147 +364,164 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje
ScopedContext global(scope, engine->qmlContext());
if (!global)
global = engine->rootContext();
- return QV4::QObjectMethod::create(global, object, property->coreIndex());
+ return QObjectMethod::create(
+ global, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
} else if (property->isSignalHandler()) {
QmlSignalHandler::initProto(engine);
- return engine->memoryManager->allocate<QV4::QmlSignalHandler>(object, property->coreIndex())->asReturnedValue();
+ return engine->memoryManager->allocate<QmlSignalHandler>(
+ object, property->coreIndex())->asReturnedValue();
} else {
ExecutionContext *global = engine->rootContext();
- return QV4::QObjectMethod::create(global, object, property->coreIndex());
+ return QObjectMethod::create(
+ global, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
}
}
QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr;
if (ep && ep->propertyCapture && !property->isConstant())
- ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
+ if (!property->isBindable() || ep->propertyCapture->expression->mustCaptureBindableProperty())
+ ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
if (property->isVarProperty()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
return vmemo->vmeProperty(property->coreIndex());
} else {
- return loadProperty(engine, object, *property);
+ return loadProperty(engine, wrapper, object, *property);
}
}
-static OptionalReturnedValue getDestroyOrToStringMethod(ExecutionEngine *v4, String *name, QObject *qobj, bool *hasProperty = nullptr)
+static OptionalReturnedValue getDestroyOrToStringMethod(
+ ExecutionEngine *v4, String *name, Heap::Object *qobj, bool *hasProperty = nullptr)
{
int index = 0;
if (name->equals(v4->id_destroy()))
- index = QV4::QObjectMethod::DestroyMethod;
+ index = QObjectMethod::DestroyMethod;
else if (name->equals(v4->id_toString()))
- index = QV4::QObjectMethod::ToStringMethod;
+ index = QObjectMethod::ToStringMethod;
else
return OptionalReturnedValue();
if (hasProperty)
*hasProperty = true;
ExecutionContext *global = v4->rootContext();
- return OptionalReturnedValue(QV4::QObjectMethod::create(global, qobj, index));
+ return OptionalReturnedValue(QObjectMethod::create(global, qobj, index));
}
-static OptionalReturnedValue getPropertyFromImports(ExecutionEngine *v4, String *name, QQmlContextData *qmlContext, QObject *qobj,
- bool *hasProperty = nullptr)
+static OptionalReturnedValue getPropertyFromImports(
+ ExecutionEngine *v4, String *name, const QQmlRefPointer<QQmlContextData> &qmlContext,
+ QObject *qobj, bool *hasProperty = nullptr)
{
- if (!qmlContext || !qmlContext->imports)
+ if (!qmlContext || !qmlContext->imports())
return OptionalReturnedValue();
- QQmlTypeNameCache::Result r = qmlContext->imports->query(name);
-
if (hasProperty)
*hasProperty = true;
- if (!r.isValid())
+ if (QQmlTypeLoader *typeLoader = v4->typeLoader()) {
+ QQmlTypeNameCache::Result r = qmlContext->imports()->query(name, typeLoader);
+
+ if (!r.isValid())
+ return OptionalReturnedValue();
+
+ if (r.scriptIndex != -1) {
+ return OptionalReturnedValue(Encode::undefined());
+ } else if (r.type.isValid()) {
+ return OptionalReturnedValue(
+ QQmlTypeWrapper::create(v4, qobj,r.type, Heap::QQmlTypeWrapper::ExcludeEnums));
+ } else if (r.importNamespace) {
+ return OptionalReturnedValue(QQmlTypeWrapper::create(
+ v4, qobj, qmlContext->imports(), r.importNamespace,
+ Heap::QQmlTypeWrapper::ExcludeEnums));
+ }
+ Q_UNREACHABLE_RETURN(OptionalReturnedValue());
+ } else {
return OptionalReturnedValue();
-
- if (r.scriptIndex != -1) {
- return OptionalReturnedValue(QV4::Encode::undefined());
- } else if (r.type.isValid()) {
- return OptionalReturnedValue(QQmlTypeWrapper::create(v4, qobj,r.type, Heap::QQmlTypeWrapper::ExcludeEnums));
- } else if (r.importNamespace) {
- return OptionalReturnedValue(QQmlTypeWrapper::create(v4, qobj, qmlContext->imports, r.importNamespace,
- Heap::QQmlTypeWrapper::ExcludeEnums));
}
- Q_UNREACHABLE();
- return OptionalReturnedValue();
}
-ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *name, QObjectWrapper::RevisionMode revisionMode,
- bool *hasProperty, bool includeImports) const
+ReturnedValue QObjectWrapper::getQmlProperty(
+ const QQmlRefPointer<QQmlContextData> &qmlContext, String *name,
+ QObjectWrapper::Flags flags, bool *hasProperty) const
{
// Keep this code in sync with ::virtualResolveLookupGetter
if (QQmlData::wasDeleted(d()->object())) {
if (hasProperty)
*hasProperty = false;
- return QV4::Encode::undefined();
+ return Encode::undefined();
}
ExecutionEngine *v4 = engine();
- if (auto methodValue = getDestroyOrToStringMethod(v4, name, d()->object(), hasProperty))
+ if (auto methodValue = getDestroyOrToStringMethod(v4, name, d(), hasProperty))
return *methodValue;
QQmlPropertyData local;
- QQmlPropertyData *result = findProperty(v4, qmlContext, name, revisionMode, &local);
+ const QQmlPropertyData *result = findProperty(qmlContext, name, flags, &local);
if (!result) {
// Check for attached properties
- if (includeImports && name->startsWithUpper()) {
- if (auto importProperty = getPropertyFromImports(v4, name, qmlContext, d()->object(), hasProperty))
+ if ((flags & IncludeImports) && name->startsWithUpper()) {
+ if (auto importProperty = getPropertyFromImports(
+ v4, name, qmlContext, d()->object(), hasProperty))
return *importProperty;
}
- return QV4::Object::virtualGet(this, name->propertyKey(), this, hasProperty);
+ return Object::virtualGet(this, name->propertyKey(), this, hasProperty);
}
QQmlData *ddata = QQmlData::get(d()->object(), false);
- if (revisionMode == QV4::QObjectWrapper::CheckRevision && result->hasRevision()) {
+ if ((flags & CheckRevision) && result->hasRevision()) {
if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result)) {
if (hasProperty)
*hasProperty = false;
- return QV4::Encode::undefined();
+ return Encode::undefined();
}
}
if (hasProperty)
*hasProperty = true;
- return getProperty(v4, d()->object(), result);
+ return getProperty(v4, d(), d()->object(), result, flags);
}
-ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty, QQmlPropertyData **property)
+ReturnedValue QObjectWrapper::getQmlProperty(
+ ExecutionEngine *engine, const QQmlRefPointer<QQmlContextData> &qmlContext,
+ Heap::Object *wrapper, QObject *object, String *name, QObjectWrapper::Flags flags,
+ bool *hasProperty, const QQmlPropertyData **property)
{
if (QQmlData::wasDeleted(object)) {
if (hasProperty)
*hasProperty = false;
- return QV4::Encode::null();
+ return Encode::null();
}
- if (auto methodValue = getDestroyOrToStringMethod(engine, name, object, hasProperty))
+ if (auto methodValue = getDestroyOrToStringMethod(engine, name, wrapper, hasProperty))
return *methodValue;
QQmlData *ddata = QQmlData::get(object, false);
QQmlPropertyData local;
- QQmlPropertyData *result = findProperty(engine, object, qmlContext, name, revisionMode, &local);
+ const QQmlPropertyData *result = findProperty(object, qmlContext, name, flags, &local);
if (result) {
- if (revisionMode == QV4::QObjectWrapper::CheckRevision && result->hasRevision()) {
- if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result)) {
+ if ((flags & QObjectWrapper::CheckRevision) && result->hasRevision()) {
+ if (ddata && ddata->propertyCache
+ && !ddata->propertyCache->isAllowedInRevision(result)) {
if (hasProperty)
*hasProperty = false;
- return QV4::Encode::undefined();
+ return Encode::undefined();
}
}
if (hasProperty)
*hasProperty = true;
- if (property)
+ if (property && result != &local)
*property = result;
- return getProperty(engine, object, result);
+ return getProperty(engine, wrapper, object, result, flags);
} else {
// Check if this object is already wrapped.
if (!ddata || (ddata->jsWrapper.isUndefined() &&
@@ -395,7 +531,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC
// Not wrapped. Last chance: try query QObjectWrapper's prototype.
// If it can't handle this, then there is no point
// to wrap the QObject just to look at an empty set of JS props.
- QV4::Object *proto = QObjectWrapper::defaultPrototype(engine);
+ Object *proto = QObjectWrapper::defaultPrototype(engine);
return proto->get(name, hasProperty);
}
}
@@ -404,29 +540,30 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC
// There's no point wrapping again, as there wouldn't be any new props.
Q_ASSERT(ddata);
- QV4::Scope scope(engine);
- QV4::Scoped<QObjectWrapper> wrapper(scope, wrap(engine, object));
- if (!wrapper) {
+ Scope scope(engine);
+ Scoped<QObjectWrapper> rewrapped(scope, wrap(engine, object));
+ if (!rewrapped) {
if (hasProperty)
*hasProperty = false;
- return QV4::Encode::null();
+ return Encode::null();
}
- return wrapper->getQmlProperty(qmlContext, name, revisionMode, hasProperty);
+ return rewrapped->getQmlProperty(qmlContext, name, flags, hasProperty);
}
-bool QObjectWrapper::setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name,
- QObjectWrapper::RevisionMode revisionMode, const Value &value)
+bool QObjectWrapper::setQmlProperty(
+ ExecutionEngine *engine, const QQmlRefPointer<QQmlContextData> &qmlContext, QObject *object,
+ String *name, QObjectWrapper::Flags flags, const Value &value)
{
if (QQmlData::wasDeleted(object))
return false;
QQmlPropertyData local;
- QQmlPropertyData *result = QQmlPropertyCache::property(engine->jsEngine(), object, name, qmlContext, local);
+ const QQmlPropertyData *result = QQmlPropertyCache::property(object, name, qmlContext, &local);
if (!result)
return false;
- if (revisionMode == QV4::QObjectWrapper::CheckRevision && result->hasRevision()) {
+ if ((flags & QObjectWrapper::CheckRevision) && result->hasRevision()) {
QQmlData *ddata = QQmlData::get(object);
if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result))
return false;
@@ -436,7 +573,31 @@ bool QObjectWrapper::setQmlProperty(ExecutionEngine *engine, QQmlContextData *qm
return true;
}
-void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, const Value &value)
+/*!
+ \internal
+ If an QObjectWrapper is created via wrap, then it needs to be stored somewhere.
+ Otherwise, the garbage collector will immediately collect it if it is already
+ past the "mark QObjectWrapper's" phase (note that QObjectWrapper are marked
+ by iterating over a list of all QObjectWrapper, and then checking if the
+ wrapper fulfills some conditions).
+ However, sometimes we don't really want to keep a reference to the wrapper,
+ but just want to make sure that it exists (and we know that the wrapper
+ already fulfills the conditions to be kept alive). Then ensureWrapper
+ can be used, which creates the wrapper and ensures that it is also
+ marked.
+ */
+void QObjectWrapper::ensureWrapper(ExecutionEngine *engine, QObject *object)
+{
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::QObjectWrapper> wrapper {scope, QV4::QObjectWrapper::wrap(engine, object)};
+ QV4::WriteBarrier::markCustom(engine, [&wrapper](QV4::MarkStack *ms) {
+ wrapper->mark(ms);
+ });
+}
+
+void QObjectWrapper::setProperty(
+ ExecutionEngine *engine, QObject *object,
+ const QQmlPropertyData *property, const Value &value)
{
if (!property->isWritable() && !property->isQList()) {
QString error = QLatin1String("Cannot assign to read-only property \"") +
@@ -445,56 +606,106 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
return;
}
- QQmlBinding *newBinding = nullptr;
- QV4::Scope scope(engine);
- QV4::ScopedFunctionObject f(scope, value);
- if (f) {
+ Scope scope(engine);
+ if (ScopedFunctionObject f(scope, value); f) {
if (!f->isBinding()) {
- if (!property->isVarProperty() && property->propType() != qMetaTypeId<QJSValue>()) {
+ const bool isAliasToAllowed = [&]() {
+ if (property->isAlias()) {
+ const QQmlPropertyIndex originalIndex(property->coreIndex(), -1);
+ auto [targetObject, targetIndex] = QQmlPropertyPrivate::findAliasTarget(object, originalIndex);
+ Q_ASSERT(targetObject);
+ const QQmlPropertyCache *targetCache
+ = QQmlData::get(targetObject)->propertyCache.data();
+ Q_ASSERT(targetCache);
+ const QQmlPropertyData *targetProperty
+ = targetCache->property(targetIndex.coreIndex());
+ object = targetObject;
+ property = targetProperty;
+ return targetProperty->isVarProperty() || targetProperty->propType() == QMetaType::fromType<QJSValue>();
+ } else {
+ return false;
+ }
+ }();
+ if (!isAliasToAllowed && !property->isVarProperty()
+ && property->propType() != QMetaType::fromType<QJSValue>()) {
// assigning a JS function to a non var or QJSValue property or is not allowed.
QString error = QLatin1String("Cannot assign JavaScript function to ");
- if (!QMetaType::typeName(property->propType()))
+ if (!QMetaType(property->propType()).name())
error += QLatin1String("[unknown property type]");
else
- error += QLatin1String(QMetaType::typeName(property->propType()));
+ error += QLatin1String(QMetaType(property->propType()).name());
scope.engine->throwError(error);
return;
}
} else {
- // binding assignment.
- QQmlContextData *callingQmlContext = scope.engine->callingQmlContext();
- QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
+ QQmlRefPointer<QQmlContextData> callingQmlContext = scope.engine->callingQmlContext();
+ Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
+ ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
+ ScopedContext ctx(scope, f->scope());
- QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
- QV4::ScopedContext ctx(scope, bindingFunction->scope());
- newBinding = QQmlBinding::create(property, f->function(), object, callingQmlContext, ctx);
- newBinding->setSourceLocation(bindingFunction->currentLocation());
- if (f->isBoundFunction())
- newBinding->setBoundFunction(static_cast<QV4::BoundFunction *>(f.getPointer()));
- newBinding->setTarget(object, *property, nullptr);
+ // binding assignment.
+ if (property->isBindable()) {
+ const QQmlPropertyIndex idx(property->coreIndex(), /*not a value type*/-1);
+ auto [targetObject, targetIndex] = QQmlPropertyPrivate::findAliasTarget(object, idx);
+ QUntypedPropertyBinding binding;
+ if (f->isBoundFunction()) {
+ auto boundFunction = static_cast<BoundFunction *>(f.getPointer());
+ binding = QQmlPropertyBinding::createFromBoundFunction(property, boundFunction, object, callingQmlContext,
+ ctx, targetObject, targetIndex);
+ } else {
+ binding = QQmlPropertyBinding::create(property, f->function(), object, callingQmlContext,
+ ctx, targetObject, targetIndex);
+ }
+ QUntypedBindable bindable;
+ void *argv = {&bindable};
+ // indirect metacall in case interceptors are installed
+ targetObject->metaObject()->metacall(targetObject, QMetaObject::BindableProperty, targetIndex.coreIndex(), &argv);
+ bool ok = bindable.setBinding(binding);
+ if (!ok) {
+ auto error = QStringLiteral("Failed to set binding on %1::%2.").
+ arg(QString::fromUtf8(object->metaObject()->className()), property->name(object));
+ scope.engine->throwError(error);
+ }
+ } else {
+ QQmlBinding *newBinding = QQmlBinding::create(property, f->function(), object, callingQmlContext, ctx);
+ newBinding->setSourceLocation(bindingFunction->currentLocation());
+ if (f->isBoundFunction())
+ newBinding->setBoundFunction(static_cast<BoundFunction *>(f.getPointer()));
+ newBinding->setTarget(object, *property, nullptr);
+ QQmlPropertyPrivate::setBinding(newBinding);
+ }
+ return;
}
}
- if (newBinding) {
- QQmlPropertyPrivate::setBinding(newBinding);
- } else {
- if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
- if (auto binding = QQmlPropertyPrivate::binding(object, QQmlPropertyIndex(property->coreIndex()))) {
- Q_ASSERT(!binding->isValueTypeProxy());
+ if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
+ if (auto binding = QQmlPropertyPrivate::binding(object, QQmlPropertyIndex(property->coreIndex()))) {
+ const auto stackFrame = engine->currentStackFrame;
+ switch (binding->kind()) {
+ case QQmlAbstractBinding::QmlBinding: {
const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
- const auto stackFrame = engine->currentStackFrame;
qCInfo(lcBindingRemoval,
"Overwriting binding on %s::%s at %s:%d that was initially bound at %s",
object->metaObject()->className(), qPrintable(property->name(object)),
qPrintable(stackFrame->source()), stackFrame->lineNumber(),
qPrintable(qmlBinding->expressionIdentifier()));
+ break;
+ }
+ case QQmlAbstractBinding::ValueTypeProxy:
+ case QQmlAbstractBinding::PropertyToPropertyBinding: {
+ qCInfo(lcBindingRemoval,
+ "Overwriting binding on %s::%s at %s:%d",
+ object->metaObject()->className(), qPrintable(property->name(object)),
+ qPrintable(stackFrame->source()), stackFrame->lineNumber());
+ break;
+ }
}
}
- QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
}
+ QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
- if (!newBinding && property->isVarProperty()) {
+ if (property->isVarProperty()) {
// allow assignment of "special" values (null, undefined, function) to var properties
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
@@ -509,65 +720,68 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
void *argv[] = { &o, 0, &status, &flags }; \
QMetaObject::metacall(object, QMetaObject::WriteProperty, property->coreIndex(), argv);
+ const QMetaType propType = property->propType();
+ // functions are already handled, except for the QJSValue case
+ Q_ASSERT(!value.as<FunctionObject>() || propType == QMetaType::fromType<QJSValue>());
+
if (value.isNull() && property->isQObject()) {
PROPERTY_STORE(QObject*, nullptr);
} else if (value.isUndefined() && property->isResettable()) {
void *a[] = { nullptr };
QMetaObject::metacall(object, QMetaObject::ResetProperty, property->coreIndex(), a);
- } else if (value.isUndefined() && property->propType() == qMetaTypeId<QVariant>()) {
+ } else if (value.isUndefined() && propType == QMetaType::fromType<QVariant>()) {
PROPERTY_STORE(QVariant, QVariant());
- } else if (value.isUndefined() && property->propType() == QMetaType::QJsonValue) {
+ } else if (value.isUndefined() && propType == QMetaType::fromType<QJsonValue>()) {
PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined));
- } else if (!newBinding && property->propType() == qMetaTypeId<QJSValue>()) {
- PROPERTY_STORE(QJSValue, QJSValue(scope.engine, value.asReturnedValue()));
- } else if (value.isUndefined() && property->propType() != qMetaTypeId<QQmlScriptString>()) {
+ } else if (propType == QMetaType::fromType<QJSValue>()) {
+ PROPERTY_STORE(QJSValue, QJSValuePrivate::fromReturnedValue(value.asReturnedValue()));
+ } else if (value.isUndefined() && propType != QMetaType::fromType<QQmlScriptString>()) {
QString error = QLatin1String("Cannot assign [undefined] to ");
- if (!QMetaType::typeName(property->propType()))
+ if (!propType.name())
error += QLatin1String("[unknown property type]");
else
- error += QLatin1String(QMetaType::typeName(property->propType()));
+ error += QLatin1String(propType.name());
scope.engine->throwError(error);
return;
- } else if (value.as<FunctionObject>()) {
- // this is handled by the binding creation above
- } else if (property->propType() == QMetaType::Int && value.isNumber()) {
- PROPERTY_STORE(int, value.asDouble());
- } else if (property->propType() == QMetaType::QReal && value.isNumber()) {
+ } else if (propType == QMetaType::fromType<int>() && value.isNumber()) {
+ PROPERTY_STORE(int, value.toInt32());
+ } else if (propType == QMetaType::fromType<qreal>() && value.isNumber()) {
PROPERTY_STORE(qreal, qreal(value.asDouble()));
- } else if (property->propType() == QMetaType::Float && value.isNumber()) {
+ } else if (propType == QMetaType::fromType<float>() && value.isNumber()) {
PROPERTY_STORE(float, float(value.asDouble()));
- } else if (property->propType() == QMetaType::Double && value.isNumber()) {
+ } else if (propType == QMetaType::fromType<double>() && value.isNumber()) {
PROPERTY_STORE(double, double(value.asDouble()));
- } else if (property->propType() == QMetaType::QString && value.isString()) {
+ } else if (propType == QMetaType::fromType<QString>() && value.isString()) {
PROPERTY_STORE(QString, value.toQStringNoThrow());
} else if (property->isVarProperty()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
vmemo->setVMEProperty(property->coreIndex(), value);
- } else if (property->propType() == qMetaTypeId<QQmlScriptString>() && (value.isUndefined() || value.isPrimitive())) {
+ } else if (propType == QMetaType::fromType<QQmlScriptString>()
+ && (value.isUndefined() || value.isPrimitive())) {
QQmlScriptString ss(value.toQStringNoThrow(), nullptr /* context */, object);
if (value.isNumber()) {
ss.d->numberValue = value.toNumber();
ss.d->isNumberLiteral = true;
} else if (value.isString()) {
- ss.d->script = QV4::CompiledData::Binding::escapedString(ss.d->script);
+ ss.d->script = CompiledData::Binding::escapedString(ss.d->script);
ss.d->isStringLiteral = true;
}
PROPERTY_STORE(QQmlScriptString, ss);
} else {
QVariant v;
- if (property->isQList())
- v = scope.engine->toVariant(value, qMetaTypeId<QList<QObject *> >());
+ if (property->isQList() && propType.flags().testFlag(QMetaType::IsQmlList))
+ v = ExecutionEngine::toVariant(value, QMetaType::fromType<QList<QObject *> >());
else
- v = scope.engine->toVariant(value, property->propType());
+ v = ExecutionEngine::toVariant(value, propType);
- QQmlContextData *callingQmlContext = scope.engine->callingQmlContext();
+ QQmlRefPointer<QQmlContextData> callingQmlContext = scope.engine->callingQmlContext();
if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) {
const char *valueType = (v.userType() == QMetaType::UnknownType)
? "an unknown type"
- : QMetaType::typeName(v.userType());
+ : QMetaType(v.userType()).name();
- const char *targetTypeName = QMetaType::typeName(property->propType());
+ const char *targetTypeName = propType.name();
if (!targetTypeName)
targetTypeName = "an unregistered type";
@@ -587,7 +801,7 @@ ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *ob
QQmlData *ddata = QQmlData::get(object, true);
if (!ddata)
- return QV4::Encode::undefined();
+ return Encode::undefined();
Scope scope(engine);
@@ -596,7 +810,7 @@ ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *ob
ddata->jsEngineId == 0 || // No one owns the QObject
!ddata->hasTaintedV4Object)) { // Someone else has used the QObject, but it isn't tainted
- QV4::ScopedValue rv(scope, create(engine, object));
+ ScopedValue rv(scope, create(engine, object));
ddata->jsWrapper.set(scope.engine, rv);
ddata->jsEngineId = engine->m_engineId;
return rv->asReturnedValue();
@@ -611,7 +825,7 @@ ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *ob
// If our tainted handle doesn't exist or has been collected, and there isn't
// a handle in the ddata, we can assume ownership of the ddata->jsWrapper
if (ddata->jsWrapper.isUndefined() && !alternateWrapper) {
- QV4::ScopedValue result(scope, create(engine, object));
+ ScopedValue result(scope, create(engine, object));
ddata->jsWrapper.set(scope.engine, result);
ddata->jsEngineId = engine->m_engineId;
return result->asReturnedValue();
@@ -629,6 +843,29 @@ ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *ob
}
}
+ReturnedValue QObjectWrapper::wrapConst_slowPath(ExecutionEngine *engine, QObject *object)
+{
+ const QObject *constObject = object;
+
+ QQmlData *ddata = QQmlData::get(object, true);
+
+ Scope scope(engine);
+ ScopedObject constWrapper(scope);
+ if (engine->m_multiplyWrappedQObjects && ddata->hasConstWrapper)
+ constWrapper = engine->m_multiplyWrappedQObjects->value(constObject);
+
+ if (!constWrapper) {
+ constWrapper = create(engine, object);
+ constWrapper->setInternalClass(constWrapper->internalClass()->cryopreserved());
+ if (!engine->m_multiplyWrappedQObjects)
+ engine->m_multiplyWrappedQObjects = new MultiplyWrappedQObjectMap;
+ engine->m_multiplyWrappedQObjects->insert(constObject, constWrapper->d());
+ ddata->hasConstWrapper = true;
+ }
+
+ return constWrapper.asReturnedValue();
+}
+
void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack)
{
if (QQmlData::wasDeleted(object))
@@ -638,10 +875,15 @@ void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack)
if (!ddata)
return;
- if (ddata->jsEngineId == markStack->engine->m_engineId)
+ const ExecutionEngine *engine = markStack->engine();
+ if (ddata->jsEngineId == engine->m_engineId)
ddata->jsWrapper.markOnce(markStack);
- else if (markStack->engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object)
- markStack->engine->m_multiplyWrappedQObjects->mark(object, markStack);
+ else if (engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object)
+ engine->m_multiplyWrappedQObjects->mark(object, markStack);
+ if (ddata->hasConstWrapper) {
+ Q_ASSERT(engine->m_multiplyWrappedQObjects);
+ engine->m_multiplyWrappedQObjects->mark(static_cast<const QObject *>(object), markStack);
+ }
}
void QObjectWrapper::setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value)
@@ -660,40 +902,36 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, int p
if (!ddata)
return;
- QQmlPropertyCache *cache = ddata->propertyCache;
- Q_ASSERT(cache);
- QQmlPropertyData *property = cache->property(propertyIndex);
+ Q_ASSERT(ddata->propertyCache);
+ const QQmlPropertyData *property = ddata->propertyCache->property(propertyIndex);
Q_ASSERT(property); // We resolved this property earlier, so it better exist!
return setProperty(engine, object, property, value);
}
bool QObjectWrapper::virtualIsEqualTo(Managed *a, Managed *b)
{
- Q_ASSERT(a->as<QV4::QObjectWrapper>());
- QV4::QObjectWrapper *qobjectWrapper = static_cast<QV4::QObjectWrapper *>(a);
- QV4::Object *o = b->as<Object>();
- if (o) {
- if (QV4::QQmlTypeWrapper *qmlTypeWrapper = o->as<QV4::QQmlTypeWrapper>())
- return qmlTypeWrapper->toVariant().value<QObject*>() == qobjectWrapper->object();
- }
+ Q_ASSERT(a->as<QObjectWrapper>());
+ const QObjectWrapper *aobjectWrapper = static_cast<QObjectWrapper *>(a);
+ if (const QQmlTypeWrapper *qmlTypeWrapper = b->as<QQmlTypeWrapper>())
+ return qmlTypeWrapper->object() == aobjectWrapper->object();
- return false;
+ // We can have a const and a non-const wrapper for the same object.
+ const QObjectWrapper *bobjectWrapper = b->as<QObjectWrapper>();
+ return bobjectWrapper && aobjectWrapper->object() == bobjectWrapper->object();
}
ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object)
{
- if (QJSEngine *jsEngine = engine->jsEngine()) {
- if (QQmlPropertyCache *cache = QQmlData::ensurePropertyCache(jsEngine, object)) {
- ReturnedValue result = QV4::Encode::null();
- void *args[] = { &result, &engine };
- if (cache->callJSFactoryMethod(object, args))
- return result;
- }
+ if (QQmlPropertyCache::ConstPtr cache = QQmlData::ensurePropertyCache(object)) {
+ ReturnedValue result = Encode::null();
+ void *args[] = { &result, &engine };
+ if (cache->callJSFactoryMethod(object, args))
+ return result;
}
- return (engine->memoryManager->allocate<QV4::QObjectWrapper>(object))->asReturnedValue();
+ return (engine->memoryManager->allocate<QObjectWrapper>(object))->asReturnedValue();
}
-QV4::ReturnedValue QObjectWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
+ReturnedValue QObjectWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
{
if (!id.isString())
return Object::virtualGet(m, id, receiver, hasProperty);
@@ -701,8 +939,8 @@ QV4::ReturnedValue QObjectWrapper::virtualGet(const Managed *m, PropertyKey id,
const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m);
Scope scope(that);
ScopedString n(scope, id.asStringOrSymbol());
- QQmlContextData *qmlContext = that->engine()->callingQmlContext();
- return that->getQmlProperty(qmlContext, n, IgnoreRevision, hasProperty, /*includeImports*/ true);
+ QQmlRefPointer<QQmlContextData> qmlContext = that->engine()->callingQmlContext();
+ return that->getQmlProperty(qmlContext, n, IncludeImports | AttachMethods, hasProperty);
}
bool QObjectWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
@@ -714,11 +952,18 @@ bool QObjectWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
ScopedString name(scope, id.asStringOrSymbol());
- if (scope.engine->hasException || QQmlData::wasDeleted(that->d()->object()))
+ if (that->internalClass()->isFrozen()) {
+ QString error = QLatin1String("Cannot assign to property \"") +
+ name->toQString() + QLatin1String("\" of read-only object");
+ scope.engine->throwError(error);
+ return false;
+ }
+
+ if (scope.hasException() || QQmlData::wasDeleted(that->d()->object()))
return false;
- QQmlContextData *qmlContext = scope.engine->callingQmlContext();
- if (!setQmlProperty(scope.engine, qmlContext, that->d()->object(), name, QV4::QObjectWrapper::IgnoreRevision, value)) {
+ QQmlRefPointer<QQmlContextData> qmlContext = scope.engine->callingQmlContext();
+ if (!setQmlProperty(scope.engine, qmlContext, that->d()->object(), name, NoFlag, value)) {
QQmlData *ddata = QQmlData::get(that->d()->object());
// Types created by QML are not extensible at run-time, but for other QObjects we can store them
// as regular JavaScript properties, like on JavaScript objects.
@@ -728,7 +973,7 @@ bool QObjectWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
scope.engine->throwError(error);
return false;
} else {
- return QV4::Object::virtualPut(m, id, value, receiver);
+ return Object::virtualPut(m, id, value, receiver);
}
}
@@ -743,34 +988,35 @@ PropertyAttributes QObjectWrapper::virtualGetOwnProperty(const Managed *m, Prope
if (!QQmlData::wasDeleted(thatObject)) {
Scope scope(m);
ScopedString n(scope, id.asStringOrSymbol());
- QQmlContextData *qmlContext = scope.engine->callingQmlContext();
+ QQmlRefPointer<QQmlContextData> qmlContext = scope.engine->callingQmlContext();
QQmlPropertyData local;
- if (that->findProperty(scope.engine, qmlContext, n, IgnoreRevision, &local)
+ if (that->findProperty(qmlContext, n, NoFlag, &local)
|| n->equals(scope.engine->id_destroy()) || n->equals(scope.engine->id_toString())) {
if (p) {
// ### probably not the fastest implementation
bool hasProperty;
- p->value = that->getQmlProperty(qmlContext, n, IgnoreRevision, &hasProperty, /*includeImports*/ true);
+ p->value = that->getQmlProperty(
+ qmlContext, n, IncludeImports | AttachMethods, &hasProperty);
}
- return QV4::Attr_Data;
+ return Attr_Data;
}
}
}
- return QV4::Object::virtualGetOwnProperty(m, id, p);
+ return Object::virtualGetOwnProperty(m, id, p);
}
struct QObjectWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
{
int propertyIndex = 0;
~QObjectWrapperOwnPropertyKeyIterator() override = default;
- PropertyKey next(const QV4::Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
+ PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
private:
QSet<QByteArray> m_alreadySeen;
};
-PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const QV4::Object *o, Property *pd, PropertyAttributes *attrs)
+PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs)
{
// Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
@@ -792,11 +1038,13 @@ PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const QV4::Object *o, Pro
ScopedString propName(scope, thatEngine->newString(QString::fromUtf8(property.name())));
++propertyIndex;
if (attrs)
- *attrs= QV4::Attr_Data;
+ *attrs= Attr_Data;
if (pd) {
QQmlPropertyData local;
local.load(property);
- pd->value = that->getProperty(thatEngine, thatObject, &local);
+ pd->value = that->getProperty(
+ thatEngine, that->d(), thatObject, &local,
+ QObjectWrapper::AttachMethods);
}
return propName->toPropertyKey();
}
@@ -817,11 +1065,13 @@ PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const QV4::Object *o, Pro
Scope scope(thatEngine);
ScopedString methodName(scope, thatEngine->newString(QString::fromUtf8(method.name())));
if (attrs)
- *attrs = QV4::Attr_Data;
+ *attrs = Attr_Data;
if (pd) {
QQmlPropertyData local;
local.load(method);
- pd->value = that->getProperty(thatEngine, thatObject, &local);
+ pd->value = that->getProperty(
+ thatEngine, that->d(), thatObject, &local,
+ QObjectWrapper::AttachMethods);
}
return methodName->toPropertyKey();
}
@@ -847,23 +1097,32 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E
const QObjectWrapper *This = static_cast<const QObjectWrapper *>(object);
ScopedString name(scope, id.asStringOrSymbol());
- QQmlContextData *qmlContext = engine->callingQmlContext();
+ QQmlRefPointer<QQmlContextData> qmlContext = engine->callingQmlContext();
QObject * const qobj = This->d()->object();
if (QQmlData::wasDeleted(qobj))
- return QV4::Encode::undefined();
-
- if (auto methodValue = getDestroyOrToStringMethod(engine, name, qobj))
- return *methodValue;
+ return Encode::undefined();
QQmlData *ddata = QQmlData::get(qobj, false);
+ if (auto methodValue = getDestroyOrToStringMethod(engine, name, This->d())) {
+ Scoped<QObjectMethod> method(scope, *methodValue);
+ setupQObjectMethodLookup(
+ lookup, ddata ? ddata : QQmlData::get(qobj, true), nullptr, This, method->d());
+ lookup->getter = Lookup::getterQObjectMethod;
+ return method.asReturnedValue();
+ }
+
if (!ddata || !ddata->propertyCache) {
QQmlPropertyData local;
- QQmlPropertyData *property = QQmlPropertyCache::property(engine->jsEngine(), qobj, name, qmlContext, local);
- return property ? getProperty(engine, qobj, property) : QV4::Encode::undefined();
+ const QQmlPropertyData *property = QQmlPropertyCache::property(
+ qobj, name, qmlContext, &local);
+ return property
+ ? getProperty(engine, This->d(), qobj, property,
+ lookup->forCall ? NoFlag : AttachMethods)
+ : Encode::undefined();
}
- QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobj, qmlContext);
+ const QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobj, qmlContext);
if (!property) {
// Check for attached properties
@@ -871,27 +1130,28 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E
if (auto importProperty = getPropertyFromImports(engine, name, qmlContext, qobj))
return *importProperty;
}
- return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
+ return Object::virtualResolveLookupGetter(object, engine, lookup);
}
- lookup->qobjectLookup.ic = This->internalClass();
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = property;
- lookup->getter = QV4::QObjectWrapper::lookupGetter;
+ if (property->isFunction()
+ && !property->isVarProperty()
+ && !property->isVMEFunction() // Handled by QObjectLookup
+ && !property->isSignalHandler()) { // TODO: Optimize SignalHandler, too
+ QV4::Heap::QObjectMethod *method = nullptr;
+ setupQObjectMethodLookup(lookup, ddata, property, This, method);
+ lookup->getter = Lookup::getterQObjectMethod;
+ return lookup->getter(lookup, engine, *object);
+ }
+
+ setupQObjectLookup(lookup, ddata, property, This);
+ lookup->getter = Lookup::getterQObject;
return lookup->getter(lookup, engine, *object);
}
-ReturnedValue QObjectWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object)
+ReturnedValue QObjectWrapper::lookupAttached(
+ Lookup *l, ExecutionEngine *engine, const Value &object)
{
- const auto revertLookup = [lookup, engine, &object]() {
- lookup->qobjectLookup.propertyCache->release();
- lookup->qobjectLookup.propertyCache = nullptr;
- lookup->getter = Lookup::getterGeneric;
- return Lookup::getterGeneric(lookup, engine, object);
- };
-
- return lookupGetterImpl(lookup, engine, object, /*useOriginalProperty*/ false, revertLookup);
+ return Lookup::getterGeneric(l, engine, object);
}
bool QObjectWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
@@ -900,20 +1160,60 @@ bool QObjectWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine
return Object::virtualResolveLookupSetter(object, engine, lookup, value);
}
-namespace QV4 {
+int QObjectWrapper::virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a)
+{
+ QObjectWrapper *wrapper = object->as<QObjectWrapper>();
+ Q_ASSERT(wrapper);
+
+ if (QObject *qObject = wrapper->object())
+ return QMetaObject::metacall(qObject, call, index, a);
+
+ return 0;
+}
+
+QString QObjectWrapper::objectToString(
+ ExecutionEngine *engine, const QMetaObject *metaObject, QObject *object)
+{
+ if (!metaObject)
+ return QLatin1String("null");
+
+ if (!object)
+ return QString::fromUtf8(metaObject->className()) + QLatin1String("(0x0)");
+
+ const int id = metaObject->indexOfMethod("toString()");
+ if (id >= 0) {
+ const QMetaMethod method = metaObject->method(id);
+ const QMetaType returnType = method.returnMetaType();
+ QVariant result(returnType);
+ method.invoke(object, QGenericReturnArgument(returnType.name(), result.data()));
+ if (result.metaType() == QMetaType::fromType<QString>())
+ return result.toString();
+ QV4::Scope scope(engine);
+ QV4::ScopedValue value(scope, engine->fromVariant(result));
+ return value->toQString();
+ }
+
+ QString result;
+ result += QString::fromUtf8(metaObject->className()) +
+ QLatin1String("(0x") + QString::number(quintptr(object), 16);
+ QString objectName = object->objectName();
+ if (!objectName.isEmpty())
+ result += QLatin1String(", \"") + objectName + QLatin1Char('\"');
+ result += QLatin1Char(')');
+ return result;
+}
struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
{
- QV4::PersistentValue function;
- QV4::PersistentValue thisObject;
- int signalIndex;
+ PersistentValue function;
+ PersistentValue thisObject;
+ QMetaMethod signal;
QObjectSlotDispatcher()
: QtPrivate::QSlotObjectBase(&impl)
- , signalIndex(-1)
{}
- static void impl(int which, QSlotObjectBase *this_, QObject *r, void **metaArgs, bool *ret)
+ static void impl(int which, QSlotObjectBase *this_, QObject *receiver, void **metaArgs, bool *ret)
{
switch (which) {
case Destroy: {
@@ -921,30 +1221,33 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
}
break;
case Call: {
+ if (QQmlData::wasDeleted(receiver))
+ break;
+
QObjectSlotDispatcher *This = static_cast<QObjectSlotDispatcher*>(this_);
- QV4::ExecutionEngine *v4 = This->function.engine();
+ ExecutionEngine *v4 = This->function.engine();
// Might be that we're still connected to a signal that's emitted long
// after the engine died. We don't track connections in a global list, so
// we need this safeguard.
if (!v4)
break;
- QQmlMetaObject::ArgTypeStorage storage;
- int *argsTypes = QQmlMetaObject(r).methodParameterTypes(This->signalIndex, &storage, nullptr);
+ QQmlMetaObject::ArgTypeStorage<9> storage;
+ QQmlMetaObject::methodParameterTypes(This->signal, &storage, nullptr);
- int argCount = argsTypes ? argsTypes[0]:0;
+ int argCount = storage.size();
- QV4::Scope scope(v4);
- QV4::ScopedFunctionObject f(scope, This->function.value());
+ Scope scope(v4);
+ ScopedFunctionObject f(scope, This->function.value());
- QV4::JSCallData jsCallData(scope, argCount);
- *jsCallData->thisObject = This->thisObject.isUndefined() ? v4->globalObject->asReturnedValue() : This->thisObject.value();
+ JSCallArguments jsCallData(scope, argCount);
+ *jsCallData.thisObject = This->thisObject.isUndefined() ? v4->globalObject->asReturnedValue() : This->thisObject.value();
for (int ii = 0; ii < argCount; ++ii) {
- int type = argsTypes[ii + 1];
- if (type == qMetaTypeId<QVariant>()) {
- jsCallData->args[ii] = v4->fromVariant(*((QVariant *)metaArgs[ii + 1]));
+ QMetaType type = storage[ii];
+ if (type == QMetaType::fromType<QVariant>()) {
+ jsCallData.args[ii] = v4->fromVariant(*((QVariant *)metaArgs[ii + 1]));
} else {
- jsCallData->args[ii] = v4->fromVariant(QVariant(type, metaArgs[ii + 1]));
+ jsCallData.args[ii] = v4->fromVariant(QVariant(type, metaArgs[ii + 1]));
}
}
@@ -952,7 +1255,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
if (scope.hasException()) {
QQmlError error = v4->catchExceptionAsQmlError();
if (error.description().isEmpty()) {
- QV4::ScopedString name(scope, f->name());
+ ScopedString name(scope, f->name());
error.setDescription(QStringLiteral("Unknown exception occurred during evaluation of connected function: %1").arg(name->toQString()));
}
if (QQmlEngine *qmlEngine = v4->qmlEngine()) {
@@ -975,15 +1278,15 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
// This is tricky. Normally the metaArgs[0] pointer is a pointer to the _function_
// for the new-style QObject::connect. Here we use the engine pointer as sentinel
// to distinguish those type of QSlotObjectBase connections from our QML connections.
- QV4::ExecutionEngine *v4 = reinterpret_cast<QV4::ExecutionEngine*>(metaArgs[0]);
+ ExecutionEngine *v4 = reinterpret_cast<ExecutionEngine*>(metaArgs[0]);
if (v4 != connection->function.engine()) {
*ret = false;
return;
}
- QV4::Scope scope(v4);
- QV4::ScopedValue function(scope, *reinterpret_cast<QV4::Value*>(metaArgs[1]));
- QV4::ScopedValue thisObject(scope, *reinterpret_cast<QV4::Value*>(metaArgs[2]));
+ Scope scope(v4);
+ ScopedValue function(scope, *reinterpret_cast<Value*>(metaArgs[1]));
+ ScopedValue thisObject(scope, *reinterpret_cast<Value*>(metaArgs[2]));
QObject *receiverToDisconnect = reinterpret_cast<QObject*>(metaArgs[3]);
int slotIndexToDisconnect = *reinterpret_cast<int*>(metaArgs[4]);
@@ -992,7 +1295,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
if (connection->thisObject.isUndefined() == thisObject->isUndefined() &&
(connection->thisObject.isUndefined() || RuntimeHelpers::strictEqual(*connection->thisObject.valueRef(), thisObject))) {
- QV4::ScopedFunctionObject f(scope, connection->function.value());
+ ScopedFunctionObject f(scope, connection->function.value());
QPair<QObject *, int> connectedFunctionData = QObjectMethod::extractQtMethod(f);
if (connectedFunctionData.first == receiverToDisconnect &&
connectedFunctionData.second == slotIndexToDisconnect) {
@@ -1019,11 +1322,9 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
};
};
-} // namespace QV4
-
ReturnedValue QObjectWrapper::method_connect(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
- QV4::Scope scope(b);
+ Scope scope(b);
if (argc == 0)
THROW_GENERIC_ERROR("Function.prototype.connect: no arguments given");
@@ -1038,11 +1339,12 @@ ReturnedValue QObjectWrapper::method_connect(const FunctionObject *b, const Valu
if (!signalObject)
THROW_GENERIC_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
- if (signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
+ auto signalMetaMethod = signalObject->metaObject()->method(signalIndex);
+ if (signalMetaMethod.methodType() != QMetaMethod::Signal)
THROW_GENERIC_ERROR("Function.prototype.connect: this object is not a signal");
- QV4::ScopedFunctionObject f(scope);
- QV4::ScopedValue object (scope, QV4::Encode::undefined());
+ ScopedFunctionObject f(scope);
+ ScopedValue object (scope, Encode::undefined());
if (argc == 1) {
f = argv[0];
@@ -1057,25 +1359,43 @@ ReturnedValue QObjectWrapper::method_connect(const FunctionObject *b, const Valu
if (!object->isUndefined() && !object->isObject())
THROW_GENERIC_ERROR("Function.prototype.connect: target this is not an object");
- QV4::QObjectSlotDispatcher *slot = new QV4::QObjectSlotDispatcher;
- slot->signalIndex = signalIndex;
+ QObjectSlotDispatcher *slot = new QObjectSlotDispatcher;
+ slot->signal = signalMetaMethod;
slot->thisObject.set(scope.engine, object);
slot->function.set(scope.engine, f);
if (QQmlData *ddata = QQmlData::get(signalObject)) {
- if (QQmlPropertyCache *propertyCache = ddata->propertyCache) {
+ if (const QQmlPropertyCache *propertyCache = ddata->propertyCache.data()) {
QQmlPropertyPrivate::flushSignal(signalObject, propertyCache->methodIndexToSignalIndex(signalIndex));
}
}
- QObjectPrivate::connect(signalObject, signalIndex, slot, Qt::AutoConnection);
+
+ QPair<QObject *, int> functionData = QObjectMethod::extractQtMethod(f); // align with disconnect
+ QObject *receiver = nullptr;
+
+ if (functionData.first)
+ receiver = functionData.first;
+ else if (auto qobjectWrapper = object->as<QV4::QObjectWrapper>())
+ receiver = qobjectWrapper->object();
+ else if (auto typeWrapper = object->as<QV4::QQmlTypeWrapper>())
+ receiver = typeWrapper->object();
+
+ if (receiver) {
+ QObjectPrivate::connect(signalObject, signalIndex, receiver, slot, Qt::AutoConnection);
+ } else {
+ qCInfo(lcObjectConnect,
+ "Could not find receiver of the connection, using sender as receiver. Disconnect "
+ "explicitly (or delete the sender) to make sure the connection is removed.");
+ QObjectPrivate::connect(signalObject, signalIndex, signalObject, slot, Qt::AutoConnection);
+ }
RETURN_UNDEFINED();
}
ReturnedValue QObjectWrapper::method_disconnect(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
- QV4::Scope scope(b);
+ Scope scope(b);
if (argc == 0)
THROW_GENERIC_ERROR("Function.prototype.disconnect: no arguments given");
@@ -1093,8 +1413,8 @@ ReturnedValue QObjectWrapper::method_disconnect(const FunctionObject *b, const V
if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
THROW_GENERIC_ERROR("Function.prototype.disconnect: this object is not a signal");
- QV4::ScopedFunctionObject functionValue(scope);
- QV4::ScopedValue functionThisValue(scope, QV4::Encode::undefined());
+ ScopedFunctionObject functionValue(scope);
+ ScopedValue functionThisValue(scope, Encode::undefined());
if (argc == 1) {
functionValue = argv[0];
@@ -1119,31 +1439,76 @@ ReturnedValue QObjectWrapper::method_disconnect(const FunctionObject *b, const V
&functionData.second
};
- QObjectPrivate::disconnect(signalObject, signalIndex, reinterpret_cast<void**>(&a));
+ QObject *receiver = nullptr;
+
+ if (functionData.first)
+ receiver = functionData.first;
+ else if (auto qobjectWrapper = functionThisValue->as<QV4::QObjectWrapper>())
+ receiver = qobjectWrapper->object();
+ else if (auto typeWrapper = functionThisValue->as<QV4::QQmlTypeWrapper>())
+ receiver = typeWrapper->object();
+
+ if (receiver) {
+ QObjectPrivate::disconnect(signalObject, signalIndex, receiver,
+ reinterpret_cast<void **>(&a));
+ } else {
+ QObjectPrivate::disconnect(signalObject, signalIndex, signalObject,
+ reinterpret_cast<void **>(&a));
+ }
RETURN_UNDEFINED();
}
-static void markChildQObjectsRecursively(QObject *parent, QV4::MarkStack *markStack)
+static void markChildQObjectsRecursively(QObject *parent, MarkStack *markStack)
{
- const QObjectList &children = parent->children();
- for (int i = 0; i < children.count(); ++i) {
- QObject *child = children.at(i);
+ QQueue<QObject *> queue;
+ queue.append(parent->children());
+
+ while (!queue.isEmpty()) {
+ QObject *child = queue.dequeue();
if (!child)
continue;
QObjectWrapper::markWrapper(child, markStack);
- markChildQObjectsRecursively(child, markStack);
+ queue.append(child->children());
}
}
-void Heap::QObjectWrapper::markObjects(Heap::Base *that, QV4::MarkStack *markStack)
+void Heap::QObjectWrapper::markObjects(Heap::Base *that, MarkStack *markStack)
{
QObjectWrapper *This = static_cast<QObjectWrapper *>(that);
if (QObject *o = This->object()) {
- QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
- if (vme)
- vme->mark(markStack);
+ if (QQmlData *ddata = QQmlData::get(o)) {
+ if (ddata->hasVMEMetaObject) {
+ if (QQmlVMEMetaObject *vme
+ = static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(o)->metaObject)) {
+ vme->mark(markStack);
+ }
+ }
+
+ if (ddata->hasConstWrapper) {
+ Scope scope(that->internalClass->engine);
+ Q_ASSERT(scope.engine->m_multiplyWrappedQObjects);
+
+ Scoped<QV4::QObjectWrapper> constWrapper(
+ scope,
+ scope.engine->m_multiplyWrappedQObjects->value(
+ static_cast<const QObject *>(o)));
+
+ Q_ASSERT(constWrapper);
+
+ if (This == constWrapper->d()) {
+ // We've got the const wrapper. Also mark the non-const one
+ if (ddata->jsEngineId == scope.engine->m_engineId)
+ ddata->jsWrapper.markOnce(markStack);
+ else
+ scope.engine->m_multiplyWrappedQObjects->mark(o, markStack);
+ } else {
+ // We've got the non-const wrapper. Also mark the const one.
+ constWrapper->mark(markStack);
+ }
+ }
+ }
// Children usually don't need to be marked, the gc keeps them alive.
// But in the rare case of a "floating" QObject without a parent that
@@ -1159,38 +1524,45 @@ void Heap::QObjectWrapper::markObjects(Heap::Base *that, QV4::MarkStack *markSta
void QObjectWrapper::destroyObject(bool lastCall)
{
Heap::QObjectWrapper *h = d();
- if (!h->internalClass)
- return; // destroyObject already got called
+ Q_ASSERT(h->internalClass);
- if (h->object()) {
- QQmlData *ddata = QQmlData::get(h->object(), false);
+ if (QObject *o = h->object()) {
+ QQmlData *ddata = QQmlData::get(o, false);
if (ddata) {
- if (!h->object()->parent() && !ddata->indestructible) {
+ if (!o->parent() && !ddata->indestructible) {
if (ddata && ddata->ownContext) {
- Q_ASSERT(ddata->ownContext == ddata->context);
- ddata->ownContext->emitDestruction();
- ddata->ownContext = nullptr;
+ Q_ASSERT(ddata->ownContext.data() == ddata->context);
+ ddata->ownContext->deepClearContextObject(o);
+ ddata->ownContext.reset();
ddata->context = nullptr;
}
- // This object is notionally destroyed now
+
+ // This object is notionally destroyed now. It might still live until the next
+ // event loop iteration, but it won't need its connections, CU, or deferredData
+ // anymore.
+
ddata->isQueuedForDeletion = true;
+ ddata->disconnectNotifiers(QQmlData::DeleteNotifyList::No);
+ ddata->compilationUnit.reset();
+
+ qDeleteAll(ddata->deferredData);
+ ddata->deferredData.clear();
+
if (lastCall)
- delete h->object();
+ delete o;
else
- h->object()->deleteLater();
+ o->deleteLater();
} else {
// If the object is C++-owned, we still have to release the weak reference we have
// to it.
ddata->jsWrapper.clear();
- if (lastCall && ddata->propertyCache) {
- ddata->propertyCache->release();
- ddata->propertyCache = nullptr;
- }
+ if (lastCall && ddata->propertyCache)
+ ddata->propertyCache.reset();
}
}
}
- h->~Data();
+ h->destroy();
}
@@ -1209,21 +1581,26 @@ public:
};
struct CallArgument {
- inline CallArgument();
- inline ~CallArgument();
+ Q_DISABLE_COPY_MOVE(CallArgument);
+
+ CallArgument() = default;
+ ~CallArgument() { cleanup(); }
+
inline void *dataPtr();
- inline void initAsType(int type);
- inline bool fromValue(int type, ExecutionEngine *, const QV4::Value &);
+ inline void initAsType(QMetaType type);
+ inline bool fromValue(QMetaType type, ExecutionEngine *, const Value &);
inline ReturnedValue toValue(ExecutionEngine *);
private:
- CallArgument(const CallArgument &);
+ // QVariantWrappedType denotes that we're storing a QVariant, but we mean
+ // the type inside the QVariant, not QVariant itself.
+ enum { QVariantWrappedType = -1 };
inline void cleanup();
template <class T, class M>
- void fromContainerValue(const QV4::Object *object, int type, M CallArgument::*member, bool &queryEngine);
+ bool fromContainerValue(const Value &object, M CallArgument::*member);
union {
float floatValue;
@@ -1262,12 +1639,12 @@ private:
QJsonValue *jsonValuePtr;
};
- int type;
+ int type = QMetaType::UnknownType;
};
}
-static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index, int returnType, int argCount,
- int *argTypes, QV4::ExecutionEngine *engine, QV4::CallData *callArgs,
+static ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index, QMetaType returnType, int argCount,
+ const QMetaType *argTypes, ExecutionEngine *engine, CallData *callArgs,
QMetaObject::Call callType = QMetaObject::InvokeMetaMethod)
{
if (argCount > 0) {
@@ -1276,7 +1653,7 @@ static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index
args[0].initAsType(returnType);
for (int ii = 0; ii < argCount; ++ii) {
if (!args[ii + 1].fromValue(argTypes[ii], engine,
- callArgs->args[ii].asValue<QV4::Value>())) {
+ callArgs->args[ii].asValue<Value>())) {
qWarning() << QString::fromLatin1("Could not convert argument %1 at").arg(ii);
const StackTrace stack = engine->stackTrace();
for (const StackFrame &frame : stack) {
@@ -1286,22 +1663,27 @@ static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index
: QString());
}
- qWarning() << QLatin1String("Passing incompatible arguments to C++ functions from "
- "JavaScript is dangerous and deprecated.");
- qWarning() << QLatin1String("This will throw a JavaScript TypeError in future "
- "releases of Qt!");
+ const bool is_signal =
+ object.metaObject()->method(index).methodType() == QMetaMethod::Signal;
+ if (is_signal) {
+ qWarning() << "Passing incompatible arguments to signals is not supported.";
+ } else {
+ return engine->throwTypeError(
+ QLatin1String("Passing incompatible arguments to C++ functions from "
+ "JavaScript is not allowed."));
+ }
}
}
- QVarLengthArray<void *, 9> argData(args.count());
- for (int ii = 0; ii < args.count(); ++ii)
+ QVarLengthArray<void *, 9> argData(args.size());
+ for (int ii = 0; ii < args.size(); ++ii)
argData[ii] = args[ii].dataPtr();
object.metacall(callType, index, argData.data());
return args[0].toValue(engine);
- } else if (returnType != QMetaType::Void) {
+ } else if (returnType != QMetaType::fromType<void>()) {
CallArgument arg;
arg.initAsType(returnType);
@@ -1321,14 +1703,35 @@ static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index
}
}
+template<typename Retrieve>
+int MatchVariant(QMetaType conversionMetaType, Retrieve &&retrieve) {
+ if (conversionMetaType == QMetaType::fromType<QVariant>())
+ return 0;
+
+ const QMetaType type = retrieve();
+ if (type == conversionMetaType)
+ return 0;
+
+ if (const QMetaObject *conversionMetaObject = conversionMetaType.metaObject()) {
+ if (const QMetaObject *mo = type.metaObject(); mo && mo->inherits(conversionMetaObject))
+ return 1;
+ }
+
+ if (QMetaType::canConvert(type, conversionMetaType))
+ return 5;
+
+ return 10;
+};
+
/*
Returns the match score for converting \a actual to be of type \a conversionType. A
zero score means "perfect match" whereas a higher score is worse.
The conversion table is copied out of the \l QScript::callQtMethod() function.
*/
-static int MatchScore(const QV4::Value &actual, int conversionType)
+static int MatchScore(const Value &actual, QMetaType conversionMetaType)
{
+ const int conversionType = conversionMetaType.id();
if (actual.isNumber()) {
switch (conversionType) {
case QMetaType::Double:
@@ -1362,6 +1765,8 @@ static int MatchScore(const QV4::Value &actual, int conversionType)
return 0;
case QMetaType::QJsonValue:
return 5;
+ case QMetaType::QUrl:
+ return 6; // we like to convert strings to URLs in QML
default:
return 10;
}
@@ -1385,13 +1790,12 @@ static int MatchScore(const QV4::Value &actual, int conversionType)
default:
return 10;
}
- } else if (actual.as<QV4::RegExpObject>()) {
+ } else if (actual.as<RegExpObject>()) {
switch (conversionType) {
- case QMetaType::QRegExp:
#if QT_CONFIG(regularexpression)
case QMetaType::QRegularExpression:
-#endif
return 0;
+#endif
default:
return 10;
}
@@ -1425,149 +1829,172 @@ static int MatchScore(const QV4::Value &actual, int conversionType)
case QMetaType::QJsonValue:
return 0;
default: {
- const char *typeName = QMetaType::typeName(conversionType);
- if (typeName && typeName[strlen(typeName) - 1] == '*')
+ if (conversionMetaType.flags().testFlag(QMetaType::IsPointer))
return 0;
else
return 10;
}
}
- } else if (const QV4::Object *obj = actual.as<QV4::Object>()) {
- if (obj->as<QV4::VariantObject>()) {
- if (conversionType == qMetaTypeId<QVariant>())
- return 0;
- if (obj->engine()->toVariant(actual, -1).userType() == conversionType)
- return 0;
- else
- return 10;
+ } else if (const Object *obj = actual.as<Object>()) {
+ if (const VariantObject *variantObject = obj->as<VariantObject>()) {
+ return MatchVariant(conversionMetaType, [variantObject]() {
+ return variantObject->d()->data().metaType();
+ });
}
- if (obj->as<QObjectWrapper>()) {
+ if (const QObjectWrapper *wrapper = obj->as<QObjectWrapper>()) {
switch (conversionType) {
case QMetaType::QObjectStar:
return 0;
default:
- return 10;
+ if (conversionMetaType.flags() & QMetaType::PointerToQObject) {
+ QObject *wrapped = wrapper->object();
+ if (!wrapped)
+ return 0;
+ if (qmlobject_can_cpp_cast(wrapped, conversionMetaType.metaObject()))
+ return 0;
+ }
}
+ return 10;
}
- if (obj->as<QV4::QQmlValueTypeWrapper>()) {
- if (obj->engine()->toVariant(actual, -1).userType() == conversionType)
- return 0;
- return 10;
- } else if (conversionType == QMetaType::QJsonObject) {
- return 5;
- } else if (conversionType == qMetaTypeId<QJSValue>()) {
- return 0;
- } else {
+ if (const QQmlTypeWrapper *wrapper = obj->as<QQmlTypeWrapper>()) {
+ const QQmlType type = wrapper->d()->type();
+ if (type.isSingleton()) {
+ const QMetaType metaType = type.typeId();
+ if (metaType == conversionMetaType)
+ return 0;
+
+ if (conversionMetaType.flags() & QMetaType::PointerToQObject
+ && metaType.flags() & QMetaType::PointerToQObject
+ && type.metaObject()->inherits(conversionMetaType.metaObject())) {
+ return 0;
+ }
+ } else if (QObject *object = wrapper->object()) {
+ if (conversionMetaType.flags() & QMetaType::PointerToQObject
+ && qmlobject_can_cpp_cast(object, conversionMetaType.metaObject())) {
+ return 0;
+ }
+ }
+
return 10;
}
- } else {
- return 10;
+ if (const Sequence *sequence = obj->as<Sequence>()) {
+ if (SequencePrototype::metaTypeForSequence(sequence) == conversionMetaType)
+ return 1;
+ else
+ return 10;
+ }
+
+ if (const QQmlValueTypeWrapper *wrapper = obj->as<QQmlValueTypeWrapper>()) {
+ return MatchVariant(conversionMetaType, [wrapper]() {
+ return wrapper->d()->isVariant()
+ ? wrapper->toVariant().metaType()
+ : wrapper->type();
+ });
+ }
+
+ if (conversionType == QMetaType::QJsonObject)
+ return 5;
+ if (conversionType == qMetaTypeId<QJSValue>())
+ return 0;
+ if (conversionType == QMetaType::QVariantMap)
+ return 5;
}
+
+ return 10;
}
-static inline int QMetaObject_methods(const QMetaObject *metaObject)
+static int numDefinedArguments(CallData *callArgs)
{
- struct Private
- {
- int revision;
- int className;
- int classInfoCount, classInfoData;
- int methodCount, methodData;
- };
-
- return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
+ int numDefinedArguments = callArgs->argc();
+ while (numDefinedArguments > 0
+ && callArgs->args[numDefinedArguments - 1].type() == StaticValue::Undefined_Type) {
+ --numDefinedArguments;
+ }
+ return numDefinedArguments;
}
-/*
-Returns the next related method, if one, or 0.
-*/
-static const QQmlPropertyData * RelatedMethod(const QQmlObjectOrGadget &object,
- const QQmlPropertyData *current,
- QQmlPropertyData &dummy,
- const QQmlPropertyCache *propertyCache)
+static bool requiresStrictArguments(const QQmlObjectOrGadget &object)
{
- if (!current->isOverload())
- return nullptr;
-
- Q_ASSERT(!current->overrideIndexIsProperty());
-
- if (propertyCache) {
- return propertyCache->method(current->overrideIndex());
- } else {
- const QMetaObject *mo = object.metaObject();
- int methodOffset = mo->methodCount() - QMetaObject_methods(mo);
-
- while (methodOffset > current->overrideIndex()) {
- mo = mo->superClass();
- methodOffset -= QMetaObject_methods(mo);
- }
-
- // If we've been called before with the same override index, then
- // we can't go any further...
- if (&dummy == current && dummy.coreIndex() == current->overrideIndex())
- return nullptr;
-
- QMetaMethod method = mo->method(current->overrideIndex());
- dummy.load(method);
-
- // Look for overloaded methods
- QByteArray methodName = method.name();
- for (int ii = current->overrideIndex() - 1; ii >= methodOffset; --ii) {
- if (methodName == mo->method(ii).name()) {
- dummy.setOverload(true);
- dummy.setOverrideIndexIsProperty(0);
- dummy.setOverrideIndex(ii);
- return &dummy;
- }
- }
-
- return &dummy;
- }
+ const QMetaObject *metaObject = object.metaObject();
+ const int indexOfClassInfo = metaObject->indexOfClassInfo("QML.StrictArguments");
+ return indexOfClassInfo != -1
+ && metaObject->classInfo(indexOfClassInfo).value() == QByteArrayView("true");
}
-static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQmlPropertyData &data,
- QV4::ExecutionEngine *engine, QV4::CallData *callArgs,
- QMetaObject::Call callType = QMetaObject::InvokeMetaMethod)
+ReturnedValue QObjectMethod::callPrecise(
+ const QQmlObjectOrGadget &object, const QQmlPropertyData &data, ExecutionEngine *engine,
+ CallData *callArgs, QMetaObject::Call callType)
{
QByteArray unknownTypeError;
- int returnType = object.methodReturnType(data, &unknownTypeError);
+ QMetaType returnType = object.methodReturnType(data, &unknownTypeError);
- if (returnType == QMetaType::UnknownType) {
+ if (!returnType.isValid()) {
return engine->throwError(QLatin1String("Unknown method return type: ")
+ QLatin1String(unknownTypeError));
}
+ auto handleTooManyArguments = [&](int expectedArguments) {
+ if (requiresStrictArguments(object)) {
+ engine->throwError(QStringLiteral("Too many arguments"));
+ return false;
+ }
+
+ const auto stackTrace = engine->stackTrace();
+ if (stackTrace.isEmpty()) {
+ qWarning().nospace().noquote()
+ << "When matching arguments for "
+ << object.className() << "::" << data.name(object.metaObject()) << "():";
+ } else {
+ const StackFrame frame = stackTrace.first();
+ qWarning().noquote() << frame.function + QLatin1Char('@') + frame.source
+ + (frame.line > 0 ? (QLatin1Char(':') + QString::number(frame.line))
+ : QString());
+ }
+
+ qWarning().noquote() << QStringLiteral("Too many arguments, ignoring %1")
+ .arg(callArgs->argc() - expectedArguments);
+ return true;
+ };
+
+ const int definedArgumentCount = numDefinedArguments(callArgs);
+
if (data.hasArguments()) {
- int *args = nullptr;
- QQmlMetaObject::ArgTypeStorage storage;
+ QQmlMetaObject::ArgTypeStorage<9> storage;
+ bool ok = false;
if (data.isConstructor())
- args = static_cast<const QQmlStaticMetaObject&>(object).constructorParameterTypes(
- data.coreIndex(), &storage, &unknownTypeError);
+ ok = object.constructorParameterTypes(data.coreIndex(), &storage, &unknownTypeError);
else
- args = object.methodParameterTypes(data.coreIndex(), &storage, &unknownTypeError);
+ ok = object.methodParameterTypes(data.coreIndex(), &storage, &unknownTypeError);
- if (!args) {
+ if (!ok) {
return engine->throwError(QLatin1String("Unknown method parameter type: ")
+ QLatin1String(unknownTypeError));
}
- if (args[0] > callArgs->argc()) {
+ if (storage.size() > callArgs->argc()) {
QString error = QLatin1String("Insufficient arguments");
return engine->throwError(error);
}
- return CallMethod(object, data.coreIndex(), returnType, args[0], args + 1, engine, callArgs, callType);
+ if (storage.size() < definedArgumentCount) {
+ if (!handleTooManyArguments(storage.size()))
+ return Encode::undefined();
+
+ }
+
+ return CallMethod(object, data.coreIndex(), returnType, storage.size(), storage.constData(), engine, callArgs, callType);
} else {
+ if (definedArgumentCount > 0 && !handleTooManyArguments(0))
+ return Encode::undefined();
return CallMethod(object, data.coreIndex(), returnType, 0, nullptr, engine, callArgs, callType);
-
}
}
@@ -1581,736 +2008,1081 @@ Resolve the overloaded method to call. The algorithm works conceptually like th
For example, if we are called with 3 parameters and there are 2 overloads that
take 2 parameters and one that takes 3, eliminate the 2 parameter overloads.
3. Find the best remaining overload based on its match score.
- If two or more overloads have the same match score, call the last one. The match
+ If two or more overloads have the same match score, return the last one. The match
score is constructed by adding the matchScore() result for each of the parameters.
*/
-static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const QQmlPropertyData &data,
- QV4::ExecutionEngine *engine, QV4::CallData *callArgs, const QQmlPropertyCache *propertyCache,
- QMetaObject::Call callType = QMetaObject::InvokeMetaMethod)
+const QQmlPropertyData *QObjectMethod::resolveOverloaded(
+ const QQmlObjectOrGadget &object, const QQmlPropertyData *methods, int methodCount,
+ ExecutionEngine *engine, CallData *callArgs)
{
- int argumentCount = callArgs->argc();
+ const int argumentCount = callArgs->argc();
+ const int definedArgumentCount = numDefinedArguments(callArgs);
- QQmlPropertyData best;
+ const QQmlPropertyData *best = nullptr;
int bestParameterScore = INT_MAX;
- int bestMatchScore = INT_MAX;
+ int bestMaxMatchScore = INT_MAX;
+ int bestSumMatchScore = INT_MAX;
- QQmlPropertyData dummy;
- const QQmlPropertyData *attempt = &data;
+ Scope scope(engine);
+ ScopedValue v(scope);
- QV4::Scope scope(engine);
- QV4::ScopedValue v(scope);
-
- do {
- QQmlMetaObject::ArgTypeStorage storage;
- int methodArgumentCount = 0;
- int *methodArgTypes = nullptr;
- if (attempt->hasArguments()) {
- int *args = object.methodParameterTypes(attempt->coreIndex(), &storage, nullptr);
- if (!args) // Must be an unknown argument
- continue;
+ for (int i = 0; i < methodCount; ++i) {
+ const QQmlPropertyData *attempt = methods + i;
- methodArgumentCount = args[0];
- methodArgTypes = args + 1;
+ if (lcOverloadResolution().isDebugEnabled()) {
+ const QQmlPropertyData &candidate = methods[i];
+ const QMetaMethod m = candidate.isConstructor()
+ ? object.metaObject()->constructor(candidate.coreIndex())
+ : object.metaObject()->method(candidate.coreIndex());
+ qCDebug(lcOverloadResolution) << "::: considering signature" << m.methodSignature();
}
- if (methodArgumentCount > argumentCount)
- continue; // We don't have sufficient arguments to call this method
+ // QQmlV4Function overrides anything that doesn't provide the exact number of arguments
+ int methodParameterScore = 1;
+ // QQmlV4Function overrides the "no idea" option, which is 10
+ int maxMethodMatchScore = 9;
+ // QQmlV4Function cannot provide a best sum of match scores as we don't match the arguments
+ int sumMethodMatchScore = bestSumMatchScore;
+
+ if (!attempt->isV4Function()) {
+ QQmlMetaObject::ArgTypeStorage<9> storage;
+ int methodArgumentCount = 0;
+ if (attempt->hasArguments()) {
+ if (attempt->isConstructor()) {
+ if (!object.constructorParameterTypes(attempt->coreIndex(), &storage, nullptr)) {
+ qCDebug(lcOverloadResolution, "rejected, could not get ctor argument types");
+ continue;
+ }
+ } else {
+ if (!object.methodParameterTypes(attempt->coreIndex(), &storage, nullptr)) {
+ qCDebug(lcOverloadResolution, "rejected, could not get ctor argument types");
+ continue;
+ }
+ }
+ methodArgumentCount = storage.size();
+ }
+
+ if (methodArgumentCount > argumentCount) {
+ qCDebug(lcOverloadResolution, "rejected, insufficient arguments");
+ continue; // We don't have sufficient arguments to call this method
+ }
- int methodParameterScore = argumentCount - methodArgumentCount;
- if (methodParameterScore > bestParameterScore)
- continue; // We already have a better option
+ methodParameterScore = (definedArgumentCount == methodArgumentCount)
+ ? 0
+ : (definedArgumentCount - methodArgumentCount + 1);
+ if (methodParameterScore > bestParameterScore) {
+ qCDebug(lcOverloadResolution) << "rejected, score too bad. own" << methodParameterScore << "vs best:" << bestParameterScore;
+ continue; // We already have a better option
+ }
- int methodMatchScore = 0;
- for (int ii = 0; ii < methodArgumentCount; ++ii) {
- methodMatchScore += MatchScore((v = Value::fromStaticValue(callArgs->args[ii])),
- methodArgTypes[ii]);
+ maxMethodMatchScore = 0;
+ sumMethodMatchScore = 0;
+ for (int ii = 0; ii < methodArgumentCount; ++ii) {
+ const int score = MatchScore((v = Value::fromStaticValue(callArgs->args[ii])),
+ storage[ii]);
+ maxMethodMatchScore = qMax(maxMethodMatchScore, score);
+ sumMethodMatchScore += score;
+ }
}
- if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
- best = *attempt;
+ if (bestParameterScore > methodParameterScore || bestMaxMatchScore > maxMethodMatchScore
+ || (bestParameterScore == methodParameterScore
+ && bestMaxMatchScore == maxMethodMatchScore
+ && bestSumMatchScore > sumMethodMatchScore)) {
+ best = attempt;
bestParameterScore = methodParameterScore;
- bestMatchScore = methodMatchScore;
+ bestMaxMatchScore = maxMethodMatchScore;
+ bestSumMatchScore = sumMethodMatchScore;
+ qCDebug(lcOverloadResolution) << "updated best" << "bestParameterScore" << bestParameterScore << "\n"
+ << "bestMaxMatchScore" << bestMaxMatchScore << "\n"
+ << "bestSumMatchScore" << bestSumMatchScore << "\n";
+ } else {
+ qCDebug(lcOverloadResolution) << "did not update best\n"
+ << "bestParameterScore" << bestParameterScore << "\t"
+ << "methodParameterScore" << methodParameterScore << "\n"
+ << "bestMaxMatchScore" << bestMaxMatchScore << "\t"
+ << "maxMethodMatchScore" << maxMethodMatchScore << "\n"
+ << "bestSumMatchScore" << bestSumMatchScore << "\t"
+ << "sumMethodMatchScore" << sumMethodMatchScore << "\n";
}
- if (bestParameterScore == 0 && bestMatchScore == 0)
+ if (bestParameterScore == 0 && bestMaxMatchScore == 0) {
+ qCDebug(lcOverloadResolution, "perfect match");
break; // We can't get better than that
+ }
- } while ((attempt = RelatedMethod(object, attempt, dummy, propertyCache)) != nullptr);
+ };
- if (best.isValid()) {
- return CallPrecise(object, best, engine, callArgs, callType);
+ if (best && best->isValid()) {
+ return best;
} else {
QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
- const QQmlPropertyData *candidate = &data;
- while (candidate) {
- error += QLatin1String("\n ") +
- QString::fromUtf8(object.metaObject()->method(candidate->coreIndex())
- .methodSignature());
- candidate = RelatedMethod(object, candidate, dummy, propertyCache);
+ for (int i = 0; i < methodCount; ++i) {
+ const QQmlPropertyData &candidate = methods[i];
+ const QMetaMethod m = candidate.isConstructor()
+ ? object.metaObject()->constructor(candidate.coreIndex())
+ : object.metaObject()->method(candidate.coreIndex());
+ error += u"\n " + QString::fromUtf8(m.methodSignature());
}
- return engine->throwError(error);
+ engine->throwError(error);
+ return nullptr;
}
}
-CallArgument::CallArgument()
-: type(QVariant::Invalid)
+static bool ExactMatch(QMetaType passed, QMetaType required, const void *data)
{
+ if (required == QMetaType::fromType<QVariant>()
+ || required == QMetaType::fromType<QJSValue>()
+ || required == QMetaType::fromType<QJSManagedValue>()) {
+ return true;
+ }
+
+ if (data) {
+ if (passed == QMetaType::fromType<QVariant>())
+ passed = static_cast<const QVariant *>(data)->metaType();
+ else if (passed == QMetaType::fromType<QJSPrimitiveValue>())
+ passed = static_cast<const QJSPrimitiveValue *>(data)->metaType();
+ }
+
+ if (passed == required)
+ return true;
+
+ if (required == QMetaType::fromType<QJSPrimitiveValue>()) {
+ switch (passed.id()) {
+ case QMetaType::UnknownType:
+ case QMetaType::Nullptr:
+ case QMetaType::Bool:
+ case QMetaType::Int:
+ case QMetaType::Double:
+ case QMetaType::QString:
+ return true;
+ default:
+ break;
+ }
+ }
+
+ return false;
}
-CallArgument::~CallArgument()
+const QQmlPropertyData *QObjectMethod::resolveOverloaded(
+ const QQmlPropertyData *methods, int methodCount,
+ void **argv, int argc, const QMetaType *types)
{
- cleanup();
+ // We only accept exact matches here. Everything else goes through the JavaScript conversion.
+ for (int i = 0; i < methodCount; ++i) {
+ const QQmlPropertyData *attempt = methods + i;
+ if (types[0].isValid() && !ExactMatch(attempt->propType(), types[0], nullptr))
+ continue;
+
+ const QMetaMethod method = attempt->metaMethod();
+ if (method.parameterCount() != argc)
+ continue;
+
+ bool valid = true;
+ for (int i = 0; i < argc; ++i) {
+ if (!ExactMatch(types[i + 1], method.parameterMetaType(i), argv[i + 1])) {
+ valid = false;
+ break;
+ }
+ }
+
+ if (valid)
+ return attempt;
+ }
+
+ return nullptr;
}
void CallArgument::cleanup()
{
- if (type == QMetaType::QString) {
+ switch (type) {
+ case QMetaType::QString:
qstringPtr->~QString();
- } else if (type == QMetaType::QByteArray) {
+ break;
+ case QMetaType::QByteArray:
qbyteArrayPtr->~QByteArray();
- } else if (type == -1 || type == QMetaType::QVariant) {
+ break;
+ case QMetaType::QVariant:
+ case QVariantWrappedType:
qvariantPtr->~QVariant();
- } else if (type == qMetaTypeId<QJSValue>()) {
- qjsValuePtr->~QJSValue();
- } else if (type == qMetaTypeId<QList<QObject *> >()) {
- qlistPtr->~QList<QObject *>();
- } else if (type == QMetaType::QJsonArray) {
+ break;
+ case QMetaType::QJsonArray:
jsonArrayPtr->~QJsonArray();
- } else if (type == QMetaType::QJsonObject) {
+ break;
+ case QMetaType::QJsonObject:
jsonObjectPtr->~QJsonObject();
- } else if (type == QMetaType::QJsonValue) {
+ break;
+ case QMetaType::QJsonValue:
jsonValuePtr->~QJsonValue();
+ break;
+ default:
+ if (type == qMetaTypeId<QJSValue>()) {
+ qjsValuePtr->~QJSValue();
+ break;
+ }
+
+ if (type == qMetaTypeId<QList<QObject *> >()) {
+ qlistPtr->~QList<QObject *>();
+ break;
+ }
+
+ // The sequence types need no cleanup because we don't own them.
+
+ break;
}
}
void *CallArgument::dataPtr()
{
- if (type == -1)
+ switch (type) {
+ case QMetaType::UnknownType:
+ return nullptr;
+ case QVariantWrappedType:
return qvariantPtr->data();
- else if (type == qMetaTypeId<std::vector<int>>())
- return stdVectorIntPtr;
- else if (type == qMetaTypeId<std::vector<qreal>>())
- return stdVectorRealPtr;
- else if (type == qMetaTypeId<std::vector<bool>>())
- return stdVectorBoolPtr;
- else if (type == qMetaTypeId<std::vector<QString>>())
- return stdVectorQStringPtr;
- else if (type == qMetaTypeId<std::vector<QUrl>>())
- return stdVectorQUrlPtr;
+ default:
+ if (type == qMetaTypeId<std::vector<int>>())
+ return stdVectorIntPtr;
+ if (type == qMetaTypeId<std::vector<qreal>>())
+ return stdVectorRealPtr;
+ if (type == qMetaTypeId<std::vector<bool>>())
+ return stdVectorBoolPtr;
+ if (type == qMetaTypeId<std::vector<QString>>())
+ return stdVectorQStringPtr;
+ if (type == qMetaTypeId<std::vector<QUrl>>())
+ return stdVectorQUrlPtr;
#if QT_CONFIG(qml_itemmodel)
- else if (type == qMetaTypeId<std::vector<QModelIndex>>())
- return stdVectorQModelIndexPtr;
+ if (type == qMetaTypeId<std::vector<QModelIndex>>())
+ return stdVectorQModelIndexPtr;
#endif
- else if (type != 0)
- return (void *)&allocData;
- return nullptr;
+ break;
+ }
+
+ return (void *)&allocData;
}
-void CallArgument::initAsType(int callType)
+void CallArgument::initAsType(QMetaType metaType)
{
- if (type != 0) { cleanup(); type = 0; }
- if (callType == QMetaType::UnknownType || callType == QMetaType::Void) return;
+ if (type != QMetaType::UnknownType)
+ cleanup();
- if (callType == qMetaTypeId<QJSValue>()) {
- qjsValuePtr = new (&allocData) QJSValue();
- type = callType;
- } else if (callType == QMetaType::Int ||
- callType == QMetaType::UInt ||
- callType == QMetaType::Bool ||
- callType == QMetaType::Double ||
- callType == QMetaType::Float) {
- type = callType;
- } else if (callType == QMetaType::QObjectStar) {
+ type = metaType.id();
+ switch (type) {
+ case QMetaType::Void:
+ type = QMetaType::UnknownType;
+ break;
+ case QMetaType::UnknownType:
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ case QMetaType::Bool:
+ case QMetaType::Double:
+ case QMetaType::Float:
+ break;
+ case QMetaType::QObjectStar:
qobjectPtr = nullptr;
- type = callType;
- } else if (callType == QMetaType::QString) {
+ break;
+ case QMetaType::QString:
qstringPtr = new (&allocData) QString();
- type = callType;
- } else if (callType == QMetaType::QVariant) {
- type = callType;
+ break;
+ case QMetaType::QVariant:
qvariantPtr = new (&allocData) QVariant();
- } else if (callType == qMetaTypeId<QList<QObject *> >()) {
- type = callType;
- qlistPtr = new (&allocData) QList<QObject *>();
- } else if (callType == QMetaType::QJsonArray) {
- type = callType;
+ break;
+ case QMetaType::QJsonArray:
jsonArrayPtr = new (&allocData) QJsonArray();
- } else if (callType == QMetaType::QJsonObject) {
- type = callType;
+ break;
+ case QMetaType::QJsonObject:
jsonObjectPtr = new (&allocData) QJsonObject();
- } else if (callType == QMetaType::QJsonValue) {
- type = callType;
+ break;
+ case QMetaType::QJsonValue:
jsonValuePtr = new (&allocData) QJsonValue();
- } else {
- type = -1;
- qvariantPtr = new (&allocData) QVariant(callType, (void *)nullptr);
+ break;
+ default: {
+ if (metaType == QMetaType::fromType<QJSValue>()) {
+ qjsValuePtr = new (&allocData) QJSValue();
+ break;
+ }
+
+ if (metaType == QMetaType::fromType<QList<QObject *>>()) {
+ qlistPtr = new (&allocData) QList<QObject *>();
+ break;
+ }
+
+ type = QVariantWrappedType;
+ qvariantPtr = new (&allocData) QVariant(metaType, (void *)nullptr);
+ break;
+ }
}
}
-#if QT_CONFIG(qml_sequence_object)
template <class T, class M>
-void CallArgument::fromContainerValue(const QV4::Object *object, int callType, M CallArgument::*member, bool &queryEngine)
+bool CallArgument::fromContainerValue(const Value &value, M CallArgument::*member)
{
- if (object && object->isListType()) {
- T* ptr = static_cast<T*>(QV4::SequencePrototype::getRawContainerPtr(object, callType));
- if (ptr) {
- (this->*member) = ptr;
- type = callType;
- queryEngine = false;
+ if (const Sequence *sequence = value.as<Sequence>()) {
+ if (T* ptr = static_cast<T *>(SequencePrototype::getRawContainerPtr(
+ sequence, QMetaType(type)))) {
+ (this->*member) = ptr;
+ return true;
+ }
}
- }
+ (this->*member) = nullptr;
+ return false;
}
-#endif
-bool CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const QV4::Value &value)
+bool CallArgument::fromValue(QMetaType metaType, ExecutionEngine *engine, const Value &value)
{
- if (type != 0) {
+ if (type != QMetaType::UnknownType)
cleanup();
- type = 0;
- }
- QV4::Scope scope(engine);
+ type = metaType.id();
- bool queryEngine = false;
- if (callType == qMetaTypeId<QJSValue>()) {
- qjsValuePtr = new (&allocData) QJSValue(scope.engine, value.asReturnedValue());
- type = qMetaTypeId<QJSValue>();
- } else if (callType == QMetaType::Int) {
+ switch (type) {
+ case QMetaType::Int:
intValue = quint32(value.toInt32());
- type = callType;
- } else if (callType == QMetaType::UInt) {
+ return true;
+ case QMetaType::UInt:
intValue = quint32(value.toUInt32());
- type = callType;
- } else if (callType == QMetaType::Bool) {
+ return true;
+ case QMetaType::Bool:
boolValue = value.toBoolean();
- type = callType;
- } else if (callType == QMetaType::Double) {
+ return true;
+ case QMetaType::Double:
doubleValue = double(value.toNumber());
- type = callType;
- } else if (callType == QMetaType::Float) {
+ return true;
+ case QMetaType::Float:
floatValue = float(value.toNumber());
- type = callType;
- } else if (callType == QMetaType::QString) {
- if (value.isNull() || value.isUndefined())
+ return true;
+ case QMetaType::QString:
+ if (value.isNullOrUndefined())
qstringPtr = new (&allocData) QString();
else
qstringPtr = new (&allocData) QString(value.toQStringNoThrow());
- type = callType;
- } else if (callType == QMetaType::QObjectStar) {
- qobjectPtr = nullptr;
- type = callType;
- if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>())
+ return true;
+ case QMetaType::QByteArray:
+ qbyteArrayPtr = new (&allocData) QByteArray();
+ ExecutionEngine::metaTypeFromJS(value, metaType, qbyteArrayPtr);
+ return true;
+ case QMetaType::QObjectStar:
+ if (const QObjectWrapper *qobjectWrapper = value.as<QObjectWrapper>()) {
qobjectPtr = qobjectWrapper->object();
- else if (const QV4::QQmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QQmlTypeWrapper>())
- queryEngine = qmlTypeWrapper->isSingleton();
- else if (!value.isNull() && !value.isUndefined()) // null and undefined are nullptr
- return false;
- } else if (callType == qMetaTypeId<QVariant>()) {
- qvariantPtr = new (&allocData) QVariant(scope.engine->toVariant(value, -1));
- type = callType;
- } else if (callType == qMetaTypeId<QList<QObject*> >()) {
- qlistPtr = new (&allocData) QList<QObject *>();
- type = callType;
- QV4::ScopedArrayObject array(scope, value);
- if (array) {
- Scoped<QV4::QObjectWrapper> qobjectWrapper(scope);
-
- uint length = array->getLength();
- for (uint ii = 0; ii < length; ++ii) {
- QObject *o = nullptr;
- qobjectWrapper = array->get(ii);
- if (!!qobjectWrapper)
- o = qobjectWrapper->object();
- qlistPtr->append(o);
- }
- } else {
- if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) {
- qlistPtr->append(qobjectWrapper->object());
- } else {
- qlistPtr->append(nullptr);
- if (!value.isNull() && !value.isUndefined())
- return false;
+ return true;
+ }
+
+ if (const QQmlTypeWrapper *qmlTypeWrapper = value.as<QQmlTypeWrapper>()) {
+ if (qmlTypeWrapper->isSingleton()) {
+ // Convert via QVariant below.
+ // TODO: Can't we just do qobjectPtr = qmlTypeWrapper->object() instead?
+ break;
+ } else if (QObject *obj = qmlTypeWrapper->object()) {
+ // attached object case
+ qobjectPtr = obj;
+ return true;
}
+
+ // If this is a plain type wrapper without an instance,
+ // then we got a namespace, and that's a type error
+ type = QMetaType::UnknownType;
+ return false;
}
- } else if (callType == QMetaType::QJsonArray) {
- QV4::ScopedArrayObject a(scope, value);
- jsonArrayPtr = new (&allocData) QJsonArray(QV4::JsonObject::toJsonArray(a));
- type = callType;
- } else if (callType == QMetaType::QJsonObject) {
- QV4::ScopedObject o(scope, value);
- jsonObjectPtr = new (&allocData) QJsonObject(QV4::JsonObject::toJsonObject(o));
- type = callType;
- } else if (callType == QMetaType::QJsonValue) {
- jsonValuePtr = new (&allocData) QJsonValue(QV4::JsonObject::toJsonValue(value));
- type = callType;
- } else if (callType == QMetaType::Void) {
+
+ qobjectPtr = nullptr;
+ return value.isNullOrUndefined(); // null and undefined are nullptr
+ case QMetaType::QVariant:
+ qvariantPtr = new (&allocData) QVariant(ExecutionEngine::toVariant(value, QMetaType {}));
+ return true;
+ case QMetaType::QJsonArray: {
+ Scope scope(engine);
+ ScopedObject o(scope, value);
+ jsonArrayPtr = new (&allocData) QJsonArray(JsonObject::toJsonArray(o));
+ return true;
+ }
+ case QMetaType::QJsonObject: {
+ Scope scope(engine);
+ ScopedObject o(scope, value);
+ jsonObjectPtr = new (&allocData) QJsonObject(JsonObject::toJsonObject(o));
+ return true;
+ }
+ case QMetaType::QJsonValue:
+ jsonValuePtr = new (&allocData) QJsonValue(JsonObject::toJsonValue(value));
+ return true;
+ case QMetaType::Void:
+ type = QMetaType::UnknownType;
+ // TODO: This only doesn't leak because a default constructed QVariant doesn't allocate.
*qvariantPtr = QVariant();
-#if QT_CONFIG(qml_sequence_object)
- } else if (callType == qMetaTypeId<std::vector<int>>()
- || callType == qMetaTypeId<std::vector<qreal>>()
- || callType == qMetaTypeId<std::vector<bool>>()
- || callType == qMetaTypeId<std::vector<QString>>()
- || callType == qMetaTypeId<std::vector<QUrl>>()
-#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>>()) {
- stdVectorIntPtr = nullptr;
- fromContainerValue<std::vector<int>>(object, callType, &CallArgument::stdVectorIntPtr, queryEngine);
- } else if (callType == qMetaTypeId<std::vector<qreal>>()) {
- stdVectorRealPtr = nullptr;
- fromContainerValue<std::vector<qreal>>(object, callType, &CallArgument::stdVectorRealPtr, queryEngine);
- } else if (callType == qMetaTypeId<std::vector<bool>>()) {
- stdVectorBoolPtr = nullptr;
- fromContainerValue<std::vector<bool>>(object, callType, &CallArgument::stdVectorBoolPtr, queryEngine);
- } else if (callType == qMetaTypeId<std::vector<QString>>()) {
- stdVectorQStringPtr = nullptr;
- fromContainerValue<std::vector<QString>>(object, callType, &CallArgument::stdVectorQStringPtr, queryEngine);
- } 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)
- & (QMetaType::PointerToQObject | QMetaType::PointerToGadget)) {
- // You can assign null or undefined to any pointer. The result is a nullptr.
- if (value.isNull() || value.isUndefined()) {
- qvariantPtr = new (&allocData) QVariant(callType, nullptr);
- type = callType;
- } else {
- queryEngine = true;
+ return true;
+ default:
+ if (type == qMetaTypeId<QJSValue>()) {
+ qjsValuePtr = new (&allocData) QJSValue;
+ QJSValuePrivate::setValue(qjsValuePtr, value.asReturnedValue());
+ return true;
}
- } else {
- queryEngine = true;
- }
- if (queryEngine) {
- qvariantPtr = new (&allocData) QVariant();
- type = -1;
+ if (type == qMetaTypeId<QList<QObject*> >()) {
+ qlistPtr = new (&allocData) QList<QObject *>();
+ Scope scope(engine);
+ ScopedArrayObject array(scope, value);
+ if (array) {
+ Scoped<QObjectWrapper> qobjectWrapper(scope);
+
+ uint length = array->getLength();
+ for (uint ii = 0; ii < length; ++ii) {
+ QObject *o = nullptr;
+ qobjectWrapper = array->get(ii);
+ if (!!qobjectWrapper)
+ o = qobjectWrapper->object();
+ qlistPtr->append(o);
+ }
+ return true;
+ }
- QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr;
- QVariant v = scope.engine->toVariant(value, callType);
+ if (const QObjectWrapper *qobjectWrapper = value.as<QObjectWrapper>()) {
+ qlistPtr->append(qobjectWrapper->object());
+ return true;
+ }
- if (v.userType() == callType) {
- *qvariantPtr = v;
- } else if (v.canConvert(callType)) {
- *qvariantPtr = v;
- qvariantPtr->convert(callType);
- } else {
- QQmlMetaObject mo = ep ? ep->rawMetaObjectForType(callType) : QQmlMetaObject();
- if (!mo.isNull()) {
- QObject *obj = ep->toQObject(v);
+ if (const QmlListWrapper *listWrapper = value.as<QmlListWrapper>()) {
+ *qlistPtr = listWrapper->d()->property()->toList<QList<QObject *>>();
+ return true;
+ }
- if (obj != nullptr && !QQmlMetaObject::canConvert(obj, mo)) {
- *qvariantPtr = QVariant(callType, nullptr);
- return false;
- }
+ qlistPtr->append(nullptr);
+ return value.isNullOrUndefined();
+ }
- *qvariantPtr = QVariant(callType, &obj);
+ if (metaType.flags() & (QMetaType::PointerToQObject | QMetaType::PointerToGadget)) {
+ // You can assign null or undefined to any pointer. The result is a nullptr.
+ if (value.isNullOrUndefined()) {
+ qvariantPtr = new (&allocData) QVariant(metaType, nullptr);
return true;
}
+ break;
+ }
- *qvariantPtr = QVariant(callType, (void *)nullptr);
- return false;
+ if (type == qMetaTypeId<std::vector<int>>()) {
+ if (fromContainerValue<std::vector<int>>(value, &CallArgument::stdVectorIntPtr))
+ return true;
+ } else if (type == qMetaTypeId<std::vector<qreal>>()) {
+ if (fromContainerValue<std::vector<qreal>>(value, &CallArgument::stdVectorRealPtr))
+ return true;
+ } else if (type == qMetaTypeId<std::vector<bool>>()) {
+ if (fromContainerValue<std::vector<bool>>(value, &CallArgument::stdVectorBoolPtr))
+ return true;
+ } else if (type == qMetaTypeId<std::vector<QString>>()) {
+ if (fromContainerValue<std::vector<QString>>(value, &CallArgument::stdVectorQStringPtr))
+ return true;
+ } else if (type == qMetaTypeId<std::vector<QUrl>>()) {
+ if (fromContainerValue<std::vector<QUrl>>(value, &CallArgument::stdVectorQUrlPtr))
+ return true;
+#if QT_CONFIG(qml_itemmodel)
+ } else if (type == qMetaTypeId<std::vector<QModelIndex>>()) {
+ if (fromContainerValue<std::vector<QModelIndex>>(
+ value, &CallArgument::stdVectorQModelIndexPtr)) {
+ return true;
+ }
+#endif
}
+ break;
}
- return true;
-}
-QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine)
-{
- QV4::Scope scope(engine);
+ // Convert via QVariant through the QML engine.
+ qvariantPtr = new (&allocData) QVariant(metaType);
+ type = QVariantWrappedType;
- if (type == qMetaTypeId<QJSValue>()) {
- return QJSValuePrivate::convertedToValue(scope.engine, *qjsValuePtr);
- } else if (type == QMetaType::Int) {
- return QV4::Encode(int(intValue));
- } else if (type == QMetaType::UInt) {
- return QV4::Encode((uint)intValue);
- } else if (type == QMetaType::Bool) {
- return QV4::Encode(boolValue);
- } else if (type == QMetaType::Double) {
- return QV4::Encode(doubleValue);
- } else if (type == QMetaType::Float) {
- return QV4::Encode(floatValue);
- } else if (type == QMetaType::QString) {
- return QV4::Encode(engine->newString(*qstringPtr));
- } else if (type == QMetaType::QByteArray) {
- return QV4::Encode(engine->newArrayBuffer(*qbyteArrayPtr));
- } else if (type == QMetaType::QObjectStar) {
- QObject *object = qobjectPtr;
- if (object)
- QQmlData::get(object, true)->setImplicitDestructible();
- return QV4::QObjectWrapper::wrap(scope.engine, object);
- } else if (type == qMetaTypeId<QList<QObject *> >()) {
- // XXX Can this be made more by using Array as a prototype and implementing
- // directly against QList<QObject*>?
- QList<QObject *> &list = *qlistPtr;
- QV4::ScopedArrayObject array(scope, scope.engine->newArrayObject());
- array->arrayReserve(list.count());
- QV4::ScopedValue v(scope);
- for (int ii = 0; ii < list.count(); ++ii)
- array->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(scope.engine, list.at(ii))));
- array->setArrayLengthUnchecked(list.count());
- return array.asReturnedValue();
- } else if (type == QMetaType::QJsonArray) {
- return QV4::JsonObject::fromJsonArray(scope.engine, *jsonArrayPtr);
- } else if (type == QMetaType::QJsonObject) {
- return QV4::JsonObject::fromJsonObject(scope.engine, *jsonObjectPtr);
- } else if (type == QMetaType::QJsonValue) {
- return QV4::JsonObject::fromJsonValue(scope.engine, *jsonValuePtr);
- } else if (type == -1 || type == qMetaTypeId<QVariant>()) {
- QVariant value = *qvariantPtr;
- QV4::ScopedValue rv(scope, scope.engine->fromVariant(value));
- QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, rv);
+ if (ExecutionEngine::metaTypeFromJS(value, metaType, qvariantPtr->data()))
+ return true;
+
+ const QVariant v = ExecutionEngine::toVariant(value, metaType);
+ return QMetaType::convert(v.metaType(), v.constData(), metaType, qvariantPtr->data());
+}
+
+ReturnedValue CallArgument::toValue(ExecutionEngine *engine)
+{
+ switch (type) {
+ case QMetaType::Int:
+ return Encode(int(intValue));
+ case QMetaType::UInt:
+ return Encode((uint)intValue);
+ case QMetaType::Bool:
+ return Encode(boolValue);
+ case QMetaType::Double:
+ return Encode(doubleValue);
+ case QMetaType::Float:
+ return Encode(floatValue);
+ case QMetaType::QString:
+ return Encode(engine->newString(*qstringPtr));
+ case QMetaType::QByteArray:
+ return Encode(engine->newArrayBuffer(*qbyteArrayPtr));
+ case QMetaType::QObjectStar:
+ if (qobjectPtr)
+ QQmlData::get(qobjectPtr, true)->setImplicitDestructible();
+ return QObjectWrapper::wrap(engine, qobjectPtr);
+ case QMetaType::QJsonArray:
+ return JsonObject::fromJsonArray(engine, *jsonArrayPtr);
+ case QMetaType::QJsonObject:
+ return JsonObject::fromJsonObject(engine, *jsonObjectPtr);
+ case QMetaType::QJsonValue:
+ return JsonObject::fromJsonValue(engine, *jsonValuePtr);
+ case QMetaType::QVariant:
+ case QVariantWrappedType: {
+ Scope scope(engine);
+ ScopedValue rv(scope, scope.engine->fromVariant(*qvariantPtr));
+ Scoped<QObjectWrapper> qobjectWrapper(scope, rv);
if (!!qobjectWrapper) {
if (QObject *object = qobjectWrapper->object())
QQmlData::get(object, true)->setImplicitDestructible();
}
return rv->asReturnedValue();
- } else {
- return QV4::Encode::undefined();
}
-}
+ default:
+ break;
+ }
-ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, int index)
-{
- Scope valueScope(scope);
- Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocate<QObjectMethod>(scope));
- method->d()->setObject(object);
+ if (type == qMetaTypeId<QJSValue>()) {
+ // The QJSValue can be passed around via dataPtr()
+ QJSValuePrivate::manageStringOnV4Heap(engine, qjsValuePtr);
+ return QJSValuePrivate::asReturnedValue(qjsValuePtr);
+ }
- if (QQmlData *ddata = QQmlData::get(object))
- method->d()->setPropertyCache(ddata->propertyCache);
+ if (type == qMetaTypeId<QList<QObject *> >()) {
+ // XXX Can this be made more by using Array as a prototype and implementing
+ // directly against QList<QObject*>?
+ QList<QObject *> &list = *qlistPtr;
+ Scope scope(engine);
+ ScopedArrayObject array(scope, engine->newArrayObject());
+ array->arrayReserve(list.size());
+ ScopedValue v(scope);
+ for (int ii = 0; ii < list.size(); ++ii)
+ array->arrayPut(ii, (v = QObjectWrapper::wrap(engine, list.at(ii))));
+ array->setArrayLengthUnchecked(list.size());
+ return array.asReturnedValue();
+ }
- method->d()->index = index;
- return method.asReturnedValue();
+ return Encode::undefined();
}
-ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index)
+ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::Object *wrapper, int index)
{
Scope valueScope(scope);
- Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocate<QObjectMethod>(scope));
- method->d()->setPropertyCache(valueType->propertyCache());
- method->d()->index = index;
- method->d()->valueTypeWrapper.set(valueScope.engine, valueType);
+ Scoped<QObjectMethod> method(
+ valueScope,
+ valueScope.engine->memoryManager->allocate<QObjectMethod>(scope, wrapper, index));
return method.asReturnedValue();
}
-void Heap::QObjectMethod::init(QV4::ExecutionContext *scope)
+ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index)
{
- Heap::FunctionObject::init(scope);
+ Scope valueScope(scope);
+ Scoped<QObjectMethod> method(
+ valueScope,
+ valueScope.engine->memoryManager->allocate<QObjectMethod>(scope, valueType, index));
+ return method.asReturnedValue();
}
-const QMetaObject *Heap::QObjectMethod::metaObject()
+ReturnedValue QObjectMethod::create(
+ ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
+ Heap::Object *wrapper, Heap::Object *object)
{
- if (propertyCache())
- return propertyCache()->createMetaObject();
- return object()->metaObject();
-}
+ Scope valueScope(engine);
-QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionEngine *engine) const
-{
- QString result;
- if (const QMetaObject *metaObject = d()->metaObject()) {
+ Scoped<QQmlValueTypeWrapper> valueTypeWrapper(valueScope);
+ if (cloneFrom->wrapper) {
+ Scoped<QQmlValueTypeWrapper> ref(valueScope, cloneFrom->wrapper);
+ if (ref) {
+ valueTypeWrapper = QQmlValueTypeWrapper::create(engine, ref->d(), wrapper);
+ } else {
+ // We cannot re-attach a plain QQmlValueTypeWrapper because don't we know what
+ // value we should operate on. Without knowledge of the property the value
+ // was read from, we cannot load the value from the given object.
+ return Encode::undefined();
+ }
+ }
- result += QString::fromUtf8(metaObject->className()) +
- QLatin1String("(0x") + QString::number((quintptr)d()->object(),16);
+ Scoped<ExecutionContext> context(valueScope, cloneFrom->scope.get());
+ Scoped<QObjectMethod> method(
+ valueScope,
+ engine->memoryManager->allocate<QV4::QObjectMethod>(
+ context, valueTypeWrapper ? valueTypeWrapper->d() : object, cloneFrom->index));
- if (d()->object()) {
- QString objectName = d()->object()->objectName();
- if (!objectName.isEmpty())
- result += QLatin1String(", \"") + objectName + QLatin1Char('\"');
- }
+ method->d()->methodCount = cloneFrom->methodCount;
- result += QLatin1Char(')');
- } else {
- result = QLatin1String("null");
+ Q_ASSERT(method->d()->methods == nullptr);
+ switch (cloneFrom->methodCount) {
+ case 0:
+ Q_ASSERT(cloneFrom->methods == nullptr);
+ break;
+ case 1:
+ Q_ASSERT(cloneFrom->methods
+ == reinterpret_cast<QQmlPropertyData *>(&cloneFrom->_singleMethod));
+ method->d()->methods = reinterpret_cast<QQmlPropertyData *>(&method->d()->_singleMethod);
+ *method->d()->methods = *cloneFrom->methods;
+ break;
+ default:
+ Q_ASSERT(cloneFrom->methods != nullptr);
+ method->d()->methods = new QQmlPropertyData[cloneFrom->methodCount];
+ memcpy(method->d()->methods, cloneFrom->methods,
+ cloneFrom->methodCount * sizeof(QQmlPropertyData));
+ break;
}
- return engine->newString(result)->asReturnedValue();
+ return method.asReturnedValue();
}
-QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionEngine *engine, const Value *args, int argc) const
+void Heap::QObjectMethod::init(QV4::ExecutionContext *scope, Object *object, int methodIndex)
{
- if (!d()->object())
- return Encode::undefined();
- if (QQmlData::keepAliveDuringGarbageCollection(d()->object()))
- return engine->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object"));
+ Heap::FunctionObject::init(scope);
+ wrapper.set(internalClass->engine, object);
+ index = methodIndex;
+}
- int delay = 0;
- if (argc > 0)
- delay = args[0].toUInt32();
+const QMetaObject *Heap::QObjectMethod::metaObject() const
+{
+ Scope scope(internalClass->engine);
- if (delay > 0)
- QTimer::singleShot(delay, d()->object(), SLOT(deleteLater()));
- else
- d()->object()->deleteLater();
+ if (Scoped<QV4::QQmlValueTypeWrapper> valueWrapper(scope, wrapper); valueWrapper)
+ return valueWrapper->metaObject();
+ if (QObject *self = object())
+ return self->metaObject();
- return Encode::undefined();
+ return nullptr;
}
-ReturnedValue QObjectMethod::virtualCall(const FunctionObject *m, const Value *thisObject, const Value *argv, int argc)
+QObject *Heap::QObjectMethod::object() const
{
- const QObjectMethod *This = static_cast<const QObjectMethod*>(m);
- return This->callInternal(thisObject, argv, argc);
+ Scope scope(internalClass->engine);
+
+ if (Scoped<QV4::QObjectWrapper> objectWrapper(scope, wrapper); objectWrapper)
+ return objectWrapper->object();
+ if (Scoped<QV4::QQmlTypeWrapper> typeWrapper(scope, wrapper); typeWrapper)
+ return typeWrapper->object();
+ return nullptr;
}
-ReturnedValue QObjectMethod::callInternal(const Value *thisObject, const Value *argv, int argc) const
+bool Heap::QObjectMethod::isDetached() const
{
- ExecutionEngine *v4 = engine();
- if (d()->index == DestroyMethod)
- return method_destroy(v4, argv, argc);
- else if (d()->index == ToStringMethod)
- return method_toString(v4);
+ if (!wrapper)
+ return true;
- QQmlObjectOrGadget object(d()->object());
- if (!d()->object()) {
- if (!d()->valueTypeWrapper)
- return Encode::undefined();
+ QV4::Scope scope(internalClass->engine);
+ if (Scoped<QV4::QQmlValueTypeWrapper> valueWrapper(scope, wrapper); valueWrapper)
+ return valueWrapper->d()->object() == nullptr;
- object = QQmlObjectOrGadget(d()->propertyCache(), d()->valueTypeWrapper->gadgetPtr());
+ return false;
+}
+
+bool Heap::QObjectMethod::isAttachedTo(QObject *o) const
+{
+ QV4::Scope scope(internalClass->engine);
+ if (Scoped<QV4::QObjectWrapper> objectWrapper(scope, wrapper); objectWrapper)
+ return objectWrapper->object() == o;
+ if (Scoped<QV4::QQmlTypeWrapper> typeWrapper(scope, wrapper); typeWrapper)
+ return typeWrapper->object() == o;
+
+ if (Scoped<QV4::QQmlValueTypeWrapper> valueWrapper(scope, wrapper); valueWrapper) {
+ QV4::Scope scope(wrapper->internalClass->engine);
+ if (QV4::Scoped<QV4::QObjectWrapper> qobject(scope, valueWrapper->d()->object()); qobject)
+ return qobject->object() == o;
+ if (QV4::Scoped<QV4::QQmlTypeWrapper> type(scope, valueWrapper->d()->object()); type)
+ return type->object() == o;
+
+ // Attached to some nested value type or sequence object
+ return false;
}
- QQmlPropertyData method;
+ return false;
+}
- if (d()->propertyCache()) {
- QQmlPropertyData *data = d()->propertyCache()->method(d()->index);
- if (!data)
- return QV4::Encode::undefined();
- method = *data;
- } else {
- const QMetaObject *mo = d()->object()->metaObject();
- const QMetaMethod moMethod = mo->method(d()->index);
- method.load(moMethod);
-
- if (method.coreIndex() == -1)
- return QV4::Encode::undefined();
-
- // Look for overloaded methods
- QByteArray methodName = moMethod.name();
- const int methodOffset = mo->methodOffset();
- for (int ii = d()->index - 1; ii >= methodOffset; --ii) {
- if (methodName == mo->method(ii).name()) {
- method.setOverload(true);
- method.setOverrideIndexIsProperty(0);
- method.setOverrideIndex(ii);
- break;
- }
- }
+Heap::QObjectMethod::ThisObjectMode Heap::QObjectMethod::checkThisObject(
+ const QMetaObject *thisMeta) const
+{
+ // Check that the metaobject matches.
+
+ if (!thisMeta) {
+ // You can only get a detached method via a lookup, and then you have a thisObject.
+ Q_ASSERT(wrapper);
+ return Included;
}
- Scope scope(v4);
- JSCallData cData(scope, argc, argv, thisObject);
- CallData *callData = cData.callData();
+ const auto check = [&](const QMetaObject *included) {
+ const auto stackFrame = internalClass->engine->currentStackFrame;
+ if (stackFrame && !stackFrame->v4Function->executableCompilationUnit()
+ ->nativeMethodsAcceptThisObjects()) {
+ qCWarning(lcMethodBehavior,
+ "%s:%d: Calling C++ methods with 'this' objects different from the one "
+ "they were retrieved from is broken, due to historical reasons. The "
+ "original object is used as 'this' object. You can allow the given "
+ "'this' object to be used by setting "
+ "'pragma NativeMethodBehavior: AcceptThisObject'",
+ qPrintable(stackFrame->source()), stackFrame->lineNumber());
+ return Included;
+ }
- if (method.isV4Function()) {
- QV4::ScopedValue rv(scope, QV4::Value::undefinedValue());
- QQmlV4Function func(callData, rv, v4);
- QQmlV4Function *funcptr = &func;
+ // destroy() and toString() can be called on all QObjects, but not on gadgets.
+ if (index < 0)
+ return thisMeta->inherits(&QObject::staticMetaObject) ? Explicit : Invalid;
- void *args[] = { nullptr, &funcptr };
- object.metacall(QMetaObject::InvokeMetaMethod, method.coreIndex(), args);
+ // Find the base type the method belongs to.
+ int methodOffset = included->methodOffset();
+ while (true) {
+ if (included == thisMeta)
+ return Explicit;
- return rv->asReturnedValue();
- }
+ if (methodOffset <= index)
+ return thisMeta->inherits(included) ? Explicit : Invalid;
- if (!method.isOverload()) {
- return CallPrecise(object, method, v4, callData);
- } else {
- return CallOverloaded(object, method, v4, callData, d()->propertyCache());
- }
-}
+ included = included->superClass();
+ Q_ASSERT(included);
+ methodOffset -= QMetaObjectPrivate::get(included)->methodCount;
+ };
-DEFINE_OBJECT_VTABLE(QObjectMethod);
+ Q_UNREACHABLE_RETURN(Invalid);
+ };
+ if (const QMetaObject *meta = metaObject())
+ return check(meta);
-void Heap::QMetaObjectWrapper::init(const QMetaObject *metaObject)
-{
- FunctionObject::init();
- this->metaObject = metaObject;
- constructors = nullptr;
- constructorCount = 0;
+ // If the QObjectMethod is detached, we can only have gotten here via a lookup.
+ // The lookup checks that the QQmlPropertyCache matches.
+ return Explicit;
}
-void Heap::QMetaObjectWrapper::destroy()
+QString Heap::QObjectMethod::name() const
{
- delete[] constructors;
-}
+ if (index == QV4::QObjectMethod::DestroyMethod)
+ return QStringLiteral("destroy");
+ else if (index == QV4::QObjectMethod::ToStringMethod)
+ return QStringLiteral("toString");
-void Heap::QMetaObjectWrapper::ensureConstructorsCache() {
+ const QMetaObject *mo = metaObject();
+ if (!mo)
+ return QString();
- const int count = metaObject->constructorCount();
- if (constructorCount != count) {
- delete[] constructors;
- constructorCount = count;
- if (count == 0) {
- constructors = nullptr;
- return;
- }
- constructors = new QQmlPropertyData[count];
-
- for (int i = 0; i < count; ++i) {
- QMetaMethod method = metaObject->constructor(i);
- QQmlPropertyData &d = constructors[i];
- d.load(method);
- d.setCoreIndex(i);
- }
+ int methodOffset = mo->methodOffset();
+ while (methodOffset > index) {
+ mo = mo->superClass();
+ methodOffset -= QMetaObjectPrivate::get(mo)->methodCount;
}
+
+ return "%1::%2"_L1.arg(QLatin1StringView{mo->className()},
+ QLatin1StringView{mo->method(index).name()});
}
+void Heap::QObjectMethod::ensureMethodsCache(const QMetaObject *thisMeta)
+{
+ if (methods) {
+ Q_ASSERT(methodCount > 0);
+ return;
+ }
-ReturnedValue QMetaObjectWrapper::create(ExecutionEngine *engine, const QMetaObject* metaObject) {
+ const QMetaObject *mo = metaObject();
- QV4::Scope scope(engine);
- Scoped<QMetaObjectWrapper> mo(scope, engine->memoryManager->allocate<QV4::QMetaObjectWrapper>(metaObject)->asReturnedValue());
- mo->init(engine);
- return mo->asReturnedValue();
-}
+ if (!mo)
+ mo = thisMeta;
-void QMetaObjectWrapper::init(ExecutionEngine *) {
- const QMetaObject & mo = *d()->metaObject;
+ Q_ASSERT(mo);
- for (int i = 0; i < mo.enumeratorCount(); i++) {
- QMetaEnum Enum = mo.enumerator(i);
- for (int k = 0; k < Enum.keyCount(); k++) {
- const char* key = Enum.key(k);
- const int value = Enum.value(k);
- defineReadonlyProperty(QLatin1String(key), Value::fromInt32(value));
+ int methodOffset = mo->methodOffset();
+ while (methodOffset > index) {
+ mo = mo->superClass();
+ methodOffset -= QMetaObjectPrivate::get(mo)->methodCount;
+ }
+ QVarLengthArray<QQmlPropertyData, 9> resolvedMethods;
+ QQmlPropertyData dummy;
+ QMetaMethod method = mo->method(index);
+ dummy.load(method);
+ dummy.setMetaObject(mo);
+ resolvedMethods.append(dummy);
+ // Look for overloaded methods
+ QByteArray methodName = method.name();
+ for (int ii = index - 1; ii >= methodOffset; --ii) {
+ if (methodName == mo->method(ii).name()) {
+ method = mo->method(ii);
+ dummy.load(method);
+ resolvedMethods.append(dummy);
}
}
+ if (resolvedMethods.size() > 1) {
+ methods = new QQmlPropertyData[resolvedMethods.size()];
+ memcpy(methods, resolvedMethods.data(), resolvedMethods.size()*sizeof(QQmlPropertyData));
+ methodCount = resolvedMethods.size();
+ } else {
+ methods = reinterpret_cast<QQmlPropertyData *>(&_singleMethod);
+ *methods = resolvedMethods.at(0);
+ methodCount = 1;
+ }
+
+ Q_ASSERT(methodCount > 0);
}
-ReturnedValue QMetaObjectWrapper::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *)
+ReturnedValue QObjectMethod::method_toString(ExecutionEngine *engine, QObject *o) const
{
- const QMetaObjectWrapper *This = static_cast<const QMetaObjectWrapper*>(f);
- return This->constructInternal(argv, argc);
+ return engine->newString(
+ QObjectWrapper::objectToString(
+ engine, o ? o->metaObject() : d()->metaObject(), o))->asReturnedValue();
}
-ReturnedValue QMetaObjectWrapper::constructInternal(const Value *argv, int argc) const
+ReturnedValue QObjectMethod::method_destroy(
+ ExecutionEngine *engine, QObject *o, const Value *args, int argc) const
{
+ if (!o)
+ return Encode::undefined();
- d()->ensureConstructorsCache();
-
- ExecutionEngine *v4 = engine();
- const QMetaObject* mo = d()->metaObject;
- if (d()->constructorCount == 0) {
- return v4->throwTypeError(QLatin1String(mo->className())
- + QLatin1String(" has no invokable constructor"));
- }
+ if (QQmlData::keepAliveDuringGarbageCollection(o))
+ return engine->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object"));
- Scope scope(v4);
- Scoped<QObjectWrapper> object(scope);
- JSCallData cData(scope, argc, argv);
- CallData *callData = cData.callData();
+ int delay = 0;
+ if (argc > 0)
+ delay = args[0].toUInt32();
- if (d()->constructorCount == 1) {
- object = callConstructor(d()->constructors[0], v4, callData);
- }
- else {
- object = callOverloadedConstructor(v4, callData);
- }
- Scoped<QMetaObjectWrapper> metaObject(scope, this);
- object->defineDefaultProperty(v4->id_constructor(), metaObject);
- object->setPrototypeOf(const_cast<QMetaObjectWrapper*>(this));
- return object.asReturnedValue();
+ if (delay > 0)
+ QTimer::singleShot(delay, o, SLOT(deleteLater()));
+ else
+ o->deleteLater();
+ return Encode::undefined();
}
-ReturnedValue QMetaObjectWrapper::callConstructor(const QQmlPropertyData &data, QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const {
+ReturnedValue QObjectMethod::virtualCall(
+ const FunctionObject *m, const Value *thisObject, const Value *argv, int argc)
+{
+ const QObjectMethod *This = static_cast<const QObjectMethod*>(m);
+ return This->callInternal(thisObject, argv, argc);
+}
- const QMetaObject* mo = d()->metaObject;
- const QQmlStaticMetaObject object(mo);
- return CallPrecise(object, data, engine, callArgs, QMetaObject::CreateInstance);
+void QObjectMethod::virtualCallWithMetaTypes(
+ const FunctionObject *m, QObject *thisObject, void **argv, const QMetaType *types, int argc)
+{
+ const QObjectMethod *This = static_cast<const QObjectMethod*>(m);
+ This->callInternalWithMetaTypes(thisObject, argv, types, argc);
}
+ReturnedValue QObjectMethod::callInternal(const Value *thisObject, const Value *argv, int argc) const
+{
+ ExecutionEngine *v4 = engine();
-ReturnedValue QMetaObjectWrapper::callOverloadedConstructor(QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const {
- const int numberOfConstructors = d()->constructorCount;
- const int argumentCount = callArgs->argc();
- const QQmlStaticMetaObject object(d()->metaObject);
+ const QMetaObject *thisMeta = nullptr;
+
+ QObject *o = nullptr;
+ Heap::QQmlValueTypeWrapper *valueWrapper = nullptr;
+ if (const QObjectWrapper *w = thisObject->as<QObjectWrapper>()) {
+ thisMeta = w->metaObject();
+ o = w->object();
+ } else if (const QQmlTypeWrapper *w = thisObject->as<QQmlTypeWrapper>()) {
+ thisMeta = w->metaObject();
+ o = w->object();
+ } else if (const QQmlValueTypeWrapper *w = thisObject->as<QQmlValueTypeWrapper>()) {
+ thisMeta = w->metaObject();
+ valueWrapper = w->d();
+ }
- QQmlPropertyData best;
- int bestParameterScore = INT_MAX;
- int bestMatchScore = INT_MAX;
+ Heap::QObjectMethod::ThisObjectMode mode = Heap::QObjectMethod::Invalid;
+ if (o && o == d()->object()) {
+ mode = Heap::QObjectMethod::Explicit;
+ // Nothing to do; objects are the same. This should be common
+ } else if (valueWrapper && valueWrapper == d()->wrapper) {
+ mode = Heap::QObjectMethod::Explicit;
+ // Nothing to do; gadgets are the same. This should be somewhat common
+ } else {
+ mode = d()->checkThisObject(thisMeta);
+ if (mode == Heap::QObjectMethod::Invalid) {
+ v4->throwError(QLatin1String("Cannot call method %1 on %2").arg(
+ d()->name(), thisObject->toQStringNoThrow()));
+ return Encode::undefined();
+ }
+ }
- QV4::Scope scope(engine);
- QV4::ScopedValue v(scope);
-
- for (int i = 0; i < numberOfConstructors; i++) {
- const QQmlPropertyData & attempt = d()->constructors[i];
- QQmlMetaObject::ArgTypeStorage storage;
- int methodArgumentCount = 0;
- int *methodArgTypes = nullptr;
- if (attempt.hasArguments()) {
- int *args = object.constructorParameterTypes(attempt.coreIndex(), &storage, nullptr);
- if (!args) // Must be an unknown argument
- continue;
+ QQmlObjectOrGadget object = [&](){
+ if (mode == Heap::QObjectMethod::Included) {
+ QV4::Scope scope(v4);
+ if (QV4::Scoped<QV4::QObjectWrapper> qobject(scope, d()->wrapper); qobject)
+ return QQmlObjectOrGadget(qobject->object());
+ if (QV4::Scoped<QV4::QQmlTypeWrapper> type(scope, d()->wrapper); type)
+ return QQmlObjectOrGadget(type->object());
+ if (QV4::Scoped<QV4::QQmlValueTypeWrapper> value(scope, d()->wrapper); value) {
+ valueWrapper = value->d();
+ return QQmlObjectOrGadget(valueWrapper->metaObject(), valueWrapper->gadgetPtr());
+ }
+ Q_UNREACHABLE();
+ } else {
+ if (o)
+ return QQmlObjectOrGadget(o);
- methodArgumentCount = args[0];
- methodArgTypes = args + 1;
+ Q_ASSERT(valueWrapper);
+ if (!valueWrapper->enforcesLocation())
+ QV4::ReferenceObject::readReference(valueWrapper);
+ return QQmlObjectOrGadget(thisMeta, valueWrapper->gadgetPtr());
}
+ }();
- if (methodArgumentCount > argumentCount)
- continue; // We don't have sufficient arguments to call this method
+ if (object.isNull())
+ return Encode::undefined();
- int methodParameterScore = argumentCount - methodArgumentCount;
- if (methodParameterScore > bestParameterScore)
- continue; // We already have a better option
+ if (d()->index == DestroyMethod)
+ return method_destroy(v4, object.qObject(), argv, argc);
+ else if (d()->index == ToStringMethod)
+ return method_toString(v4, object.qObject());
- int methodMatchScore = 0;
- for (int ii = 0; ii < methodArgumentCount; ++ii) {
- methodMatchScore += MatchScore((v = Value::fromStaticValue(callArgs->args[ii])),
- methodArgTypes[ii]);
- }
+ d()->ensureMethodsCache(thisMeta);
- if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
- best = attempt;
- bestParameterScore = methodParameterScore;
- bestMatchScore = methodMatchScore;
+ Scope scope(v4);
+ JSCallData cData(thisObject, argv, argc);
+ CallData *callData = cData.callData(scope);
+
+ const QQmlPropertyData *method = d()->methods;
+
+ // If we call the method, we have to write back any value type references afterwards.
+ // The method might change the value.
+ const auto doCall = [&](const auto &call) {
+ if (!method->isConstant()) {
+ if (valueWrapper && valueWrapper->isReference()) {
+ ScopedValue rv(scope, call());
+ valueWrapper->writeBack();
+ return rv->asReturnedValue();
+ }
}
- if (bestParameterScore == 0 && bestMatchScore == 0)
- break; // We can't get better than that
+ return call();
};
- if (best.isValid()) {
- return CallPrecise(object, best, engine, callArgs, QMetaObject::CreateInstance);
- } else {
- QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
- for (int i = 0; i < numberOfConstructors; i++) {
- const QQmlPropertyData & candidate = d()->constructors[i];
- error += QLatin1String("\n ") +
- QString::fromUtf8(d()->metaObject->constructor(candidate.coreIndex())
- .methodSignature());
- }
+ if (d()->methodCount != 1) {
+ Q_ASSERT(d()->methodCount > 0);
+ method = resolveOverloaded(object, d()->methods, d()->methodCount, v4, callData);
+ if (method == nullptr)
+ return Encode::undefined();
+ }
+
+ if (method->isV4Function()) {
+ return doCall([&]() {
+ ScopedValue rv(scope, Value::undefinedValue());
+ QQmlV4Function func(callData, rv, v4);
+ QQmlV4FunctionPtr funcptr = &func;
- return engine->throwError(error);
+ void *args[] = { nullptr, &funcptr };
+ object.metacall(QMetaObject::InvokeMetaMethod, method->coreIndex(), args);
+
+ return rv->asReturnedValue();
+ });
}
+
+ return doCall([&]() { return callPrecise(object, *method, v4, callData); });
}
-bool QMetaObjectWrapper::virtualIsEqualTo(Managed *a, Managed *b)
+struct ToStringMetaMethod
{
- Q_ASSERT(a->as<QMetaObjectWrapper>());
- QMetaObjectWrapper *aMetaObject = a->as<QMetaObjectWrapper>();
- QMetaObjectWrapper *bMetaObject = b->as<QMetaObjectWrapper>();
- if (!bMetaObject)
- return true;
- return aMetaObject->metaObject() == bMetaObject->metaObject();
-}
+ constexpr int parameterCount() const { return 0; }
+ constexpr QMetaType returnMetaType() const { return QMetaType::fromType<QString>(); }
+ constexpr QMetaType parameterMetaType(int) const { return QMetaType(); }
+};
+
+void QObjectMethod::callInternalWithMetaTypes(
+ QObject *thisObject, void **argv, const QMetaType *types, int argc) const
+{
+ ExecutionEngine *v4 = engine();
+
+ const QMetaObject *thisMeta = nullptr;
+ Heap::QQmlValueTypeWrapper *valueWrapper = nullptr;
+
+ if (thisObject) {
+ thisMeta = thisObject->metaObject();
+ } else {
+ Q_ASSERT(Value::fromHeapObject(d()->wrapper).as<QQmlValueTypeWrapper>());
+ valueWrapper = d()->wrapper.cast<Heap::QQmlValueTypeWrapper>();
+ thisMeta = valueWrapper->metaObject();
+ }
+
+ QQmlObjectOrGadget object = [&](){
+ if (thisObject)
+ return QQmlObjectOrGadget(thisObject);
+
+ Scope scope(v4);
+ Scoped<QQmlValueTypeWrapper> wrapper(scope, d()->wrapper);
+ Q_ASSERT(wrapper);
+
+ Heap::QQmlValueTypeWrapper *valueWrapper = wrapper->d();
+ if (!valueWrapper->enforcesLocation())
+ QV4::ReferenceObject::readReference(valueWrapper);
+ return QQmlObjectOrGadget(thisMeta, valueWrapper->gadgetPtr());
+ }();
+
+ if (object.isNull())
+ return;
+
+ if (d()->index == DestroyMethod) {
+ // method_destroy will use at most one argument
+ QV4::convertAndCall(
+ v4, thisObject, argv, types, std::min(argc, 1),
+ [this, v4, object](const Value *thisObject, const Value *argv, int argc) {
+ Q_UNUSED(thisObject);
+ return method_destroy(v4, object.qObject(), argv, argc);
+ });
+ return;
+ }
+
+ if (d()->index == ToStringMethod) {
+ const ToStringMetaMethod metaMethod;
+ QV4::coerceAndCall(
+ v4, &metaMethod, argv, types, argc,
+ [v4, thisMeta, object](void **argv, int) {
+ *static_cast<QString *>(argv[0])
+ = QObjectWrapper::objectToString(v4, thisMeta, object.qObject());
+ });
+ return;
+ }
-DEFINE_OBJECT_VTABLE(QMetaObjectWrapper);
+ d()->ensureMethodsCache(thisMeta);
+ const QQmlPropertyData *method = d()->methods;
+ if (d()->methodCount != 1) {
+ Q_ASSERT(d()->methodCount > 0);
+ method = resolveOverloaded(d()->methods, d()->methodCount, argv, argc, types);
+ }
+ if (!method || method->isV4Function()) {
+ QV4::convertAndCall(
+ v4, thisObject, argv, types, argc,
+ [this](const Value *thisObject, const Value *argv, int argc) {
+ return callInternal(thisObject, argv, argc);
+ });
+ } else {
+ const QMetaMethod metaMethod = method->metaMethod();
+ QV4::coerceAndCall(
+ v4, &metaMethod, argv, types, argc,
+ [v4, object, valueWrapper, method](void **argv, int argc) {
+ Q_UNUSED(argc);
+
+ // If we call the method, we have to write back any value type references afterwards.
+ // The method might change the value.
+ object.metacall(QMetaObject::InvokeMetaMethod, method->coreIndex(), argv);
+ if (!method->isConstant()) {
+ if (valueWrapper && valueWrapper->isReference())
+ valueWrapper->writeBack();
+ }
+ // If the method returns a QObject* we need to track it on the JS heap
+ // (if it's destructible).
+ QObject *qobjectPtr = nullptr;
+ const QMetaType resultType = method->propType();
+ if (argv[0]) {
+ if (resultType.flags() & QMetaType::PointerToQObject) {
+ qobjectPtr = *static_cast<QObject **>(argv[0]);
+ } else if (resultType == QMetaType::fromType<QVariant>()) {
+ const QVariant *result = static_cast<const QVariant *>(argv[0]);
+ const QMetaType variantType = result->metaType();
+ if (variantType.flags() & QMetaType::PointerToQObject)
+ qobjectPtr = *static_cast<QObject *const *>(result->data());
+ }
+ }
+
+ if (qobjectPtr) {
+ QQmlData *ddata = QQmlData::get(qobjectPtr, true);
+ if (!ddata->explicitIndestructibleSet) {
+ ddata->indestructible = false;
+ QObjectWrapper::ensureWrapper(v4, qobjectPtr);
+ }
+ }
+ });
+ }
+}
+
+DEFINE_OBJECT_VTABLE(QObjectMethod);
void Heap::QmlSignalHandler::init(QObject *object, int signalIndex)
{
@@ -2321,56 +3093,59 @@ void Heap::QmlSignalHandler::init(QObject *object, int signalIndex)
DEFINE_OBJECT_VTABLE(QmlSignalHandler);
-void QmlSignalHandler::initProto(ExecutionEngine *engine)
+ReturnedValue QmlSignalHandler::call(const Value *thisObject, const Value *argv, int argc) const
{
- if (engine->signalHandlerPrototype()->d_unchecked())
- return;
+ const QString handlerName = QQmlSignalNames::signalNameToHandlerName(
+ object()->metaObject()->method(signalIndex()).name());
+ qCWarning(lcSignalHandler).noquote()
+ << QStringLiteral("Property '%1' of object %2 is a signal handler. You should "
+ "not call it directly. Make it a proper function and call "
+ "that or emit the signal.")
+ .arg(handlerName, thisObject->toQStringNoThrow());
- Scope scope(engine);
- ScopedObject o(scope, engine->newObject());
- QV4::ScopedString connect(scope, engine->newIdentifier(QStringLiteral("connect")));
- QV4::ScopedString disconnect(scope, engine->newIdentifier(QStringLiteral("disconnect")));
- o->put(connect, QV4::ScopedValue(scope, engine->functionPrototype()->get(connect)));
- o->put(disconnect, QV4::ScopedValue(scope, engine->functionPrototype()->get(disconnect)));
+ Scope scope(engine());
+ Scoped<QObjectMethod> method(
+ scope, QObjectMethod::create(
+ scope.engine->rootContext(),
+ static_cast<Heap::QObjectWrapper *>(nullptr),
+ signalIndex()));
- engine->jsObjects[QV4::ExecutionEngine::SignalHandlerProto] = o->d();
+ return method->call(thisObject, argv, argc);
}
-void MultiplyWrappedQObjectMap::insert(QObject *key, Heap::Object *value)
+void QmlSignalHandler::initProto(ExecutionEngine *engine)
{
- QHash<QObject*, QV4::WeakValue>::operator[](key).set(value->internalClass->engine, value);
- connect(key, SIGNAL(destroyed(QObject*)), this, SLOT(removeDestroyedObject(QObject*)));
-}
-
+ if (engine->signalHandlerPrototype()->d_unchecked())
+ return;
+ Scope scope(engine);
+ ScopedObject o(scope, engine->newObject());
+ ScopedString connect(scope, engine->newIdentifier(QStringLiteral("connect")));
+ ScopedString disconnect(scope, engine->newIdentifier(QStringLiteral("disconnect")));
+ o->put(connect, ScopedValue(scope, engine->functionPrototype()->get(connect)));
+ o->put(disconnect, ScopedValue(scope, engine->functionPrototype()->get(disconnect)));
-MultiplyWrappedQObjectMap::Iterator MultiplyWrappedQObjectMap::erase(MultiplyWrappedQObjectMap::Iterator it)
-{
- disconnect(it.key(), SIGNAL(destroyed(QObject*)), this, SLOT(removeDestroyedObject(QObject*)));
- return QHash<QObject*, QV4::WeakValue>::erase(it);
+ engine->jsObjects[ExecutionEngine::SignalHandlerProto] = o->d();
}
-void MultiplyWrappedQObjectMap::remove(QObject *key)
-{
- Iterator it = find(key);
- if (it == end())
- return;
- erase(it);
-}
-void MultiplyWrappedQObjectMap::mark(QObject *key, MarkStack *markStack)
+MultiplyWrappedQObjectMap::Iterator MultiplyWrappedQObjectMap::erase(
+ MultiplyWrappedQObjectMap::Iterator it)
{
- Iterator it = find(key);
- if (it == end())
- return;
- it->markOnce(markStack);
+ const QObjectBiPointer key = it.key();
+ const QObject *obj = key.isT1() ? key.asT1() : key.asT2();
+ disconnect(obj, &QObject::destroyed, this, &MultiplyWrappedQObjectMap::removeDestroyedObject);
+ return QHash<QObjectBiPointer, WeakValue>::erase(it);
}
void MultiplyWrappedQObjectMap::removeDestroyedObject(QObject *object)
{
- QHash<QObject*, QV4::WeakValue>::remove(object);
+ QHash<QObjectBiPointer, WeakValue>::remove(object);
+ QHash<QObjectBiPointer, WeakValue>::remove(static_cast<const QObject *>(object));
}
+} // namespace QV4
+
QT_END_NAMESPACE
#include "moc_qv4qobjectwrapper_p.cpp"
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index ac9cad2bdb..1af8fc887f 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4QOBJECTWRAPPER_P_H
#define QV4QOBJECTWRAPPER_P_H
@@ -51,16 +15,17 @@
// We mean it.
//
+#include <private/qbipointer_p.h>
+#include <private/qintrusivelist_p.h>
+#include <private/qqmldata_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4value_p.h>
+
#include <QtCore/qglobal.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qpair.h>
#include <QtCore/qhash.h>
-#include <private/qqmldata_p.h>
-#include <private/qintrusivelist_p.h>
-
-#include <private/qv4value_p.h>
-#include <private/qv4functionobject_p.h>
-#include <private/qv4lookup_p.h>
QT_BEGIN_NAMESPACE
@@ -68,6 +33,7 @@ class QObject;
class QQmlData;
class QQmlPropertyCache;
class QQmlPropertyData;
+class QQmlObjectOrGadget;
namespace QV4 {
struct QObjectSlotDispatcher;
@@ -92,49 +58,44 @@ struct Q_QML_EXPORT QObjectWrapper : Object {
static void markObjects(Heap::Base *that, MarkStack *markStack);
private:
- QQmlQPointer<QObject> qObj;
+ QV4QPointer<QObject> qObj;
};
#define QObjectMethodMembers(class, Member) \
- Member(class, Pointer, QQmlValueTypeWrapper *, valueTypeWrapper) \
- Member(class, NoMark, QQmlQPointer<QObject>, qObj) \
- Member(class, NoMark, QQmlPropertyCache *, _propertyCache) \
- Member(class, NoMark, int, index)
+ Member(class, Pointer, Object *, wrapper) \
-DECLARE_HEAP_OBJECT(QObjectMethod, FunctionObject) {
- DECLARE_MARKOBJECTS(QObjectMethod);
+DECLARE_EXPORTED_HEAP_OBJECT(QObjectMethod, FunctionObject) {
+ DECLARE_MARKOBJECTS(QObjectMethod)
- void init(QV4::ExecutionContext *scope);
+ QQmlPropertyData *methods;
+ alignas(alignof(QQmlPropertyData)) std::byte _singleMethod[sizeof(QQmlPropertyData)];
+ int methodCount;
+ int index;
+
+ void init(QV4::ExecutionContext *scope, Object *wrapper, int index);
void destroy()
{
- setPropertyCache(nullptr);
- qObj.destroy();
+ if (methods != reinterpret_cast<const QQmlPropertyData *>(&_singleMethod))
+ delete[] methods;
FunctionObject::destroy();
}
- QQmlPropertyCache *propertyCache() const { return _propertyCache; }
- void setPropertyCache(QQmlPropertyCache *c) {
- if (c)
- c->addref();
- if (_propertyCache)
- _propertyCache->release();
- _propertyCache = c;
- }
+ void ensureMethodsCache(const QMetaObject *thisMeta);
+ QString name() const;
- const QMetaObject *metaObject();
- QObject *object() const { return qObj.data(); }
- void setObject(QObject *o) { qObj = o; }
+ const QMetaObject *metaObject() const;
+ QObject *object() const;
-};
+ bool isDetached() const;
+ bool isAttachedTo(QObject *o) const;
-struct QMetaObjectWrapper : FunctionObject {
- const QMetaObject* metaObject;
- QQmlPropertyData *constructors;
- int constructorCount;
+ enum ThisObjectMode {
+ Invalid,
+ Included,
+ Explicit,
+ };
- void init(const QMetaObject* metaObject);
- void destroy();
- void ensureConstructorsCache();
+ QV4::Heap::QObjectMethod::ThisObjectMode checkThisObject(const QMetaObject *thisMeta) const;
};
struct QmlSignalHandler : Object {
@@ -149,7 +110,7 @@ struct QmlSignalHandler : Object {
void setObject(QObject *o) { qObj = o; }
private:
- QQmlQPointer<QObject> qObj;
+ QV4QPointer<QObject> qObj;
};
}
@@ -159,55 +120,108 @@ struct Q_QML_EXPORT QObjectWrapper : public Object
V4_OBJECT2(QObjectWrapper, Object)
V4_NEEDS_DESTROY
- enum RevisionMode { IgnoreRevision, CheckRevision };
+ enum Flag {
+ NoFlag = 0x0,
+ CheckRevision = 0x1,
+ AttachMethods = 0x2,
+ AllowOverride = 0x4,
+ IncludeImports = 0x8,
+ };
+
+ Q_DECLARE_FLAGS(Flags, Flag);
static void initializeBindings(ExecutionEngine *engine);
+ const QMetaObject *metaObject() const
+ {
+ if (QObject *o = object())
+ return o->metaObject();
+ return nullptr;
+ }
+
QObject *object() const { return d()->object(); }
- ReturnedValue getQmlProperty(QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = nullptr, bool includeImports = false) const;
- static ReturnedValue getQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = nullptr, QQmlPropertyData **property = nullptr);
+ ReturnedValue getQmlProperty(
+ const QQmlRefPointer<QQmlContextData> &qmlContext, String *name,
+ Flags flags, bool *hasProperty = nullptr) const;
+
+ static ReturnedValue getQmlProperty(
+ ExecutionEngine *engine, const QQmlRefPointer<QQmlContextData> &qmlContext,
+ Heap::Object *wrapper, QObject *object, String *name, Flags flags,
+ bool *hasProperty = nullptr, const QQmlPropertyData **property = nullptr);
- static bool setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value);
+ static bool setQmlProperty(
+ ExecutionEngine *engine, const QQmlRefPointer<QQmlContextData> &qmlContext,
+ QObject *object, String *name, Flags flags, const Value &value);
+ Q_NODISCARD_X("Use ensureWrapper if you don't need the return value")
static ReturnedValue wrap(ExecutionEngine *engine, QObject *object);
+ Q_NODISCARD_X("Throwing the const wrapper away can cause it to be garbage collected")
+ static ReturnedValue wrapConst(ExecutionEngine *engine, QObject *object);
+ static void ensureWrapper(ExecutionEngine *engine, QObject *object);
static void markWrapper(QObject *object, MarkStack *markStack);
using Object::get;
static void setProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, const Value &value);
void setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value);
+ static void setProperty(
+ ExecutionEngine *engine, QObject *object,
+ const QQmlPropertyData *property, const Value &value);
void destroyObject(bool lastCall);
- static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property);
+ static ReturnedValue getProperty(
+ ExecutionEngine *engine, Heap::Object *wrapper, QObject *object,
+ const QQmlPropertyData *property, Flags flags);
static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
- static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object);
- template <typename ReversalFunctor> static ReturnedValue lookupGetterImpl(Lookup *l, ExecutionEngine *engine, const Value &object, bool useOriginalProperty, ReversalFunctor revert);
- static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
+ static ReturnedValue lookupAttached(Lookup *l, ExecutionEngine *engine, const Value &object);
+
+ template <typename ReversalFunctor> static ReturnedValue lookupPropertyGetterImpl(
+ Lookup *l, ExecutionEngine *engine, const Value &object,
+ Flags flags, ReversalFunctor revert);
+ template <typename ReversalFunctor> static ReturnedValue lookupMethodGetterImpl(
+ Lookup *l, ExecutionEngine *engine, const Value &object,
+ Flags flags, ReversalFunctor revert);
+ static bool virtualResolveLookupSetter(
+ Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
+ static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
-protected:
- static void setProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, const Value &value);
+ static int virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a);
+
+ static QString objectToString(
+ ExecutionEngine *engine, const QMetaObject *metaObject, QObject *object);
+protected:
static bool virtualIsEqualTo(Managed *that, Managed *o);
static ReturnedValue create(ExecutionEngine *engine, QObject *object);
- static QQmlPropertyData *findProperty(ExecutionEngine *engine, QObject *o, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local);
- QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const;
+ static const QQmlPropertyData *findProperty(
+ QObject *o, const QQmlRefPointer<QQmlContextData> &qmlContext,
+ String *name, Flags flags, QQmlPropertyData *local);
+
+ const QQmlPropertyData *findProperty(
+ const QQmlRefPointer<QQmlContextData> &qmlContext,
+ String *name, Flags flags, QQmlPropertyData *local) const;
- static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
+ static ReturnedValue virtualGet(
+ const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p);
- static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
- static ReturnedValue method_connect(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_disconnect(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_connect(
+ const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_disconnect(
+ const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
private:
Q_NEVER_INLINE static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object);
+ Q_NEVER_INLINE static ReturnedValue wrapConst_slowPath(ExecutionEngine *engine, QObject *object);
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QObjectWrapper::Flags)
+
inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
{
if (Q_UNLIKELY(QQmlData::wasDeleted(object)))
@@ -222,8 +236,29 @@ inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *obje
return wrap_slowPath(engine, object);
}
+// Unfortunately we still need a non-const QObject* here because QQmlData needs to register itself in QObjectPrivate.
+inline ReturnedValue QObjectWrapper::wrapConst(ExecutionEngine *engine, QObject *object)
+{
+ if (Q_UNLIKELY(QQmlData::wasDeleted(object)))
+ return QV4::Encode::null();
+
+ return wrapConst_slowPath(engine, object);
+}
+
+inline bool canConvert(const QQmlPropertyCache *fromMo, const QQmlPropertyCache *toMo)
+{
+ while (fromMo) {
+ if (fromMo == toMo)
+ return true;
+ fromMo = fromMo->parent().data();
+ }
+ return false;
+}
+
template <typename ReversalFunctor>
-inline ReturnedValue QObjectWrapper::lookupGetterImpl(Lookup *lookup, ExecutionEngine *engine, const Value &object, bool useOriginalProperty, ReversalFunctor revertLookup)
+inline ReturnedValue QObjectWrapper::lookupPropertyGetterImpl(
+ Lookup *lookup, ExecutionEngine *engine, const Value &object,
+ QObjectWrapper::Flags flags, ReversalFunctor revertLookup)
{
// we can safely cast to a QV4::Object here. If object is something else,
// the internal class won't match
@@ -231,7 +266,7 @@ inline ReturnedValue QObjectWrapper::lookupGetterImpl(Lookup *lookup, ExecutionE
if (!o || o->internalClass != lookup->qobjectLookup.ic)
return revertLookup();
- const Heap::QObjectWrapper *This = static_cast<const Heap::QObjectWrapper *>(o);
+ Heap::QObjectWrapper *This = static_cast<Heap::QObjectWrapper *>(o);
QObject *qobj = This->object();
if (QQmlData::wasDeleted(qobj))
return QV4::Encode::undefined();
@@ -240,26 +275,68 @@ inline ReturnedValue QObjectWrapper::lookupGetterImpl(Lookup *lookup, ExecutionE
if (!ddata)
return revertLookup();
- QQmlPropertyData *property = lookup->qobjectLookup.propertyData;
- if (ddata->propertyCache != lookup->qobjectLookup.propertyCache) {
- if (property->isOverridden() && (!useOriginalProperty || property->isFunction() || property->isSignalHandler()))
+ const QQmlPropertyData *property = lookup->qobjectLookup.propertyData;
+ if (ddata->propertyCache.data() != lookup->qobjectLookup.propertyCache) {
+ // If the property is overridden and the lookup allows overrides to be considered,
+ // we have to revert here and redo the lookup from scratch.
+ if (property->isOverridden()
+ && ((flags & AllowOverride)
+ || property->isFunction()
+ || property->isSignalHandler())) {
return revertLookup();
-
- QQmlPropertyCache *fromMo = ddata->propertyCache;
- QQmlPropertyCache *toMo = lookup->qobjectLookup.propertyCache;
- bool canConvert = false;
- while (fromMo) {
- if (fromMo == toMo) {
- canConvert = true;
- break;
- }
- fromMo = fromMo->parent();
}
- if (!canConvert)
+
+ if (!canConvert(ddata->propertyCache.data(), lookup->qobjectLookup.propertyCache))
+ return revertLookup();
+ }
+
+ return getProperty(engine, This, qobj, property, flags);
+}
+
+template <typename ReversalFunctor>
+inline ReturnedValue QObjectWrapper::lookupMethodGetterImpl(
+ Lookup *lookup, ExecutionEngine *engine, const Value &object,
+ QObjectWrapper::Flags flags, ReversalFunctor revertLookup)
+{
+ // we can safely cast to a QV4::Object here. If object is something else,
+ // the internal class won't match
+ Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
+ if (!o || o->internalClass != lookup->qobjectMethodLookup.ic)
+ return revertLookup();
+
+ Heap::QObjectWrapper *This = static_cast<Heap::QObjectWrapper *>(o);
+ QObject *qobj = This->object();
+ if (QQmlData::wasDeleted(qobj))
+ return QV4::Encode::undefined();
+
+ QQmlData *ddata = QQmlData::get(qobj, /*create*/false);
+ if (!ddata)
+ return revertLookup();
+
+ const QQmlPropertyData *property = lookup->qobjectMethodLookup.propertyData;
+ if (ddata->propertyCache.data() != lookup->qobjectMethodLookup.propertyCache) {
+ if (property && property->isOverridden())
return revertLookup();
+
+ if (!canConvert(ddata->propertyCache.data(), lookup->qobjectMethodLookup.propertyCache))
+ return revertLookup();
+ }
+
+ if (Heap::QObjectMethod *method = lookup->qobjectMethodLookup.method) {
+ if (method->isDetached())
+ return method->asReturnedValue();
}
- return getProperty(engine, qobj, property);
+ if (!property) // was toString() or destroy()
+ return revertLookup();
+
+ QV4::Scope scope(engine);
+ QV4::ScopedValue v(scope, getProperty(engine, This, qobj, property, flags));
+ if (!v->as<QObjectMethod>())
+ return revertLookup();
+
+ lookup->qobjectMethodLookup.method.set(engine, static_cast<Heap::QObjectMethod *>(v->heapObject()));
+ return v->asReturnedValue();
}
struct QQmlValueTypeWrapper;
@@ -271,41 +348,50 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
enum { DestroyMethod = -1, ToStringMethod = -2 };
- static ReturnedValue create(QV4::ExecutionContext *scope, QObject *object, int index);
- static ReturnedValue create(QV4::ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index);
+ static ReturnedValue create(QV4::ExecutionContext *scope, Heap::Object *wrapper, int index);
+ static ReturnedValue create(
+ QV4::ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index);
+ static ReturnedValue create(QV4::ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
+ Heap::Object *wrapper, Heap::Object *object);
int methodIndex() const { return d()->index; }
QObject *object() const { return d()->object(); }
- QV4::ReturnedValue method_toString(QV4::ExecutionEngine *engine) const;
- QV4::ReturnedValue method_destroy(QV4::ExecutionEngine *ctx, const Value *args, int argc) const;
+ QV4::ReturnedValue method_toString(QV4::ExecutionEngine *engine, QObject *o) const;
+ QV4::ReturnedValue method_destroy(
+ QV4::ExecutionEngine *ctx, QObject *o, const Value *args, int argc) const;
+ void method_destroy(
+ QV4::ExecutionEngine *engine, QObject *o,
+ void **argv, const QMetaType *types, int argc) const;
- static ReturnedValue virtualCall(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue virtualCall(
+ const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static void virtualCallWithMetaTypes(
+ const FunctionObject *m, QObject *thisObject,
+ void **argv, const QMetaType *types, int argc);
- ReturnedValue callInternal(const Value *thisObject, const Value *argv, int argc) const;
+ ReturnedValue callInternal(
+ const Value *thisObject, const Value *argv, int argc) const;
+ void callInternalWithMetaTypes(
+ QObject *thisObject, void **argv, const QMetaType *types, int argc) const;
static QPair<QObject *, int> extractQtMethod(const QV4::FunctionObject *function);
-};
+private:
+ friend struct QMetaObjectWrapper;
-struct Q_QML_EXPORT QMetaObjectWrapper : public QV4::FunctionObject
-{
- V4_OBJECT2(QMetaObjectWrapper, QV4::FunctionObject)
- V4_NEEDS_DESTROY
-
- static ReturnedValue create(ExecutionEngine *engine, const QMetaObject* metaObject);
- const QMetaObject *metaObject() const { return d()->metaObject; }
+ static const QQmlPropertyData *resolveOverloaded(
+ const QQmlObjectOrGadget &object, const QQmlPropertyData *methods, int methodCount,
+ ExecutionEngine *engine, CallData *callArgs);
-protected:
- static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
- static bool virtualIsEqualTo(Managed *a, Managed *b);
-
-private:
- void init(ExecutionEngine *engine);
- ReturnedValue constructInternal(const Value *argv, int argc) const;
- ReturnedValue callConstructor(const QQmlPropertyData &data, QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const;
- ReturnedValue callOverloadedConstructor(QV4::ExecutionEngine *engine, QV4::CallData *callArgs) const;
+ static const QQmlPropertyData *resolveOverloaded(
+ const QQmlPropertyData *methods, int methodCount,
+ void **argv, int argc, const QMetaType *types);
+ static ReturnedValue callPrecise(
+ const QQmlObjectOrGadget &object, const QQmlPropertyData &data,
+ ExecutionEngine *engine, CallData *callArgs,
+ QMetaObject::Call callType = QMetaObject::InvokeMetaMethod);
};
struct Q_QML_EXPORT QmlSignalHandler : public QV4::Object
@@ -317,24 +403,37 @@ struct Q_QML_EXPORT QmlSignalHandler : public QV4::Object
int signalIndex() const { return d()->signalIndex; }
QObject *object() const { return d()->object(); }
+ ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const;
+
static void initProto(ExecutionEngine *v4);
};
+using QObjectBiPointer = QBiPointer<QObject, const QObject>;
+
class MultiplyWrappedQObjectMap : public QObject,
- private QHash<QObject*, QV4::WeakValue>
+ private QHash<QObjectBiPointer, QV4::WeakValue>
{
Q_OBJECT
public:
- typedef QHash<QObject*, QV4::WeakValue>::ConstIterator ConstIterator;
- typedef QHash<QObject*, QV4::WeakValue>::Iterator Iterator;
+ typedef QHash<QObjectBiPointer, QV4::WeakValue>::ConstIterator ConstIterator;
+ typedef QHash<QObjectBiPointer, QV4::WeakValue>::Iterator Iterator;
+
+ using value_type = QHash<QObjectBiPointer, QV4::WeakValue>::value_type;
+
+ ConstIterator begin() const { return QHash<QObjectBiPointer, QV4::WeakValue>::constBegin(); }
+ Iterator begin() { return QHash<QObjectBiPointer, QV4::WeakValue>::begin(); }
+ ConstIterator end() const { return QHash<QObjectBiPointer, QV4::WeakValue>::constEnd(); }
+ Iterator end() { return QHash<QObjectBiPointer, QV4::WeakValue>::end(); }
- ConstIterator begin() const { return QHash<QObject*, QV4::WeakValue>::constBegin(); }
- Iterator begin() { return QHash<QObject*, QV4::WeakValue>::begin(); }
- ConstIterator end() const { return QHash<QObject*, QV4::WeakValue>::constEnd(); }
- Iterator end() { return QHash<QObject*, QV4::WeakValue>::end(); }
+ template<typename Pointer>
+ void insert(Pointer key, Heap::Object *value)
+ {
+ QHash<QObjectBiPointer, WeakValue>::operator[](key).set(value->internalClass->engine, value);
+ connect(key, SIGNAL(destroyed(QObject*)), this, SLOT(removeDestroyedObject(QObject*)));
+ }
- void insert(QObject *key, Heap::Object *value);
- ReturnedValue value(QObject *key) const
+ template<typename Pointer>
+ ReturnedValue value(Pointer key) const
{
ConstIterator it = find(key);
return it == end()
@@ -343,8 +442,24 @@ public:
}
Iterator erase(Iterator it);
- void remove(QObject *key);
- void mark(QObject *key, MarkStack *markStack);
+
+ template<typename Pointer>
+ void remove(Pointer key)
+ {
+ Iterator it = find(key);
+ if (it == end())
+ return;
+ erase(it);
+ }
+
+ template<typename Pointer>
+ void mark(Pointer key, MarkStack *markStack)
+ {
+ Iterator it = find(key);
+ if (it == end())
+ return;
+ it->markOnce(markStack);
+ }
private Q_SLOTS:
void removeDestroyedObject(QObject*);
diff --git a/src/qml/jsruntime/qv4referenceobject.cpp b/src/qml/jsruntime/qv4referenceobject.cpp
new file mode 100644
index 0000000000..af6ee60abc
--- /dev/null
+++ b/src/qml/jsruntime/qv4referenceobject.cpp
@@ -0,0 +1,10 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qv4referenceobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_OBJECT_VTABLE(QV4::ReferenceObject);
+
+QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4referenceobject_p.h b/src/qml/jsruntime/qv4referenceobject_p.h
new file mode 100644
index 0000000000..094749ce6e
--- /dev/null
+++ b/src/qml/jsruntime/qv4referenceobject_p.h
@@ -0,0 +1,171 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QV4REFERENCEOBJECT_P_H
+#define QV4REFERENCEOBJECT_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/qv4object_p.h>
+#include <private/qv4stackframe_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+namespace Heap {
+
+
+#define ReferenceObjectMembers(class, Member) \
+ Member(class, Pointer, Object *, m_object)
+
+DECLARE_HEAP_OBJECT(ReferenceObject, Object) {
+ DECLARE_MARKOBJECTS(ReferenceObject);
+
+ enum Flag : quint8 {
+ NoFlag = 0,
+ CanWriteBack = 1 << 0,
+ IsVariant = 1 << 1,
+ EnforcesLocation = 1 << 2,
+ };
+ Q_DECLARE_FLAGS(Flags, Flag);
+
+ void init(Object *object, int property, Flags flags)
+ {
+ setObject(object);
+ m_property = property;
+ m_flags = flags;
+ Object::init();
+ }
+
+ Flags flags() const { return Flags(m_flags); }
+
+ Object *object() const { return m_object.get(); }
+ void setObject(Object *object) { m_object.set(internalClass->engine, object); }
+
+ int property() const { return m_property; }
+
+ bool canWriteBack() const { return hasFlag(CanWriteBack); }
+ bool isVariant() const { return hasFlag(IsVariant); }
+ bool enforcesLocation() const { return hasFlag(EnforcesLocation); }
+
+ void setLocation(const Function *function, quint16 statement)
+ {
+ m_function = function;
+ m_statementIndex = statement;
+ }
+
+ const Function *function() const { return m_function; }
+ quint16 statementIndex() const { return m_statementIndex; }
+
+ bool isAttachedToProperty() const
+ {
+ if (enforcesLocation()) {
+ if (CppStackFrame *frame = internalClass->engine->currentStackFrame) {
+ if (frame->v4Function != function() || frame->statementNumber() != statementIndex())
+ return false;
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool isReference() const { return m_object; }
+
+private:
+
+ bool hasFlag(Flag flag) const
+ {
+ return m_flags & quint8(flag);
+ }
+
+ void setFlag(Flag flag, bool set)
+ {
+ m_flags = set ? (m_flags | quint8(flag)) : (m_flags & ~quint8(flag));
+ }
+
+ const Function *m_function;
+ int m_property;
+ quint16 m_statementIndex;
+ quint8 m_flags;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(ReferenceObject::Flags)
+
+} // namespace Heap
+
+
+struct ReferenceObject : public Object
+{
+ V4_OBJECT2(ReferenceObject, Object)
+ V4_NEEDS_DESTROY
+
+public:
+ static constexpr const int AllProperties = -1;
+
+ template<typename HeapObject>
+ static bool readReference(HeapObject *ref)
+ {
+ if (!ref->object())
+ return false;
+
+ QV4::Scope scope(ref->internalClass->engine);
+ QV4::ScopedObject object(scope, ref->object());
+
+ if (ref->isVariant()) {
+ QVariant variant;
+ void *a[] = { &variant };
+ return object->metacall(QMetaObject::ReadProperty, ref->property(), a)
+ && ref->setVariant(variant);
+ }
+
+ void *a[] = { ref->storagePointer() };
+ return object->metacall(QMetaObject::ReadProperty, ref->property(), a);
+ }
+
+ template<typename HeapObject>
+ static bool writeBack(HeapObject *ref, int internalIndex = AllProperties)
+ {
+ if (!ref->object() || !ref->canWriteBack())
+ return false;
+
+ QV4::Scope scope(ref->internalClass->engine);
+ QV4::ScopedObject object(scope, ref->object());
+
+ int flags = QQmlPropertyData::HasInternalIndex;
+ int status = -1;
+ if (ref->isVariant()) {
+ QVariant variant = ref->toVariant();
+ void *a[] = { &variant, nullptr, &status, &flags, &internalIndex };
+ return object->metacall(QMetaObject::WriteProperty, ref->property(), a);
+ }
+
+ void *a[] = { ref->storagePointer(), nullptr, &status, &flags, &internalIndex };
+ return object->metacall(QMetaObject::WriteProperty, ref->property(), a);
+ }
+
+ template<typename HeapObject>
+ static HeapObject *detached(HeapObject *ref)
+ {
+ if (ref->object() && !ref->enforcesLocation() && !readReference(ref))
+ return ref; // It's dead. No point in detaching it anymore
+
+ return ref->detached();
+ }
+};
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4REFERENCEOBJECT_P_H
diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp
index 0772770d63..dc9dbe48ae 100644
--- a/src/qml/jsruntime/qv4reflect.cpp
+++ b/src/qml/jsruntime/qv4reflect.cpp
@@ -1,44 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4reflect_p.h"
-#include "qv4symbol_p.h"
#include "qv4runtimeapi_p.h"
#include "qv4objectproto_p.h"
#include "qv4propertykey_p.h"
@@ -76,7 +39,10 @@ struct CallArgs {
static CallArgs createListFromArrayLike(Scope &scope, const Object *o)
{
- int len = o->getLength();
+ int len = scope.engine->safeForAllocLength(o->getLength());
+ if (scope.engine->hasException)
+ return {nullptr, 0};
+
Value *arguments = scope.alloc(len);
for (int i = 0; i < len; ++i) {
@@ -98,7 +64,8 @@ ReturnedValue Reflect::method_apply(const FunctionObject *f, const Value *, cons
if (scope.hasException())
return Encode::undefined();
- return static_cast<const FunctionObject &>(argv[0]).call(&argv[1], arguments.argv, arguments.argc);
+ return checkedResult(scope.engine, static_cast<const FunctionObject &>(argv[0]).call(
+ &argv[1], arguments.argv, arguments.argc));
}
ReturnedValue Reflect::method_construct(const FunctionObject *f, const Value *, const Value *argv, int argc)
@@ -127,14 +94,14 @@ ReturnedValue Reflect::method_defineProperty(const FunctionObject *f, const Valu
ScopedObject O(scope, argv[0]);
ScopedPropertyKey name(scope, (argc > 1 ? argv[1] : Value::undefinedValue()).toPropertyKey(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
ScopedValue attributes(scope, argc > 2 ? argv[2] : Value::undefinedValue());
ScopedProperty pd(scope);
PropertyAttributes attrs;
ObjectPrototype::toPropertyDescriptor(scope.engine, attributes, pd, &attrs);
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
bool result = O->defineOwnProperty(name, pd, attrs);
@@ -198,7 +165,7 @@ ReturnedValue Reflect::method_has(const FunctionObject *f, const Value *, const
const Value *index = argc > 1 ? &argv[1] : &undef;
ScopedPropertyKey name(scope, index->toPropertyKey(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return false;
return Encode(o->hasProperty(name));
@@ -267,7 +234,7 @@ ReturnedValue Reflect::method_set(const FunctionObject *f, const Value *, const
ScopedValue receiver(scope, argc >3 ? argv[3] : argv[0]);
ScopedPropertyKey propertyKey(scope, index->toPropertyKey(scope.engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return false;
bool result = o->put(propertyKey, val, receiver);
return Encode(result);
diff --git a/src/qml/jsruntime/qv4reflect_p.h b/src/qml/jsruntime/qv4reflect_p.h
index d480e1d914..40e1874686 100644
--- a/src/qml/jsruntime/qv4reflect_p.h
+++ b/src/qml/jsruntime/qv4reflect_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4REFLECT_H
#define QV4REFLECT_H
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index 4ed1dbd5aa..9c48199157 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4regexp_p.h"
#include "qv4engine_p.h"
@@ -45,19 +9,23 @@
using namespace QV4;
+#if ENABLE(YARR_JIT)
+static constexpr quint8 RegexpJitThreshold = 5;
+#endif
+
static JSC::RegExpFlags jscFlags(uint flags)
{
JSC::RegExpFlags jscFlags = JSC::NoFlags;
if (flags & CompiledData::RegExp::RegExp_Global)
- jscFlags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagGlobal);
+ jscFlags = static_cast<JSC::RegExpFlags>(jscFlags | JSC::FlagGlobal);
if (flags & CompiledData::RegExp::RegExp_IgnoreCase)
- jscFlags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagIgnoreCase);
+ jscFlags = static_cast<JSC::RegExpFlags>(jscFlags | JSC::FlagIgnoreCase);
if (flags & CompiledData::RegExp::RegExp_Multiline)
- jscFlags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagMultiline);
+ jscFlags = static_cast<JSC::RegExpFlags>(jscFlags | JSC::FlagMultiline);
if (flags & CompiledData::RegExp::RegExp_Unicode)
- jscFlags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagUnicode);
+ jscFlags = static_cast<JSC::RegExpFlags>(jscFlags | JSC::FlagUnicode);
if (flags & CompiledData::RegExp::RegExp_Sticky)
- jscFlags = static_cast<JSC::RegExpFlags>(flags | JSC::FlagSticky);
+ jscFlags = static_cast<JSC::RegExpFlags>(jscFlags | JSC::FlagSticky);
return jscFlags;
}
@@ -73,20 +41,65 @@ DEFINE_MANAGED_VTABLE(RegExp);
uint RegExp::match(const QString &string, int start, uint *matchOffsets)
{
- static const uint offsetJITFail = std::numeric_limits<unsigned>::max() - 1;
-
if (!isValid())
return JSC::Yarr::offsetNoMatch;
+#if ENABLE(YARR_JIT)
+ auto *priv = d();
+
+ auto regenerateByteCode = [](Heap::RegExp *regexp) {
+ JSC::Yarr::ErrorCode error = JSC::Yarr::ErrorCode::NoError;
+ JSC::Yarr::YarrPattern yarrPattern(WTF::String(*regexp->pattern), jscFlags(regexp->flags),
+ error);
+
+ // As we successfully parsed the pattern before, we should still be able to.
+ Q_ASSERT(error == JSC::Yarr::ErrorCode::NoError);
+
+ regexp->byteCode = JSC::Yarr::byteCompile(
+ yarrPattern,
+ regexp->internalClass->engine->bumperPointerAllocator).release();
+ };
+
+ auto removeJitCode = [](Heap::RegExp *regexp) {
+ delete regexp->jitCode;
+ regexp->jitCode = nullptr;
+ regexp->jitFailed = true;
+ };
+
+ auto removeByteCode = [](Heap::RegExp *regexp) {
+ delete regexp->byteCode;
+ regexp->byteCode = nullptr;
+ };
+
+ if (!priv->jitCode && !priv->jitFailed && priv->internalClass->engine->canJIT()
+ && (string.length() > 1024 || priv->matchCount++ == RegexpJitThreshold)) {
+ removeByteCode(priv);
+
+ JSC::Yarr::ErrorCode error = JSC::Yarr::ErrorCode::NoError;
+ JSC::Yarr::YarrPattern yarrPattern(
+ WTF::String(*priv->pattern), jscFlags(priv->flags), error);
+ if (!yarrPattern.m_containsBackreferences) {
+ priv->jitCode = new JSC::Yarr::YarrCodeBlock;
+ JSC::VM *vm = static_cast<JSC::VM *>(priv->internalClass->engine);
+ JSC::Yarr::jitCompile(yarrPattern, JSC::Yarr::Char16, vm, *priv->jitCode);
+ }
+
+ if (!priv->hasValidJITCode()) {
+ removeJitCode(priv);
+ regenerateByteCode(priv);
+ }
+ }
+#endif
+
WTF::String s(string);
#if ENABLE(YARR_JIT)
- auto *priv = d();
if (priv->hasValidJITCode()) {
+ static const uint offsetJITFail = std::numeric_limits<unsigned>::max() - 1;
uint ret = JSC::Yarr::offsetNoMatch;
#if ENABLE(YARR_JIT_ALL_PARENS_EXPRESSIONS)
char buffer[8192];
- ret = uint(priv->jitCode->execute(s.characters16(), start, s.length(),
+ ret = uint(priv->jitCode->execute(s.characters16(), start, s.size(),
(int*)matchOffsets, buffer, 8192).start);
#else
ret = uint(priv->jitCode->execute(s.characters16(), start, s.length(),
@@ -95,34 +108,25 @@ uint RegExp::match(const QString &string, int start, uint *matchOffsets)
if (ret != offsetJITFail)
return ret;
+ removeJitCode(priv);
// JIT failed. We need byteCode to run the interpreter.
- if (!priv->byteCode) {
- JSC::Yarr::ErrorCode error = JSC::Yarr::ErrorCode::NoError;
- JSC::Yarr::YarrPattern yarrPattern(WTF::String(*priv->pattern), jscFlags(priv->flags),
- error);
-
- // As we successfully parsed the pattern before, we should still be able to.
- Q_ASSERT(error == JSC::Yarr::ErrorCode::NoError);
-
- priv->byteCode = JSC::Yarr::byteCompile(
- yarrPattern,
- priv->internalClass->engine->bumperPointerAllocator).release();
- }
+ Q_ASSERT(!priv->byteCode);
+ regenerateByteCode(priv);
}
#endif // ENABLE(YARR_JIT)
- return JSC::Yarr::interpret(byteCode(), s.characters16(), string.length(), start, matchOffsets);
+ return JSC::Yarr::interpret(byteCode(), s.characters16(), string.size(), start, matchOffsets);
}
QString RegExp::getSubstitution(const QString &matched, const QString &str, int position, const Value *captures, int nCaptures, const QString &replacement)
{
QString result;
- int matchedLength = matched.length();
- Q_ASSERT(position >= 0 && position <= str.length());
+ int matchedLength = matched.size();
+ Q_ASSERT(position >= 0 && position <= str.size());
int tailPos = position + matchedLength;
int seenDollar = -1;
- for (int i = 0; i < replacement.length(); ++i) {
+ for (int i = 0; i < replacement.size(); ++i) {
QChar ch = replacement.at(i);
if (seenDollar >= 0) {
if (ch.unicode() == '$') {
@@ -135,7 +139,7 @@ QString RegExp::getSubstitution(const QString &matched, const QString &str, int
result += str.mid(tailPos);
} else if (ch.unicode() >= '0' && ch.unicode() <= '9') {
int n = ch.unicode() - '0';
- if (i + 1 < replacement.length()) {
+ if (i + 1 < replacement.size()) {
ch = replacement.at(i + 1);
if (ch.unicode() >= '0' && ch.unicode() <= '9') {
n = n*10 + (ch.unicode() - '0');
@@ -212,25 +216,15 @@ void Heap::RegExp::init(ExecutionEngine *engine, const QString &pattern, uint fl
this->flags = flags;
valid = false;
+ jitFailed = false;
+ matchCount = 0;
JSC::Yarr::ErrorCode error = JSC::Yarr::ErrorCode::NoError;
JSC::Yarr::YarrPattern yarrPattern(WTF::String(pattern), jscFlags(flags), error);
if (error != JSC::Yarr::ErrorCode::NoError)
return;
subPatternCount = yarrPattern.m_numSubpatterns;
-#if ENABLE(YARR_JIT)
- if (!yarrPattern.m_containsBackreferences && engine->canJIT()) {
- jitCode = new JSC::Yarr::YarrCodeBlock;
- JSC::VM *vm = static_cast<JSC::VM *>(engine);
- JSC::Yarr::jitCompile(yarrPattern, JSC::Yarr::Char16, vm, *jitCode);
- }
-#else
- Q_UNUSED(engine)
-#endif
- if (hasValidJITCode()) {
- valid = true;
- return;
- }
+ Q_UNUSED(engine);
byteCode = JSC::Yarr::byteCompile(yarrPattern, internalClass->engine->bumperPointerAllocator).release();
if (byteCode)
valid = true;
diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h
index 6afb10ea95..8a178dd2f6 100644
--- a/src/qml/jsruntime/qv4regexp_p.h
+++ b/src/qml/jsruntime/qv4regexp_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4REGEXP_H
#define QV4REGEXP_H
@@ -102,11 +66,13 @@ struct RegExp : Base {
int subPatternCount;
uint flags;
bool valid;
+ bool jitFailed;
+ quint8 matchCount;
QString flagsAsString() const;
int captureCount() const { return subPatternCount + 1; }
};
-Q_STATIC_ASSERT(std::is_trivial< RegExp >::value);
+Q_STATIC_ASSERT(std::is_trivial_v<RegExp>);
}
@@ -164,7 +130,7 @@ inline RegExpCacheKey::RegExpCacheKey(const RegExp::Data *re)
, flags(re->flags)
{}
-inline uint qHash(const RegExpCacheKey& key, uint seed = 0) Q_DECL_NOTHROW
+inline size_t qHash(const RegExpCacheKey& key, size_t seed = 0) noexcept
{ return qHash(key.pattern, seed); }
class RegExpCache : public QHash<RegExpCacheKey, WeakValue>
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index c1a42c4afa..acb9f0acfc 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -1,46 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4regexpobject_p.h"
-#include "qv4objectproto_p.h"
#include "qv4regexp_p.h"
-#include "qv4stringobject_p.h"
#include <private/qv4mm_p.h>
#include "qv4scopedvalue_p.h"
#include "qv4jscall_p.h"
@@ -49,7 +11,6 @@
#include "private/qlocale_tools_p.h"
#include <QtCore/QDebug>
-#include <QtCore/qregexp.h>
#if QT_CONFIG(regularexpression)
#include <QtCore/qregularexpression.h>
#endif
@@ -60,8 +21,6 @@
QT_BEGIN_NAMESPACE
-Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
-
using namespace QV4;
DEFINE_OBJECT_VTABLE(RegExpObject);
@@ -84,57 +43,40 @@ void Heap::RegExpObject::init(QV4::RegExp *value)
o->initProperties();
}
-// Converts a QRegExp to a JS RegExp.
-// The conversion is not 100% exact since ECMA regexp and QRegExp
-// have different semantics/flags, but we try to do our best.
-void Heap::RegExpObject::init(const QRegExp &re)
-{
- Object::init();
-
- // Convert the pattern to a ECMAScript pattern.
- QString pattern = QT_PREPEND_NAMESPACE(qt_regexp_toCanonical)(re.pattern(), re.patternSyntax());
- if (re.isMinimal()) {
- QString ecmaPattern;
- int len = pattern.length();
- ecmaPattern.reserve(len);
- int i = 0;
- const QChar *wc = pattern.unicode();
- bool inBracket = false;
- while (i < len) {
- QChar c = wc[i++];
- ecmaPattern += c;
- switch (c.unicode()) {
- case '?':
- case '+':
- case '*':
- case '}':
- if (!inBracket)
- ecmaPattern += QLatin1Char('?');
- break;
- case '\\':
- if (i < len)
- ecmaPattern += wc[i++];
- break;
- case '[':
- inBracket = true;
- break;
- case ']':
- inBracket = false;
- break;
- default:
- break;
- }
+static QString minimalPattern(const QString &pattern)
+{
+ QString ecmaPattern;
+ int len = pattern.size();
+ ecmaPattern.reserve(len);
+ int i = 0;
+ const QChar *wc = pattern.unicode();
+ bool inBracket = false;
+ while (i < len) {
+ QChar c = wc[i++];
+ ecmaPattern += c;
+ switch (c.unicode()) {
+ case '?':
+ case '+':
+ case '*':
+ case '}':
+ if (!inBracket)
+ ecmaPattern += QLatin1Char('?');
+ break;
+ case '\\':
+ if (i < len)
+ ecmaPattern += wc[i++];
+ break;
+ case '[':
+ inBracket = true;
+ break;
+ case ']':
+ inBracket = false;
+ break;
+ default:
+ break;
}
- pattern = ecmaPattern;
}
-
- Scope scope(internalClass->engine);
- Scoped<QV4::RegExpObject> o(scope, this);
-
- uint flags = (re.caseSensitivity() == Qt::CaseInsensitive ? CompiledData::RegExp::RegExp_IgnoreCase : CompiledData::RegExp::RegExp_NoFlags);
- o->d()->value.set(scope.engine, QV4::RegExp::create(scope.engine, pattern, flags));
-
- o->initProperties();
+ return ecmaPattern;
}
#if QT_CONFIG(regularexpression)
@@ -148,10 +90,16 @@ void Heap::RegExpObject::init(const QRegularExpression &re)
Scope scope(internalClass->engine);
Scoped<QV4::RegExpObject> o(scope, this);
- const uint flags = (re.patternOptions() & QRegularExpression::CaseInsensitiveOption)
- ? CompiledData::RegExp::RegExp_IgnoreCase
- : CompiledData::RegExp::RegExp_NoFlags;
- o->d()->value.set(scope.engine, QV4::RegExp::create(scope.engine, re.pattern(), flags));
+ QRegularExpression::PatternOptions options = re.patternOptions();
+ uint flags = (options & QRegularExpression::CaseInsensitiveOption)
+ ? CompiledData::RegExp::RegExp_IgnoreCase
+ : CompiledData::RegExp::RegExp_NoFlags;
+ if (options & QRegularExpression::MultilineOption)
+ flags |= CompiledData::RegExp::RegExp_Multiline;
+ QString pattern = re.pattern();
+ if (options & QRegularExpression::InvertedGreedinessOption)
+ pattern = minimalPattern(pattern);
+ o->d()->value.set(scope.engine, QV4::RegExp::create(scope.engine, pattern, flags));
o->initProperties();
}
#endif
@@ -163,26 +111,18 @@ void RegExpObject::initProperties()
Q_ASSERT(value());
}
-// Converts a JS RegExp to a QRegExp.
-// The conversion is not 100% exact since ECMA regexp and QRegExp
-// have different semantics/flags, but we try to do our best.
-QRegExp RegExpObject::toQRegExp() const
-{
- Qt::CaseSensitivity caseSensitivity = (value()->flags & CompiledData::RegExp::RegExp_IgnoreCase) ? Qt::CaseInsensitive : Qt::CaseSensitive;
- return QRegExp(*value()->pattern, caseSensitivity, QRegExp::RegExp2);
-}
-
#if QT_CONFIG(regularexpression)
// Converts a JS RegExp to a QRegularExpression.
// The conversion is not 100% exact since ECMA regexp and QRegularExpression
// have different semantics/flags, but we try to do our best.
QRegularExpression RegExpObject::toQRegularExpression() const
{
- QRegularExpression::PatternOptions caseSensitivity
- = (value()->flags & CompiledData::RegExp::RegExp_IgnoreCase)
- ? QRegularExpression::CaseInsensitiveOption
- : QRegularExpression::NoPatternOption;
- return QRegularExpression(*value()->pattern, caseSensitivity);
+ QRegularExpression::PatternOptions options = QRegularExpression::NoPatternOption;
+ if (value()->flags & CompiledData::RegExp::RegExp_IgnoreCase)
+ options |= QRegularExpression::CaseInsensitiveOption;
+ if (value()->flags & CompiledData::RegExp::RegExp_Multiline)
+ options |= QRegularExpression::MultilineOption;
+ return QRegularExpression(*value()->pattern, options);
}
#endif
@@ -193,7 +133,7 @@ QString RegExpObject::toString() const
p = QStringLiteral("(?:)");
} else {
// escape certain parts, see ch. 15.10.4
- p.replace('/', QLatin1String("\\/"));
+ p.replace(u'/', QLatin1String("\\/"));
}
return p;
}
@@ -204,7 +144,7 @@ ReturnedValue RegExpObject::builtinExec(ExecutionEngine *engine, const String *s
Scope scope(engine);
int offset = (global() || sticky()) ? lastIndex() : 0;
- if (offset < 0 || offset > s.length()) {
+ if (offset < 0 || offset > s.size()) {
setLastIndex(0);
RETURN_RESULT(Encode::null());
}
@@ -228,7 +168,7 @@ ReturnedValue RegExpObject::builtinExec(ExecutionEngine *engine, const String *s
int len = value()->captureCount();
array->arrayReserve(len);
ScopedValue v(scope);
- int strlen = s.length();
+ int strlen = s.size();
for (int i = 0; i < len; ++i) {
int start = matchOffsets[i * 2];
int end = matchOffsets[i * 2 + 1];
@@ -290,7 +230,7 @@ uint parseFlags(Scope &scope, const QV4::Value *f)
if (scope.hasException())
return flags;
QString str = s->toQString();
- for (int i = 0; i < str.length(); ++i) {
+ for (int i = 0; i < str.size(); ++i) {
if (str.at(i) == QLatin1Char('g') && !(flags & CompiledData::RegExp::RegExp_Global)) {
flags |= CompiledData::RegExp::RegExp_Global;
} else if (str.at(i) == QLatin1Char('i') && !(flags & CompiledData::RegExp::RegExp_IgnoreCase)) {
@@ -440,7 +380,7 @@ ReturnedValue RegExpPrototype::execFirstMatch(const FunctionObject *b, const Val
QString s = str->toQString();
int offset = r->lastIndex();
- if (offset < 0 || offset > s.length()) {
+ if (offset < 0 || offset > s.size()) {
r->setLastIndex(0);
RETURN_RESULT(Encode::null());
}
@@ -481,6 +421,8 @@ ReturnedValue RegExpPrototype::exec(ExecutionEngine *engine, const Object *o, co
ScopedFunctionObject exec(scope, o->get(key));
if (exec) {
ScopedValue result(scope, exec->call(o, s, 1));
+ if (scope.hasException())
+ RETURN_UNDEFINED();
if (!result->isNull() && !result->isObject())
return scope.engine->throwTypeError();
return result->asReturnedValue();
@@ -498,7 +440,7 @@ ReturnedValue RegExpPrototype::method_exec(const FunctionObject *b, const Value
if (!r)
return scope.engine->throwTypeError();
- ScopedValue arg(scope, argc ? argv[0]: Value::undefinedValue());
+ ScopedValue arg(scope, argc ? argv[0] : Value::undefinedValue());
ScopedString str(scope, arg->toString(scope.engine));
if (scope.hasException())
RETURN_UNDEFINED();
@@ -574,7 +516,7 @@ ReturnedValue RegExpPrototype::method_get_ignoreCase(const FunctionObject *f, co
static int advanceStringIndex(int index, const QString &str, bool unicode)
{
if (unicode) {
- if (index < str.length() - 1 &&
+ if (index < str.size() - 1 &&
str.at(index).isHighSurrogate() &&
str.at(index + 1).isLowSurrogate())
++index;
@@ -663,7 +605,7 @@ ReturnedValue RegExpPrototype::method_replace(const FunctionObject *f, const Val
if (scope.hasException())
return Encode::undefined();
- int lengthS = s->toQString().length();
+ int lengthS = s->toQString().size();
ScopedString replaceValue(scope);
ScopedFunctionObject replaceFunction(scope, (argc > 1 ? argv[1] : Value::undefinedValue()));
@@ -715,7 +657,7 @@ ReturnedValue RegExpPrototype::method_replace(const FunctionObject *f, const Val
if (scope.hasException())
return Encode::undefined();
QString m = matchString->toQString();
- int matchLength = m.length();
+ int matchLength = m.size();
v = resultObject->get(scope.engine->id_index());
int position = v->toInt32();
position = qMax(qMin(position, lengthS), 0);
@@ -724,19 +666,21 @@ ReturnedValue RegExpPrototype::method_replace(const FunctionObject *f, const Val
int n = 1;
Scope innerScope(scope.engine);
- JSCallData cData(scope, nCaptures + 3);
+ JSCallArguments cData(scope, nCaptures + 3);
while (n <= nCaptures) {
v = resultObject->get(PropertyKey::fromArrayIndex(n));
if (!v->isUndefined())
- cData->args[n] = v->toString(scope.engine);
+ cData.args[n] = v->toString(scope.engine);
++n;
}
QString replacement;
if (functionalReplace) {
- cData->args[0] = matchString;
- cData->args[nCaptures + 1] = Encode(position);
- cData->args[nCaptures + 2] = s;
+ cData.args[0] = matchString;
+ cData.args[nCaptures + 1] = Encode(position);
+ cData.args[nCaptures + 2] = s;
ScopedValue replValue(scope, replaceFunction->call(cData));
+ if (scope.hasException())
+ return Encode::undefined();
replacement = replValue->toQString();
} else {
replacement = RegExp::getSubstitution(matchString->toQString(), s->toQString(), position, cData.args, nCaptures, replaceValue->toQString());
@@ -744,12 +688,12 @@ ReturnedValue RegExpPrototype::method_replace(const FunctionObject *f, const Val
if (scope.hasException())
return Encode::undefined();
if (position >= nextSourcePosition) {
- accumulatedResult += s->toQString().midRef(nextSourcePosition, position - nextSourcePosition) + replacement;
+ accumulatedResult += QStringView{s->toQString()}.mid(nextSourcePosition, position - nextSourcePosition) + replacement;
nextSourcePosition = position + matchLength;
}
}
if (nextSourcePosition < lengthS) {
- accumulatedResult += s->toQString().midRef(nextSourcePosition);
+ accumulatedResult += QStringView{s->toQString()}.mid(nextSourcePosition);
}
return scope.engine->newString(accumulatedResult)->asReturnedValue();
}
@@ -840,7 +784,7 @@ ReturnedValue RegExpPrototype::method_split(const FunctionObject *f, const Value
return A->asReturnedValue();
QString S = s->toQString();
- int size = S.length();
+ int size = S.size();
if (size == 0) {
ScopedValue z(scope, exec(scope.engine, splitter, s));
if (z->isNull())
@@ -961,8 +905,8 @@ ReturnedValue RegExpPrototype::method_compile(const FunctionObject *b, const Val
return scope.engine->throwTypeError();
Scoped<RegExpObject> re(scope, scope.engine->regExpCtor()->callAsConstructor(argv, argc));
-
- r->d()->value.set(scope.engine, re->value());
+ if (re) // Otherwise the regexp constructor should have thrown an exception
+ r->d()->value.set(scope.engine, re->value());
return Encode::undefined();
}
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index b94889e9f0..8d52300013 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4REGEXPOBJECT_H
#define QV4REGEXPOBJECT_H
@@ -50,21 +14,13 @@
// We mean it.
//
-#include "qv4runtime_p.h"
-#include "qv4engine_p.h"
-#include "qv4context_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4string_p.h"
-#include "qv4managed_p.h"
-#include "qv4property_p.h"
-#include "qv4objectiterator_p.h"
-#include "qv4regexp_p.h"
-
-#include <QtCore/QString>
-#include <QtCore/QHash>
-#include <QtCore/QScopedPointer>
-#include <cstdio>
-#include <cassert>
+#include <private/qv4context_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4managed_p.h>
+
+#include <QtCore/qhash.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -80,7 +36,6 @@ DECLARE_HEAP_OBJECT(RegExpObject, Object) {
void init();
void init(QV4::RegExp *value);
- void init(const QRegExp &re);
#if QT_CONFIG(regularexpression)
void init(const QRegularExpression &re);
#endif
@@ -93,7 +48,7 @@ DECLARE_HEAP_OBJECT(RegExpObject, Object) {
Member(class, NoMark, int, lastMatchEnd)
DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) {
- DECLARE_MARKOBJECTS(RegExpCtor);
+ DECLARE_MARKOBJECTS(RegExpCtor)
void init(QV4::ExecutionContext *scope);
void clearLastMatch();
@@ -101,7 +56,7 @@ DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) {
}
-struct Q_QML_PRIVATE_EXPORT RegExpObject: Object {
+struct Q_QML_EXPORT RegExpObject: Object {
V4_OBJECT2(RegExpObject, Object)
Q_MANAGED_TYPE(RegExpObject)
V4_INTERNALCLASS(RegExpObject)
@@ -140,7 +95,6 @@ struct Q_QML_PRIVATE_EXPORT RegExpObject: Object {
return setProperty(Index_LastIndex, Value::fromInt32(index));
}
- QRegExp toQRegExp() const;
#if QT_CONFIG(regularexpression)
QRegularExpression toQRegularExpression() const;
#endif
@@ -152,11 +106,19 @@ struct Q_QML_PRIVATE_EXPORT RegExpObject: Object {
return s->toQString();
}
- Heap::RegExp *value() const { return d()->value; }
- uint flags() const { return d()->value->flags; }
- bool global() const { return d()->value->global(); }
- bool sticky() const { return d()->value->sticky(); }
- bool unicode() const { return d()->value->unicode(); }
+ // We cannot name Heap::RegExp here since we don't want to include qv4regexp_p.h but we still
+ // want to keep the methods inline. We shift the requirement to name the type to the caller by
+ // making it a template.
+ template<typename RegExp = Heap::RegExp>
+ RegExp *value() const { return d()->value; }
+ template<typename RegExp = Heap::RegExp>
+ uint flags() const { return value<RegExp>()->flags; }
+ template<typename RegExp = Heap::RegExp>
+ bool global() const { return value<RegExp>()->global(); }
+ template<typename RegExp = Heap::RegExp>
+ bool sticky() const { return value<RegExp>()->sticky(); }
+ template<typename RegExp = Heap::RegExp>
+ bool unicode() const { return value<RegExp>()->unicode(); }
ReturnedValue builtinExec(ExecutionEngine *engine, const String *s);
};
diff --git a/src/qml/jsruntime/qv4resolvedtypereference.cpp b/src/qml/jsruntime/qv4resolvedtypereference.cpp
new file mode 100644
index 0000000000..7dcf2cd0b8
--- /dev/null
+++ b/src/qml/jsruntime/qv4resolvedtypereference.cpp
@@ -0,0 +1,98 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qv4resolvedtypereference_p.h"
+
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtQml/qqmlpropertymap.h>
+#include <QtCore/qcryptographichash.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+template <typename T>
+bool qtTypeInherits(const QMetaObject *mo) {
+ while (mo) {
+ if (mo == &T::staticMetaObject)
+ return true;
+ mo = mo->superClass();
+ }
+ return false;
+}
+
+void ResolvedTypeReference::doDynamicTypeCheck()
+{
+ const QMetaObject *mo = nullptr;
+ if (m_typePropertyCache)
+ mo = m_typePropertyCache->firstCppMetaObject();
+ else if (m_type.isValid())
+ mo = m_type.metaObject();
+ else if (m_compilationUnit)
+ mo = m_compilationUnit->rootPropertyCache()->firstCppMetaObject();
+ m_isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
+}
+
+/*!
+Returns the property cache, if one alread exists. The cache is not referenced.
+*/
+QQmlPropertyCache::ConstPtr ResolvedTypeReference::propertyCache() const
+{
+ if (m_type.isValid())
+ return m_typePropertyCache;
+ else
+ return m_compilationUnit->rootPropertyCache();
+}
+
+/*!
+Returns the property cache, creating one if it doesn't already exist. The cache is not referenced.
+*/
+QQmlPropertyCache::ConstPtr ResolvedTypeReference::createPropertyCache()
+{
+ if (m_typePropertyCache) {
+ return m_typePropertyCache;
+ } else if (m_type.isValid()) {
+ const QMetaObject *metaObject = m_type.metaObject();
+ if (!metaObject) // value type of non-Q_GADGET base with extension
+ metaObject = m_type.extensionMetaObject();
+ if (metaObject)
+ m_typePropertyCache = QQmlMetaType::propertyCache(metaObject, m_version);
+ return m_typePropertyCache;
+ } else {
+ Q_ASSERT(m_compilationUnit);
+ return m_compilationUnit->rootPropertyCache();
+ }
+}
+
+bool ResolvedTypeReference::addToHash(
+ QCryptographicHash *hash, QHash<quintptr, QByteArray> *checksums)
+{
+ if (m_type.isInlineComponentType()) {
+
+ // A reference to an inline component in the same file will have
+ // - no compilation unit since we cannot resolve the compilation unit before it's built.
+ // - a property cache since we've assigned one in buildMetaObjectsIncrementally().
+ // - a QQmlType that says it's an inline component.
+ // We don't have to add such a thing to the hash since if it changes, the QML document
+ // itself changes, leading to a new timestamp, which is checked before the checksum.
+ if (!m_compilationUnit)
+ return !m_typePropertyCache.isNull();
+
+ } else if (m_type.isValid()) {
+ bool ok = false;
+ if (QQmlPropertyCache::ConstPtr propertyCache = createPropertyCache())
+ hash->addData(propertyCache->checksum(checksums, &ok));
+ else
+ Q_ASSERT(m_type.module() == QLatin1String("QML")); // a builtin without metaobject
+ return ok;
+ }
+ if (!m_compilationUnit)
+ return false;
+ hash->addData({m_compilationUnit->unitData()->md5Checksum,
+ sizeof(m_compilationUnit->unitData()->md5Checksum)});
+ return true;
+}
+
+} // namespace QV4
+
+QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4resolvedtypereference_p.h b/src/qml/jsruntime/qv4resolvedtypereference_p.h
new file mode 100644
index 0000000000..4aaafdd71c
--- /dev/null
+++ b/src/qml/jsruntime/qv4resolvedtypereference_p.h
@@ -0,0 +1,113 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QV4RESOLVEDTYPEREFERNCE_P_H
+#define QV4RESOLVEDTYPEREFERNCE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/private/qtqmlglobal_p.h>
+#include <QtQml/private/qqmlrefcount_p.h>
+#include <QtQml/private/qqmlpropertycache_p.h>
+#include <QtQml/private/qqmltype_p.h>
+#include <QtQml/private/qv4compileddata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCryptographicHash;
+namespace QV4 {
+
+class ResolvedTypeReference
+{
+ Q_DISABLE_COPY_MOVE(ResolvedTypeReference)
+public:
+ ResolvedTypeReference() = default;
+ ~ResolvedTypeReference()
+ {
+ if (m_stronglyReferencesCompilationUnit && m_compilationUnit)
+ m_compilationUnit->release();
+ }
+
+ QQmlPropertyCache::ConstPtr propertyCache() const;
+ QQmlPropertyCache::ConstPtr createPropertyCache();
+ bool addToHash(QCryptographicHash *hash, QHash<quintptr, QByteArray> *checksums);
+
+ void doDynamicTypeCheck();
+
+ QQmlType type() const { return m_type; }
+ void setType(QQmlType type) { m_type = std::move(type); }
+
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit()
+ {
+ return m_compilationUnit;
+ }
+
+ void setCompilationUnit(QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit)
+ {
+ if (m_compilationUnit == unit.data())
+ return;
+ if (m_stronglyReferencesCompilationUnit) {
+ if (m_compilationUnit)
+ m_compilationUnit->release();
+ m_compilationUnit = unit.take();
+ } else {
+ m_compilationUnit = unit.data();
+ }
+ }
+
+ bool referencesCompilationUnit() const { return m_stronglyReferencesCompilationUnit; }
+ void setReferencesCompilationUnit(bool doReference)
+ {
+ if (doReference == m_stronglyReferencesCompilationUnit)
+ return;
+ m_stronglyReferencesCompilationUnit = doReference;
+ if (!m_compilationUnit)
+ return;
+ if (doReference) {
+ m_compilationUnit->addref();
+ } else if (m_compilationUnit->count() == 1) {
+ m_compilationUnit->release();
+ m_compilationUnit = nullptr;
+ } else {
+ m_compilationUnit->release();
+ }
+ }
+
+ QQmlPropertyCache::ConstPtr typePropertyCache() const { return m_typePropertyCache; }
+ void setTypePropertyCache(QQmlPropertyCache::ConstPtr cache)
+ {
+ m_typePropertyCache = std::move(cache);
+ }
+
+ QTypeRevision version() const { return m_version; }
+ void setVersion(QTypeRevision version) { m_version = version; }
+
+ bool isFullyDynamicType() const { return m_isFullyDynamicType; }
+ void setFullyDynamicType(bool fullyDynamic) { m_isFullyDynamicType = fullyDynamic; }
+
+private:
+ QQmlType m_type;
+ QQmlPropertyCache::ConstPtr m_typePropertyCache;
+ QV4::CompiledData::CompilationUnit *m_compilationUnit = nullptr;
+
+ QTypeRevision m_version = QTypeRevision::zero();
+ // Types such as QQmlPropertyMap can add properties dynamically at run-time and
+ // therefore cannot have a property cache installed when instantiated.
+ bool m_isFullyDynamicType = false;
+ bool m_stronglyReferencesCompilationUnit = true;
+};
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4RESOLVEDTYPEREFERNCE_P_H
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 21a0017728..c51c94ffe4 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1,81 +1,44 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4global_p.h"
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
#include "qv4runtime_p.h"
-#include "qv4engine_p.h"
-#include "qv4object_p.h"
-#include "qv4objectproto_p.h"
-#include "qv4globalobject_p.h"
-#include "qv4stringobject_p.h"
-#include "qv4argumentsobject_p.h"
-#include "qv4objectiterator_p.h"
-#include "qv4dateobject_p.h"
-#include "qv4lookup_p.h"
-#include "qv4function_p.h"
-#include "qv4numberobject_p.h"
-#include "qv4regexp_p.h"
-#include "qv4regexpobject_p.h"
-#include "private/qlocale_tools_p.h"
-#include "qv4scopedvalue_p.h"
-#include "qv4jscall_p.h"
-#include <private/qv4qmlcontext_p.h>
-#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"
-
-#include <QtCore/QDebug>
-#include <cassert>
-#include <cstdio>
-#include <stdlib.h>
+#include <private/qqmltypewrapper_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qv4argumentsobject_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4function_p.h>
+#include <private/qv4generatorobject_p.h>
+#include <private/qv4global_p.h>
+#include <private/qv4globalobject_p.h>
+#include <private/qv4jscall_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4math_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4regexp_p.h>
+#include <private/qv4regexpobject_p.h>
+#include <private/qv4scopedvalue_p.h>
+#include <private/qv4stackframe_p.h>
+#include <private/qv4symbol_p.h>
#include <wtf/MathExtras.h>
+#include <QtCore/private/qlocale_tools_p.h>
+#include <QtCore/qdebug.h>
+
#ifdef QV4_COUNT_RUNTIME_FUNCTIONS
-# include <QtCore/QBuffer>
-# include <QtCore/QDebug>
+# include <QtCore/qbuffer.h>
#endif // QV4_COUNT_RUNTIME_FUNCTIONS
+#include <cassert>
+#include <cstdio>
+#include <stdlib.h>
+
QT_BEGIN_NAMESPACE
namespace QV4 {
@@ -179,7 +142,7 @@ struct RuntimeCounters::Data {
}
std::sort(lines.begin(), lines.end(), Line::less);
outs << lines.size() << " counters:" << endl;
- for (const Line &line : qAsConst(lines))
+ for (const Line &line : std::as_const(lines))
outs << qSetFieldWidth(10) << line.count << qSetFieldWidth(0)
<< " | " << line.func
<< " | " << pretty(line.tag1)
@@ -252,7 +215,7 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
*result = qdtoa(num, &decpt, &sign);
if (decpt <= ecma_shortest_low || decpt > ecma_shortest_high) {
- if (result->length() > 1)
+ if (result->size() > 1)
result->insert(1, dot);
result->append(QLatin1Char('e'));
if (decpt > 0)
@@ -260,10 +223,10 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix)
result->append(QString::number(decpt - 1));
} else if (decpt <= 0) {
result->prepend(QLatin1String("0.") + QString(-decpt, zero));
- } else if (decpt < result->length()) {
+ } else if (decpt < result->size()) {
result->insert(decpt, dot);
} else {
- result->append(QString(decpt - result->length(), zero));
+ result->append(QString(decpt - result->size(), zero));
}
if (sign && num)
@@ -319,7 +282,7 @@ ReturnedValue Runtime::Closure::call(ExecutionEngine *engine, int functionId)
QV4::Function *clos = engine->currentStackFrame->v4Function->executableCompilationUnit()
->runtimeFunctions[functionId];
Q_ASSERT(clos);
- ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
+ ExecutionContext *current = engine->currentContext();
if (clos->isGenerator())
return GeneratorFunction::create(current, clos)->asReturnedValue();
return FunctionObject::createScriptFunction(current, clos)->asReturnedValue();
@@ -329,7 +292,7 @@ Bool Runtime::DeleteProperty_NoThrow::call(ExecutionEngine *engine, const Value
{
Scope scope(engine);
ScopedObject o(scope, base.toObject(engine));
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
Q_ASSERT(o);
@@ -354,7 +317,7 @@ Bool Runtime::DeleteName_NoThrow::call(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).deleteProperty(name);
+ return engine->currentContext()->deleteProperty(name);
}
ReturnedValue Runtime::DeleteName::call(ExecutionEngine *engine, Function *function, int name)
@@ -368,7 +331,7 @@ ReturnedValue Runtime::DeleteName::call(ExecutionEngine *engine, Function *funct
}
}
-QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Value &lval, const Value &rval)
+static QV4::ReturnedValue doInstanceof(ExecutionEngine *engine, const Value &lval, const Value &rval)
{
// 11.8.6, 5: rval must be an Object
const Object *rhs = rval.as<Object>();
@@ -384,13 +347,44 @@ QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Valu
Scope scope(engine);
ScopedValue hasInstance(scope, rhs->get(engine->symbol_hasInstance()));
if (hasInstance->isUndefined())
- return rhs->instanceOf(lval);
+ return Encode(rhs->instanceOf(lval));
+
FunctionObject *fHasInstance = hasInstance->as<FunctionObject>();
if (!fHasInstance)
return engine->throwTypeError();
- ScopedValue result(scope, fHasInstance->call(&rval, &lval, 1));
- return Encode(result->toBoolean());
+ return Encode(fHasInstance->call(&rval, &lval, 1));
+}
+
+QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Value &lval, const Value &rval)
+{
+ Scope scope(engine);
+ ScopedValue result(scope, doInstanceof(engine, lval, rval));
+ return scope.hasException() ? Encode::undefined() : Encode(result->toBoolean());
+}
+
+QV4::ReturnedValue Runtime::As::call(ExecutionEngine *engine, const Value &lval, const Value &rval)
+{
+ Scope scope(engine);
+ ScopedValue result(scope, doInstanceof(engine, lval, rval));
+
+ if (scope.hasException()) {
+ // "foo instanceof valueType" must not throw an exception.
+ // So this can only be an object type.
+ engine->catchException();
+ return Encode::null();
+ }
+
+ if (result->toBoolean())
+ return lval.asReturnedValue();
+ else if (result->isBoolean())
+ return Encode::null();
+
+ // Try to convert the value type
+ if (Scoped<QQmlTypeWrapper> typeWrapper(scope, rval); typeWrapper)
+ return coerce(engine, lval, typeWrapper->d()->type(), false);
+
+ return Encode::undefined();
}
QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left, const Value &right)
@@ -408,7 +402,16 @@ QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left,
double RuntimeHelpers::stringToNumber(const QString &string)
{
- const QStringRef s = QStringRef(&string).trimmed();
+ // The actual maximum valid length is certainly shorter, but due to the sheer number of
+ // different number formatting variants, we rather err on the side of caution here.
+ // For example, you can have up to 772 valid decimal digits left of the dot, as stated in the
+ // libdoubleconversion sources. The same maximum value would be represented by roughly 3.5 times
+ // as many binary digits.
+ const int excessiveLength = 16 * 1024;
+ if (string.size() > excessiveLength)
+ return qQNaN();
+
+ const QStringView s = QStringView(string).trimmed();
if (s.startsWith(QLatin1Char('0'))) {
int base = -1;
if (s.startsWith(QLatin1String("0x")) || s.startsWith(QLatin1String("0X")))
@@ -506,6 +509,8 @@ ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const
ScopedValue conv(scope, object->get(meth1));
if (FunctionObject *o = conv->as<FunctionObject>()) {
result = o->call(object, nullptr, 0);
+ if (engine->hasException)
+ return Encode::undefined();
if (result->isPrimitive())
return result->asReturnedValue();
}
@@ -516,6 +521,8 @@ ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const
conv = object->get(meth2);
if (FunctionObject *o = conv->as<FunctionObject>()) {
result = o->call(object, nullptr, 0);
+ if (engine->hasException)
+ return Encode::undefined();
if (result->isPrimitive())
return result->asReturnedValue();
}
@@ -577,7 +584,7 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, Value val
goto redo;
}
case Value::Integer_Type:
- return RuntimeHelpers::stringFromNumber(engine, value.int_32());
+ return engine->newString(QString::number(value.int_32()));
default: // double
return RuntimeHelpers::stringFromNumber(engine, value.doubleValue());
} // switch
@@ -651,7 +658,7 @@ static Q_NEVER_INLINE ReturnedValue getElementIntFallback(ExecutionEngine *engin
ScopedObject o(scope, object);
if (!o) {
if (const String *str = object.as<String>()) {
- if (idx >= (uint)str->toQString().length()) {
+ if (idx >= (uint)str->toQString().size()) {
return Encode::undefined();
}
const QString s = str->toQString().mid(idx, 1);
@@ -789,8 +796,10 @@ ReturnedValue Runtime::GetIterator::call(ExecutionEngine *engine, const Value &i
ScopedFunctionObject f(scope, o->get(engine->symbol_iterator()));
if (!f)
return engine->throwTypeError();
- JSCallData cData(scope, 0, nullptr, o);
+ JSCallData cData(o, nullptr, 0);
ScopedObject it(scope, f->call(cData));
+ if (engine->hasException)
+ return Encode::undefined();
if (!it)
return engine->throwTypeError();
return it->asReturnedValue();
@@ -810,7 +819,7 @@ ReturnedValue Runtime::IteratorNext::call(ExecutionEngine *engine, const Value &
engine->throwTypeError();
return Encode(true);
}
- JSCallData cData(scope, 0, nullptr, &iterator);
+ JSCallData cData(&iterator, nullptr, 0);
ScopedObject o(scope, f->call(cData));
if (scope.hasException())
return Encode(true);
@@ -853,6 +862,8 @@ ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, c
engine->hasException = false;
ScopedValue ret(scope, static_cast<const Object &>(iterator).get(engine->id_return()));
+ if (engine->hasException)
+ return Encode(true);
if (ret->isUndefined()) {
// propagate return()
return Encode::undefined();
@@ -867,14 +878,13 @@ ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, c
ScopedValue t(scope, static_cast<const Object &>(iterator).get(engine->id_throw()));
if (engine->hasException)
- return Encode::undefined();
+ return Encode(true);
if (t->isUndefined()) {
// no throw method on the iterator
- ScopedValue done(scope, Encode(false));
- IteratorClose::call(engine, iterator, done);
- if (engine->hasException)
- return Encode::undefined();
- return engine->throwTypeError();
+ IteratorClose::call(engine, iterator);
+ if (!engine->hasException)
+ engine->throwTypeError();
+ return Encode(true);
}
f = t->as<FunctionObject>();
arg = exceptionValue;
@@ -885,14 +895,18 @@ ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, c
f = next->as<FunctionObject>();
}
- if (!f)
- return engine->throwTypeError();
+ if (!f) {
+ engine->throwTypeError();
+ return Encode(true);
+ }
ScopedObject o(scope, f->call(&iterator, arg, 1));
if (scope.hasException())
return Encode(true);
- if (!o)
- return engine->throwTypeError();
+ if (!o) {
+ engine->throwTypeError();
+ return Encode(true);
+ }
ScopedValue d(scope, o->get(engine->id_done()));
if (scope.hasException())
@@ -900,18 +914,15 @@ ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, c
bool done = d->toBoolean();
if (done) {
*object = o->get(engine->id_value());
- return returnCalled ? Encode::undefined() : Encode(true);
+ return (returnCalled && !engine->hasException) ? Encode::undefined() : Encode(true);
}
*object = o;
return Encode(false);
}
-ReturnedValue Runtime::IteratorClose::call(ExecutionEngine *engine, const Value &iterator, const Value &done)
+ReturnedValue Runtime::IteratorClose::call(ExecutionEngine *engine, const Value &iterator)
{
Q_ASSERT(iterator.isObject());
- Q_ASSERT(done.isBoolean());
- if (done.booleanValue())
- return Encode::undefined();
Scope scope(engine);
ScopedValue e(scope);
@@ -972,7 +983,7 @@ void Runtime::StoreNameSloppy::call(ExecutionEngine *engine, int nameIndex, cons
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- ExecutionContext::Error e = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).setProperty(name, value);
+ ExecutionContext::Error e = engine->currentContext()->setProperty(name, value);
if (e == ExecutionContext::RangeError)
engine->globalObject->put(name, value);
@@ -982,7 +993,7 @@ void Runtime::StoreNameStrict::call(ExecutionEngine *engine, int nameIndex, cons
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- ExecutionContext::Error e = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).setProperty(name, value);
+ ExecutionContext::Error e = engine->currentContext()->setProperty(name, value);
if (e == ExecutionContext::TypeError)
engine->throwTypeError();
else if (e == ExecutionContext::RangeError)
@@ -1013,32 +1024,50 @@ ReturnedValue Runtime::LoadName::call(ExecutionEngine *engine, int nameIndex)
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name);
+ return engine->currentContext()->getProperty(name);
}
static Object *getSuperBase(Scope &scope)
{
- if (scope.engine->currentStackFrame->jsFrame->thisObject.isEmpty()) {
- scope.engine->throwReferenceError(QStringLiteral("Missing call to super()."), QString(), 0, 0);
- return nullptr;
+ ScopedFunctionObject f(scope);
+ ScopedObject homeObject(scope);
+ if (scope.engine->currentStackFrame->isJSTypesFrame()) {
+ JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(
+ scope.engine->currentStackFrame);
+
+ if (frame->jsFrame->thisObject.isEmpty()) {
+ scope.engine->throwReferenceError(
+ QStringLiteral("Missing call to super()."), QString(), 0, 0);
+ return nullptr;
+ }
+
+ f = Value::fromStaticValue(frame->jsFrame->function);
+ homeObject = f->getHomeObject();
+ } else {
+ Q_ASSERT(scope.engine->currentStackFrame->isMetaTypesFrame());
+ MetaTypesStackFrame *frame = static_cast<MetaTypesStackFrame *>(
+ scope.engine->currentStackFrame);
+ if (frame->thisObject() == nullptr) {
+ scope.engine->throwReferenceError(
+ QStringLiteral("Missing call to super()."), QString(), 0, 0);
+ return nullptr;
+ }
}
- ScopedFunctionObject f(
- scope, Value::fromStaticValue(scope.engine->currentStackFrame->jsFrame->function));
- ScopedObject homeObject(scope, f->getHomeObject());
if (!homeObject) {
- ScopedContext ctx(scope, static_cast<ExecutionContext *>(&scope.engine->currentStackFrame->jsFrame->context));
+ ScopedContext ctx(scope, scope.engine->currentContext());
Q_ASSERT(ctx);
while (ctx) {
if (CallContext *c = ctx->asCallContext()) {
f = c->d()->function;
QV4::Function *fn = f->function();
- if (fn && !fn->isArrowFunction() && !fn->isEval)
+ if (fn && !fn->isArrowFunction() && fn->kind != Function::Eval)
break;
}
ctx = ctx->d()->outer;
}
- homeObject = f->getHomeObject();
+ if (f)
+ homeObject = f->getHomeObject();
}
if (!homeObject) {
scope.engine->throwTypeError();
@@ -1062,8 +1091,18 @@ ReturnedValue Runtime::LoadSuperProperty::call(ExecutionEngine *engine, const Va
ScopedPropertyKey key(scope, property.toPropertyKey(engine));
if (engine->hasException)
return Encode::undefined();
- return base->get(
- key, &(engine->currentStackFrame->jsFrame->thisObject.asValue<Value>()));
+
+ if (scope.engine->currentStackFrame->isJSTypesFrame()) {
+ JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(
+ scope.engine->currentStackFrame);
+ return base->get(key, &(frame->jsFrame->thisObject.asValue<Value>()));
+ } else {
+ Q_ASSERT(scope.engine->currentStackFrame->isMetaTypesFrame());
+ MetaTypesStackFrame *frame = static_cast<MetaTypesStackFrame *>(
+ scope.engine->currentStackFrame);
+ Scoped<QObjectWrapper> wrapper(scope, QObjectWrapper::wrap(engine, frame->thisObject()));
+ return base->get(key, wrapper);
+ }
}
void Runtime::StoreSuperProperty::call(ExecutionEngine *engine, const Value &property, const Value &value)
@@ -1075,8 +1114,20 @@ void Runtime::StoreSuperProperty::call(ExecutionEngine *engine, const Value &pro
ScopedPropertyKey key(scope, property.toPropertyKey(engine));
if (engine->hasException)
return;
- bool result = base->put(
- key, value, &(engine->currentStackFrame->jsFrame->thisObject.asValue<Value>()));
+
+ bool result;
+ if (scope.engine->currentStackFrame->isJSTypesFrame()) {
+ JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(
+ scope.engine->currentStackFrame);
+ result = base->put(key, value, &(frame->jsFrame->thisObject.asValue<Value>()));
+ } else {
+ Q_ASSERT(scope.engine->currentStackFrame->isMetaTypesFrame());
+ MetaTypesStackFrame *frame = static_cast<MetaTypesStackFrame *>(
+ scope.engine->currentStackFrame);
+ Scoped<QObjectWrapper> wrapper(scope, QObjectWrapper::wrap(engine, frame->thisObject()));
+ result = base->put(key, value, wrapper);
+ }
+
if (!result && engine->currentStackFrame->v4Function->isStrict())
engine->throwTypeError();
}
@@ -1116,9 +1167,23 @@ void Runtime::SetLookupStrict::call(Function *f, const Value &base, int index, c
ReturnedValue Runtime::LoadSuperConstructor::call(ExecutionEngine *engine, const Value &t)
{
- if (engine->currentStackFrame->thisObject() != Value::emptyValue().asReturnedValue()) {
- return engine->throwReferenceError(QStringLiteral("super() already called."), QString(), 0, 0); // ### fix line number
+ if (engine->currentStackFrame->isJSTypesFrame()) {
+ JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(engine->currentStackFrame);
+ if (frame->thisObject() != Value::emptyValue().asReturnedValue()) {
+ // ### TODO: fix line number
+ return engine->throwReferenceError(
+ QStringLiteral("super() already called."), QString(), 0, 0);
+ }
+ } else {
+ Q_ASSERT(engine->currentStackFrame->isMetaTypesFrame());
+ MetaTypesStackFrame *frame = static_cast<MetaTypesStackFrame *>(engine->currentStackFrame);
+ if (frame->thisObject() != nullptr) {
+ // ### TODO: fix line number
+ return engine->throwReferenceError(
+ QStringLiteral("super() already called."), QString(), 0, 0);
+ }
}
+
const FunctionObject *f = t.as<FunctionObject>();
if (!f)
return engine->throwTypeError();
@@ -1332,7 +1397,8 @@ ReturnedValue Runtime::CallGlobalLookup::call(ExecutionEngine *engine, uint inde
engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
}
- return static_cast<FunctionObject &>(function).call(&thisObject, argv, argc);
+ return checkedResult(engine, static_cast<FunctionObject &>(function).call(
+ &thisObject, argv, argc));
}
ReturnedValue Runtime::CallQmlContextPropertyLookup::call(ExecutionEngine *engine, uint index,
@@ -1347,7 +1413,8 @@ ReturnedValue Runtime::CallQmlContextPropertyLookup::call(ExecutionEngine *engin
engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
}
- return static_cast<FunctionObject &>(function).call(thisObject, argv, argc);
+ return checkedResult(engine, static_cast<FunctionObject &>(function).call(
+ thisObject, argv, argc));
}
ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Value *argv, int argc)
@@ -1355,8 +1422,8 @@ ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Val
Scope scope(engine);
ScopedValue thisObject(scope);
- ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context);
- ScopedFunctionObject function(scope, ctx.getPropertyAndBase(engine->id_eval(), thisObject));
+ ScopedFunctionObject function(
+ scope, engine->currentContext()->getPropertyAndBase(engine->id_eval(), thisObject));
if (engine->hasException)
return Encode::undefined();
@@ -1366,7 +1433,7 @@ ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Val
if (function->d() == engine->evalFunction()->d())
return static_cast<EvalFunction *>(function.getPointer())->evalCall(thisObject, argv, argc, true);
- return function->call(thisObject, argv, argc);
+ return checkedResult(engine, function->call(thisObject, argv, argc));
}
ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Value *argv, int argc)
@@ -1375,8 +1442,7 @@ ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Va
ScopedValue thisObject(scope);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context);
- ScopedFunctionObject f(scope, ctx.getPropertyAndBase(name, thisObject));
+ ScopedFunctionObject f(scope, engine->currentContext()->getPropertyAndBase(name, thisObject));
if (engine->hasException)
return Encode::undefined();
@@ -1386,7 +1452,7 @@ ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Va
->runtimeStrings[nameIndex]->toQString());
}
- return f->call(thisObject, argv, argc);
+ return checkedResult(engine, f->call(thisObject, argv, argc));
}
ReturnedValue Runtime::CallProperty::call(ExecutionEngine *engine, const Value &baseRef, int nameIndex, Value *argv, int argc)
@@ -1428,7 +1494,7 @@ ReturnedValue Runtime::CallProperty::call(ExecutionEngine *engine, const Value &
return engine->throwTypeError(error);
}
- return f->call(base, argv, argc);
+ return checkedResult(engine, f->call(base, argv, argc));
}
ReturnedValue Runtime::CallPropertyLookup::call(ExecutionEngine *engine, const Value &base, uint index, Value *argv, int argc)
@@ -1437,28 +1503,17 @@ ReturnedValue Runtime::CallPropertyLookup::call(ExecutionEngine *engine, const V
// ok to have the value on the stack here
Value f = Value::fromReturnedValue(l->getter(l, engine, base));
- if (!f.isFunctionObject())
- return engine->throwTypeError();
-
- return static_cast<FunctionObject &>(f).call(&base, argv, argc);
-}
+ if (Q_LIKELY(f.isFunctionObject()))
+ return checkedResult(engine, static_cast<FunctionObject &>(f).call(&base, argv, argc));
-ReturnedValue Runtime::CallElement::call(ExecutionEngine *engine, const Value &baseRef, const Value &index, Value *argv, int argc)
-{
- const Value *base = &baseRef;
- Scope scope(engine);
- ScopedValue thisObject(scope, base->toObject(engine));
- base = thisObject;
+ if (QmlSignalHandler *handler = f.as<QmlSignalHandler>())
+ return checkedResult(engine, handler->call(&base, argv, argc));
- ScopedPropertyKey str(scope, index.toPropertyKey(engine));
- if (engine->hasException)
- return Encode::undefined();
-
- ScopedFunctionObject f(scope, static_cast<const Object *>(base)->get(str));
- if (!f)
- return engine->throwTypeError();
-
- return f->call(base, argv, argc);
+ const QString message = QStringLiteral("Property '%1' of object %2 is not a function")
+ .arg(engine->currentStackFrame->v4Function->compilationUnit
+ ->runtimeStrings[l->nameIndex]->toQString())
+ .arg(base.toQStringNoThrow());
+ return engine->throwTypeError(message);
}
ReturnedValue Runtime::CallValue::call(ExecutionEngine *engine, const Value &func, Value *argv, int argc)
@@ -1466,7 +1521,8 @@ ReturnedValue Runtime::CallValue::call(ExecutionEngine *engine, const Value &fun
if (!func.isFunctionObject())
return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
Value undef = Value::undefinedValue();
- return static_cast<const FunctionObject &>(func).call(&undef, argv, argc);
+ return checkedResult(engine, static_cast<const FunctionObject &>(func).call(
+ &undef, argv, argc));
}
ReturnedValue Runtime::CallWithReceiver::call(ExecutionEngine *engine, const Value &func,
@@ -1474,7 +1530,8 @@ ReturnedValue Runtime::CallWithReceiver::call(ExecutionEngine *engine, const Val
{
if (!func.isFunctionObject())
return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
- return static_cast<const FunctionObject &>(func).call(&thisObject, argv, argc);
+ return checkedResult(engine, static_cast<const FunctionObject &>(func).call(
+ &thisObject, argv, argc));
}
struct CallArgs {
@@ -1501,16 +1558,21 @@ static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc)
// spread element
++i;
it = Runtime::GetIterator::call(scope.engine, argv[i], /* ForInIterator */ 1);
- if (scope.engine->hasException)
+ if (scope.hasException())
return { nullptr, 0 };
while (1) {
done = Runtime::IteratorNext::call(scope.engine, it, v);
- if (scope.engine->hasException)
+ if (scope.hasException())
return { nullptr, 0 };
Q_ASSERT(done->isBoolean());
if (done->booleanValue())
break;
++argCount;
+ constexpr auto safetyMargin = 100; // leave some space on the stack for actual work with the elements
+ if (qint64(scope.engine->jsStackLimit - scope.engine->jsStackTop) < safetyMargin) {
+ scope.engine->throwRangeError(QLatin1String("Too many elements in array to use it with the spread operator"));
+ return { nullptr, 0 };
+ }
v = scope.alloc<Scope::Uninitialized>();
}
}
@@ -1528,7 +1590,8 @@ ReturnedValue Runtime::CallWithSpread::call(ExecutionEngine *engine, const Value
if (engine->hasException)
return Encode::undefined();
- return static_cast<const FunctionObject &>(function).call(&thisObject, arguments.argv, arguments.argc);
+ return checkedResult(engine, static_cast<const FunctionObject &>(function).call(
+ &thisObject, arguments.argv, arguments.argc));
}
ReturnedValue Runtime::Construct::call(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc)
@@ -1552,7 +1615,7 @@ ReturnedValue Runtime::ConstructWithSpread::call(ExecutionEngine *engine, const
return static_cast<const FunctionObject &>(function).callAsConstructor(arguments.argv, arguments.argc, &newTarget);
}
-ReturnedValue Runtime::TailCall::call(CppStackFrame *frame, ExecutionEngine *engine)
+ReturnedValue Runtime::TailCall::call(JSTypesStackFrame *frame, ExecutionEngine *engine)
{
// IMPORTANT! The JIT assumes that this method has the same amount (or less) arguments than
// the jitted function, so it can safely do a tail call.
@@ -1568,18 +1631,19 @@ ReturnedValue Runtime::TailCall::call(CppStackFrame *frame, ExecutionEngine *eng
return engine->throwTypeError();
const FunctionObject &fo = static_cast<const FunctionObject &>(function);
- if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger()
+ if (!frame->callerCanHandleTailCall() || !fo.canBeTailCalled() || engine->debugger()
|| unsigned(argc) > fo.formalParameterCount()) {
// Cannot tailcall, do a normal call:
- return fo.call(&thisObject, argv, argc);
+ return checkedResult(engine, fo.call(&thisObject, argv, argc));
}
- memcpy(frame->jsFrame->args, argv, argc * sizeof(Value));
- frame->init(engine, fo.function(), frame->jsFrame->argValues<Value>(), argc,
- frame->callerCanHandleTailCall);
- frame->setupJSFrame(frame->savedStackTop, fo, fo.scope(), thisObject, Primitive::undefinedValue());
- engine->jsStackTop = frame->savedStackTop + frame->requiredJSStackFrameSize();
- frame->pendingTailCall = true;
+ memmove(frame->jsFrame->args, argv, argc * sizeof(Value));
+ frame->init(fo.function(), frame->jsFrame->argValues<Value>(), argc,
+ frame->callerCanHandleTailCall());
+ frame->setupJSFrame(frame->framePointer(), fo, fo.scope(), thisObject,
+ Primitive::undefinedValue());
+ engine->jsStackTop = frame->framePointer() + frame->requiredJSStackFrameSize();
+ frame->setPendingTailCall(true);
return Encode::undefined();
}
@@ -1624,20 +1688,21 @@ QV4::ReturnedValue Runtime::TypeofName::call(ExecutionEngine *engine, int nameIn
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- ScopedValue prop(scope, static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name));
+ ScopedValue prop(scope, engine->currentContext()->getProperty(name));
// typeof doesn't throw. clear any possible exception
scope.engine->hasException = false;
return TypeofValue::call(engine, prop);
}
-void Runtime::PushCallContext::call(CppStackFrame *frame)
+void Runtime::PushCallContext::call(JSTypesStackFrame *frame)
{
frame->jsFrame->context = ExecutionContext::newCallContext(frame)->asReturnedValue();
}
ReturnedValue Runtime::PushWithContext::call(ExecutionEngine *engine, const Value &acc)
{
- CallData *jsFrame = engine->currentStackFrame->jsFrame;
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
+ CallData *jsFrame = static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame;
Value &newAcc = jsFrame->accumulator.asValue<Value>();
newAcc = Value::fromHeapObject(acc.toObject(engine));
if (!engine->hasException) {
@@ -1652,18 +1717,23 @@ ReturnedValue Runtime::PushWithContext::call(ExecutionEngine *engine, const Valu
void Runtime::PushCatchContext::call(ExecutionEngine *engine, int blockIndex, int exceptionVarNameIndex)
{
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
auto name = engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex];
- engine->currentStackFrame->jsFrame->context = ExecutionContext::newCatchContext(engine->currentStackFrame, blockIndex, name)->asReturnedValue();
+ static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame->context
+ = ExecutionContext::newCatchContext(engine->currentStackFrame, blockIndex, name)->asReturnedValue();
}
void Runtime::PushBlockContext::call(ExecutionEngine *engine, int index)
{
- engine->currentStackFrame->jsFrame->context = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue();
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
+ static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame->context
+ = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue();
}
void Runtime::CloneBlockContext::call(ExecutionEngine *engine)
{
- auto frame = engine->currentStackFrame;
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
+ auto frame = static_cast<JSTypesStackFrame *>(engine->currentStackFrame);
auto context = static_cast<Heap::CallContext *>(
Value::fromStaticValue(frame->jsFrame->context).m());
frame->jsFrame->context =
@@ -1672,18 +1742,20 @@ void Runtime::CloneBlockContext::call(ExecutionEngine *engine)
void Runtime::PushScriptContext::call(ExecutionEngine *engine, int index)
{
- Q_ASSERT(engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_GlobalContext ||
- engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_QmlContext);
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
+ Q_ASSERT(engine->currentContext()->d()->type == Heap::ExecutionContext::Type_GlobalContext ||
+ engine->currentContext()->d()->type == Heap::ExecutionContext::Type_QmlContext);
ReturnedValue c = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue();
engine->setScriptContext(c);
- engine->currentStackFrame->jsFrame->context = c;
+ static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame->context = c;
}
void Runtime::PopScriptContext::call(ExecutionEngine *engine)
{
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
ReturnedValue root = engine->rootContext()->asReturnedValue();
engine->setScriptContext(root);
- engine->currentStackFrame->jsFrame->context = root;
+ static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame->context = root;
}
void Runtime::ThrowReferenceError::call(ExecutionEngine *engine, int nameIndex)
@@ -1715,7 +1787,7 @@ void Runtime::DeclareVar::call(ExecutionEngine *engine, Bool deletable, int name
{
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).createMutableBinding(name, deletable);
+ engine->currentContext()->createMutableBinding(name, deletable);
}
ReturnedValue Runtime::ArrayLiteral::call(ExecutionEngine *engine, Value *values, uint length)
@@ -1768,7 +1840,7 @@ ReturnedValue Runtime::ObjectLiteral::call(ExecutionEngine *engine, int classId,
arg = ObjectLiteralArgument::Value;
fnName = name->asFunctionName(engine, prefix);
- ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
+ ExecutionContext *current = engine->currentContext();
if (clos->isGenerator())
value = MemberGeneratorFunction::create(current, clos, o, fnName)->asReturnedValue();
else
@@ -1826,7 +1898,7 @@ ReturnedValue Runtime::CreateClass::call(ExecutionEngine *engine, int classIndex
ScopedObject proto(scope, engine->newObject());
proto->setPrototypeUnchecked(protoParent);
- ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
+ ExecutionContext *current = engine->currentContext();
ScopedFunctionObject constructor(scope);
QV4::Function *f = cls->constructorFunction != UINT_MAX ? unit->runtimeFunctions[cls->constructorFunction] : nullptr;
@@ -1910,14 +1982,18 @@ QV4::ReturnedValue Runtime::CreateMappedArgumentsObject::call(ExecutionEngine *e
QV4::ReturnedValue Runtime::CreateUnmappedArgumentsObject::call(ExecutionEngine *engine)
{
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_StrictArgumentsObject);
- return engine->memoryManager->allocObject<StrictArgumentsObject>(ic, engine->currentStackFrame)->asReturnedValue();
+ return engine->memoryManager->allocObject<StrictArgumentsObject>(
+ ic, static_cast<JSTypesStackFrame *>(engine->currentStackFrame))->asReturnedValue();
}
QV4::ReturnedValue Runtime::CreateRestParameter::call(ExecutionEngine *engine, int argIndex)
{
- const Value *values = engine->currentStackFrame->originalArguments + argIndex;
- int nValues = engine->currentStackFrame->originalArgumentsCount - argIndex;
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
+ JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(engine->currentStackFrame);
+ const Value *values = frame->argv() + argIndex;
+ int nValues = frame->argc() - argIndex;
if (nValues <= 0)
return engine->newArrayObject(0)->asReturnedValue();
return engine->newArrayObject(values, nValues)->asReturnedValue();
@@ -2049,9 +2125,7 @@ ReturnedValue Runtime::Exp::call(const Value &base, const Value &exp)
{
double b = base.toNumber();
double e = exp.toNumber();
- if (qt_is_inf(e) && (b == 1 || b == -1))
- return Encode(qt_qnan());
- return Encode(pow(b,e));
+ return Encode(QQmlPrivate::jsExponentiate(b, e));
}
ReturnedValue Runtime::BitAnd::call(const Value &left, const Value &right)
@@ -2173,35 +2247,23 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
Value *lhsGuard = nullptr;
Value *rhsGuard = nullptr;
- redo:
+ redo:
if (lhs.asReturnedValue() == rhs.asReturnedValue())
return !lhs.isNaN();
- int lt = lhs.quickType();
- int rt = rhs.quickType();
- if (rt < lt) {
- qSwap(lhs, rhs);
- qSwap(lt, rt);
- }
+ quint32 lt = lhs.quickType();
+ quint32 rt = rhs.quickType();
- switch (lt) {
- case QV4::Value::QT_ManagedOrUndefined:
+ // LHS: Check if managed
+ if ((lt & (Value::ManagedMask >> Value::Tag_Shift)) == 0) {
if (lhs.isUndefined())
return rhs.isNullOrUndefined();
- Q_FALLTHROUGH();
- case QV4::Value::QT_ManagedOrUndefined1:
- case QV4::Value::QT_ManagedOrUndefined2:
- case QV4::Value::QT_ManagedOrUndefined3:
- // LHS: Managed
- switch (rt) {
- case QV4::Value::QT_ManagedOrUndefined:
+
+ // RHS: Check if managed
+ if ((rt & (Value::ManagedMask >> Value::Tag_Shift)) == 0) {
if (rhs.isUndefined())
return false;
- Q_FALLTHROUGH();
- case QV4::Value::QT_ManagedOrUndefined1:
- case QV4::Value::QT_ManagedOrUndefined2:
- case QV4::Value::QT_ManagedOrUndefined3: {
- // RHS: Managed
+
Heap::Base *l = lhs.m();
Heap::Base *r = rhs.m();
Q_ASSERT(l);
@@ -2211,15 +2273,18 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
if (l->internalClass->vtable->isStringOrSymbol) {
scope.set(&rhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(rhs), PREFERREDTYPE_HINT), r->internalClass->engine);
rhs = rhsGuard->asReturnedValue();
- break;
+ goto redo;
} else {
Q_ASSERT(r->internalClass->vtable->isStringOrSymbol);
scope.set(&lhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT), l->internalClass->engine);
lhs = lhsGuard->asReturnedValue();
- break;
+ goto redo;
}
return false;
}
+
+lhs_managed_and_rhs_not:
+ switch (rt) {
case QV4::Value::QT_Empty:
Q_UNREACHABLE();
case QV4::Value::QT_Null:
@@ -2227,7 +2292,7 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
case QV4::Value::QT_Bool:
case QV4::Value::QT_Int:
rhs = Value::fromDouble(rhs.int_32());
- // fall through
+ Q_FALLTHROUGH();
default: // double
if (lhs.m()->internalClass->vtable->isStringOrSymbol) {
return lhs.m()->internalClass->vtable->isString ? (RuntimeHelpers::toNumber(lhs) == rhs.doubleValue()) : false;
@@ -2237,6 +2302,15 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
}
}
goto redo;
+ } else if ((rt & (Value::ManagedMask >> Value::Tag_Shift)) == 0) {
+ if (rhs.isUndefined())
+ return lhs.isNull(); // Can't be undefined
+ qSwap(lhs, rhs);
+ qSwap(lt, rt);
+ goto lhs_managed_and_rhs_not;
+ }
+
+ switch (lt) {
case QV4::Value::QT_Empty:
Q_UNREACHABLE();
case QV4::Value::QT_Null:
@@ -2244,13 +2318,10 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
case QV4::Value::QT_Bool:
case QV4::Value::QT_Int:
switch (rt) {
- case QV4::Value::QT_ManagedOrUndefined:
- case QV4::Value::QT_ManagedOrUndefined1:
- case QV4::Value::QT_ManagedOrUndefined2:
- case QV4::Value::QT_ManagedOrUndefined3:
case QV4::Value::QT_Empty:
- case QV4::Value::QT_Null:
Q_UNREACHABLE();
+ case QV4::Value::QT_Null:
+ return false;
case QV4::Value::QT_Bool:
case QV4::Value::QT_Int:
return lhs.int_32() == rhs.int_32();
@@ -2258,8 +2329,17 @@ Bool Runtime::CompareEqual::call(const Value &left, const Value &right)
return lhs.int_32() == rhs.doubleValue();
}
default: // double
- Q_ASSERT(rhs.isDouble());
- return lhs.doubleValue() == rhs.doubleValue();
+ switch (rt) {
+ case QV4::Value::QT_Empty:
+ Q_UNREACHABLE();
+ case QV4::Value::QT_Null:
+ return false;
+ case QV4::Value::QT_Bool:
+ case QV4::Value::QT_Int:
+ return lhs.doubleValue() == rhs.int_32();
+ default: // double
+ return lhs.doubleValue() == rhs.doubleValue();
+ }
}
}
@@ -2331,7 +2411,6 @@ QHash<const void *, const char *> Runtime::symbolTable()
{symbol<CallName>(), "CallName" },
{symbol<CallProperty>(), "CallProperty" },
{symbol<CallPropertyLookup>(), "CallPropertyLookup" },
- {symbol<CallElement>(), "CallElement" },
{symbol<CallValue>(), "CallValue" },
{symbol<CallWithReceiver>(), "CallWithReceiver" },
{symbol<CallPossiblyDirectEval>(), "CallPossiblyDirectEval" },
@@ -2401,6 +2480,7 @@ QHash<const void *, const char *> Runtime::symbolTable()
{symbol<UMinus>(), "UMinus" },
{symbol<Instanceof>(), "Instanceof" },
+ {symbol<As>(), "As" },
{symbol<In>(), "In" },
{symbol<Add>(), "Add" },
{symbol<Sub>(), "Sub" },
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index cb89b7e6c0..a012728cd9 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMLJS_RUNTIME_H
#define QMLJS_RUNTIME_H
@@ -52,7 +16,6 @@
#include "qv4global_p.h"
#include "qv4value_p.h"
-#include "qv4math_p.h"
#include "qv4runtimeapi_p.h"
#include <QtCore/qnumeric.h>
@@ -95,7 +58,7 @@ enum TypeHint {
STRING_HINT
};
-struct Q_QML_PRIVATE_EXPORT RuntimeHelpers {
+struct Q_QML_EXPORT RuntimeHelpers {
static ReturnedValue objectDefaultValue(const Object *object, int typeHint);
static ReturnedValue toPrimitive(const Value &value, TypeHint typeHint);
static ReturnedValue ordinaryToPrimitive(ExecutionEngine *engine, const Object *object, String *typeHint);
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index d155187e48..fdee6ac580 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4RUNTIMEAPI_P_H
#define QV4RUNTIMEAPI_P_H
@@ -59,7 +23,7 @@ namespace QV4 {
typedef uint Bool;
-struct Q_QML_PRIVATE_EXPORT Runtime {
+struct Q_QML_EXPORT Runtime {
typedef ReturnedValue (*UnaryOperation)(const Value &value);
typedef ReturnedValue (*BinaryOperation)(const Value &left, const Value &right);
typedef ReturnedValue (*BinaryOperationContext)(ExecutionEngine *, const Value &left, const Value &right);
@@ -79,418 +43,418 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
static constexpr bool lastArgumentIsOutputValue = out == LastArgumentIsOutputValue::Yes;
};
using PureMethod = Method<Throws::No, ChangesContext::No, Pure::Yes>;
- using IteratorMethod = Method<Throws::Yes, ChangesContext::No, Pure::No,
+ using IteratorMethod = Method<Throws::No, ChangesContext::No, Pure::No,
LastArgumentIsOutputValue::Yes>;
/* call */
- struct Q_QML_PRIVATE_EXPORT CallGlobalLookup : Method<Throws::Yes>
+ struct Q_QML_EXPORT CallGlobalLookup : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, uint, Value[], int);
};
- struct Q_QML_PRIVATE_EXPORT CallQmlContextPropertyLookup : Method<Throws::Yes>
+ struct Q_QML_EXPORT CallQmlContextPropertyLookup : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, uint, Value[], int);
};
- struct Q_QML_PRIVATE_EXPORT CallName : Method<Throws::Yes>
+ struct Q_QML_EXPORT CallName : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, int, Value[], int);
};
- struct Q_QML_PRIVATE_EXPORT CallProperty : Method<Throws::Yes>
+ struct Q_QML_EXPORT CallProperty : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, int, Value[], int);
};
- struct Q_QML_PRIVATE_EXPORT CallPropertyLookup : Method<Throws::Yes>
+ struct Q_QML_EXPORT CallPropertyLookup : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, uint, Value[], int);
};
- struct Q_QML_PRIVATE_EXPORT CallElement : Method<Throws::Yes>
- {
- static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int);
- };
- struct Q_QML_PRIVATE_EXPORT CallValue : Method<Throws::Yes>
+ struct Q_QML_EXPORT CallValue : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, Value[], int);
};
- struct Q_QML_PRIVATE_EXPORT CallWithReceiver : Method<Throws::Yes>
+ struct Q_QML_EXPORT CallWithReceiver : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int);
};
- struct Q_QML_PRIVATE_EXPORT CallPossiblyDirectEval : Method<Throws::Yes>
+ struct Q_QML_EXPORT CallPossiblyDirectEval : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, Value[], int);
};
- struct Q_QML_PRIVATE_EXPORT CallWithSpread : Method<Throws::Yes>
+ struct Q_QML_EXPORT CallWithSpread : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int);
};
- struct Q_QML_PRIVATE_EXPORT TailCall : Method<Throws::Yes>
+ struct Q_QML_EXPORT TailCall : Method<Throws::Yes>
{
- static ReturnedValue call(CppStackFrame *, ExecutionEngine *);
+ static ReturnedValue call(JSTypesStackFrame *, ExecutionEngine *engine);
};
/* construct */
- struct Q_QML_PRIVATE_EXPORT Construct : Method<Throws::Yes>
+ struct Q_QML_EXPORT Construct : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int);
};
- struct Q_QML_PRIVATE_EXPORT ConstructWithSpread : Method<Throws::Yes>
+ struct Q_QML_EXPORT ConstructWithSpread : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int);
};
/* load & store */
- struct Q_QML_PRIVATE_EXPORT StoreNameStrict : Method<Throws::Yes>
+ struct Q_QML_EXPORT StoreNameStrict : Method<Throws::Yes>
{
static void call(ExecutionEngine *, int, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT StoreNameSloppy : Method<Throws::Yes>
+ struct Q_QML_EXPORT StoreNameSloppy : Method<Throws::Yes>
{
static void call(ExecutionEngine *, int, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT StoreProperty : Method<Throws::Yes>
+ struct Q_QML_EXPORT StoreProperty : Method<Throws::Yes>
{
static void call(ExecutionEngine *, const Value &, int, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT StoreElement : Method<Throws::Yes>
+ struct Q_QML_EXPORT StoreElement : Method<Throws::Yes>
{
static void call(ExecutionEngine *, const Value &, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT LoadProperty : Method<Throws::Yes>
+ struct Q_QML_EXPORT LoadProperty : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, int);
};
- struct Q_QML_PRIVATE_EXPORT LoadName : Method<Throws::Yes>
+ struct Q_QML_EXPORT LoadName : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, int);
};
- struct Q_QML_PRIVATE_EXPORT LoadElement : Method<Throws::Yes>
+ struct Q_QML_EXPORT LoadElement : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT LoadSuperProperty : Method<Throws::Yes>
+ struct Q_QML_EXPORT LoadSuperProperty : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT StoreSuperProperty : Method<Throws::Yes>
+ struct Q_QML_EXPORT StoreSuperProperty : Method<Throws::Yes>
{
static void call(ExecutionEngine *, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT LoadSuperConstructor : Method<Throws::Yes>
+ struct Q_QML_EXPORT LoadSuperConstructor : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT LoadGlobalLookup : Method<Throws::Yes>
+ struct Q_QML_EXPORT LoadGlobalLookup : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, Function *, int);
};
- struct Q_QML_PRIVATE_EXPORT LoadQmlContextPropertyLookup : Method<Throws::Yes>
+ struct Q_QML_EXPORT LoadQmlContextPropertyLookup : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, uint);
};
- struct Q_QML_PRIVATE_EXPORT GetLookup : Method<Throws::Yes>
+ struct Q_QML_EXPORT GetLookup : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, Function *, const Value &, int);
};
- struct Q_QML_PRIVATE_EXPORT SetLookupStrict : Method<Throws::Yes>
+ struct Q_QML_EXPORT SetLookupStrict : Method<Throws::Yes>
{
static void call(Function *, const Value &, int, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT SetLookupSloppy : Method<Throws::Yes>
+ struct Q_QML_EXPORT SetLookupSloppy : Method<Throws::Yes>
{
static void call(Function *, const Value &, int, const Value &);
};
/* typeof */
- struct Q_QML_PRIVATE_EXPORT TypeofValue : PureMethod
+ struct Q_QML_EXPORT TypeofValue : PureMethod
{
static ReturnedValue call(ExecutionEngine *, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT TypeofName : Method<Throws::No>
+ struct Q_QML_EXPORT TypeofName : Method<Throws::No>
{
static ReturnedValue call(ExecutionEngine *, int);
};
/* delete */
- struct Q_QML_PRIVATE_EXPORT DeleteProperty_NoThrow : Method<Throws::No>
+ struct Q_QML_EXPORT DeleteProperty_NoThrow : Method<Throws::No>
{
static Bool call(ExecutionEngine *, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT DeleteProperty : Method<Throws::Yes>
+ struct Q_QML_EXPORT DeleteProperty : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, Function *, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT DeleteName_NoThrow : Method<Throws::No>
+ struct Q_QML_EXPORT DeleteName_NoThrow : Method<Throws::No>
{
static Bool call(ExecutionEngine *, int);
};
- struct Q_QML_PRIVATE_EXPORT DeleteName : Method<Throws::Yes>
+ struct Q_QML_EXPORT DeleteName : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, Function *, int);
};
/* exceptions & scopes */
- struct Q_QML_PRIVATE_EXPORT ThrowException : Method<Throws::Yes>
+ struct Q_QML_EXPORT ThrowException : Method<Throws::Yes>
{
static void call(ExecutionEngine *, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT PushCallContext : Method<Throws::No, ChangesContext::Yes>
+ struct Q_QML_EXPORT PushCallContext : Method<Throws::No, ChangesContext::Yes>
{
- static void call(CppStackFrame *);
+ static void call(JSTypesStackFrame *);
};
- struct Q_QML_PRIVATE_EXPORT PushWithContext : Method<Throws::Yes, ChangesContext::Yes>
+ struct Q_QML_EXPORT PushWithContext : Method<Throws::Yes, ChangesContext::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT PushCatchContext : Method<Throws::No, ChangesContext::Yes>
+ struct Q_QML_EXPORT PushCatchContext : Method<Throws::No, ChangesContext::Yes>
{
static void call(ExecutionEngine *, int, int);
};
- struct Q_QML_PRIVATE_EXPORT PushBlockContext : Method<Throws::No, ChangesContext::Yes>
+ struct Q_QML_EXPORT PushBlockContext : Method<Throws::No, ChangesContext::Yes>
{
static void call(ExecutionEngine *, int);
};
- struct Q_QML_PRIVATE_EXPORT CloneBlockContext : Method<Throws::No, ChangesContext::Yes>
+ struct Q_QML_EXPORT CloneBlockContext : Method<Throws::No, ChangesContext::Yes>
{
static void call(ExecutionEngine *);
};
- struct Q_QML_PRIVATE_EXPORT PushScriptContext : Method<Throws::No, ChangesContext::Yes>
+ struct Q_QML_EXPORT PushScriptContext : Method<Throws::No, ChangesContext::Yes>
{
static void call(ExecutionEngine *, int);
};
- struct Q_QML_PRIVATE_EXPORT PopScriptContext : Method<Throws::No, ChangesContext::Yes>
+ struct Q_QML_EXPORT PopScriptContext : Method<Throws::No, ChangesContext::Yes>
{
static void call(ExecutionEngine *);
};
- struct Q_QML_PRIVATE_EXPORT ThrowReferenceError : Method<Throws::Yes>
+ struct Q_QML_EXPORT ThrowReferenceError : Method<Throws::Yes>
{
static void call(ExecutionEngine *, int);
};
- struct Q_QML_PRIVATE_EXPORT ThrowOnNullOrUndefined : Method<Throws::Yes>
+ struct Q_QML_EXPORT ThrowOnNullOrUndefined : Method<Throws::Yes>
{
static void call(ExecutionEngine *, const Value &);
};
/* closures */
- struct Q_QML_PRIVATE_EXPORT Closure : Method<Throws::No>
+ struct Q_QML_EXPORT Closure : Method<Throws::No>
{
static ReturnedValue call(ExecutionEngine *, int);
};
/* Function header */
- struct Q_QML_PRIVATE_EXPORT ConvertThisToObject : Method<Throws::Yes>
+ struct Q_QML_EXPORT ConvertThisToObject : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT DeclareVar : Method<Throws::Yes>
+ struct Q_QML_EXPORT DeclareVar : Method<Throws::Yes>
{
static void call(ExecutionEngine *, Bool, int);
};
- struct Q_QML_PRIVATE_EXPORT CreateMappedArgumentsObject : Method<Throws::No>
+ struct Q_QML_EXPORT CreateMappedArgumentsObject : Method<Throws::No>
{
static ReturnedValue call(ExecutionEngine *);
};
- struct Q_QML_PRIVATE_EXPORT CreateUnmappedArgumentsObject : Method<Throws::No>
+ struct Q_QML_EXPORT CreateUnmappedArgumentsObject : Method<Throws::No>
{
static ReturnedValue call(ExecutionEngine *);
};
- struct Q_QML_PRIVATE_EXPORT CreateRestParameter : PureMethod
+ struct Q_QML_EXPORT CreateRestParameter : PureMethod
{
static ReturnedValue call(ExecutionEngine *, int);
};
/* literals */
- struct Q_QML_PRIVATE_EXPORT ArrayLiteral : Method<Throws::Yes>
+ struct Q_QML_EXPORT ArrayLiteral : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, Value[], uint);
};
- struct Q_QML_PRIVATE_EXPORT ObjectLiteral : Method<Throws::Yes>
+ struct Q_QML_EXPORT ObjectLiteral : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, int, Value[], int);
};
- struct Q_QML_PRIVATE_EXPORT CreateClass : Method<Throws::Yes>
+ struct Q_QML_EXPORT CreateClass : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, int, const Value &, Value[]);
};
/* for-in, for-of and array destructuring */
- struct Q_QML_PRIVATE_EXPORT GetIterator : Method<Throws::Yes>
+ struct Q_QML_EXPORT GetIterator : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, int);
};
- struct Q_QML_PRIVATE_EXPORT IteratorNext : IteratorMethod
+ struct Q_QML_EXPORT IteratorNext : IteratorMethod
{
static ReturnedValue call(ExecutionEngine *, const Value &, Value *);
};
- struct Q_QML_PRIVATE_EXPORT IteratorNextForYieldStar : IteratorMethod
+ struct Q_QML_EXPORT IteratorNextForYieldStar : IteratorMethod
{
static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value *);
};
- struct Q_QML_PRIVATE_EXPORT IteratorClose : Method<Throws::Yes>
+ struct Q_QML_EXPORT IteratorClose : Method<Throws::No>
{
- static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
+ static ReturnedValue call(ExecutionEngine *, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT DestructureRestElement : Method<Throws::Yes>
+ struct Q_QML_EXPORT DestructureRestElement : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &);
};
/* conversions */
- struct Q_QML_PRIVATE_EXPORT ToObject : Method<Throws::Yes>
+ struct Q_QML_EXPORT ToObject : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT ToBoolean : PureMethod
+ struct Q_QML_EXPORT ToBoolean : PureMethod
{
static Bool call(const Value &);
};
- struct Q_QML_PRIVATE_EXPORT ToNumber : Method<Throws::Yes>
+ struct Q_QML_EXPORT ToNumber : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &);
};
/* unary operators */
- struct Q_QML_PRIVATE_EXPORT UMinus : Method<Throws::Yes>
+ struct Q_QML_EXPORT UMinus : Method<Throws::Yes>
{
static ReturnedValue call(const Value &);
};
/* binary operators */
- struct Q_QML_PRIVATE_EXPORT Instanceof : Method<Throws::Yes>
+ struct Q_QML_EXPORT Instanceof : Method<Throws::Yes>
+ {
+ static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
+ };
+ struct Q_QML_EXPORT As : Method<Throws::No>
{
static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT In : Method<Throws::Yes>
+ struct Q_QML_EXPORT In : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT Add : Method<Throws::Yes>
+ struct Q_QML_EXPORT Add : Method<Throws::Yes>
{
static ReturnedValue call(ExecutionEngine *, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT Sub : Method<Throws::Yes>
+ struct Q_QML_EXPORT Sub : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT Mul : Method<Throws::Yes>
+ struct Q_QML_EXPORT Mul : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT Div : Method<Throws::Yes>
+ struct Q_QML_EXPORT Div : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT Mod : Method<Throws::Yes>
+ struct Q_QML_EXPORT Mod : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT Exp : Method<Throws::Yes>
+ struct Q_QML_EXPORT Exp : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT BitAnd : Method<Throws::Yes>
+ struct Q_QML_EXPORT BitAnd : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT BitOr : Method<Throws::Yes>
+ struct Q_QML_EXPORT BitOr : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT BitXor : Method<Throws::Yes>
+ struct Q_QML_EXPORT BitXor : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT Shl : Method<Throws::Yes>
+ struct Q_QML_EXPORT Shl : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT Shr : Method<Throws::Yes>
+ struct Q_QML_EXPORT Shr : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT UShr : Method<Throws::Yes>
+ struct Q_QML_EXPORT UShr : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT GreaterThan : Method<Throws::Yes>
+ struct Q_QML_EXPORT GreaterThan : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT LessThan : Method<Throws::Yes>
+ struct Q_QML_EXPORT LessThan : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT GreaterEqual : Method<Throws::Yes>
+ struct Q_QML_EXPORT GreaterEqual : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT LessEqual : Method<Throws::Yes>
+ struct Q_QML_EXPORT LessEqual : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT Equal : Method<Throws::Yes>
+ struct Q_QML_EXPORT Equal : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT NotEqual : Method<Throws::Yes>
+ struct Q_QML_EXPORT NotEqual : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT StrictEqual : Method<Throws::Yes>
+ struct Q_QML_EXPORT StrictEqual : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT StrictNotEqual : Method<Throws::Yes>
+ struct Q_QML_EXPORT StrictNotEqual : Method<Throws::Yes>
{
static ReturnedValue call(const Value &, const Value &);
};
/* comparisons */
- struct Q_QML_PRIVATE_EXPORT CompareGreaterThan : Method<Throws::Yes>
+ struct Q_QML_EXPORT CompareGreaterThan : Method<Throws::Yes>
{
static Bool call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT CompareLessThan : Method<Throws::Yes>
+ struct Q_QML_EXPORT CompareLessThan : Method<Throws::Yes>
{
static Bool call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT CompareGreaterEqual : Method<Throws::Yes>
+ struct Q_QML_EXPORT CompareGreaterEqual : Method<Throws::Yes>
{
static Bool call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT CompareLessEqual : Method<Throws::Yes>
+ struct Q_QML_EXPORT CompareLessEqual : Method<Throws::Yes>
{
static Bool call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT CompareEqual : Method<Throws::Yes>
+ struct Q_QML_EXPORT CompareEqual : Method<Throws::Yes>
{
static Bool call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT CompareNotEqual : Method<Throws::Yes>
+ struct Q_QML_EXPORT CompareNotEqual : Method<Throws::Yes>
{
static Bool call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT CompareStrictEqual : Method<Throws::Yes>
+ struct Q_QML_EXPORT CompareStrictEqual : Method<Throws::Yes>
{
static Bool call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT CompareStrictNotEqual : Method<Throws::Yes>
+ struct Q_QML_EXPORT CompareStrictNotEqual : Method<Throws::Yes>
{
static Bool call(const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT CompareInstanceof : Method<Throws::Yes>
+ struct Q_QML_EXPORT CompareInstanceof : Method<Throws::Yes>
{
static Bool call(ExecutionEngine *, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT CompareIn : Method<Throws::Yes>
+ struct Q_QML_EXPORT CompareIn : Method<Throws::Yes>
{
static Bool call(ExecutionEngine *, const Value &, const Value &);
};
- struct Q_QML_PRIVATE_EXPORT RegexpLiteral : PureMethod
+ struct Q_QML_EXPORT RegexpLiteral : PureMethod
{
static ReturnedValue call(ExecutionEngine *, int);
};
- struct Q_QML_PRIVATE_EXPORT GetTemplateObject : PureMethod
+ struct Q_QML_EXPORT GetTemplateObject : PureMethod
{
static ReturnedValue call(Function *, int);
};
diff --git a/src/qml/jsruntime/qv4runtimecodegen.cpp b/src/qml/jsruntime/qv4runtimecodegen.cpp
index 162d75db63..c7b05aeffe 100644
--- a/src/qml/jsruntime/qv4runtimecodegen.cpp
+++ b/src/qml/jsruntime/qv4runtimecodegen.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4engine_p.h"
#include "qv4runtimecodegen_p.h"
@@ -67,7 +31,7 @@ void RuntimeCodegen::generateFromFunctionExpression(const QString &fileName,
_module->rootContext = _module->functions.at(index);
}
-void RuntimeCodegen::throwSyntaxError(const AST::SourceLocation &loc, const QString &detail)
+void RuntimeCodegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
{
if (hasError())
return;
@@ -76,7 +40,7 @@ void RuntimeCodegen::throwSyntaxError(const AST::SourceLocation &loc, const QStr
engine->throwSyntaxError(detail, _module->fileName, loc.startLine, loc.startColumn);
}
-void RuntimeCodegen::throwReferenceError(const AST::SourceLocation &loc, const QString &detail)
+void RuntimeCodegen::throwReferenceError(const SourceLocation &loc, const QString &detail)
{
if (hasError())
return;
diff --git a/src/qml/jsruntime/qv4runtimecodegen_p.h b/src/qml/jsruntime/qv4runtimecodegen_p.h
index 71aaf1fb55..35058be2cb 100644
--- a/src/qml/jsruntime/qv4runtimecodegen_p.h
+++ b/src/qml/jsruntime/qv4runtimecodegen_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4RUNTIMECODEGEN_P_H
#define QV4RUNTIMECODEGEN_P_H
@@ -69,8 +33,8 @@ public:
QQmlJS::AST::FunctionExpression *ast,
Compiler::Module *module);
- void throwSyntaxError(const QQmlJS::AST::SourceLocation &loc, const QString &detail) override;
- void throwReferenceError(const QQmlJS::AST::SourceLocation &loc, const QString &detail) override;
+ void throwSyntaxError(const QQmlJS::SourceLocation &loc, const QString &detail) override;
+ void throwReferenceError(const QQmlJS::SourceLocation &loc, const QString &detail) override;
private:
ExecutionEngine *engine;
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index e4aceef3ee..ddd312b893 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4SCOPEDVALUE_P_H
#define QV4SCOPEDVALUE_P_H
@@ -68,9 +32,14 @@ namespace QV4 {
struct ScopedValue;
+inline bool hasExceptionOrIsInterrupted(ExecutionEngine *engine)
+{
+ return engine->hasException || engine->isInterrupted.loadRelaxed();
+}
+
#define CHECK_EXCEPTION() \
do { \
- if (scope.hasException()) { \
+ if (hasExceptionOrIsInterrupted(scope.engine)) { \
return QV4::Encode::undefined(); \
} \
} while (false)
@@ -124,6 +93,10 @@ struct Scope {
/* Be careful when using Uninitialized, the stack has to be fully initialized before calling into the memory manager again */
Uninitialized
};
+
+ template <AllocMode mode = Undefined>
+ Value *alloc(qint64 nValues) const = delete; // use safeForAllocLength
+
template <AllocMode mode = Undefined>
QML_NEARLY_ALWAYS_INLINE Value *alloc(int nValues) const
{
@@ -172,6 +145,9 @@ private:
struct ScopedValue
{
+ ScopedValue(const ScopedValue &) = default;
+ ScopedValue(ScopedValue &&) = default;
+
ScopedValue(const Scope &scope)
{
ptr = scope.alloc<Scope::Uninitialized>();
@@ -381,11 +357,6 @@ struct Scoped
return *this;
}
- Scoped<T> &operator=(const Scoped<T> &other) {
- *ptr = *other.ptr;
- return *this;
- }
-
Scoped<T> &operator=(T *t) {
setPointer(t);
return *this;
@@ -446,7 +417,7 @@ struct ScopedProperty
{
ScopedProperty(Scope &scope)
{
- property = reinterpret_cast<Property*>(scope.alloc(sizeof(Property) / sizeof(Value)));
+ property = reinterpret_cast<Property*>(scope.alloc(int(sizeof(Property) / sizeof(Value))));
}
Property *operator->() { return property; }
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 2fab9e4b7b..894426ce3b 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -1,57 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4script_p.h"
#include <private/qv4mm_p.h>
-#include "qv4functionobject_p.h"
#include "qv4function_p.h"
#include "qv4context_p.h"
#include "qv4debugging_p.h"
-#include "qv4profiling_p.h"
#include "qv4scopedvalue_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 <private/qqmlengine_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
#include <private/qv4profiling_p.h>
#include <qv4runtimecodegen_p.h>
@@ -64,14 +26,15 @@ 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)
- , compilationUnit(compilationUnit), vmFunction(nullptr), parseAsBinding(true)
+ , compilationUnit(compilationUnit), parseAsBinding(true)
{
if (qml)
qmlContext.set(v4, *qml);
parsed = true;
- vmFunction = compilationUnit ? compilationUnit->linkToEngine(v4) : nullptr;
+ vmFunction.set(v4,
+ compilationUnit ? compilationUnit->rootFunction() : nullptr);
}
Script::~Script()
@@ -83,19 +46,17 @@ void Script::parse()
if (parsed)
return;
- using namespace QV4::Compiler;
-
parsed = true;
ExecutionEngine *v4 = context->engine();
Scope valueScope(v4);
- Module module(v4->debugger() != nullptr);
+ QV4::Compiler::Module module(v4->debugger() != nullptr);
if (sourceCode.startsWith(QLatin1String("function("))) {
static const int snippetLength = 70;
qWarning() << "Warning: Using function expressions as statements in scripts is not compliant with the ECMAScript specification:\n"
- << (sourceCode.leftRef(snippetLength) + QLatin1String("..."))
+ << (QStringView{sourceCode}.left(snippetLength) + QLatin1String("..."))
<< "\nThis will throw a syntax error in Qt 5.12. If you want a function expression, surround it by parentheses.";
}
@@ -109,10 +70,10 @@ void Script::parse()
const auto diagnosticMessages = parser.diagnosticMessages();
for (const DiagnosticMessage &m : diagnosticMessages) {
if (m.isError()) {
- valueScope.engine->throwSyntaxError(m.message, sourceFile, m.line, m.column);
+ valueScope.engine->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn);
return;
} else {
- qWarning() << sourceFile << ':' << m.line << ':' << m.column
+ qWarning() << sourceFile << ':' << m.loc.startLine << ':' << m.loc.startColumn
<< ": warning: " << m.message;
}
}
@@ -134,8 +95,8 @@ void Script::parse()
if (v4->hasException)
return;
- compilationUnit = QV4::ExecutableCompilationUnit::create(cg.generateCompilationUnit());
- vmFunction = compilationUnit->linkToEngine(v4);
+ compilationUnit = v4->insertCompilationUnit(cg.generateCompilationUnit());
+ vmFunction.set(v4, compilationUnit->rootFunction());
}
if (!vmFunction) {
@@ -173,7 +134,7 @@ Function *Script::function()
return vmFunction;
}
-QV4::CompiledData::CompilationUnit Script::precompile(
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(
QV4::Compiler::Module *module, QQmlJS::Engine *jsEngine,
Compiler::JSUnitGenerator *unitGenerator, const QString &fileName, const QString &finalUrl,
const QString &source, QList<QQmlError> *reportedErrors,
@@ -209,8 +170,8 @@ QV4::CompiledData::CompilationUnit Script::precompile(
const auto v4Error = cg.error();
QQmlError error;
error.setUrl(cg.url());
- error.setLine(v4Error.line);
- error.setColumn(v4Error.column);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(v4Error.loc.startLine));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(v4Error.loc.startColumn));
error.setDescription(v4Error.message);
reportedErrors->append(error);
}
@@ -226,10 +187,20 @@ Script *Script::createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlCo
error->clear();
QQmlMetaType::CachedUnitLookupError cacheError = QQmlMetaType::CachedUnitLookupError::NoError;
- if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(originalUrl, &cacheError)) {
+ const ExecutionEngine::DiskCacheOptions options = engine->diskCacheOptions();
+ if (const QQmlPrivate::CachedQmlUnit *cachedUnit
+ = (options & ExecutionEngine::DiskCache::Aot)
+ ? QQmlMetaType::findCachedCompilationUnit(
+ originalUrl,
+ (options & ExecutionEngine::DiskCache::AotByteCode)
+ ? QQmlMetaType::AcceptUntyped
+ : QQmlMetaType::RequireFullyTyped,
+ &cacheError)
+ : nullptr) {
QQmlRefPointer<QV4::ExecutableCompilationUnit> jsUnit
- = QV4::ExecutableCompilationUnit::create(
- QV4::CompiledData::CompilationUnit(cachedUnit));
+ = engine->insertCompilationUnit(
+ QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>(
+ cachedUnit->qmlData, cachedUnit->aotCompiledFunctions));
return new QV4::Script(engine, qmlContext, jsUnit);
}
diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h
index aecedea701..7b3dcae486 100644
--- a/src/qml/jsruntime/qv4script_p.h
+++ b/src/qml/jsruntime/qv4script_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4SCRIPT_H
#define QV4SCRIPT_H
@@ -72,11 +36,11 @@ struct Q_QML_EXPORT Script {
Script(ExecutionContext *scope, QV4::Compiler::ContextType mode, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
: sourceFile(source), line(line), column(column), sourceCode(sourceCode)
, context(scope), strictMode(false), inheritContext(false), parsed(false), contextType(mode)
- , vmFunction(nullptr), parseAsBinding(false) {}
+ , parseAsBinding(false) {}
Script(ExecutionEngine *engine, QmlContext *qml, bool parseAsBinding, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
: sourceFile(source), line(line), column(column), sourceCode(sourceCode)
, context(engine->rootContext()), strictMode(false), inheritContext(true), parsed(false)
- , vmFunction(nullptr), parseAsBinding(parseAsBinding) {
+ , parseAsBinding(parseAsBinding) {
if (qml)
qmlContext.set(engine, *qml);
}
@@ -93,7 +57,7 @@ struct Q_QML_EXPORT Script {
QV4::Compiler::ContextType contextType = QV4::Compiler::ContextType::Eval;
QV4::PersistentValue qmlContext;
QQmlRefPointer<ExecutableCompilationUnit> compilationUnit;
- Function *vmFunction;
+ QV4::WriteBarrier::Pointer<Function> vmFunction;
bool parseAsBinding;
void parse();
@@ -101,7 +65,7 @@ struct Q_QML_EXPORT Script {
Function *function();
- static QV4::CompiledData::CompilationUnit precompile(
+ static QQmlRefPointer<QV4::CompiledData::CompilationUnit> precompile(
QV4::Compiler::Module *module, QQmlJS::Engine *jsEngine,
Compiler::JSUnitGenerator *unitGenerator, const QString &fileName,
const QString &finalUrl, const QString &source,
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 77a98247ac..cc899428c2 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtQml/qqml.h>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtCore/qsequentialiterable.h>
#include "qv4sequenceobject_p.h"
@@ -46,19 +10,56 @@
#include <private/qqmlengine_p.h>
#include <private/qv4scopedvalue_p.h>
#include <private/qv4jscall_p.h>
-#include "qv4runtime_p.h"
-#include "qv4objectiterator_p.h"
+#include <private/qqmlmetatype_p.h>
+#include <private/qqmltype_p_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
-#if QT_CONFIG(qml_itemmodel)
-#include <private/qqmlmodelindexvaluetype_p.h>
-#include <QtCore/qabstractitemmodel.h>
-#endif
#include <algorithm>
QT_BEGIN_NAMESPACE
-using namespace QV4;
+namespace QV4 {
+
+DEFINE_OBJECT_VTABLE(Sequence);
+
+static ReturnedValue doGetIndexed(const Sequence *s, qsizetype index) {
+ QV4::Scope scope(s->engine());
+
+ Heap::ReferenceObject::Flags flags =
+ Heap::ReferenceObject::EnforcesLocation;
+ if (s->d()->metaSequence().canSetValueAtIndex())
+ flags |= Heap::ReferenceObject::CanWriteBack;
+ if (s->d()->valueMetaType() == QMetaType::fromType<QVariant>())
+ flags |= Heap::ReferenceObject::IsVariant;
+
+ QV4::ScopedValue v(scope, scope.engine->fromVariant(
+ s->at(index), s->d(), index, flags));
+ if (QQmlValueTypeWrapper *ref = v->as<QQmlValueTypeWrapper>()) {
+ if (CppStackFrame *frame = scope.engine->currentStackFrame)
+ ref->d()->setLocation(frame->v4Function, frame->statementNumber());
+ // No need to read the reference. at() has done that already.
+ }
+ return v->asReturnedValue();
+}
+
+template<typename Compare>
+void sortSequence(Sequence *sequence, const Compare &compare)
+{
+ /* non-const */ Heap::Sequence *p = sequence->d();
+
+ QSequentialIterable iterable(p->metaSequence(), p->listType(), p->storagePointer());
+ if (iterable.canRandomAccessIterate()) {
+ std::sort(QSequentialIterable::RandomAccessIterator(iterable.mutableBegin()),
+ QSequentialIterable::RandomAccessIterator(iterable.mutableEnd()),
+ compare);
+ } else if (iterable.canReverseIterate()) {
+ std::sort(QSequentialIterable::BidirectionalIterator(iterable.mutableBegin()),
+ QSequentialIterable::BidirectionalIterator(iterable.mutableEnd()),
+ compare);
+ } else {
+ qWarning() << "Container has no suitable iterator for sorting";
+ }
+}
// helper function to generate valid warnings if errors occur during sequence operations.
static void generateWarning(QV4::ExecutionEngine *v4, const QString& description)
@@ -76,637 +77,532 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
QQmlEnginePrivate::warning(engine, retn);
}
-// 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
+struct SequenceOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
+{
+ ~SequenceOwnPropertyKeyIterator() override = default;
+ PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override
+ {
+ const Sequence *s = static_cast<const Sequence *>(o);
+
+ if (s->d()->isReference() && !s->loadReference())
+ return PropertyKey::invalid();
+
+ const qsizetype size = s->size();
+ if (size > 0 && qIsAtMostSizetypeLimit(arrayIndex, size - 1)) {
+ const uint index = arrayIndex;
+ ++arrayIndex;
+ if (attrs)
+ *attrs = QV4::Attr_Data;
+ if (pd)
+ pd->value = doGetIndexed(s, index);
+ return PropertyKey::fromArrayIndex(index);
+ }
+
+ if (memberIndex == 0) {
+ ++memberIndex;
+ return o->engine()->id_length()->propertyKey();
+ }
-#define FOREACH_QML_SEQUENCE_TYPE(F) \
- F(int, IntVector, QVector<int>, 0) \
- F(qreal, RealVector, QVector<qreal>, 0.0) \
- F(bool, BoolVector, QVector<bool>, false) \
- F(int, IntStdVector, std::vector<int>, 0) \
- F(qreal, RealStdVector, std::vector<qreal>, 0.0) \
- F(bool, BoolStdVector, std::vector<bool>, false) \
- F(int, Int, QList<int>, 0) \
- F(qreal, Real, QList<qreal>, 0.0) \
- F(bool, Bool, QList<bool>, false) \
- F(QString, String, QList<QString>, QString()) \
- F(QString, QString, QStringList, QString()) \
- F(QString, StringVector, QVector<QString>, QString()) \
- F(QString, StringStdVector, std::vector<QString>, QString()) \
- F(QUrl, Url, QList<QUrl>, QUrl()) \
- F(QUrl, UrlVector, QVector<QUrl>, QUrl()) \
- F(QUrl, UrlStdVector, std::vector<QUrl>, QUrl()) \
- FOREACH_QML_SEQUENCE_TYPE_FOR_ITEMMODEL(F)
+ // You cannot add any own properties via the regular JavaScript interfaces.
+ return PropertyKey::invalid();
+ }
+};
-static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QString &element)
+struct SequenceCompareFunctor
{
- return engine->newString(element)->asReturnedValue();
-}
+ SequenceCompareFunctor(QV4::ExecutionEngine *v4, const QV4::Value &compareFn)
+ : m_v4(v4), m_compareFn(&compareFn)
+ {}
-static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *, int element)
-{
- return QV4::Encode(element);
-}
+ bool operator()(const QVariant &lhs, const QVariant &rhs)
+ {
+ QV4::Scope scope(m_v4);
+ ScopedFunctionObject compare(scope, m_compareFn);
+ if (!compare)
+ return m_v4->throwTypeError();
+ Value *argv = scope.alloc(2);
+ argv[0] = m_v4->fromVariant(lhs);
+ argv[1] = m_v4->fromVariant(rhs);
+ QV4::ScopedValue result(scope, compare->call(m_v4->globalObject, argv, 2));
+ if (scope.hasException())
+ return false;
+ return result->toNumber() < 0;
+ }
-static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QUrl &element)
-{
- return engine->newString(element.toString())->asReturnedValue();
-}
+private:
+ QV4::ExecutionEngine *m_v4;
+ const QV4::Value *m_compareFn;
+};
-#if QT_CONFIG(qml_itemmodel)
-static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QModelIndex &element)
+struct SequenceDefaultCompareFunctor
{
- const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(QMetaType::QModelIndex);
- return QV4::QQmlValueTypeWrapper::create(engine, QVariant(element), vtmo, QMetaType::QModelIndex);
-}
+ bool operator()(const QVariant &lhs, const QVariant &rhs)
+ {
+ return lhs.toString() < rhs.toString();
+ }
+};
-static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QItemSelectionRange &element)
+void Heap::Sequence::initTypes(QMetaType listType, QMetaSequence metaSequence)
{
- int metaTypeId = qMetaTypeId<QItemSelectionRange>();
- const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(metaTypeId);
- return QV4::QQmlValueTypeWrapper::create(engine, QVariant::fromValue(element), vtmo, metaTypeId);
+ m_listType = listType.iface();
+ Q_ASSERT(m_listType);
+ m_metaSequence = metaSequence.iface();
+ Q_ASSERT(m_metaSequence);
+ QV4::Scope scope(internalClass->engine);
+ QV4::Scoped<QV4::Sequence> o(scope, this);
+ o->setArrayType(Heap::ArrayData::Custom);
}
-#endif
-static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *, qreal element)
+void Heap::Sequence::init(QMetaType listType, QMetaSequence metaSequence, const void *container)
{
- return QV4::Encode(element);
+ ReferenceObject::init(nullptr, -1, NoFlag);
+ initTypes(listType, metaSequence);
+ m_container = listType.create(container);
}
-static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *, bool element)
+void Heap::Sequence::init(
+ QMetaType listType, QMetaSequence metaSequence, const void *container,
+ Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags)
{
- return QV4::Encode(element);
+ ReferenceObject::init(object, propertyIndex, flags);
+ initTypes(listType, metaSequence);
+
+ if (CppStackFrame *frame = internalClass->engine->currentStackFrame)
+ setLocation(frame->v4Function, frame->statementNumber());
+ if (container)
+ m_container = listType.create(container);
+ else if (flags & EnforcesLocation)
+ QV4::ReferenceObject::readReference(this);
}
-static QString convertElementToString(const QString &element)
+Heap::Sequence *Heap::Sequence::detached() const
{
- return element;
+ return internalClass->engine->memoryManager->allocate<QV4::Sequence>(
+ QMetaType(m_listType), QMetaSequence(m_metaSequence), m_container);
}
-static QString convertElementToString(int element)
+void Heap::Sequence::destroy()
{
- return QString::number(element);
+ if (m_container)
+ listType().destroy(m_container);
+ ReferenceObject::destroy();
}
-static QString convertElementToString(const QUrl &element)
+void *Heap::Sequence::storagePointer()
{
- return element.toString();
+ if (!m_container)
+ m_container = listType().create();
+ return m_container;
}
-#if QT_CONFIG(qml_itemmodel)
-static QString convertElementToString(const QModelIndex &element)
+bool Heap::Sequence::setVariant(const QVariant &variant)
{
- return reinterpret_cast<const QQmlModelIndexValueType *>(&element)->toString();
+ const QMetaType variantReferenceType = variant.metaType();
+ if (variantReferenceType != listType()) {
+ // This is a stale reference. That is, the property has been
+ // overwritten with a different type in the meantime.
+ // We need to modify this reference to the updated type, if
+ // possible, or return false if it is not a sequence.
+ const QQmlType newType = QQmlMetaType::qmlListType(variantReferenceType);
+ if (newType.isSequentialContainer()) {
+ if (m_container)
+ listType().destroy(m_container);
+ m_listType = newType.qListTypeId().iface();
+ m_metaSequence = newType.listMetaSequence().iface();
+ m_container = listType().create(variant.constData());
+ return true;
+ } else {
+ return false;
+ }
+ }
+ if (m_container) {
+ variantReferenceType.destruct(m_container);
+ variantReferenceType.construct(m_container, variant.constData());
+ } else {
+ m_container = variantReferenceType.create(variant.constData());
+ }
+ return true;
}
-
-static QString convertElementToString(const QItemSelectionRange &element)
+QVariant Heap::Sequence::toVariant() const
{
- return reinterpret_cast<const QQmlItemSelectionRangeValueType *>(&element)->toString();
+ return QVariant(listType(), m_container);
}
-#endif
-static QString convertElementToString(qreal element)
+qsizetype Sequence::size() const
{
- QString qstr;
- RuntimeHelpers::numberToString(&qstr, element, 10);
- return qstr;
+ const auto *p = d();
+ Q_ASSERT(p->storagePointer()); // Must readReference() before
+ return p->metaSequence().size(p->storagePointer());
}
-static QString convertElementToString(bool element)
+QVariant Sequence::at(qsizetype index) const
{
- if (element)
- return QStringLiteral("true");
- else
- return QStringLiteral("false");
+ const auto *p = d();
+ Q_ASSERT(p->storagePointer()); // Must readReference() before
+ const QMetaType v = p->valueMetaType();
+ QVariant result;
+ if (v == QMetaType::fromType<QVariant>()) {
+ p->metaSequence().valueAtIndex(p->storagePointer(), index, &result);
+ } else {
+ result = QVariant(v);
+ p->metaSequence().valueAtIndex(p->storagePointer(), index, result.data());
+ }
+ return result;
}
-template <typename ElementType> ElementType convertValueToElement(const Value &value);
-template <> QString convertValueToElement(const Value &value)
+template<typename Action>
+void convertAndDo(const QVariant &item, const QMetaType v, Action action)
{
- return value.toQString();
+ if (item.metaType() == v) {
+ action(item.constData());
+ } else if (v == QMetaType::fromType<QVariant>()) {
+ action(&item);
+ } else {
+ QVariant converted = item;
+ if (!converted.convert(v))
+ converted = QVariant(v);
+ action(converted.constData());
+ }
}
-template <> int convertValueToElement(const Value &value)
+void Sequence::append(const QVariant &item)
{
- return value.toInt32();
+ Heap::Sequence *p = d();
+ convertAndDo(item, p->valueMetaType(), [p](const void *data) {
+ p->metaSequence().addValueAtEnd(p->storagePointer(), data);
+ });
}
-template <> QUrl convertValueToElement(const Value &value)
+void Sequence::append(qsizetype num, const QVariant &item)
{
- return QUrl(value.toQString());
+ Heap::Sequence *p = d();
+ convertAndDo(item, p->valueMetaType(), [p, num](const void *data) {
+ const QMetaSequence m = p->metaSequence();
+ void *container = p->storagePointer();
+ for (qsizetype i = 0; i < num; ++i)
+ m.addValueAtEnd(container, data);
+ });
}
-#if QT_CONFIG(qml_itemmodel)
-template <> QModelIndex convertValueToElement(const Value &value)
+void Sequence::replace(qsizetype index, const QVariant &item)
{
- const QQmlValueTypeWrapper *v = value.as<QQmlValueTypeWrapper>();
- if (v)
- return v->toVariant().toModelIndex();
- return QModelIndex();
+ Heap::Sequence *p = d();
+ convertAndDo(item, p->valueMetaType(), [p, index](const void *data) {
+ p->metaSequence().setValueAtIndex(p->storagePointer(), index, data);
+ });
}
-template <> QItemSelectionRange convertValueToElement(const Value &value)
+void Sequence::removeLast(qsizetype num)
{
- const QQmlValueTypeWrapper *v = value.as<QQmlValueTypeWrapper>();
- if (v)
- return v->toVariant().value<QItemSelectionRange>();
- return QItemSelectionRange();
-}
-#endif
+ auto *p = d();
+ const QMetaSequence m = p->metaSequence();
-template <> qreal convertValueToElement(const Value &value)
-{
- return value.toNumber();
+ if (m.canEraseRangeAtIterator() && m.hasRandomAccessIterator() && num > 1) {
+ void *i = m.end(p->storagePointer());
+ m.advanceIterator(i, -num);
+ void *j = m.end(p->storagePointer());
+ m.eraseRangeAtIterator(p->storagePointer(), i, j);
+ m.destroyIterator(i);
+ m.destroyIterator(j);
+ } else {
+ for (int i = 0; i < num; ++i)
+ m.removeValueAtEnd(p->storagePointer());
+ }
}
-template <> bool convertValueToElement(const Value &value)
+ReturnedValue Sequence::containerGetIndexed(qsizetype index, bool *hasProperty) const
{
- return value.toBoolean();
-}
-
-namespace QV4 {
-
-template <typename Container> struct QQmlSequence;
-
-namespace Heap {
+ if (d()->isReference() && !loadReference())
+ return Encode::undefined();
-template <typename Container>
-struct QQmlSequence : Object {
- void init(const Container &container);
- void init(QObject *object, int propertyIndex, bool readOnly);
- void destroy() {
- delete container;
- object.destroy();
- Object::destroy();
+ if (index >= 0 && index < size()) {
+ if (hasProperty)
+ *hasProperty = true;
+ return doGetIndexed(this, index);
}
-
- mutable Container *container;
- QQmlQPointer<QObject> object;
- int propertyIndex;
- bool isReference : 1;
- bool isReadOnly : 1;
-};
-
+ if (hasProperty)
+ *hasProperty = false;
+ return Encode::undefined();
}
-template <typename Container>
-struct QQmlSequence : public QV4::Object
+bool Sequence::containerPutIndexed(qsizetype index, const Value &value)
{
- V4_OBJECT2(QQmlSequence<Container>, QV4::Object)
- Q_MANAGED_TYPE(QmlSequence)
- V4_PROTOTYPE(sequencePrototype)
- V4_NEEDS_DESTROY
-public:
+ if (internalClass()->engine->hasException)
+ return false;
- void init()
- {
- defineAccessorProperty(QStringLiteral("length"), method_get_length, method_set_length);
+ if (d()->isReadOnly()) {
+ engine()->throwTypeError(QLatin1String("Cannot insert into a readonly container"));
+ return false;
}
- QV4::ReturnedValue containerGetIndexed(uint index, bool *hasProperty) const
- {
- /* Qt containers have int (rather than uint) allowable indexes. */
- if (index > INT_MAX) {
- generateWarning(engine(), QLatin1String("Index out of range during indexed get"));
- if (hasProperty)
- *hasProperty = false;
- return Encode::undefined();
- }
- if (d()->isReference) {
- if (!d()->object) {
- if (hasProperty)
- *hasProperty = false;
- return Encode::undefined();
- }
- loadReference();
- }
- if (index < size_t(d()->container->size())) {
- if (hasProperty)
- *hasProperty = true;
- return convertElementToValue(engine(), qAsConst(*(d()->container))[index]);
- }
- if (hasProperty)
- *hasProperty = false;
- return Encode::undefined();
- }
+ if (d()->isReference() && !loadReference())
+ return false;
- bool containerPutIndexed(uint index, const QV4::Value &value)
- {
- if (internalClass()->engine->hasException)
- return false;
+ const qsizetype count = size();
+ const QMetaType valueType = d()->valueMetaType();
+ const QVariant element = ExecutionEngine::toVariant(value, valueType, false);
- /* Qt containers have int (rather than uint) allowable indexes. */
- if (index > INT_MAX) {
- generateWarning(engine(), QLatin1String("Index out of range during indexed set"));
- return false;
- }
+ if (index < 0)
+ return false;
- if (d()->isReadOnly)
- return false;
+ if (index == count) {
+ append(element);
+ } else if (index < count) {
+ replace(index, element);
+ } else {
+ /* according to ECMA262r3 we need to insert */
+ /* the value at the given index, increasing length to index+1. */
+ append(index - count,
+ valueType == QMetaType::fromType<QVariant>() ? QVariant() : QVariant(valueType));
+ append(element);
+ }
- if (d()->isReference) {
- if (!d()->object)
- return false;
- loadReference();
- }
+ if (d()->object())
+ storeReference();
+ return true;
+}
- size_t count = size_t(d()->container->size());
+SequenceOwnPropertyKeyIterator *containerOwnPropertyKeys(const Object *m, Value *target)
+{
+ *target = *m;
+ return new SequenceOwnPropertyKeyIterator;
+}
- typename Container::value_type element = convertValueToElement<typename Container::value_type>(value);
+bool Sequence::containerDeleteIndexedProperty(qsizetype index)
+{
+ if (d()->isReadOnly())
+ return false;
+ if (d()->isReference() && !loadReference())
+ return false;
+ if (index < 0 || index >= size())
+ return false;
- if (index == count) {
- d()->container->push_back(element);
- } else if (index < count) {
- (*d()->container)[index] = element;
- } else {
- /* according to ECMA262r3 we need to insert */
- /* the value at the given index, increasing length to index+1. */
- d()->container->reserve(index + 1);
- while (index > count++) {
- d()->container->push_back(typename Container::value_type());
- }
- d()->container->push_back(element);
- }
+ /* according to ECMA262r3 it should be Undefined, */
+ /* but we cannot, so we insert a default-value instead. */
+ replace(index, QVariant());
- if (d()->isReference)
- storeReference();
- return true;
- }
+ if (d()->object())
+ storeReference();
- QV4::PropertyAttributes containerQueryIndexed(uint index) const
- {
- /* Qt containers have int (rather than uint) allowable indexes. */
- if (index > INT_MAX) {
- generateWarning(engine(), QLatin1String("Index out of range during indexed query"));
- return QV4::Attr_Invalid;
- }
- if (d()->isReference) {
- if (!d()->object)
- return QV4::Attr_Invalid;
- loadReference();
- }
- return (index < size_t(d()->container->size())) ? QV4::Attr_Data : QV4::Attr_Invalid;
- }
+ return true;
+}
- struct OwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
- {
- ~OwnPropertyKeyIterator() override = default;
- PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override
- {
- const QQmlSequence *s = static_cast<const QQmlSequence *>(o);
-
- if (s->d()->isReference) {
- if (!s->d()->object)
- return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
- s->loadReference();
- }
+bool Sequence::containerIsEqualTo(Managed *other)
+{
+ if (!other)
+ return false;
+ Sequence *otherSequence = other->as<Sequence>();
+ if (!otherSequence)
+ return false;
+ if (d()->object() && otherSequence->d()->object()) {
+ return d()->object() == otherSequence->d()->object()
+ && d()->property() == otherSequence->d()->property();
+ } else if (!d()->object() && !otherSequence->d()->object()) {
+ return this == otherSequence;
+ }
+ return false;
+}
- if (arrayIndex < static_cast<uint>(s->d()->container->size())) {
- uint index = arrayIndex;
- ++arrayIndex;
- if (attrs)
- *attrs = QV4::Attr_Data;
- if (pd)
- pd->value = convertElementToValue(s->engine(), s->d()->container->at(index));
- return PropertyKey::fromArrayIndex(index);
- }
+bool Sequence::sort(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ if (d()->isReadOnly())
+ return false;
+ if (d()->isReference() && !loadReference())
+ return false;
- return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
- }
- };
+ if (argc == 1 && argv[0].as<FunctionObject>())
+ sortSequence(this, SequenceCompareFunctor(f->engine(), argv[0]));
+ else
+ sortSequence(this, SequenceDefaultCompareFunctor());
- static OwnPropertyKeyIterator *containerOwnPropertyKeys(const Object *m, Value *target)
- {
- *target = *m;
- return new OwnPropertyKeyIterator;
- }
+ if (d()->object())
+ storeReference();
- bool containerDeleteIndexedProperty(uint index)
- {
- /* Qt containers have int (rather than uint) allowable indexes. */
- if (index > INT_MAX)
- return false;
- if (d()->isReadOnly)
- return false;
- if (d()->isReference) {
- if (!d()->object)
- return false;
- loadReference();
- }
+ return true;
+}
- if (index >= size_t(d()->container->size()))
- return false;
+void *Sequence::getRawContainerPtr() const
+{ return d()->storagePointer(); }
- /* according to ECMA262r3 it should be Undefined, */
- /* but we cannot, so we insert a default-value instead. */
- (*d()->container)[index] = typename Container::value_type();
+bool Sequence::loadReference() const
+{
+ Q_ASSERT(d()->object());
+ // If locations are enforced we only read once
+ return d()->enforcesLocation() || QV4::ReferenceObject::readReference(d());
+}
- if (d()->isReference)
- storeReference();
+bool Sequence::storeReference()
+{
+ Q_ASSERT(d()->object());
+ return d()->isAttachedToProperty() && QV4::ReferenceObject::writeBack(d());
+}
- return true;
- }
+ReturnedValue Sequence::virtualGet(const Managed *that, PropertyKey id, const Value *receiver, bool *hasProperty)
+{
+ if (id.isArrayIndex()) {
+ const uint index = id.asArrayIndex();
+ if (qIsAtMostSizetypeLimit(index))
+ return static_cast<const Sequence *>(that)->containerGetIndexed(qsizetype(index), hasProperty);
- bool containerIsEqualTo(Managed *other)
- {
- if (!other)
- return false;
- QQmlSequence<Container> *otherSequence = other->as<QQmlSequence<Container> >();
- if (!otherSequence)
- return false;
- if (d()->isReference && otherSequence->d()->isReference) {
- return d()->object == otherSequence->d()->object && d()->propertyIndex == otherSequence->d()->propertyIndex;
- } else if (!d()->isReference && !otherSequence->d()->isReference) {
- return this == otherSequence;
- }
+ generateWarning(that->engine(), QLatin1String("Index out of range during indexed get"));
return false;
}
- struct DefaultCompareFunctor
- {
- bool operator()(typename Container::value_type lhs, typename Container::value_type rhs)
- {
- return convertElementToString(lhs) < convertElementToString(rhs);
- }
- };
-
- struct CompareFunctor
- {
- CompareFunctor(QV4::ExecutionEngine *v4, const QV4::Value &compareFn)
- : m_v4(v4), m_compareFn(&compareFn)
- {}
-
- bool operator()(typename Container::value_type lhs, typename Container::value_type rhs)
- {
- QV4::Scope scope(m_v4);
- ScopedFunctionObject compare(scope, m_compareFn);
- if (!compare)
- return m_v4->throwTypeError();
- Value *argv = scope.alloc(2);
- argv[0] = convertElementToValue(m_v4, lhs);
- argv[1] = convertElementToValue(m_v4, rhs);
- QV4::ScopedValue result(scope, compare->call(m_v4->globalObject, argv, 2));
- return result->toNumber() < 0;
- }
-
- private:
- QV4::ExecutionEngine *m_v4;
- const QV4::Value *m_compareFn;
- };
-
- bool sort(const FunctionObject *f, const Value *, const Value *argv, int argc)
- {
- if (d()->isReadOnly)
- return false;
- if (d()->isReference) {
- if (!d()->object)
- return false;
- loadReference();
- }
+ return Object::virtualGet(that, id, receiver, hasProperty);
+}
- if (argc == 1 && argv[0].as<FunctionObject>()) {
- CompareFunctor cf(f->engine(), argv[0]);
- std::sort(d()->container->begin(), d()->container->end(), cf);
- } else {
- DefaultCompareFunctor cf;
- std::sort(d()->container->begin(), d()->container->end(), cf);
- }
+qint64 Sequence::virtualGetLength(const Managed *m)
+{
+ const Sequence *s = static_cast<const Sequence *>(m);
+ if (s->d()->isReference() && !s->loadReference())
+ return 0;
+ return s->size();
+}
- if (d()->isReference)
- storeReference();
+bool Sequence::virtualPut(Managed *that, PropertyKey id, const Value &value, Value *receiver)
+{
+ if (id.isArrayIndex()) {
+ const uint index = id.asArrayIndex();
+ if (qIsAtMostSizetypeLimit(index))
+ return static_cast<Sequence *>(that)->containerPutIndexed(qsizetype(index), value);
- return true;
+ generateWarning(that->engine(), QLatin1String("Index out of range during indexed set"));
+ return false;
}
+ return Object::virtualPut(that, id, value, receiver);
+}
- static QV4::ReturnedValue method_get_length(const FunctionObject *b, const Value *thisObject, const Value *, int)
- {
- QV4::Scope scope(b);
- QV4::Scoped<QQmlSequence<Container>> This(scope, thisObject->as<QQmlSequence<Container> >());
- if (!This)
- THROW_TYPE_ERROR();
+bool Sequence::virtualDeleteProperty(Managed *that, PropertyKey id)
+{
+ if (id.isArrayIndex()) {
+ const uint index = id.asArrayIndex();
+ if (qIsAtMostSizetypeLimit(index))
+ return static_cast<Sequence *>(that)->containerDeleteIndexedProperty(qsizetype(index));
- if (This->d()->isReference) {
- if (!This->d()->object)
- RETURN_RESULT(Encode(0));
- This->loadReference();
- }
- RETURN_RESULT(Encode(qint32(This->d()->container->size())));
+ generateWarning(that->engine(), QLatin1String("Index out of range during indexed delete"));
+ return false;
}
+ return Object::virtualDeleteProperty(that, id);
+}
- static QV4::ReturnedValue method_set_length(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
- {
- QV4::Scope scope(f);
- QV4::Scoped<QQmlSequence<Container>> This(scope, thisObject->as<QQmlSequence<Container> >());
- if (!This)
- THROW_TYPE_ERROR();
+bool Sequence::virtualIsEqualTo(Managed *that, Managed *other)
+{
+ return static_cast<Sequence *>(that)->containerIsEqualTo(other);
+}
- quint32 newLength = argc ? argv[0].toUInt32() : 0;
- /* Qt containers have int (rather than uint) allowable indexes. */
- if (newLength > INT_MAX) {
- generateWarning(scope.engine, QLatin1String("Index out of range during length set"));
- RETURN_UNDEFINED();
- }
+OwnPropertyKeyIterator *Sequence::virtualOwnPropertyKeys(const Object *m, Value *target)
+{
+ return containerOwnPropertyKeys(m, target);
+}
- if (This->d()->isReadOnly)
- THROW_TYPE_ERROR();
+int Sequence::virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a)
+{
+ Sequence *sequence = static_cast<Sequence *>(object);
+ Q_ASSERT(sequence);
- /* Read the sequence from the QObject property if we're a reference */
- if (This->d()->isReference) {
- if (!This->d()->object)
- RETURN_UNDEFINED();
- This->loadReference();
- }
- /* Determine whether we need to modify the sequence */
- quint32 newCount = static_cast<quint32>(newLength);
- quint32 count = static_cast<quint32>(This->d()->container->size());
- if (newCount == count) {
- RETURN_UNDEFINED();
- } else if (newCount > count) {
- /* according to ECMA262r3 we need to insert */
- /* undefined values increasing length to newLength. */
- /* We cannot, so we insert default-values instead. */
- This->d()->container->reserve(newCount);
- while (newCount > count++) {
- This->d()->container->push_back(typename Container::value_type());
- }
- } else {
- /* according to ECMA262r3 we need to remove */
- /* elements until the sequence is the required length. */
- if (newCount < count) {
- This->d()->container->erase(This->d()->container->begin() + newCount, This->d()->container->end());
- }
- }
- /* write back if required. */
- if (This->d()->isReference) {
- /* write back. already checked that object is non-null, so skip that check here. */
- This->storeReference();
- }
- RETURN_UNDEFINED();
+ switch (call) {
+ case QMetaObject::ReadProperty: {
+ const QMetaType valueType = sequence->d()->valueMetaType();
+ if (sequence->d()->isReference() && !sequence->loadReference())
+ return 0;
+ const QMetaSequence metaSequence = sequence->d()->metaSequence();
+ if (metaSequence.valueMetaType() != valueType)
+ return 0; // value metatype is not what the caller expects anymore.
+
+ const void *storagePointer = sequence->d()->storagePointer();
+ if (index < 0 || index >= metaSequence.size(storagePointer))
+ return 0;
+ metaSequence.valueAtIndex(storagePointer, index, a[0]);
+ break;
+ }
+ case QMetaObject::WriteProperty: {
+ void *storagePointer = sequence->d()->storagePointer();
+ const QMetaSequence metaSequence = sequence->d()->metaSequence();
+ if (index < 0 || index >= metaSequence.size(storagePointer))
+ return 0;
+ metaSequence.setValueAtIndex(storagePointer, index, a[0]);
+ if (sequence->d()->isReference())
+ sequence->storeReference();
+ break;
+ }
+ default:
+ return 0; // not supported
}
- QVariant toVariant() const
- { return QVariant::fromValue<Container>(*d()->container); }
+ return -1;
+}
- static QVariant toVariant(QV4::ArrayObject *array)
- {
- QV4::Scope scope(array->engine());
- Container result;
- quint32 length = array->getLength();
- QV4::ScopedValue v(scope);
- for (quint32 i = 0; i < length; ++i)
- result.push_back(convertValueToElement<typename Container::value_type>((v = array->get(i))));
- return QVariant::fromValue(result);
- }
+static QV4::ReturnedValue method_get_length(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ QV4::Scope scope(b);
+ QV4::Scoped<Sequence> This(scope, thisObject->as<Sequence>());
+ if (!This)
+ THROW_TYPE_ERROR();
- void* getRawContainerPtr() const
- { return d()->container; }
+ if (This->d()->isReference() && !This->loadReference())
+ return Encode::undefined();
- void loadReference() const
- {
- Q_ASSERT(d()->object);
- Q_ASSERT(d()->isReference);
- void *a[] = { d()->container, nullptr };
- QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->propertyIndex, a);
- }
+ const qsizetype size = This->size();
+ if (qIsAtMostUintLimit(size))
+ RETURN_RESULT(Encode(uint(size)));
- void storeReference()
- {
- Q_ASSERT(d()->object);
- Q_ASSERT(d()->isReference);
- int status = -1;
- QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding;
- void *a[] = { d()->container, nullptr, &status, &flags };
- QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a);
- }
+ return scope.engine->throwRangeError(QLatin1String("Sequence length out of range"));
+}
- static QV4::ReturnedValue virtualGet(const QV4::Managed *that, PropertyKey id, const Value *receiver, bool *hasProperty)
- {
- if (!id.isArrayIndex())
- return Object::virtualGet(that, id, receiver, hasProperty);
- return static_cast<const QQmlSequence<Container> *>(that)->containerGetIndexed(id.asArrayIndex(), hasProperty);
- }
- static bool virtualPut(Managed *that, PropertyKey id, const QV4::Value &value, Value *receiver)
- {
- if (id.isArrayIndex())
- return static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(id.asArrayIndex(), value);
- return Object::virtualPut(that, id, value, receiver);
- }
- static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index)
- { return static_cast<const QQmlSequence<Container> *>(that)->containerQueryIndexed(index); }
- static bool virtualDeleteProperty(QV4::Managed *that, PropertyKey id)
- {
- if (id.isArrayIndex()) {
- uint index = id.asArrayIndex();
- return static_cast<QQmlSequence<Container> *>(that)->containerDeleteIndexedProperty(index);
- }
- return Object::virtualDeleteProperty(that, id);
+static QV4::ReturnedValue method_set_length(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ QV4::Scope scope(f);
+ QV4::Scoped<Sequence> This(scope, thisObject->as<Sequence>());
+ if (!This)
+ THROW_TYPE_ERROR();
+
+ bool ok = false;
+ const quint32 argv0 = argc ? argv[0].asArrayLength(&ok) : 0;
+ if (!ok || !qIsAtMostSizetypeLimit(argv0)) {
+ generateWarning(scope.engine, QLatin1String("Index out of range during length set"));
+ RETURN_UNDEFINED();
}
- static bool virtualIsEqualTo(Managed *that, Managed *other)
- { return static_cast<QQmlSequence<Container> *>(that)->containerIsEqualTo(other); }
- static QV4::OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target)
- { return static_cast<const QQmlSequence<Container> *>(m)->containerOwnPropertyKeys(m, target);}
-};
+ if (This->d()->isReadOnly())
+ THROW_TYPE_ERROR();
+ const qsizetype newCount = qsizetype(argv0);
-template <typename Container>
-void Heap::QQmlSequence<Container>::init(const Container &container)
-{
- Object::init();
- this->container = new Container(container);
- propertyIndex = -1;
- isReference = false;
- isReadOnly = false;
- object.init();
+ /* Read the sequence from the QObject property if we're a reference */
+ if (This->d()->isReference() && !This->loadReference())
+ RETURN_UNDEFINED();
- QV4::Scope scope(internalClass->engine);
- QV4::Scoped<QV4::QQmlSequence<Container> > o(scope, this);
- o->setArrayType(Heap::ArrayData::Custom);
- o->init();
-}
+ /* Determine whether we need to modify the sequence */
+ const qsizetype count = This->size();
+ if (newCount == count) {
+ RETURN_UNDEFINED();
+ } else if (newCount > count) {
+ const QMetaType valueMetaType = This->d()->valueMetaType();
+ /* according to ECMA262r3 we need to insert */
+ /* undefined values increasing length to newLength. */
+ /* We cannot, so we insert default-values instead. */
+ This->append(newCount - count, QVariant(valueMetaType));
+ } else {
+ /* according to ECMA262r3 we need to remove */
+ /* elements until the sequence is the required length. */
+ Q_ASSERT(newCount < count);
+ This->removeLast(count - newCount);
+ }
-template <typename Container>
-void Heap::QQmlSequence<Container>::init(QObject *object, int propertyIndex, bool readOnly)
-{
- Object::init();
- this->container = new Container;
- this->propertyIndex = propertyIndex;
- isReference = true;
- this->isReadOnly = readOnly;
- this->object.init(object);
- QV4::Scope scope(internalClass->engine);
- QV4::Scoped<QV4::QQmlSequence<Container> > o(scope, this);
- o->setArrayType(Heap::ArrayData::Custom);
- o->loadReference();
- o->init();
-}
+ /* write back if required. */
+ if (This->d()->object())
+ This->storeReference();
+ RETURN_UNDEFINED();
}
-namespace QV4 {
-
-typedef QQmlSequence<QVector<int> > QQmlIntVectorList;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlIntVectorList);
-typedef QQmlSequence<QVector<qreal> > QQmlRealVectorList;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlRealVectorList);
-typedef QQmlSequence<QVector<bool> > QQmlBoolVectorList;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolVectorList);
-typedef QQmlSequence<std::vector<int> > QQmlIntStdVectorList;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlIntStdVectorList);
-typedef QQmlSequence<std::vector<qreal> > QQmlRealStdVectorList;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlRealStdVectorList);
-typedef QQmlSequence<std::vector<bool> > QQmlBoolStdVectorList;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolStdVectorList);
-typedef QQmlSequence<QStringList> QQmlQStringList;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQStringList);
-typedef QQmlSequence<QList<QString> > QQmlStringList;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringList);
-typedef QQmlSequence<QVector<QString> > QQmlStringVectorList;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringVectorList);
-typedef QQmlSequence<std::vector<QString> > QQmlStringStdVectorList;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringStdVectorList);
-typedef QQmlSequence<QList<int> > QQmlIntList;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlIntList);
-typedef QQmlSequence<QList<QUrl> > QQmlUrlList;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlList);
-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;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexVectorList);
-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;
-DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlRealList);
-
-}
-
-#define REGISTER_QML_SEQUENCE_METATYPE(unused, unused2, SequenceType, unused3) qRegisterMetaType<SequenceType>(#SequenceType);
void SequencePrototype::init()
{
- FOREACH_QML_SEQUENCE_TYPE(REGISTER_QML_SEQUENCE_METATYPE)
defineDefaultProperty(QStringLiteral("sort"), method_sort, 1);
defineDefaultProperty(engine()->id_valueOf(), method_valueOf, 0);
+ defineAccessorProperty(QStringLiteral("length"), method_get_length, method_set_length);
}
-#undef REGISTER_QML_SEQUENCE_METATYPE
ReturnedValue SequencePrototype::method_valueOf(const FunctionObject *f, const Value *thisObject, const Value *, int)
{
@@ -717,132 +613,142 @@ ReturnedValue SequencePrototype::method_sort(const FunctionObject *b, const Valu
{
Scope scope(b);
QV4::ScopedObject o(scope, thisObject);
- if (!o || !o->isListType())
+ if (!o || !o->isV4SequenceType())
THROW_TYPE_ERROR();
if (argc >= 2)
return o.asReturnedValue();
-#define CALL_SORT(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue) \
- if (QQml##SequenceElementTypeName##List *s = o->as<QQml##SequenceElementTypeName##List>()) { \
- if (!s->sort(b, thisObject, argv, argc)) \
- THROW_TYPE_ERROR(); \
- } else
-
- FOREACH_QML_SEQUENCE_TYPE(CALL_SORT)
+ if (auto *s = o->as<Sequence>()) {
+ if (!s->sort(b, thisObject, argv, argc))
+ THROW_TYPE_ERROR();
+ }
-#undef CALL_SORT
- {}
return o.asReturnedValue();
}
-#define IS_SEQUENCE(unused1, unused2, SequenceType, unused3) \
- if (sequenceTypeId == qMetaTypeId<SequenceType>()) { \
- return true; \
- } else
-
-bool SequencePrototype::isSequenceType(int sequenceTypeId)
-{
- FOREACH_QML_SEQUENCE_TYPE(IS_SEQUENCE) { /* else */ return false; }
-}
-#undef IS_SEQUENCE
-
-#define NEW_REFERENCE_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \
- if (sequenceType == qMetaTypeId<SequenceType>()) { \
- QV4::ScopedObject obj(scope, engine->memoryManager->allocate<QQml##ElementTypeName##List>(object, propertyIndex, readOnly)); \
- return obj.asReturnedValue(); \
- } else
-
-ReturnedValue SequencePrototype::newSequence(QV4::ExecutionEngine *engine, int sequenceType, QObject *object, int propertyIndex, bool readOnly, bool *succeeded)
+ReturnedValue SequencePrototype::newSequence(
+ QV4::ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data,
+ Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags)
{
- QV4::Scope scope(engine);
// This function is called when the property is a QObject Q_PROPERTY of
- // the given sequence type. Internally we store a typed-sequence
+ // the given sequence type. Internally we store a sequence
// (as well as object ptr + property index for updated-read and write-back)
// and so access/mutate avoids variant conversion.
- *succeeded = true;
- FOREACH_QML_SEQUENCE_TYPE(NEW_REFERENCE_SEQUENCE) { /* else */ *succeeded = false; return QV4::Encode::undefined(); }
+
+ return engine->memoryManager->allocate<Sequence>(
+ type, metaSequence, data, object, propertyIndex, flags)->asReturnedValue();
}
-#undef NEW_REFERENCE_SEQUENCE
-#define NEW_COPY_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \
- if (sequenceType == qMetaTypeId<SequenceType>()) { \
- QV4::ScopedObject obj(scope, engine->memoryManager->allocate<QQml##ElementTypeName##List>(v.value<SequenceType >())); \
- return obj.asReturnedValue(); \
- } else
+ReturnedValue SequencePrototype::fromVariant(QV4::ExecutionEngine *engine, const QVariant &v)
+{
+ const QMetaType type = v.metaType();
+ const QQmlType qmlType = QQmlMetaType::qmlListType(type);
+ if (qmlType.isSequentialContainer())
+ return fromData(engine, type, qmlType.listMetaSequence(), v.constData());
+
+ QSequentialIterable iterable;
+ if (QMetaType::convert(
+ type, v.constData(), QMetaType::fromType<QSequentialIterable>(), &iterable)) {
+ return fromData(engine, type, iterable.metaContainer(), v.constData());
+ }
-ReturnedValue SequencePrototype::fromVariant(QV4::ExecutionEngine *engine, const QVariant& v, bool *succeeded)
+ return Encode::undefined();
+}
+
+ReturnedValue SequencePrototype::fromData(
+ ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data)
{
- QV4::Scope scope(engine);
// This function is called when assigning a sequence value to a normal JS var
// in a JS block. Internally, we store a sequence of the specified type.
// Access and mutation is extremely fast since it will not need to modify any
// QObject property.
- int sequenceType = v.userType();
- *succeeded = true;
- FOREACH_QML_SEQUENCE_TYPE(NEW_COPY_SEQUENCE) { /* else */ *succeeded = false; return QV4::Encode::undefined(); }
-}
-#undef NEW_COPY_SEQUENCE
-#define SEQUENCE_TO_VARIANT(ElementType, ElementTypeName, SequenceType, unused) \
- if (QQml##ElementTypeName##List *list = object->as<QQml##ElementTypeName##List>()) \
- return list->toVariant(); \
- else
+ return engine->memoryManager->allocate<Sequence>(type, metaSequence, data)->asReturnedValue();
+}
-QVariant SequencePrototype::toVariant(Object *object)
+QVariant SequencePrototype::toVariant(const Sequence *object)
{
- Q_ASSERT(object->isListType());
- FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_TO_VARIANT) { /* else */ return QVariant(); }
-}
+ Q_ASSERT(object->isV4SequenceType());
+ const auto *p = object->d();
-#undef SEQUENCE_TO_VARIANT
-#define SEQUENCE_TO_VARIANT(ElementType, ElementTypeName, SequenceType, unused) \
- if (typeHint == qMetaTypeId<SequenceType>()) { \
- return QQml##ElementTypeName##List::toVariant(a); \
- } else
+ // Note: For historical reasons, we ignore the result of loadReference()
+ // here. This allows us to retain sequences whose objects have vaninshed
+ // as "var" properties. It comes at the price of potentially returning
+ // outdated data. This is the behavior sequences have always shown.
+ if (p->isReference())
+ object->loadReference();
+ if (!p->hasData())
+ return QVariant();
-QVariant SequencePrototype::toVariant(const QV4::Value &array, int typeHint, bool *succeeded)
-{
- *succeeded = true;
+ return QVariant(p->listType(), p->storagePointer());
+}
- if (!array.as<ArrayObject>()) {
- *succeeded = false;
+QVariant SequencePrototype::toVariant(const QV4::Value &array, QMetaType typeHint)
+{
+ if (!array.as<ArrayObject>())
return QVariant();
- }
+
QV4::Scope scope(array.as<Object>()->engine());
QV4::ScopedArrayObject a(scope, array);
- FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_TO_VARIANT) { /* else */ *succeeded = false; return QVariant(); }
-}
+ const QQmlType type = QQmlMetaType::qmlListType(typeHint);
+ if (type.isSequentialContainer()) {
+ const QQmlTypePrivate *priv = type.priv();
+ const QMetaSequence *meta = &priv->extraData.sequentialContainerTypeData;
+ const QMetaType containerMetaType(priv->listId);
+ QVariant result(containerMetaType);
+ qint64 length = a->getLength();
+ Q_ASSERT(length >= 0);
+ Q_ASSERT(length <= qint64(std::numeric_limits<quint32>::max()));
-#undef SEQUENCE_TO_VARIANT
+ QV4::ScopedValue v(scope);
+ for (quint32 i = 0; i < quint32(length); ++i) {
+ const QMetaType valueMetaType = priv->typeId;
+ QVariant variant = ExecutionEngine::toVariant(a->get(i), valueMetaType, false);
+ if (valueMetaType == QMetaType::fromType<QVariant>()) {
+ meta->addValueAtEnd(result.data(), &variant);
+ } else {
+ const QMetaType originalType = variant.metaType();
+ if (originalType != valueMetaType) {
+ const QVariant converted = QQmlValueTypeProvider::createValueType(
+ variant, valueMetaType);
+ if (converted.isValid()) {
+ variant = converted;
+ } else if (!variant.convert(valueMetaType) && originalType.isValid()) {
+ // If the original type was void, we're converting a "hole" in a sparse
+ // array. There is no point in warning about that.
+ qWarning().noquote()
+ << QLatin1String("Could not convert array value "
+ "at position %1 from %2 to %3")
+ .arg(QString::number(i),
+ QString::fromUtf8(originalType.name()),
+ QString::fromUtf8(valueMetaType.name()));
+ }
+ }
+ meta->addValueAtEnd(result.data(), variant.constData());
+ }
+ }
+ return result;
+ }
-#define SEQUENCE_GET_RAWCONTAINERPTR(ElementType, ElementTypeName, SequenceType, unused) \
- if (const QQml##ElementTypeName##List *list = [&]() -> const QQml##ElementTypeName##List* \
- { if (typeHint == qMetaTypeId<SequenceType>()) return object->as<QQml##ElementTypeName##List>(); return nullptr;}()) \
- return list->getRawContainerPtr(); \
- else
+ return QVariant();
+}
-void* SequencePrototype::getRawContainerPtr(const Object *object, int typeHint)
+void *SequencePrototype::getRawContainerPtr(const Sequence *object, QMetaType typeHint)
{
- FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_GET_RAWCONTAINERPTR) { /* else */ return nullptr; }
+ if (object->d()->listType() == typeHint)
+ return object->getRawContainerPtr();
+ return nullptr;
}
-#undef SEQUENCE_GET_RAWCONTAINERPTR
-
-#define MAP_META_TYPE(ElementType, ElementTypeName, SequenceType, unused) \
- if (object->as<QQml##ElementTypeName##List>()) { \
- return qMetaTypeId<SequenceType>(); \
- } else
-
-int SequencePrototype::metaTypeForSequence(const QV4::Object *object)
+QMetaType SequencePrototype::metaTypeForSequence(const Sequence *object)
{
- FOREACH_QML_SEQUENCE_TYPE(MAP_META_TYPE)
- /*else*/ {
- return -1;
- }
+ return object->d()->listType();
}
-#undef MAP_META_TYPE
+} // namespace QV4
QT_END_NAMESPACE
+
+#include "moc_qv4sequenceobject_p.cpp"
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index 886dfaa521..3d1baf6c77 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4SEQUENCEWRAPPER_P_H
#define QV4SEQUENCEWRAPPER_P_H
@@ -53,19 +17,18 @@
#include <QtCore/qglobal.h>
#include <QtCore/qvariant.h>
+#include <QtQml/qqml.h>
-#include "qv4value_p.h"
-#include "qv4object_p.h"
-#include "qv4context_p.h"
-#include "qv4string_p.h"
-
-QT_REQUIRE_CONFIG(qml_sequence_object);
+#include <private/qv4referenceobject_p.h>
+#include <private/qv4value_p.h>
+#include <private/qv4object_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
-struct Q_QML_PRIVATE_EXPORT SequencePrototype : public QV4::Object
+struct Sequence;
+struct Q_QML_EXPORT SequencePrototype : public QV4::Object
{
V4_PROTOTYPE(arrayPrototype)
void init();
@@ -73,17 +36,118 @@ struct Q_QML_PRIVATE_EXPORT SequencePrototype : public QV4::Object
static ReturnedValue method_valueOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_sort(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static bool isSequenceType(int sequenceTypeId);
- static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool readOnly, bool *succeeded);
- static ReturnedValue fromVariant(QV4::ExecutionEngine *engine, const QVariant& v, bool *succeeded);
- static int metaTypeForSequence(const Object *object);
- static QVariant toVariant(Object *object);
- static QVariant toVariant(const Value &array, int typeHint, bool *succeeded);
- static void* getRawContainerPtr(const Object *object, int typeHint);
+ static ReturnedValue newSequence(
+ QV4::ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data,
+ Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags);
+ static ReturnedValue fromVariant(QV4::ExecutionEngine *engine, const QVariant &vd);
+ static ReturnedValue fromData(
+ QV4::ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data);
+
+ static QMetaType metaTypeForSequence(const Sequence *object);
+ static QVariant toVariant(const Sequence *object);
+ static QVariant toVariant(const Value &array, QMetaType typeHint);
+ static void *getRawContainerPtr(const Sequence *object, QMetaType typeHint);
+};
+
+namespace Heap {
+
+struct Sequence : ReferenceObject
+{
+ void init(QMetaType listType, QMetaSequence metaSequence, const void *container);
+ void init(QMetaType listType, QMetaSequence metaSequence, const void *container,
+ Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags);
+
+ Sequence *detached() const;
+ void destroy();
+
+ bool hasData() const { return m_container != nullptr; }
+ void *storagePointer();
+ const void *storagePointer() const { return m_container; }
+
+ bool isReadOnly() const { return m_object && !canWriteBack(); }
+
+ bool setVariant(const QVariant &variant);
+ QVariant toVariant() const;
+
+ QMetaType listType() const { return QMetaType(m_listType); }
+ QMetaType valueMetaType() const { return QMetaType(m_metaSequence->valueMetaType); }
+ QMetaSequence metaSequence() const { return QMetaSequence(m_metaSequence); }
+
+private:
+ void initTypes(QMetaType listType, QMetaSequence metaSequence);
+
+ void *m_container;
+ const QtPrivate::QMetaTypeInterface *m_listType;
+ const QtMetaContainerPrivate::QMetaSequenceInterface *m_metaSequence;
+};
+
+}
+
+struct Q_QML_EXPORT Sequence : public QV4::ReferenceObject
+{
+ V4_OBJECT2(Sequence, QV4::ReferenceObject)
+ Q_MANAGED_TYPE(V4Sequence)
+ V4_PROTOTYPE(sequencePrototype)
+ V4_NEEDS_DESTROY
+public:
+ static QV4::ReturnedValue virtualGet(
+ const QV4::Managed *that, PropertyKey id, const Value *receiver, bool *hasProperty);
+ static qint64 virtualGetLength(const Managed *m);
+ static bool virtualPut(Managed *that, PropertyKey id, const QV4::Value &value, Value *receiver);
+ static bool virtualDeleteProperty(QV4::Managed *that, PropertyKey id);
+ static bool virtualIsEqualTo(Managed *that, Managed *other);
+ static QV4::OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
+ static int virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a);
+
+ qsizetype size() const;
+ QVariant at(qsizetype index) const;
+ void append(const QVariant &item);
+ void append(qsizetype num, const QVariant &item);
+ void replace(qsizetype index, const QVariant &item);
+ void removeLast(qsizetype num);
+
+ QV4::ReturnedValue containerGetIndexed(qsizetype index, bool *hasProperty) const;
+ bool containerPutIndexed(qsizetype index, const QV4::Value &value);
+ bool containerDeleteIndexedProperty(qsizetype index);
+ bool containerIsEqualTo(Managed *other);
+ bool sort(const FunctionObject *f, const Value *, const Value *argv, int argc);
+ void *getRawContainerPtr() const;
+ bool loadReference() const;
+ bool storeReference();
};
}
+#define QT_DECLARE_SEQUENTIAL_CONTAINER(LOCAL, FOREIGN, VALUE) \
+ struct LOCAL \
+ { \
+ Q_GADGET \
+ QML_ANONYMOUS \
+ QML_SEQUENTIAL_CONTAINER(VALUE) \
+ QML_FOREIGN(FOREIGN) \
+ QML_ADDED_IN_VERSION(2, 0) \
+ }
+
+// We use the original QT_COORD_TYPE name because that will match up with relevant other
+// types in plugins.qmltypes (if you use either float or double, that is; otherwise you're
+// on your own).
+#ifdef QT_COORD_TYPE
+QT_DECLARE_SEQUENTIAL_CONTAINER(QStdRealVectorForeign, std::vector<qreal>, QT_COORD_TYPE);
+QT_DECLARE_SEQUENTIAL_CONTAINER(QRealListForeign, QList<qreal>, QT_COORD_TYPE);
+#else
+QT_DECLARE_SEQUENTIAL_CONTAINER(QRealStdVectorForeign, std::vector<qreal>, double);
+QT_DECLARE_SEQUENTIAL_CONTAINER(QRealListForeign, QList<qreal>, double);
+#endif
+
+QT_DECLARE_SEQUENTIAL_CONTAINER(QDoubleStdVectorForeign, std::vector<double>, double);
+QT_DECLARE_SEQUENTIAL_CONTAINER(QFloatStdVectorForeign, std::vector<float>, float);
+QT_DECLARE_SEQUENTIAL_CONTAINER(QIntStdVectorForeign, std::vector<int>, int);
+QT_DECLARE_SEQUENTIAL_CONTAINER(QBoolStdVectorForeign, std::vector<bool>, bool);
+QT_DECLARE_SEQUENTIAL_CONTAINER(QStringStdVectorForeign, std::vector<QString>, QString);
+QT_DECLARE_SEQUENTIAL_CONTAINER(QUrlStdVectorForeign, std::vector<QUrl>, QUrl);
+
+#undef QT_DECLARE_SEQUENTIAL_CONTAINER
+
QT_END_NAMESPACE
#endif // QV4SEQUENCEWRAPPER_P_H
diff --git a/src/qml/jsruntime/qv4setiterator.cpp b/src/qml/jsruntime/qv4setiterator.cpp
index d32e2079a0..0491d26352 100644
--- a/src/qml/jsruntime/qv4setiterator.cpp
+++ b/src/qml/jsruntime/qv4setiterator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Crimson AS <info@crimson.no>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Crimson AS <info@crimson.no>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qv4iterator_p.h>
#include <private/qv4estable_p.h>
diff --git a/src/qml/jsruntime/qv4setiterator_p.h b/src/qml/jsruntime/qv4setiterator_p.h
index 78eda6d57b..37f912e01a 100644
--- a/src/qml/jsruntime/qv4setiterator_p.h
+++ b/src/qml/jsruntime/qv4setiterator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Crimson AS <info@crimson.no>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Crimson AS <info@crimson.no>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4SETITERATOR_P_H
#define QV4SETITERATOR_P_H
@@ -66,7 +30,7 @@ namespace Heap {
Member(class, NoMark, quint32, setNextIndex)
DECLARE_HEAP_OBJECT(SetIteratorObject, Object) {
- DECLARE_MARKOBJECTS(SetIteratorObject);
+ DECLARE_MARKOBJECTS(SetIteratorObject)
void init(Object *obj, QV4::ExecutionEngine *engine)
{
Object::init();
diff --git a/src/qml/jsruntime/qv4setobject.cpp b/src/qml/jsruntime/qv4setobject.cpp
index 1664d1bd71..a7589a40db 100644
--- a/src/qml/jsruntime/qv4setobject.cpp
+++ b/src/qml/jsruntime/qv4setobject.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Crimson AS <info@crimson.no>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Crimson AS <info@crimson.no>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4setobject_p.h"
@@ -44,6 +8,7 @@
#include "qv4symbol_p.h"
using namespace QV4;
+using namespace Qt::Literals::StringLiterals;
DEFINE_OBJECT_VTABLE(SetCtor);
DEFINE_OBJECT_VTABLE(WeakSetCtor);
@@ -73,7 +38,7 @@ ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv,
if (argc > 0) {
ScopedValue iterable(scope, argv[0]);
if (!iterable->isUndefined() && !iterable->isNull()) {
- ScopedFunctionObject adder(scope, a->get(ScopedString(scope, scope.engine->newString(QString::fromLatin1("add")))));
+ ScopedFunctionObject adder(scope, a->get(ScopedString(scope, scope.engine->newString(u"add"_s))));
if (!adder)
return scope.engine->throwTypeError();
ScopedObject iter(scope, Runtime::GetIterator::call(scope.engine, iterable, true));
@@ -90,10 +55,8 @@ ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv,
return a.asReturnedValue();
adder->call(a, nextValue, 1);
- if (scope.engine->hasException) {
- ScopedValue falsey(scope, Encode(false));
- return Runtime::IteratorClose::call(scope.engine, iter, falsey);
- }
+ if (scope.hasException())
+ return Runtime::IteratorClose::call(scope.engine, iter);
}
}
}
diff --git a/src/qml/jsruntime/qv4setobject_p.h b/src/qml/jsruntime/qv4setobject_p.h
index 21584e2132..6ed44b4ed9 100644
--- a/src/qml/jsruntime/qv4setobject_p.h
+++ b/src/qml/jsruntime/qv4setobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Crimson AS <info@crimson.no>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Crimson AS <info@crimson.no>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4SETOBJECT_P_H
#define QV4SETOBJECT_P_H
diff --git a/src/qml/jsruntime/qv4sparsearray.cpp b/src/qml/jsruntime/qv4sparsearray.cpp
index 8930c9a94d..656c496a2a 100644
--- a/src/qml/jsruntime/qv4sparsearray.cpp
+++ b/src/qml/jsruntime/qv4sparsearray.cpp
@@ -1,47 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4sparsearray_p.h"
-#include "qv4runtime_p.h"
-#include "qv4object_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4scopedvalue_p.h"
#include <stdlib.h>
#ifdef QT_QMAP_DEBUG
@@ -359,7 +319,7 @@ static inline void qMapDeallocate(SparseArrayNode *node, int alignment)
SparseArrayNode *SparseArray::createNode(uint sl, SparseArrayNode *parent, bool left)
{
- SparseArrayNode *node = static_cast<SparseArrayNode *>(qMapAllocate(sizeof(SparseArrayNode), Q_ALIGNOF(SparseArrayNode)));
+ SparseArrayNode *node = static_cast<SparseArrayNode *>(qMapAllocate(sizeof(SparseArrayNode), alignof(SparseArrayNode)));
Q_CHECK_PTR(node);
node->p = (quintptr)parent;
diff --git a/src/qml/jsruntime/qv4sparsearray_p.h b/src/qml/jsruntime/qv4sparsearray_p.h
index c1e50c8dcf..7da42a4985 100644
--- a/src/qml/jsruntime/qv4sparsearray_p.h
+++ b/src/qml/jsruntime/qv4sparsearray_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4SPARSEARRAY_H
#define QV4SPARSEARRAY_H
@@ -146,8 +110,8 @@ struct Q_QML_EXPORT SparseArray
{
SparseArray();
~SparseArray() {
- if (root())
- freeTree(header.left, Q_ALIGNOF(SparseArrayNode));
+ if (SparseArrayNode *n = root())
+ freeTree(n, alignof(SparseArrayNode));
}
SparseArray(const SparseArray &other);
@@ -236,10 +200,10 @@ inline uint SparseArray::pop_front()
idx = n->value;
deleteNode(n);
// adjust all size_left indices on the path to leftmost item by 1
- SparseArrayNode *n = root();
- while (n) {
- n->size_left -= 1;
- n = n->left;
+ SparseArrayNode *rootNode = root();
+ while (rootNode) {
+ rootNode->size_left -= 1;
+ rootNode = rootNode->left;
}
}
return idx;
@@ -323,37 +287,45 @@ inline QList<int> SparseArray::keys() const
inline const SparseArrayNode *SparseArray::lowerBound(uint akey) const
{
- const SparseArrayNode *lb = root()->lowerBound(akey);
- if (!lb)
- lb = end();
- return lb;
+ if (SparseArrayNode *n = root()) {
+ if (const SparseArrayNode *lb = n->lowerBound(akey))
+ return lb;
+ }
+
+ return end();
}
inline SparseArrayNode *SparseArray::lowerBound(uint akey)
{
- SparseArrayNode *lb = root()->lowerBound(akey);
- if (!lb)
- lb = end();
- return lb;
+ if (SparseArrayNode *n = root()) {
+ if (SparseArrayNode *lb = n->lowerBound(akey))
+ return lb;
+ }
+
+ return end();
}
inline const SparseArrayNode *SparseArray::upperBound(uint akey) const
{
- const SparseArrayNode *ub = root()->upperBound(akey);
- if (!ub)
- ub = end();
- return ub;
+ if (SparseArrayNode *n = root()) {
+ if (const SparseArrayNode *ub = n->upperBound(akey))
+ return ub;
+ }
+
+ return end();
}
inline SparseArrayNode *SparseArray::upperBound(uint akey)
{
- SparseArrayNode *ub = root()->upperBound(akey);
- if (!ub)
- ub = end();
- return ub;
+ if (SparseArrayNode *n = root()) {
+ if (SparseArrayNode *ub = n->upperBound(akey))
+ return ub;
+ }
+
+ return end();
}
}
diff --git a/src/qml/jsruntime/qv4sqlerrors.cpp b/src/qml/jsruntime/qv4sqlerrors.cpp
new file mode 100644
index 0000000000..c942871702
--- /dev/null
+++ b/src/qml/jsruntime/qv4sqlerrors.cpp
@@ -0,0 +1,27 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qv4sqlerrors_p.h"
+#include "private/qv4engine_p.h"
+#include "private/qv4object_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+void qt_add_sqlexceptions(QV4::ExecutionEngine *engine)
+{
+ Scope scope(engine);
+ ScopedObject sqlexception(scope, engine->newObject());
+ sqlexception->defineReadonlyProperty(QStringLiteral("UNKNOWN_ERR"), Value::fromInt32(SQLEXCEPTION_UNKNOWN_ERR));
+ sqlexception->defineReadonlyProperty(QStringLiteral("DATABASE_ERR"), Value::fromInt32(SQLEXCEPTION_DATABASE_ERR));
+ sqlexception->defineReadonlyProperty(QStringLiteral("VERSION_ERR"), Value::fromInt32(SQLEXCEPTION_VERSION_ERR));
+ sqlexception->defineReadonlyProperty(QStringLiteral("TOO_LARGE_ERR"), Value::fromInt32(SQLEXCEPTION_TOO_LARGE_ERR));
+ sqlexception->defineReadonlyProperty(QStringLiteral("QUOTA_ERR"), Value::fromInt32(SQLEXCEPTION_QUOTA_ERR));
+ sqlexception->defineReadonlyProperty(QStringLiteral("SYNTAX_ERR"), Value::fromInt32(SQLEXCEPTION_SYNTAX_ERR));
+ sqlexception->defineReadonlyProperty(QStringLiteral("CONSTRAINT_ERR"), Value::fromInt32(SQLEXCEPTION_CONSTRAINT_ERR));
+ sqlexception->defineReadonlyProperty(QStringLiteral("TIMEOUT_ERR"), Value::fromInt32(SQLEXCEPTION_TIMEOUT_ERR));
+ engine->globalObject->defineDefaultProperty(QStringLiteral("SQLException"), sqlexception);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4sqlerrors_p.h b/src/qml/jsruntime/qv4sqlerrors_p.h
new file mode 100644
index 0000000000..b6c5d5446d
--- /dev/null
+++ b/src/qml/jsruntime/qv4sqlerrors_p.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QV8SQLERRORS_P_H
+#define QV8SQLERRORS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+#define SQLEXCEPTION_UNKNOWN_ERR 1
+#define SQLEXCEPTION_DATABASE_ERR 2
+#define SQLEXCEPTION_VERSION_ERR 3
+#define SQLEXCEPTION_TOO_LARGE_ERR 4
+#define SQLEXCEPTION_QUOTA_ERR 5
+#define SQLEXCEPTION_SYNTAX_ERR 6
+#define SQLEXCEPTION_CONSTRAINT_ERR 7
+#define SQLEXCEPTION_TIMEOUT_ERR 8
+
+namespace QV4 {
+struct ExecutionEngine;
+}
+
+void qt_add_sqlexceptions(QV4::ExecutionEngine *engine);
+
+QT_END_NAMESPACE
+
+#endif // QV8SQLERRORS_P_H
diff --git a/src/qml/jsruntime/qv4stackframe.cpp b/src/qml/jsruntime/qv4stackframe.cpp
index a716c53aea..5117e745a0 100644
--- a/src/qml/jsruntime/qv4stackframe.cpp
+++ b/src/qml/jsruntime/qv4stackframe.cpp
@@ -1,42 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
#include "qv4stackframe_p.h"
+#include <private/qv4qobjectwrapper_p.h>
#include <QtCore/qstring.h>
using namespace QV4;
@@ -51,24 +17,54 @@ QString CppStackFrame::function() const
return v4Function ? v4Function->name()->toQString() : QString();
}
-int CppStackFrame::lineNumber() const
+static const CompiledData::CodeOffsetToLineAndStatement *lineAndStatement(const CppStackFrame *frame)
{
- if (!v4Function)
- return -1;
+ if (!frame->v4Function || frame->instructionPointer <= 0)
+ return nullptr;
- auto findLine = [](const CompiledData::CodeOffsetToLine &entry, uint offset) {
+ auto findLine = [](const CompiledData::CodeOffsetToLineAndStatement &entry, uint offset) {
return entry.codeOffset < offset;
};
- const QV4::CompiledData::Function *cf = v4Function->compiledFunction;
- uint offset = instructionPointer;
- const CompiledData::CodeOffsetToLine *lineNumbers = cf->lineNumberTable();
- uint nLineNumbers = cf->nLineNumbers;
- const CompiledData::CodeOffsetToLine *line = std::lower_bound(lineNumbers, lineNumbers + nLineNumbers, offset, findLine) - 1;
- return line->line;
+ const QV4::CompiledData::Function *cf = frame->v4Function->compiledFunction;
+ const uint offset = frame->instructionPointer;
+ const CompiledData::CodeOffsetToLineAndStatement *lineAndStatementNumbers
+ = cf->lineAndStatementNumberTable();
+ const uint nLineAndStatementNumbers = cf->nLineAndStatementNumbers;
+ return std::lower_bound(
+ lineAndStatementNumbers, lineAndStatementNumbers + nLineAndStatementNumbers,
+ offset, findLine) - 1;
}
-ReturnedValue CppStackFrame::thisObject() const {
- return jsFrame->thisObject.asReturnedValue();
+int CppStackFrame::lineNumber() const
+{
+ if (auto *line = lineAndStatement(this))
+ return line->line;
+ return missingLineNumber();
+}
+
+int CppStackFrame::statementNumber() const
+{
+ if (auto *statement = lineAndStatement(this))
+ return statement->statement;
+ return -1;
}
+int CppStackFrame::missingLineNumber() const
+{
+ // Remove the first bit so that we can cast to positive int and negate.
+ // Remove the last bit so that it can't be -1.
+ const int result = -int(quintptr(this) & 0x7ffffffe);
+ Q_ASSERT(result < -1);
+ return result;
+}
+
+ReturnedValue QV4::CppStackFrame::thisObject() const
+{
+ if (isJSTypesFrame())
+ return static_cast<const JSTypesStackFrame *>(this)->thisObject();
+
+ Q_ASSERT(isMetaTypesFrame());
+ const auto metaTypesFrame = static_cast<const MetaTypesStackFrame *>(this);
+ return QObjectWrapper::wrap(metaTypesFrame->context()->engine(), metaTypesFrame->thisObject());
+}
diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h
index bf689a74bc..f24b0b2433 100644
--- a/src/qml/jsruntime/qv4stackframe_p.h
+++ b/src/qml/jsruntime/qv4stackframe_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4STACKFRAME_H
#define QV4STACKFRAME_H
@@ -50,61 +14,179 @@
// We mean it.
//
+#include <private/qv4scopedvalue_p.h>
#include <private/qv4context_p.h>
#include <private/qv4enginebase_p.h>
#include <private/qv4calldata_p.h>
#include <private/qv4function_p.h>
+#include <type_traits>
+
QT_BEGIN_NAMESPACE
namespace QV4 {
-struct Q_QML_EXPORT CppStackFrame {
- EngineBase *engine;
- Value *savedStackTop;
+struct CppStackFrame;
+struct Q_QML_EXPORT CppStackFrameBase
+{
+ enum class Kind : quint8 { JS, Meta };
+
CppStackFrame *parent;
Function *v4Function;
- CallData *jsFrame;
- const Value *originalArguments;
int originalArgumentsCount;
int instructionPointer;
- const char *yield;
- const char *unwindHandler;
- const char *unwindLabel;
- int unwindLevel;
- bool yieldIsIterator;
- bool callerCanHandleTailCall;
- bool pendingTailCall;
- bool isTailCalling;
-
- void init(EngineBase *engine, Function *v4Function, const Value *argv, int argc, bool callerCanHandleTailCall = false) {
- this->engine = engine;
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_MSVC(4201) // nonstandard extension used: nameless struct/union
+ union {
+ struct {
+ Value *savedStackTop;
+ CallData *jsFrame;
+ const Value *originalArguments;
+ const char *yield;
+ const char *unwindHandler;
+ const char *unwindLabel;
+ int unwindLevel;
+ bool yieldIsIterator;
+ bool callerCanHandleTailCall;
+ bool pendingTailCall;
+ bool isTailCalling;
+ };
+ struct {
+ ExecutionContext *context;
+ QObject *thisObject;
+ const QMetaType *metaTypes;
+ void **returnAndArgs;
+ bool returnValueIsUndefined;
+ };
+ };
+ QT_WARNING_POP
+
+ Kind kind;
+};
+
+struct Q_QML_EXPORT CppStackFrame : protected CppStackFrameBase
+{
+ // We want to have those public but we can't declare them as public without making the struct
+ // non-standard layout. So we have this other struct with "using" in between.
+ using CppStackFrameBase::instructionPointer;
+ using CppStackFrameBase::v4Function;
+
+ void init(Function *v4Function, int argc, Kind kind) {
this->v4Function = v4Function;
- originalArguments = argv;
originalArgumentsCount = argc;
instructionPointer = 0;
- yield = nullptr;
- unwindHandler = nullptr;
- unwindLabel = nullptr;
- unwindLevel = 0;
- yieldIsIterator = false;
- this->callerCanHandleTailCall = callerCanHandleTailCall;
- pendingTailCall = false;
- isTailCalling = false;
+ this->kind = kind;
}
- void push() {
+ bool isJSTypesFrame() const { return kind == Kind::JS; }
+ bool isMetaTypesFrame() const { return kind == Kind::Meta; }
+
+ QString source() const;
+ QString function() const;
+ int lineNumber() const;
+ int statementNumber() const;
+
+ int missingLineNumber() const;
+
+ CppStackFrame *parentFrame() const { return parent; }
+ void setParentFrame(CppStackFrame *parentFrame) { parent = parentFrame; }
+
+ int argc() const { return originalArgumentsCount; }
+
+ inline ExecutionContext *context() const;
+
+ Heap::CallContext *callContext() const { return callContext(context()->d()); }
+ ReturnedValue thisObject() const;
+
+protected:
+ CppStackFrame() = default;
+
+ void push(EngineBase *engine)
+ {
+ Q_ASSERT(kind == Kind::JS || kind == Kind::Meta);
parent = engine->currentStackFrame;
engine->currentStackFrame = this;
- savedStackTop = engine->jsStackTop;
}
- void pop() {
+ void pop(EngineBase *engine)
+ {
engine->currentStackFrame = parent;
- engine->jsStackTop = savedStackTop;
}
+ Heap::CallContext *callContext(Heap::ExecutionContext *ctx) const
+ {
+ while (ctx->type != Heap::ExecutionContext::Type_CallContext)
+ ctx = ctx->outer;
+ return static_cast<Heap::CallContext *>(ctx);
+ }
+};
+
+struct Q_QML_EXPORT MetaTypesStackFrame : public CppStackFrame
+{
+ using CppStackFrame::push;
+ using CppStackFrame::pop;
+
+ void init(Function *v4Function, QObject *thisObject, ExecutionContext *context,
+ void **returnAndArgs, const QMetaType *metaTypes, int argc)
+ {
+ CppStackFrame::init(v4Function, argc, Kind::Meta);
+ CppStackFrameBase::thisObject = thisObject;
+ CppStackFrameBase::context = context;
+ CppStackFrameBase::metaTypes = metaTypes;
+ CppStackFrameBase::returnAndArgs = returnAndArgs;
+ CppStackFrameBase::returnValueIsUndefined = false;
+ }
+
+ QMetaType returnType() const { return metaTypes[0]; }
+ void *returnValue() const { return returnAndArgs[0]; }
+
+ bool isReturnValueUndefined() const { return CppStackFrameBase::returnValueIsUndefined; }
+ void setReturnValueUndefined() { CppStackFrameBase::returnValueIsUndefined = true; }
+
+ const QMetaType *argTypes() const { return metaTypes + 1; }
+ void **argv() const { return returnAndArgs + 1; }
+
+ const QMetaType *returnAndArgTypes() const { return metaTypes; }
+ void **returnAndArgValues() const { return returnAndArgs; }
+
+ QObject *thisObject() const { return CppStackFrameBase::thisObject; }
+
+ ExecutionContext *context() const { return CppStackFrameBase::context; }
+ void setContext(ExecutionContext *context) { CppStackFrameBase::context = context; }
+
+ Heap::CallContext *callContext() const
+ {
+ return CppStackFrame::callContext(CppStackFrameBase::context->d());
+ }
+};
+
+struct Q_QML_EXPORT JSTypesStackFrame : public CppStackFrame
+{
+ using CppStackFrame::jsFrame;
+
+ // The JIT needs to poke directly into those using offsetof
+ using CppStackFrame::unwindHandler;
+ using CppStackFrame::unwindLabel;
+ using CppStackFrame::unwindLevel;
+
+ void init(Function *v4Function, const Value *argv, int argc,
+ bool callerCanHandleTailCall = false)
+ {
+ CppStackFrame::init(v4Function, argc, Kind::JS);
+ CppStackFrame::originalArguments = argv;
+ CppStackFrame::yield = nullptr;
+ CppStackFrame::unwindHandler = nullptr;
+ CppStackFrame::yieldIsIterator = false;
+ CppStackFrame::callerCanHandleTailCall = callerCanHandleTailCall;
+ CppStackFrame::pendingTailCall = false;
+ CppStackFrame::isTailCalling = false;
+ CppStackFrame::unwindLabel = nullptr;
+ CppStackFrame::unwindLevel = 0;
+ }
+
+ const Value *argv() const { return originalArguments; }
+
static uint requiredJSStackFrameSize(uint nRegisters) {
return CallData::HeaderSize() + nRegisters;
}
@@ -114,13 +196,17 @@ struct Q_QML_EXPORT CppStackFrame {
uint requiredJSStackFrameSize() const {
return requiredJSStackFrameSize(v4Function);
}
+
void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope,
const Value &thisObject, const Value &newTarget = Value::undefinedValue()) {
setupJSFrame(stackSpace, function, scope, thisObject, newTarget,
- v4Function->nFormals, v4Function->compiledFunction->nRegisters);
+ v4Function->compiledFunction->nFormals,
+ v4Function->compiledFunction->nRegisters);
}
- void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope,
- const Value &thisObject, const Value &newTarget, uint nFormals, uint nRegisters)
+
+ void setupJSFrame(
+ Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope,
+ const Value &thisObject, const Value &newTarget, uint nFormals, uint nRegisters)
{
jsFrame = reinterpret_cast<CallData *>(stackSpace);
jsFrame->function = function;
@@ -134,13 +220,17 @@ struct Q_QML_EXPORT CppStackFrame {
argc = nFormals;
jsFrame->setArgc(argc);
- memcpy(jsFrame->args, originalArguments, argc*sizeof(Value));
+ // memcpy requires non-null ptr, even if argc * sizeof(Value) == 0
+ if (originalArguments)
+ memcpy(jsFrame->args, originalArguments, argc * sizeof(Value));
Q_STATIC_ASSERT(Encode::undefined() == 0);
- memset(jsFrame->args + argc, 0, (nRegisters - argc)*sizeof(Value));
+ memset(jsFrame->args + argc, 0, (nRegisters - argc) * sizeof(Value));
if (v4Function && v4Function->compiledFunction) {
- const int firstDeadZoneRegister = v4Function->compiledFunction->firstTemporalDeadZoneRegister;
- const int registerDeadZoneSize = v4Function->compiledFunction->sizeOfRegisterTemporalDeadZone;
+ const int firstDeadZoneRegister
+ = v4Function->compiledFunction->firstTemporalDeadZoneRegister;
+ const int registerDeadZoneSize
+ = v4Function->compiledFunction->sizeOfRegisterTemporalDeadZone;
const Value * tdzEnd = stackSpace + firstDeadZoneRegister + registerDeadZoneSize;
for (Value *v = stackSpace + firstDeadZoneRegister; v < tdzEnd; ++v)
@@ -148,22 +238,92 @@ struct Q_QML_EXPORT CppStackFrame {
}
}
- QString source() const;
- QString function() const;
- inline QV4::ExecutionContext *context() const {
+ ExecutionContext *context() const
+ {
return static_cast<ExecutionContext *>(&jsFrame->context);
}
- int lineNumber() const;
- inline QV4::Heap::CallContext *callContext() const {
- Heap::ExecutionContext *ctx = static_cast<ExecutionContext &>(jsFrame->context).d();\
- while (ctx->type != Heap::ExecutionContext::Type_CallContext)
- ctx = ctx->outer;
- return static_cast<Heap::CallContext *>(ctx);
+ void setContext(ExecutionContext *context)
+ {
+ jsFrame->context = context;
+ }
+
+ Heap::CallContext *callContext() const
+ {
+ return CppStackFrame::callContext(static_cast<ExecutionContext &>(jsFrame->context).d());
+ }
+
+ bool isTailCalling() const { return CppStackFrame::isTailCalling; }
+ void setTailCalling(bool tailCalling) { CppStackFrame::isTailCalling = tailCalling; }
+
+ bool pendingTailCall() const { return CppStackFrame::pendingTailCall; }
+ void setPendingTailCall(bool pending) { CppStackFrame::pendingTailCall = pending; }
+
+ const char *yield() const { return CppStackFrame::yield; }
+ void setYield(const char *yield) { CppStackFrame::yield = yield; }
+
+ bool yieldIsIterator() const { return CppStackFrame::yieldIsIterator; }
+ void setYieldIsIterator(bool isIter) { CppStackFrame::yieldIsIterator = isIter; }
+
+ bool callerCanHandleTailCall() const { return CppStackFrame::callerCanHandleTailCall; }
+
+ ReturnedValue thisObject() const
+ {
+ return jsFrame->thisObject.asReturnedValue();
+ }
+
+ Value *framePointer() const { return savedStackTop; }
+
+ void push(EngineBase *engine) {
+ CppStackFrame::push(engine);
+ savedStackTop = engine->jsStackTop;
+ }
+
+ void pop(EngineBase *engine) {
+ CppStackFrame::pop(engine);
+ engine->jsStackTop = savedStackTop;
}
- ReturnedValue thisObject() const;
};
+inline ExecutionContext *CppStackFrame::context() const
+{
+ if (isJSTypesFrame())
+ return static_cast<const JSTypesStackFrame *>(this)->context();
+
+ Q_ASSERT(isMetaTypesFrame());
+ return static_cast<const MetaTypesStackFrame *>(this)->context();
+}
+
+struct ScopedStackFrame
+{
+ ScopedStackFrame(const Scope &scope, ExecutionContext *context)
+ : engine(scope.engine)
+ {
+ if (auto currentFrame = engine->currentStackFrame) {
+ frame.init(currentFrame->v4Function, nullptr, context, nullptr, nullptr, 0);
+ frame.instructionPointer = currentFrame->instructionPointer;
+ } else {
+ frame.init(nullptr, nullptr, context, nullptr, nullptr, 0);
+ }
+ frame.push(engine);
+ }
+
+ ~ScopedStackFrame()
+ {
+ frame.pop(engine);
+ }
+
+private:
+ ExecutionEngine *engine = nullptr;
+ MetaTypesStackFrame frame;
+};
+
+Q_STATIC_ASSERT(sizeof(CppStackFrame) == sizeof(JSTypesStackFrame));
+Q_STATIC_ASSERT(sizeof(CppStackFrame) == sizeof(MetaTypesStackFrame));
+Q_STATIC_ASSERT(std::is_standard_layout_v<CppStackFrame>);
+Q_STATIC_ASSERT(std::is_standard_layout_v<JSTypesStackFrame>);
+Q_STATIC_ASSERT(std::is_standard_layout_v<MetaTypesStackFrame>);
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index 223f4a4769..8b5594b43b 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -1,48 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4string_p.h"
#include "qv4value_p.h"
#include "qv4identifiertable_p.h"
#include "qv4runtime_p.h"
-#include "qv4objectproto_p.h"
-#include "qv4stringobject_p.h"
+#include <QtQml/private/qv4mm_p.h>
#include <QtCore/QHash>
#include <QtCore/private/qnumeric_p.h>
@@ -91,18 +54,14 @@ bool String::virtualIsEqualTo(Managed *t, Managed *o)
void Heap::String::init(const QString &t)
{
- Base::init();
-
+ QString mutableText(t);
+ StringOrSymbol::init(mutableText.data_ptr());
subtype = String::StringType_Unknown;
-
- text = const_cast<QString &>(t).data_ptr();
- text->ref.ref();
}
void Heap::ComplexString::init(String *l, String *r)
{
- Base::init();
-
+ StringOrSymbol::init();
subtype = String::StringType_AddedString;
left = l;
@@ -125,7 +84,7 @@ void Heap::ComplexString::init(String *l, String *r)
void Heap::ComplexString::init(Heap::String *ref, int from, int len)
{
Q_ASSERT(ref->length() >= from + len);
- Base::init();
+ StringOrSymbol::init();
subtype = String::StringType_SubString;
@@ -136,11 +95,11 @@ void Heap::ComplexString::init(Heap::String *ref, int from, int len)
void Heap::StringOrSymbol::destroy()
{
- if (text) {
- internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(-text->size) * (int)sizeof(QChar));
- if (!text->ref.deref())
- QStringData::deallocate(text);
+ if (subtype < Heap::String::StringType_AddedString) {
+ internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(
+ qptrdiff(-text()->size) * qptrdiff(sizeof(QChar)));
}
+ text().~QStringPrivate();
Base::destroy();
}
@@ -164,27 +123,27 @@ uint String::toUInt(bool *ok) const
void String::createPropertyKeyImpl() const
{
- if (!d()->text)
+ if (d()->subtype >= Heap::String::StringType_AddedString)
d()->simplifyString();
- Q_ASSERT(d()->text);
+ Q_ASSERT(d()->subtype < Heap::String::StringType_AddedString);
engine()->identifierTable->asPropertyKey(this);
}
void Heap::String::simplifyString() const
{
- Q_ASSERT(!text);
+ Q_ASSERT(subtype >= StringType_AddedString);
int l = length();
QString result(l, Qt::Uninitialized);
QChar *ch = const_cast<QChar *>(result.constData());
append(this, ch);
- text = result.data_ptr();
- text->ref.ref();
+ text() = result.data_ptr();
const ComplexString *cs = static_cast<const ComplexString *>(this);
identifier = PropertyKey::invalid();
cs->left = cs->right = nullptr;
- internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(text->size) * (qptrdiff)sizeof(QChar));
+ internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(
+ qptrdiff(text().size) * qptrdiff(sizeof(QChar)));
subtype = StringType_Unknown;
}
@@ -206,43 +165,58 @@ bool Heap::String::startsWithUpper() const
offset = cs->from;
}
Q_ASSERT(str->subtype < Heap::String::StringType_Complex);
- return str->text->size > offset && QChar::isUpper(str->text->data()[offset]);
+ return str->text().size > offset && QChar::isUpper(str->text().data()[offset]);
}
void Heap::String::append(const String *data, QChar *ch)
{
- std::vector<const String *> worklist;
+ // in-order visitation with explicit stack
+ // where leaf nodes are "real" strings that get appended to ch
+
+ enum StatusTag : bool { NotVisited, Visited };
+ using Pointer = QTaggedPointer<const String, StatusTag>;
+
+ std::vector<Pointer> worklist;
worklist.reserve(32);
- worklist.push_back(data);
+ worklist.push_back(Pointer(data));
while (!worklist.empty()) {
- const String *item = worklist.back();
- worklist.pop_back();
+ Pointer item = worklist.back();
+ if (item.tag() == Visited) {
+ Q_ASSERT(item->subtype == StringType_AddedString);
+ const ComplexString *cs = static_cast<const ComplexString *>(item.data());
+ worklist.pop_back();
+ worklist.push_back(Pointer(cs->right));
+ continue;
+ }
if (item->subtype == StringType_AddedString) {
- const ComplexString *cs = static_cast<const ComplexString *>(item);
- worklist.push_back(cs->right);
- worklist.push_back(cs->left);
+ // we need to keep the node in the worklist, as we still need to handle "right"
+ worklist.back().setTag(Visited);
+ const ComplexString *cs = static_cast<const ComplexString *>(item.data());
+ worklist.push_back(Pointer(cs->left));
} else if (item->subtype == StringType_SubString) {
- const ComplexString *cs = static_cast<const ComplexString *>(item);
+ worklist.pop_back();
+ const ComplexString *cs = static_cast<const ComplexString *>(item.data());
memcpy(ch, cs->left->toQString().constData() + cs->from, cs->len*sizeof(QChar));
ch += cs->len;
} else {
- memcpy(static_cast<void *>(ch), static_cast<const void *>(item->text->data()), item->text->size * sizeof(QChar));
- ch += item->text->size;
+ worklist.pop_back();
+ memcpy(static_cast<void *>(ch), item->text().data(), item->text().size * sizeof(QChar));
+ ch += item->text().size;
}
}
}
void Heap::StringOrSymbol::createHashValue() const
{
- if (!text) {
+ if (subtype >= StringType_AddedString) {
Q_ASSERT(internalClass->vtable->isString);
static_cast<const Heap::String *>(this)->simplifyString();
}
- Q_ASSERT(text);
- const QChar *ch = reinterpret_cast<const QChar *>(text->data());
- const QChar *end = ch + text->size;
+ Q_ASSERT(subtype < StringType_AddedString);
+ const QChar *ch = reinterpret_cast<const QChar *>(text().data());
+ const QChar *end = ch + text().size;
stringHash = QV4::String::calculateHashValue(ch, end, &subtype);
}
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index 52fe09cd72..370baadc98 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4STRING_H
#define QV4STRING_H
@@ -65,7 +29,7 @@ struct PropertyKey;
namespace Heap {
-struct Q_QML_PRIVATE_EXPORT StringOrSymbol : Base
+struct Q_QML_EXPORT StringOrSymbol : Base
{
enum StringType {
StringType_Symbol,
@@ -77,7 +41,18 @@ struct Q_QML_PRIVATE_EXPORT StringOrSymbol : Base
StringType_Complex = StringType_AddedString
};
- mutable QStringData *text;
+ void init() {
+ Base::init();
+ new (&textStorage) QStringPrivate;
+ }
+
+ void init(QStringPrivate text)
+ {
+ Base::init();
+ new (&textStorage) QStringPrivate(std::move(text));
+ }
+
+ mutable struct { alignas(QStringPrivate) unsigned char data[sizeof(QStringPrivate)]; } textStorage;
mutable PropertyKey identifier;
mutable uint subtype;
mutable uint stringHash;
@@ -85,12 +60,11 @@ struct Q_QML_PRIVATE_EXPORT StringOrSymbol : Base
static void markObjects(Heap::Base *that, MarkStack *markStack);
void destroy();
+ QStringPrivate &text() const { return *reinterpret_cast<QStringPrivate *>(&textStorage); }
+
inline QString toQString() const {
- if (!text)
- return QString();
- QStringDataPtr ptr = { text };
- text->ref.ref();
- return QString(ptr);
+ QStringPrivate dd = text();
+ return QString(std::move(dd));
}
void createHashValue() const;
inline unsigned hashValue() const {
@@ -102,7 +76,7 @@ struct Q_QML_PRIVATE_EXPORT StringOrSymbol : Base
}
};
-struct Q_QML_PRIVATE_EXPORT String : StringOrSymbol {
+struct Q_QML_EXPORT String : StringOrSymbol {
static void markObjects(Heap::Base *that, MarkStack *markStack);
const VTable *vtable() const {
@@ -113,14 +87,12 @@ struct Q_QML_PRIVATE_EXPORT String : StringOrSymbol {
void simplifyString() const;
int length() const;
std::size_t retainedTextSize() const {
- return subtype >= StringType_Complex ? 0 : (std::size_t(text->size) * sizeof(QChar));
+ return subtype >= StringType_Complex ? 0 : (std::size_t(text().size) * sizeof(QChar));
}
inline QString toQString() const {
if (subtype >= StringType_Complex)
simplifyString();
- QStringDataPtr ptr = { text };
- text->ref.ref();
- return QString(ptr);
+ return StringOrSymbol::toQString();
}
inline bool isEqualTo(const String *other) const {
if (this == other)
@@ -141,7 +113,7 @@ struct Q_QML_PRIVATE_EXPORT String : StringOrSymbol {
private:
static void append(const String *data, QChar *ch);
};
-Q_STATIC_ASSERT(std::is_trivial< String >::value);
+Q_STATIC_ASSERT(std::is_trivial_v<String>);
struct ComplexString : String {
void init(String *l, String *n);
@@ -154,16 +126,17 @@ struct ComplexString : String {
};
int len;
};
-Q_STATIC_ASSERT(std::is_trivial< ComplexString >::value);
+Q_STATIC_ASSERT(std::is_trivial_v<ComplexString>);
inline
int String::length() const {
- return text ? text->size : static_cast<const ComplexString *>(this)->len;
+ // TODO: ensure that our strings never actually grow larger than INT_MAX
+ return subtype < StringType_AddedString ? int(text().size) : static_cast<const ComplexString *>(this)->len;
}
}
-struct Q_QML_PRIVATE_EXPORT StringOrSymbol : public Managed {
+struct Q_QML_EXPORT StringOrSymbol : public Managed {
V4_MANAGED(StringOrSymbol, Managed)
V4_NEEDS_DESTROY
enum {
@@ -182,7 +155,7 @@ public:
}
};
-struct Q_QML_PRIVATE_EXPORT String : public StringOrSymbol {
+struct Q_QML_EXPORT String : public StringOrSymbol {
V4_MANAGED(String, StringOrSymbol)
Q_MANAGED_TYPE(String)
V4_INTERNALCLASS(String)
@@ -222,6 +195,12 @@ struct Q_QML_PRIVATE_EXPORT String : public StringOrSymbol {
return calculateHashValue(ch, end, subtype);
}
+ static uint createHashValueDisallowingArrayIndex(const QChar *ch, int length, uint *subtype)
+ {
+ const QChar *end = ch + length;
+ return calculateHashValue<String::DisallowArrayIndex>(ch, end, subtype);
+ }
+
static uint createHashValue(const char *ch, int length, uint *subtype)
{
const char *end = ch + length;
@@ -235,15 +214,19 @@ protected:
static qint64 virtualGetLength(const Managed *m);
public:
- template <typename T>
+ enum IndicesBehavior {Default, DisallowArrayIndex};
+ template <IndicesBehavior Behavior = Default, typename T>
static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype)
{
// array indices get their number as hash value
- uint h = stringToArrayIndex(ch, end);
- if (h != UINT_MAX) {
- if (subtype)
- *subtype = Heap::StringOrSymbol::StringType_ArrayIndex;
- return h;
+ uint h = UINT_MAX;
+ if constexpr (Behavior != DisallowArrayIndex) {
+ h = stringToArrayIndex(ch, end);
+ if (h != UINT_MAX) {
+ if (subtype)
+ *subtype = Heap::StringOrSymbol::StringType_ArrayIndex;
+ return h;
+ }
}
while (ch < end) {
@@ -252,7 +235,7 @@ public:
}
if (subtype)
- *subtype = (charToUInt(ch) == '@') ? Heap::StringOrSymbol::StringType_Symbol : Heap::StringOrSymbol::StringType_Regular;
+ *subtype = (ch != end && charToUInt(ch) == '@') ? Heap::StringOrSymbol::StringType_Symbol : Heap::StringOrSymbol::StringType_Regular;
return h;
}
};
diff --git a/src/qml/jsruntime/qv4stringiterator.cpp b/src/qml/jsruntime/qv4stringiterator.cpp
index 62db83ff26..9cb2711efb 100644
--- a/src/qml/jsruntime/qv4stringiterator.cpp
+++ b/src/qml/jsruntime/qv4stringiterator.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Crimson AS <info@crimson.no>
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 Crimson AS <info@crimson.no>
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qv4iterator_p.h>
#include <private/qv4stringiterator_p.h>
@@ -71,7 +35,7 @@ ReturnedValue StringIteratorPrototype::method_next(const FunctionObject *b, cons
quint32 index = thisObject->d()->nextIndex;
QString str = s->toQString();
- quint32 len = str.length();
+ quint32 len = str.size();
if (index >= len) {
thisObject->d()->iteratedString.set(scope.engine, nullptr);
diff --git a/src/qml/jsruntime/qv4stringiterator_p.h b/src/qml/jsruntime/qv4stringiterator_p.h
index 672ccc9963..742b8a895d 100644
--- a/src/qml/jsruntime/qv4stringiterator_p.h
+++ b/src/qml/jsruntime/qv4stringiterator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4STRINGITERATOR_P_H
#define QV4STRINGITERATOR_P_H
@@ -66,7 +30,7 @@ namespace Heap {
Member(class, NoMark, quint32, nextIndex)
DECLARE_HEAP_OBJECT(StringIteratorObject, Object) {
- DECLARE_MARKOBJECTS(StringIteratorObject);
+ DECLARE_MARKOBJECTS(StringIteratorObject)
void init(String *str, QV4::ExecutionEngine *engine)
{
Object::init();
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 9b4a2d575e..ad3c39c7b9 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -1,47 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4stringobject_p.h"
#include "qv4regexp_p.h"
#include "qv4regexpobject_p.h"
-#include "qv4objectproto_p.h"
#include <private/qv4mm_p.h>
#include "qv4scopedvalue_p.h"
#include "qv4symbol_p.h"
@@ -51,6 +14,7 @@
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QStringList>
+#include <QtQml/private/qv4runtime_p.h>
#include <cassert>
@@ -62,10 +26,11 @@
# include "qplatformdefs.h"
# endif
#else
-# include <windows.h>
+# include <qt_windows.h>
#endif
using namespace QV4;
+using namespace Qt::Literals::StringLiterals;
DEFINE_OBJECT_VTABLE(StringObject);
@@ -87,7 +52,7 @@ void Heap::StringObject::init(const QV4::String *str)
Heap::String *Heap::StringObject::getIndex(uint index) const
{
QString str = string->toQString();
- if (index >= (uint)str.length())
+ if (index >= (uint)str.size())
return nullptr;
return internalClass->engine->newString(str.mid(index, 1));
}
@@ -103,7 +68,7 @@ bool StringObject::virtualDeleteProperty(Managed *m, PropertyKey id)
if (id.isArrayIndex()) {
StringObject *o = static_cast<StringObject *>(m);
uint index = id.asArrayIndex();
- if (index < static_cast<uint>(o->d()->string->toQString().length()))
+ if (index < static_cast<uint>(o->d()->string->toQString().size()))
return false;
}
return Object::virtualDeleteProperty(m, id);
@@ -119,7 +84,7 @@ struct StringObjectOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
PropertyKey StringObjectOwnPropertyKeyIterator::next(const QV4::Object *o, Property *pd, PropertyAttributes *attrs)
{
const StringObject *s = static_cast<const StringObject *>(o);
- uint slen = s->d()->string->toQString().length();
+ uint slen = s->d()->string->toQString().size();
if (arrayIndex < slen) {
uint index = arrayIndex;
++arrayIndex;
@@ -155,7 +120,7 @@ PropertyAttributes StringObject::virtualGetOwnProperty(const Managed *m, Propert
if (id.isArrayIndex()) {
const uint index = id.asArrayIndex();
const auto s = static_cast<const StringObject *>(m);
- if (index < uint(s->d()->string->toQString().length())) {
+ if (index < uint(s->d()->string->toQString().size())) {
if (p)
p->value = s->getIndex(index);
return Attr_NotConfigurable|Attr_NotWritable;
@@ -208,7 +173,6 @@ ReturnedValue StringCtor::method_fromCharCode(const FunctionObject *b, const Val
*ch = QChar(argv[i].toUInt16());
++ch;
}
- *ch = 0;
return Encode(b->engine()->newString(str));
}
@@ -231,11 +195,10 @@ ReturnedValue StringCtor::method_fromCodePoint(const FunctionObject *f, const Va
++ch;
*ch = QChar::lowSurrogate(cp);
} else {
- *ch = cp;
+ *ch = QChar(cp);
}
++ch;
}
- *ch = 0;
result.truncate(ch - result.constData());
return e->newString(result)->asReturnedValue();
}
@@ -268,14 +231,14 @@ ReturnedValue StringCtor::method_raw(const FunctionObject *f, const Value *, con
while (1) {
val = raw->get(nextIndex);
result += val->toQString();
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
if (nextIndex + 1 == literalSegments)
return scope.engine->newString(result)->asReturnedValue();
if (nextIndex < static_cast<uint>(argc))
result += argv[nextIndex].toQString();
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
++nextIndex;
}
@@ -371,12 +334,12 @@ ReturnedValue StringPrototype::method_charAt(const FunctionObject *b, const Valu
if (v4->hasException)
return QV4::Encode::undefined();
- int pos = 0;
+ double pos = 0;
if (argc > 0)
- pos = (int) argv[0].toInteger();
+ pos = argv[0].toInteger();
QString result;
- if (pos >= 0 && pos < str.length())
+ if (pos >= 0 && pos < str.size())
result += str.at(pos);
return Encode(v4->newString(result));
@@ -389,12 +352,12 @@ ReturnedValue StringPrototype::method_charCodeAt(const FunctionObject *b, const
if (v4->hasException)
return QV4::Encode::undefined();
- int pos = 0;
+ double pos = 0;
if (argc > 0)
- pos = (int) argv[0].toInteger();
+ pos = argv[0].toInteger();
- if (pos >= 0 && pos < str.length())
+ if (pos >= 0 && pos < str.size())
RETURN_RESULT(Encode(str.at(pos).unicode()));
return Encode(qt_qnan());
@@ -407,7 +370,7 @@ ReturnedValue StringPrototype::method_codePointAt(const FunctionObject *f, const
if (v4->hasException)
return QV4::Encode::undefined();
- int index = argc ? argv[0].toInteger() : 0;
+ double index = argc ? argv[0].toInteger() : 0.0;
if (v4->hasException)
return QV4::Encode::undefined();
@@ -457,14 +420,14 @@ ReturnedValue StringPrototype::method_endsWith(const FunctionObject *b, const Va
if (v4->hasException)
return Encode::undefined();
- int pos = value.length();
+ double pos = value.size();
if (argc > 1)
- pos = (int) argv[1].toInteger();
+ pos = argv[1].toInteger();
- if (pos == value.length())
+ if (pos == value.size())
RETURN_RESULT(Encode(value.endsWith(searchString)));
- QStringRef stringToSearch = value.leftRef(pos);
+ QStringView stringToSearch = QStringView{value}.left(pos);
return Encode(stringToSearch.endsWith(searchString));
}
@@ -479,13 +442,13 @@ ReturnedValue StringPrototype::method_indexOf(const FunctionObject *b, const Val
if (v4->hasException)
return Encode::undefined();
- int pos = 0;
+ double pos = 0;
if (argc > 1)
- pos = (int) argv[1].toInteger();
+ pos = argv[1].toInteger();
int index = -1;
- if (! value.isEmpty())
- index = value.indexOf(searchString, qMin(qMax(pos, 0), value.length()));
+ if (!value.isEmpty())
+ index = value.indexOf(searchString, qMin(qMax(pos, 0.0), double(value.size())));
return Encode(index);
}
@@ -503,18 +466,18 @@ ReturnedValue StringPrototype::method_includes(const FunctionObject *b, const Va
if (v4->hasException)
return Encode::undefined();
- int pos = 0;
+ double pos = 0;
if (argc > 1) {
const Value &posArg = argv[1];
- pos = (int) posArg.toInteger();
+ pos = posArg.toInteger();
if (!posArg.isInteger() && posArg.isNumber() && qIsInf(posArg.toNumber()))
- pos = value.length();
+ pos = value.size();
}
if (pos == 0)
RETURN_RESULT(Encode(value.contains(searchString)));
- QStringRef stringToSearch = value.midRef(pos);
+ QStringView stringToSearch = QStringView{value}.mid(pos);
return Encode(stringToSearch.contains(searchString));
}
@@ -533,10 +496,10 @@ ReturnedValue StringPrototype::method_lastIndexOf(const FunctionObject *b, const
if (std::isnan(position))
position = +qInf();
else
- position = trunc(position);
+ position = std::trunc(position);
- int pos = trunc(qMin(qMax(position, 0.0), double(value.length())));
- if (!searchString.isEmpty() && pos == value.length())
+ int pos = std::trunc(qMin(qMax(position, 0.0), double(value.size())));
+ if (!searchString.isEmpty() && pos == value.size())
--pos;
if (searchString.isNull() && pos == 0)
RETURN_RESULT(Encode(-1));
@@ -571,7 +534,7 @@ ReturnedValue StringPrototype::method_match(const FunctionObject *b, const Value
ScopedFunctionObject fo(scope, f);
if (!fo)
return scope.engine->throwTypeError();
- return fo->call(r, thisObject, 1);
+ return checkedResult(scope.engine, fo->call(r, thisObject, 1));
}
}
@@ -591,7 +554,7 @@ ReturnedValue StringPrototype::method_match(const FunctionObject *b, const Value
ScopedFunctionObject match(scope, that->get(scope.engine->symbol_match()));
if (!match)
return scope.engine->throwTypeError();
- return match->call(that, s, 1);
+ return checkedResult(scope.engine, match->call(that, s, 1));
}
ReturnedValue StringPrototype::method_normalize(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
@@ -634,10 +597,10 @@ ReturnedValue StringPrototype::method_padEnd(const FunctionObject *f, const Valu
if (!argc)
return s->asReturnedValue();
- int maxLen = argv[0].toInteger();
+ double maxLen = argv[0].toInteger();
if (maxLen <= s->d()->length())
return s->asReturnedValue();
- QString fillString = (argc > 1 && !argv[1].isUndefined()) ? argv[1].toQString() : QString::fromLatin1(" ");
+ QString fillString = (argc > 1 && !argv[1].isUndefined()) ? argv[1].toQString() : u" "_s;
if (v4->hasException)
return Encode::undefined();
@@ -645,17 +608,17 @@ ReturnedValue StringPrototype::method_padEnd(const FunctionObject *f, const Valu
return s->asReturnedValue();
QString padded = s->toQString();
- int oldLength = padded.length();
+ int oldLength = padded.size();
int toFill = maxLen - oldLength;
padded.resize(maxLen);
QChar *ch = padded.data() + oldLength;
while (toFill) {
- int copy = qMin(fillString.length(), toFill);
+ int copy = qMin(fillString.size(), toFill);
memcpy(ch, fillString.constData(), copy*sizeof(QChar));
toFill -= copy;
ch += copy;
}
- *ch = 0;
+ *ch = QChar::Null;
return v4->newString(padded)->asReturnedValue();
}
@@ -673,10 +636,10 @@ ReturnedValue StringPrototype::method_padStart(const FunctionObject *f, const Va
if (!argc)
return s->asReturnedValue();
- int maxLen = argv[0].toInteger();
+ double maxLen = argv[0].toInteger();
if (maxLen <= s->d()->length())
return s->asReturnedValue();
- QString fillString = (argc > 1 && !argv[1].isUndefined()) ? argv[1].toQString() : QString::fromLatin1(" ");
+ QString fillString = (argc > 1 && !argv[1].isUndefined()) ? argv[1].toQString() : u" "_s;
if (v4->hasException)
return Encode::undefined();
@@ -684,20 +647,20 @@ ReturnedValue StringPrototype::method_padStart(const FunctionObject *f, const Va
return s->asReturnedValue();
QString original = s->toQString();
- int oldLength = original.length();
+ int oldLength = original.size();
int toFill = maxLen - oldLength;
QString padded;
padded.resize(maxLen);
QChar *ch = padded.data();
while (toFill) {
- int copy = qMin(fillString.length(), toFill);
+ int copy = qMin(fillString.size(), toFill);
memcpy(ch, fillString.constData(), copy*sizeof(QChar));
toFill -= copy;
ch += copy;
}
memcpy(ch, original.constData(), oldLength*sizeof(QChar));
ch += oldLength;
- *ch = 0;
+ *ch = QChar::Null;
return v4->newString(padded)->asReturnedValue();
}
@@ -720,9 +683,9 @@ ReturnedValue StringPrototype::method_repeat(const FunctionObject *b, const Valu
static void appendReplacementString(QString *result, const QString &input, const QString& replaceValue, uint* matchOffsets, int captureCount)
{
- result->reserve(result->length() + replaceValue.length());
- for (int i = 0; i < replaceValue.length(); ++i) {
- if (replaceValue.at(i) == QLatin1Char('$') && i < replaceValue.length() - 1) {
+ result->reserve(result->size() + replaceValue.size());
+ for (int i = 0; i < replaceValue.size(); ++i) {
+ if (replaceValue.at(i) == QLatin1Char('$') && i < replaceValue.size() - 1) {
ushort ch = replaceValue.at(i + 1).unicode();
uint substStart = JSC::Yarr::offsetNoMatch;
uint substEnd = JSC::Yarr::offsetNoMatch;
@@ -741,12 +704,12 @@ static void appendReplacementString(QString *result, const QString &input, const
skip = 1;
} else if (ch == '\'') {
substStart = matchOffsets[1];
- substEnd = input.length();
+ substEnd = input.size();
skip = 1;
} else if (ch >= '0' && ch <= '9') {
uint capture = ch - '0';
skip = 1;
- if (i < replaceValue.length() - 2) {
+ if (i < replaceValue.size() - 2) {
ch = replaceValue.at(i + 2).unicode();
if (ch >= '0' && ch <= '9') {
uint c = capture*10 + ch - '0';
@@ -765,7 +728,7 @@ static void appendReplacementString(QString *result, const QString &input, const
}
i += skip;
if (substStart != JSC::Yarr::offsetNoMatch && substEnd != JSC::Yarr::offsetNoMatch)
- *result += input.midRef(substStart, substEnd - substStart);
+ *result += QStringView{input}.mid(substStart, substEnd - substStart);
else if (skip == 0) // invalid capture reference. Taken as literal value
*result += replaceValue.at(i);
} else {
@@ -831,7 +794,7 @@ ReturnedValue StringPrototype::method_replace(const FunctionObject *b, const Val
if (idx != -1) {
numStringMatches = 1;
matchOffsets[0] = idx;
- matchOffsets[1] = idx + searchString.length();
+ matchOffsets[1] = idx + searchString.size();
}
}
@@ -840,7 +803,7 @@ ReturnedValue StringPrototype::method_replace(const FunctionObject *b, const Val
ScopedValue replaceValue(scope, argc > 1 ? argv[1] : Value::undefinedValue());
ScopedFunctionObject searchCallback(scope, replaceValue);
if (!!searchCallback) {
- result.reserve(string.length() + 10*numStringMatches);
+ result.reserve(string.size() + 10*numStringMatches);
ScopedValue entry(scope);
Value *arguments = scope.alloc(numCaptures + 2);
int lastEnd = 0;
@@ -862,14 +825,15 @@ ReturnedValue StringPrototype::method_replace(const FunctionObject *b, const Val
Value that = Value::undefinedValue();
replacement = searchCallback->call(&that, arguments, numCaptures + 2);
- result += string.midRef(lastEnd, matchStart - lastEnd);
+ CHECK_EXCEPTION();
+ result += QStringView{string}.mid(lastEnd, matchStart - lastEnd);
result += replacement->toQString();
lastEnd = matchEnd;
}
- result += string.midRef(lastEnd);
+ result += QStringView{string}.mid(lastEnd);
} else {
QString newString = replaceValue->toQString();
- result.reserve(string.length() + numStringMatches*newString.size());
+ result.reserve(string.size() + numStringMatches*newString.size());
int lastEnd = 0;
for (int i = 0; i < numStringMatches; ++i) {
@@ -879,11 +843,11 @@ ReturnedValue StringPrototype::method_replace(const FunctionObject *b, const Val
if (matchStart == JSC::Yarr::offsetNoMatch)
continue;
- result += string.midRef(lastEnd, matchStart - lastEnd);
+ result += QStringView{string}.mid(lastEnd, matchStart - lastEnd);
appendReplacementString(&result, string, newString, matchOffsets + baseIndex, numCaptures);
lastEnd = matchEnd;
}
- result += string.midRef(lastEnd);
+ result += QStringView{string}.mid(lastEnd);
}
if (matchOffsets != _matchOffsets)
@@ -896,13 +860,13 @@ ReturnedValue StringPrototype::method_search(const FunctionObject *b, const Valu
{
Scope scope(b);
QString string = getThisString(scope.engine, thisObject);
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
Scoped<RegExpObject> regExp(scope, argc ? argv[0] : Value::undefinedValue());
if (!regExp) {
regExp = scope.engine->regExpCtor()->callAsConstructor(argv, 1);
- if (scope.engine->hasException)
+ if (scope.hasException())
return QV4::Encode::undefined();
Q_ASSERT(regExp);
@@ -1012,7 +976,7 @@ ReturnedValue StringPrototype::method_split(const FunctionObject *b, const Value
} else {
QString separator = separatorValue->toQString();
if (separator.isEmpty()) {
- for (uint i = 0; i < qMin(limit, uint(text.length())); ++i)
+ for (uint i = 0; i < qMin(limit, uint(text.size())); ++i)
array->push_back((s = scope.engine->newString(text.mid(i, 1))));
return array.asReturnedValue();
}
@@ -1044,14 +1008,14 @@ ReturnedValue StringPrototype::method_startsWith(const FunctionObject *b, const
if (v4->hasException)
return Encode::undefined();
- int pos = 0;
+ double pos = 0;
if (argc > 1)
- pos = (int) argv[1].toInteger();
+ pos = argv[1].toInteger();
if (pos == 0)
return Encode(value.startsWith(searchString));
- QStringRef stringToSearch = value.midRef(pos);
+ QStringView stringToSearch = QStringView{value}.mid(pos);
RETURN_RESULT(Encode(stringToSearch.startsWith(searchString)));
}
@@ -1070,7 +1034,7 @@ ReturnedValue StringPrototype::method_substr(const FunctionObject *b, const Valu
if (argc > 1)
length = argv[1].toInteger();
- double count = value.length();
+ double count = value.size();
if (start < 0)
start = qMax(count + start, 0.0);
@@ -1088,7 +1052,7 @@ ReturnedValue StringPrototype::method_substring(const FunctionObject *b, const V
if (v4->hasException)
return QV4::Encode::undefined();
- int length = value.length();
+ int length = value.size();
double start = 0;
double end = length;
@@ -1161,11 +1125,11 @@ ReturnedValue StringPrototype::method_trim(const FunctionObject *b, const Value
const QChar *chars = s.constData();
int start, end;
- for (start = 0; start < s.length(); ++start) {
+ for (start = 0; start < s.size(); ++start) {
if (!chars[start].isSpace() && chars[start].unicode() != 0xfeff)
break;
}
- for (end = s.length() - 1; end >= start; --end) {
+ for (end = s.size() - 1; end >= start; --end) {
if (!chars[end].isSpace() && chars[end].unicode() != 0xfeff)
break;
}
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index 794ee91575..451a989ef4 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4STRINGOBJECT_P_H
#define QV4STRINGOBJECT_P_H
@@ -64,7 +28,7 @@ namespace Heap {
Member(class, Pointer, String *, string)
DECLARE_HEAP_OBJECT(StringObject, Object) {
- DECLARE_MARKOBJECTS(StringObject);
+ DECLARE_MARKOBJECTS(StringObject)
enum {
LengthPropertyIndex = 0
diff --git a/src/qml/jsruntime/qv4symbol.cpp b/src/qml/jsruntime/qv4symbol.cpp
index 004a9938e2..5f7ec89fd2 100644
--- a/src/qml/jsruntime/qv4symbol.cpp
+++ b/src/qml/jsruntime/qv4symbol.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qv4symbol_p.h>
#include <qv4functionobject_p.h>
@@ -50,10 +14,9 @@ DEFINE_OBJECT_VTABLE(SymbolObject);
void Heap::Symbol::init(const QString &s)
{
Q_ASSERT(s.at(0) == QLatin1Char('@'));
- identifier = PropertyKey::fromStringOrSymbol(this);
QString desc(s);
- text = desc.data_ptr();
- text->ref.ref();
+ StringOrSymbol::init(desc.data_ptr());
+ identifier = PropertyKey::fromStringOrSymbol(internalClass->engine, this);
}
void Heap::SymbolCtor::init(QV4::ExecutionContext *scope)
@@ -88,7 +51,7 @@ ReturnedValue SymbolCtor::virtualCallAsConstructor(const FunctionObject *f, cons
ReturnedValue SymbolCtor::method_for(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
Scope scope(f);
- ScopedValue k(scope, argc ? argv[0]: Value::undefinedValue());
+ ScopedValue k(scope, argc ? argv[0] : Value::undefinedValue());
ScopedString key(scope, k->toString(scope.engine));
if (scope.hasException())
return Encode::undefined();
@@ -183,5 +146,5 @@ Heap::Symbol *Symbol::create(ExecutionEngine *e, const QString &s)
QString Symbol::descriptiveString() const
{
- return QLatin1String("Symbol(") + toQString().midRef(1) + QLatin1String(")");
+ return QLatin1String("Symbol(") + QStringView{toQString()}.mid(1) + QLatin1String(")");
}
diff --git a/src/qml/jsruntime/qv4symbol_p.h b/src/qml/jsruntime/qv4symbol_p.h
index c7e12b512b..e56510bd69 100644
--- a/src/qml/jsruntime/qv4symbol_p.h
+++ b/src/qml/jsruntime/qv4symbol_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4_SYMBOL_H
#define QV4_SYMBOL_H
@@ -72,7 +36,7 @@ struct Symbol : StringOrSymbol {
Member(class, Pointer, Symbol *, symbol)
DECLARE_HEAP_OBJECT(SymbolObject, Object) {
- DECLARE_MARKOBJECTS(SymbolObject);
+ DECLARE_MARKOBJECTS(SymbolObject)
void init(const QV4::Symbol *s);
};
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index 7d33167762..6c72eaba5f 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -1,47 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4typedarray_p.h"
#include "qv4arrayiterator_p.h"
#include "qv4arraybuffer_p.h"
-#include "qv4string_p.h"
-#include "qv4jscall_p.h"
#include "qv4symbol_p.h"
#include "qv4runtime_p.h"
#include <QtCore/qatomic.h>
@@ -63,7 +25,7 @@ static inline int toInt32(Value v)
Q_ASSERT(v.isNumber());
if (v.isInteger())
return v.integerValue();
- return Double::toInt32(v.doubleValue());
+ return QJSNumberCoercion::toInteger(v.doubleValue());
}
static inline double toDouble(Value v)
@@ -296,18 +258,21 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f,
if (!argc || !argv[0].isObject()) {
// ECMA 6 22.2.1.1
- qint64 l = argc ? argv[0].toIndex() : 0;
- if (scope.engine->hasException)
+ const double l = argc ? argv[0].toInteger() : 0;
+ if (scope.hasException())
return Encode::undefined();
- // ### lift UINT_MAX restriction
- if (l < 0 || l > UINT_MAX)
+ if (l < 0 || l > std::numeric_limits<int>::max())
+ return scope.engine->throwRangeError(QLatin1String("Index out of range."));
+
+ const double byteLength = l * operations[that->d()->type].bytesPerElement;
+
+ // TODO: This is an artificial restriction due to the fact that we store the byteLength in
+ // uint below. We should allow up to INT_MAX elements of any size.
+ if (byteLength > std::numeric_limits<uint>::max())
return scope.engine->throwRangeError(QLatin1String("Index out of range."));
- uint len = (uint)l;
- if (l != len)
- scope.engine->throwRangeError(QStringLiteral("Non integer length for typed array."));
- uint byteLength = len * operations[that->d()->type].bytesPerElement;
- Scoped<ArrayBuffer> buffer(scope, scope.engine->newArrayBuffer(byteLength));
- if (scope.engine->hasException)
+
+ Scoped<ArrayBuffer> buffer(scope, scope.engine->newArrayBuffer(size_t(byteLength)));
+ if (scope.hasException())
return Encode::undefined();
Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
@@ -322,15 +287,15 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f,
if (!!typedArray) {
// ECMA 6 22.2.1.2
Scoped<ArrayBuffer> buffer(scope, typedArray->d()->buffer);
- if (!buffer || buffer->isDetachedBuffer())
+ if (!buffer || buffer->hasDetachedArrayData())
return scope.engine->throwTypeError();
- uint srcElementSize = typedArray->d()->type->bytesPerElement;
+ uint srcElementSize = typedArray->bytesPerElement();
uint destElementSize = operations[that->d()->type].bytesPerElement;
- uint byteLength = typedArray->d()->byteLength;
+ uint byteLength = typedArray->byteLength();
uint destByteLength = byteLength*destElementSize/srcElementSize;
Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(destByteLength));
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
@@ -338,8 +303,8 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f,
array->d()->byteLength = destByteLength;
array->d()->byteOffset = 0;
- const char *src = buffer->d()->data->data() + typedArray->d()->byteOffset;
- char *dest = newBuffer->d()->data->data();
+ const char *src = buffer->constArrayData() + typedArray->byteOffset();
+ char *dest = newBuffer->arrayData();
// check if src and new type have the same size. In that case we can simply memcpy the data
if (srcElementSize == destElementSize) {
@@ -365,27 +330,27 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f,
double dbyteOffset = argc > 1 ? argv[1].toInteger() : 0;
- if (buffer->isDetachedBuffer())
+ if (buffer->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint byteOffset = (uint)dbyteOffset;
uint elementSize = operations[that->d()->type].bytesPerElement;
- if (dbyteOffset < 0 || (byteOffset % elementSize) || dbyteOffset > buffer->byteLength())
+ if (dbyteOffset < 0 || (byteOffset % elementSize) || dbyteOffset > buffer->arrayDataLength())
return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid byteOffset"));
uint byteLength;
if (argc < 3 || argv[2].isUndefined()) {
- byteLength = buffer->byteLength() - byteOffset;
- if (buffer->byteLength() < byteOffset || byteLength % elementSize)
+ byteLength = buffer->arrayDataLength() - byteOffset;
+ if (buffer->arrayDataLength() < byteOffset || byteLength % elementSize)
return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
} else {
double l = qBound(0., argv[2].toInteger(), (double)UINT_MAX);
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
- if (buffer->isDetachedBuffer())
+ if (buffer->hasDetachedArrayData())
return scope.engine->throwTypeError();
l *= elementSize;
- if (buffer->byteLength() - byteOffset < l)
+ if (buffer->arrayDataLength() - byteOffset < l)
return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length"));
byteLength = (uint)l;
}
@@ -403,15 +368,15 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f,
ScopedObject o(scope, argc ? argv[0] : Value::undefinedValue());
uint l = (uint) qBound(0., ScopedValue(scope, o->get(scope.engine->id_length()))->toInteger(), (double)UINT_MAX);
- if (scope.engine->hasException)
+ if (scope.hasException())
return scope.engine->throwTypeError();
uint elementSize = operations[that->d()->type].bytesPerElement;
size_t bufferSize;
- if (mul_overflow(size_t(l), size_t(elementSize), &bufferSize))
+ if (qMulOverflow(size_t(l), size_t(elementSize), &bufferSize))
return scope.engine->throwRangeError(QLatin1String("new TypedArray: invalid length"));
Scoped<ArrayBuffer> newBuffer(scope, scope.engine->newArrayBuffer(bufferSize));
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
@@ -420,15 +385,15 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f,
array->d()->byteOffset = 0;
uint idx = 0;
- char *b = newBuffer->d()->data->data();
+ char *b = newBuffer->arrayData();
ScopedValue val(scope);
while (idx < l) {
val = o->get(idx);
val = val->convertedToNumber();
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
array->d()->type->write(b, val);
- if (scope.engine->hasException)
+ if (scope.hasException())
return Encode::undefined();
++idx;
b += elementSize;
@@ -465,7 +430,7 @@ ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Val
Scope scope(static_cast<const Object *>(m)->engine());
Scoped<TypedArray> a(scope, static_cast<const TypedArray *>(m));
- if (a->d()->buffer->isDetachedBuffer())
+ if (a->hasDetachedArrayData())
return scope.engine->throwTypeError();
if (!isArrayIndex || id.asArrayIndex() >= a->length()) {
@@ -474,13 +439,13 @@ ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Val
return Encode::undefined();
}
- uint bytesPerElement = a->d()->type->bytesPerElement;
- uint byteOffset = a->d()->byteOffset + id.asArrayIndex() * bytesPerElement;
- Q_ASSERT(byteOffset + bytesPerElement <= (uint)a->d()->buffer->byteLength());
+ uint bytesPerElement = a->bytesPerElement();
+ uint byteOffset = a->byteOffset() + id.asArrayIndex() * bytesPerElement;
+ Q_ASSERT(byteOffset + bytesPerElement <= a->arrayDataLength());
if (hasProperty)
*hasProperty = true;
- return a->d()->type->read(a->d()->buffer->data->data() + byteOffset);
+ return a->d()->type->read(a->constArrayData() + byteOffset);
}
bool TypedArray::virtualHasProperty(const Managed *m, PropertyKey id)
@@ -490,7 +455,7 @@ bool TypedArray::virtualHasProperty(const Managed *m, PropertyKey id)
return Object::virtualHasProperty(m, id);
const TypedArray *a = static_cast<const TypedArray *>(m);
- if (a->d()->buffer->isDetachedBuffer()) {
+ if (a->hasDetachedArrayData()) {
a->engine()->throwTypeError();
return false;
}
@@ -521,7 +486,7 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu
Scope scope(v4);
Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m));
- if (a->d()->buffer->isDetachedBuffer())
+ if (a->hasDetachedArrayData())
return scope.engine->throwTypeError();
if (!isArrayIndex)
@@ -531,14 +496,14 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu
if (index >= a->length())
return false;
- uint bytesPerElement = a->d()->type->bytesPerElement;
- uint byteOffset = a->d()->byteOffset + index * bytesPerElement;
- Q_ASSERT(byteOffset + bytesPerElement <= (uint)a->d()->buffer->byteLength());
+ uint bytesPerElement = a->bytesPerElement();
+ uint byteOffset = a->byteOffset() + index * bytesPerElement;
+ Q_ASSERT(byteOffset + bytesPerElement <= a->arrayDataLength());
Value v = Value::fromReturnedValue(value.convertedToNumber());
- if (scope.hasException() || a->d()->buffer->isDetachedBuffer())
+ if (scope.hasException() || a->hasDetachedArrayData())
return scope.engine->throwTypeError();
- a->d()->type->write(a->d()->buffer->data->data() + byteOffset, v);
+ a->d()->type->write(a->arrayData() + byteOffset, v);
return true;
}
@@ -564,12 +529,12 @@ bool TypedArray::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Prop
ExecutionEngine *engine = a->engine();
Value v = Value::fromReturnedValue(p->value.convertedToNumber());
- if (engine->hasException || a->d()->buffer->isDetachedBuffer())
+ if (engine->hasException || a->hasDetachedArrayData())
return engine->throwTypeError();
- uint bytesPerElement = a->d()->type->bytesPerElement;
- uint byteOffset = a->d()->byteOffset + index * bytesPerElement;
- Q_ASSERT(byteOffset + bytesPerElement <= (uint)a->d()->buffer->byteLength());
- a->d()->type->write(a->d()->buffer->data->data() + byteOffset, v);
+ uint bytesPerElement = a->bytesPerElement();
+ uint byteOffset = a->byteOffset() + index * bytesPerElement;
+ Q_ASSERT(byteOffset + bytesPerElement <= a->arrayDataLength());
+ a->d()->type->write(a->arrayData() + byteOffset, v);
}
return true;
}
@@ -638,10 +603,10 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_get_byteLength(const Function
if (!v)
return v4->throwTypeError();
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->hasDetachedArrayData())
return Encode(0);
- return Encode(v->d()->byteLength);
+ return Encode(v->byteLength());
}
ReturnedValue IntrinsicTypedArrayPrototype::method_get_byteOffset(const FunctionObject *b, const Value *thisObject, const Value *, int)
@@ -651,10 +616,10 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_get_byteOffset(const Function
if (!v)
return v4->throwTypeError();
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->hasDetachedArrayData())
return Encode(0);
- return Encode(v->d()->byteOffset);
+ return Encode(v->byteOffset());
}
ReturnedValue IntrinsicTypedArrayPrototype::method_get_length(const FunctionObject *b, const Value *thisObject, const Value *, int)
@@ -664,67 +629,66 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_get_length(const FunctionObje
if (!v)
return v4->throwTypeError();
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->hasDetachedArrayData())
return Encode(0);
- return Encode(v->d()->byteLength/v->d()->type->bytesPerElement);
+ return Encode(v->length());
}
ReturnedValue IntrinsicTypedArrayPrototype::method_copyWithin(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(f);
- Scoped<TypedArray> O(scope, thisObject);
- if (!O || O->d()->buffer->isDetachedBuffer())
+ Scoped<TypedArray> instance(scope, thisObject);
+ if (!instance || instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
if (!argc)
- return O->asReturnedValue();
+ return instance->asReturnedValue();
- qint64 len = static_cast<uint>(O->length());
+ const double len = instance->length();
+ Q_ASSERT(std::isfinite(len));
- qint64 to = static_cast<qint64>(argv[0].toInteger());
- if (to < 0)
- to = qMax(len + to, 0ll);
- else
- to = qMin(to, len);
+ const double target = argv[0].toInteger();
- qint64 from = (argc > 1) ? static_cast<qint64>(argv[1].toInteger()) : 0ll;
- if (from < 0)
- from = qMax(len + from, 0ll);
- else
- from = qMin(from, len);
-
- double fend = argv[2].toInteger();
- if (fend > len)
- fend = len;
- qint64 end = (argc > 2 && !argv[2].isUndefined()) ? static_cast<qint64>(fend) : len;
- if (end < 0)
- end = qMax(len + end, 0ll);
- else
- end = qMin(end, len);
+ const double start = (argc > 1)
+ ? argv[1].toInteger()
+ : 0;
- qint64 count = qMin(end - from, len - to);
+ const double end = (argc > 2 && !argv[2].isUndefined())
+ ? argv[2].toInteger()
+ : len;
- if (count <= 0)
- return O->asReturnedValue();
+ const double fin = end < 0
+ ? std::max(len + end, 0.0)
+ : std::min(end, len);
- if (O->d()->buffer->isDetachedBuffer())
- return scope.engine->throwTypeError();
+ const qsizetype from = start < 0
+ ? std::max(len + start, 0.0)
+ : std::min(start, len);
+
+ const qsizetype to = target < 0
+ ? std::max(len + target, 0.0)
+ : std::min(target, len);
+
+ const qsizetype count = std::min(fin - from, len - to);
+
+ if (count <= 0)
+ return instance->asReturnedValue();
if (from != to) {
- int elementSize = O->d()->type->bytesPerElement;
- char *data = O->d()->buffer->data->data() + O->d()->byteOffset;
- memmove(data + to*elementSize, data + from*elementSize, count*elementSize);
+ int elementSize = instance->bytesPerElement();
+ char *data = instance->arrayData() + instance->byteOffset();
+ memmove(data + to * elementSize, data + from * elementSize, count * elementSize);
}
- return O->asReturnedValue();
+ return instance->asReturnedValue();
}
ReturnedValue IntrinsicTypedArrayPrototype::method_entries(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
Scope scope(b);
Scoped<TypedArray> v(scope, thisObject);
- if (!v || v->d()->buffer->isDetachedBuffer())
+ if (!v || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
Scoped<ArrayIteratorObject> ao(scope, scope.engine->newArrayIteratorObject(v));
@@ -736,7 +700,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_every(const FunctionObject *b
{
Scope scope(b);
Scoped<TypedArray> v(scope, thisObject);
- if (!v || v->d()->buffer->isDetachedBuffer())
+ if (!v || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = v->length();
@@ -749,13 +713,13 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_every(const FunctionObject *b
ScopedValue r(scope);
Value *arguments = scope.alloc(3);
- const char *data = v->d()->buffer->data->data();
- uint bytesPerElement = v->d()->type->bytesPerElement;
- uint byteOffset = v->d()->byteOffset;
+ const char *data = v->constArrayData();
+ uint bytesPerElement = v->bytesPerElement();
+ uint byteOffset = v->byteOffset();
bool ok = true;
for (uint k = 0; ok && k < len; ++k) {
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->hasDetachedArrayData())
return scope.engine->throwTypeError();
arguments[0] = v->d()->type->read(data + byteOffset + k * bytesPerElement);
@@ -763,6 +727,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_every(const FunctionObject *b
arguments[1] = Value::fromDouble(k);
arguments[2] = v;
r = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
ok = r->toBoolean();
}
return Encode(ok);
@@ -772,7 +737,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_fill(const FunctionObject *b,
{
Scope scope(b);
Scoped<TypedArray> v(scope, thisObject);
- if (!v || v->d()->buffer->isDetachedBuffer())
+ if (!v || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = v->length();
@@ -799,12 +764,12 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_fill(const FunctionObject *b,
double val = argc ? argv[0].toNumber() : std::numeric_limits<double>::quiet_NaN();
Value value = Value::fromDouble(val);
- if (scope.hasException() || v->d()->buffer->isDetachedBuffer())
+ if (scope.hasException() || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
- char *data = v->d()->buffer->data->data();
- uint bytesPerElement = v->d()->type->bytesPerElement;
- uint byteOffset = v->d()->byteOffset;
+ char *data = v->arrayData();
+ uint bytesPerElement = v->bytesPerElement();
+ uint byteOffset = v->byteOffset();
while (k < fin) {
v->d()->type->write(data + byteOffset + k * bytesPerElement, value);
@@ -825,7 +790,7 @@ static TypedArray *typedArraySpeciesCreate(Scope &scope, const TypedArray *insta
Value *arguments = scope.alloc(1);
arguments[0] = Encode(len);
Scoped<TypedArray> a(scope, constructor->callAsConstructor(arguments, 1));
- if (!a || a->d()->buffer->isDetachedBuffer() || a->length() < len) {
+ if (!a || a->hasDetachedArrayData() || a->length() < len) {
scope.engine->throwTypeError();
return nullptr;
}
@@ -836,7 +801,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_filter(const FunctionObject *
{
Scope scope(b);
Scoped<TypedArray> instance(scope, thisObject);
- if (!instance || instance->d()->buffer->isDetachedBuffer())
+ if (!instance || instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = instance->length();
@@ -852,7 +817,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_filter(const FunctionObject *
uint to = 0;
for (uint k = 0; k < len; ++k) {
- if (instance->d()->buffer->isDetachedBuffer())
+ if (instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
bool exists;
arguments[0] = instance->get(k, &exists);
@@ -862,6 +827,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_filter(const FunctionObject *
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
selected = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
if (selected->toBoolean()) {
++arguments;
scope.alloc(1);
@@ -883,7 +849,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_find(const FunctionObject *b,
{
Scope scope(b);
Scoped<TypedArray> v(scope, thisObject);
- if (!v || v->d()->buffer->isDetachedBuffer())
+ if (!v || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = v->length();
@@ -898,7 +864,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_find(const FunctionObject *b,
ScopedValue that(scope, argc > 1 ? argv[1] : Value::undefinedValue());
for (uint k = 0; k < len; ++k) {
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->hasDetachedArrayData())
return scope.engine->throwTypeError();
arguments[0] = v->get(k);
CHECK_EXCEPTION();
@@ -919,7 +885,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_findIndex(const FunctionObjec
{
Scope scope(b);
Scoped<TypedArray> v(scope, thisObject);
- if (!v || v->d()->buffer->isDetachedBuffer())
+ if (!v || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = v->length();
@@ -934,7 +900,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_findIndex(const FunctionObjec
ScopedValue that(scope, argc > 1 ? argv[1] : Value::undefinedValue());
for (uint k = 0; k < len; ++k) {
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->hasDetachedArrayData())
return scope.engine->throwTypeError();
arguments[0] = v->get(k);
CHECK_EXCEPTION();
@@ -955,7 +921,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_forEach(const FunctionObject
{
Scope scope(b);
Scoped<TypedArray> v(scope, thisObject);
- if (!v || v->d()->buffer->isDetachedBuffer())
+ if (!v || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = v->length();
@@ -968,7 +934,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_forEach(const FunctionObject
Value *arguments = scope.alloc(3);
for (uint k = 0; k < len; ++k) {
- if (v->d()->buffer->isDetachedBuffer())
+ if (v->hasDetachedArrayData())
return scope.engine->throwTypeError();
bool exists;
arguments[0] = v->get(k, &exists);
@@ -987,7 +953,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_includes(const FunctionObject
{
Scope scope(b);
Scoped<TypedArray> v(scope, thisObject);
- if (!v || v->d()->buffer->isDetachedBuffer())
+ if (!v || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = v->length();
@@ -1025,7 +991,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_indexOf(const FunctionObject
{
Scope scope(b);
Scoped<TypedArray> v(scope, thisObject);
- if (!v || v->d()->buffer->isDetachedBuffer())
+ if (!v || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = v->length();
@@ -1068,58 +1034,51 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_indexOf(const FunctionObject
return Encode(-1);
}
-ReturnedValue IntrinsicTypedArrayPrototype::method_join(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue IntrinsicTypedArrayPrototype::method_join(
+ const FunctionObject *functionObject, const Value *thisObject, const Value *argv, int argc)
{
- Scope scope(b);
- Scoped<TypedArray> v(scope, thisObject);
- if (!v || v->d()->buffer->isDetachedBuffer())
+ Scope scope(functionObject);
+ Scoped<TypedArray> typedArray(scope, thisObject);
+ if (!typedArray || typedArray->hasDetachedArrayData())
return scope.engine->throwTypeError();
- uint len = v->length();
-
- ScopedValue arg(scope, argc ? argv[0] : Value::undefinedValue());
+ // We cannot optimize the resolution of the argument away if length is 0.
+ // It may have side effects.
+ ScopedValue argument(scope, argc ? argv[0] : Value::undefinedValue());
+ const QString separator = argument->isUndefined()
+ ? QStringLiteral(",")
+ : argument->toQString();
- QString r4;
- if (arg->isUndefined())
- r4 = QStringLiteral(",");
- else
- r4 = arg->toQString();
-
- const quint32 r2 = len;
-
- if (!r2)
+ const quint32 length = typedArray->length();
+ if (!length)
return Encode(scope.engine->newString());
- QString R;
+ QString result;
- //
- // crazy!
- //
ScopedString name(scope, scope.engine->newString(QStringLiteral("0")));
- ScopedValue r6(scope, v->get(name));
- if (!r6->isNullOrUndefined())
- R = r6->toQString();
+ ScopedValue value(scope, typedArray->get(name));
+ if (!value->isNullOrUndefined())
+ result = value->toQString();
- ScopedValue r12(scope);
- for (quint32 k = 1; k < r2; ++k) {
- R += r4;
+ for (quint32 i = 1; i < length; ++i) {
+ result += separator;
- name = Value::fromDouble(k).toString(scope.engine);
- r12 = v->get(name);
+ name = Value::fromDouble(i).toString(scope.engine);
+ value = typedArray->get(name);
CHECK_EXCEPTION();
- if (!r12->isNullOrUndefined())
- R += r12->toQString();
+ if (!value->isNullOrUndefined())
+ result += value->toQString();
}
- return Encode(scope.engine->newString(R));
+ return Encode(scope.engine->newString(result));
}
ReturnedValue IntrinsicTypedArrayPrototype::method_keys(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
Scope scope(b);
Scoped<TypedArray> v(scope, thisObject);
- if (!v || v->d()->buffer->isDetachedBuffer())
+ if (!v || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
Scoped<ArrayIteratorObject> ao(scope, scope.engine->newArrayIteratorObject(v));
@@ -1132,7 +1091,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_lastIndexOf(const FunctionObj
{
Scope scope(b);
Scoped<TypedArray> instance(scope, thisObject);
- if (!instance || instance->d()->buffer->isDetachedBuffer())
+ if (!instance || instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = instance->length();
@@ -1175,7 +1134,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_map(const FunctionObject *b,
{
Scope scope(b);
Scoped<TypedArray> instance(scope, thisObject);
- if (!instance || instance->d()->buffer->isDetachedBuffer())
+ if (!instance || instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = instance->length();
@@ -1194,13 +1153,14 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_map(const FunctionObject *b,
Value *arguments = scope.alloc(3);
for (uint k = 0; k < len; ++k) {
- if (instance->d()->buffer->isDetachedBuffer())
+ if (instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
arguments[0] = instance->get(k);
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
mapped = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
a->put(k, mapped);
}
return a->asReturnedValue();
@@ -1210,7 +1170,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduce(const FunctionObject *
{
Scope scope(b);
Scoped<TypedArray> instance(scope, thisObject);
- if (!instance || instance->d()->buffer->isDetachedBuffer())
+ if (!instance || instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = instance->length();
@@ -1240,7 +1200,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduce(const FunctionObject *
Value *arguments = scope.alloc(4);
while (k < len) {
- if (instance->d()->buffer->isDetachedBuffer())
+ if (instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
bool kPresent;
v = instance->get(k, &kPresent);
@@ -1250,6 +1210,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduce(const FunctionObject *
arguments[2] = Value::fromDouble(k);
arguments[3] = instance;
acc = callback->call(nullptr, arguments, 4);
+ CHECK_EXCEPTION();
}
++k;
}
@@ -1260,7 +1221,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduceRight(const FunctionObj
{
Scope scope(b);
Scoped<TypedArray> instance(scope, thisObject);
- if (!instance || instance->d()->buffer->isDetachedBuffer())
+ if (!instance || instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = instance->length();
@@ -1295,7 +1256,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduceRight(const FunctionObj
Value *arguments = scope.alloc(4);
while (k > 0) {
- if (instance->d()->buffer->isDetachedBuffer())
+ if (instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
bool kPresent;
v = instance->get(k - 1, &kPresent);
@@ -1305,6 +1266,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduceRight(const FunctionObj
arguments[2] = Value::fromDouble(k - 1);
arguments[3] = instance;
acc = callback->call(nullptr, arguments, 4);
+ CHECK_EXCEPTION();
}
--k;
}
@@ -1315,7 +1277,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reverse(const FunctionObject
{
Scope scope(b);
Scoped<TypedArray> instance(scope, thisObject);
- if (!instance || instance->d()->buffer->isDetachedBuffer())
+ if (!instance || instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint length = instance->length();
@@ -1342,7 +1304,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_some(const FunctionObject *b,
{
Scope scope(b);
Scoped<TypedArray> instance(scope, thisObject);
- if (!instance || instance->d()->buffer->isDetachedBuffer())
+ if (!instance || instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = instance->length();
@@ -1356,7 +1318,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_some(const FunctionObject *b,
Value *arguments = scope.alloc(3);
for (uint k = 0; k < len; ++k) {
- if (instance->d()->buffer->isDetachedBuffer())
+ if (instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
bool exists;
arguments[0] = instance->get(k, &exists);
@@ -1366,6 +1328,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_some(const FunctionObject *b,
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
result = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
if (result->toBoolean())
return Encode(true);
}
@@ -1377,7 +1340,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_values(const FunctionObject *
{
Scope scope(b);
Scoped<TypedArray> v(scope, thisObject);
- if (!v || v->d()->buffer->isDetachedBuffer())
+ if (!v || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
Scoped<ArrayIteratorObject> ao(scope, scope.engine->newArrayIteratorObject(v));
@@ -1394,45 +1357,46 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_set(const FunctionObject *b,
Scoped<ArrayBuffer> buffer(scope, a->d()->buffer);
double doffset = argc >= 2 ? argv[1].toInteger() : 0;
- if (scope.engine->hasException)
+ if (scope.hasException())
RETURN_UNDEFINED();
- if (!buffer || buffer->isDetachedBuffer())
+ if (!buffer || buffer->hasDetachedArrayData())
return scope.engine->throwTypeError();
if (doffset < 0 || doffset >= UINT_MAX)
RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")));
uint offset = (uint)doffset;
- uint elementSize = a->d()->type->bytesPerElement;
+ uint elementSize = a->bytesPerElement();
Scoped<TypedArray> srcTypedArray(scope, argv[0]);
if (!srcTypedArray) {
// src is a regular object
ScopedObject o(scope, argv[0].toObject(scope.engine));
- if (scope.engine->hasException || !o)
+ if (scope.hasException() || !o)
return scope.engine->throwTypeError();
double len = ScopedValue(scope, o->get(scope.engine->id_length()))->toNumber();
uint l = (uint)len;
- if (scope.engine->hasException || l != len)
+ if (scope.hasException() || l != len)
return scope.engine->throwTypeError();
- if (offset + l > a->length())
+ const uint aLength = a->length();
+ if (offset > aLength || l > aLength - offset)
RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")));
uint idx = 0;
- if (buffer->isDetachedBuffer())
+ if (buffer->hasDetachedArrayData())
return scope.engine->throwTypeError();
- char *b = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize;
+ char *b = buffer->arrayData() + a->byteOffset() + offset*elementSize;
ScopedValue val(scope);
while (idx < l) {
val = o->get(idx);
if (scope.hasException())
return Encode::undefined();
val = val->convertedToNumber();
- if (scope.hasException() || buffer->isDetachedBuffer())
+ if (scope.hasException() || buffer->hasDetachedArrayData())
return scope.engine->throwTypeError();
a->d()->type->write(b, val);
- if (scope.engine->hasException)
+ if (scope.hasException())
RETURN_UNDEFINED();
++idx;
b += elementSize;
@@ -1442,31 +1406,33 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_set(const FunctionObject *b,
// src is a typed array
Scoped<ArrayBuffer> srcBuffer(scope, srcTypedArray->d()->buffer);
- if (!srcBuffer || srcBuffer->isDetachedBuffer())
+ if (!srcBuffer || srcBuffer->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint l = srcTypedArray->length();
- if (offset + l > a->length())
+
+ const uint aLength = a->length();
+ if (offset > aLength || l > aLength - offset)
RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")));
- char *dest = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize;
- const char *src = srcBuffer->d()->data->data() + srcTypedArray->d()->byteOffset;
+ char *dest = buffer->arrayData() + a->byteOffset() + offset*elementSize;
+ const char *src = srcBuffer->d()->constArrayData() + srcTypedArray->byteOffset();
if (srcTypedArray->d()->type == a->d()->type) {
// same type of typed arrays, use memmove (as srcbuffer and buffer could be the same)
- memmove(dest, src, srcTypedArray->d()->byteLength);
+ memmove(dest, src, srcTypedArray->byteLength());
RETURN_UNDEFINED();
}
char *srcCopy = nullptr;
if (buffer->d() == srcBuffer->d()) {
// same buffer, need to take a temporary copy, to not run into problems
- srcCopy = new char[srcTypedArray->d()->byteLength];
- memcpy(srcCopy, src, srcTypedArray->d()->byteLength);
+ srcCopy = new char[srcTypedArray->byteLength()];
+ memcpy(srcCopy, src, srcTypedArray->byteLength());
src = srcCopy;
}
// typed arrays of different kind, need to manually loop
- uint srcElementSize = srcTypedArray->d()->type->bytesPerElement;
+ uint srcElementSize = srcTypedArray->bytesPerElement();
TypedArrayOperations::Read read = srcTypedArray->d()->type->read;
TypedArrayOperations::Write write = a->d()->type->write;
for (uint i = 0; i < l; ++i) {
@@ -1485,7 +1451,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_slice(const FunctionObject *b
{
Scope scope(b);
Scoped<TypedArray> instance(scope, thisObject);
- if (!instance || instance->d()->buffer->isDetachedBuffer())
+ if (!instance || instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = instance->length();
@@ -1517,10 +1483,10 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_slice(const FunctionObject *b
ScopedValue v(scope);
uint n = 0;
for (uint i = start; i < end; ++i) {
- if (instance->d()->buffer->isDetachedBuffer())
+ if (instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
v = instance->get(i);
- if (a->d()->buffer->isDetachedBuffer())
+ if (a->hasDetachedArrayData())
return scope.engine->throwTypeError();
a->put(n, v);
++n;
@@ -1552,7 +1518,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_subarray(const FunctionObject
if (end < begin)
end = begin;
- if (scope.engine->hasException)
+ if (scope.hasException())
RETURN_UNDEFINED();
int newLen = end - begin;
@@ -1563,10 +1529,10 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_subarray(const FunctionObject
Value *arguments = scope.alloc(3);
arguments[0] = buffer;
- arguments[1] = Encode(a->d()->byteOffset + begin*a->d()->type->bytesPerElement);
+ arguments[1] = Encode(a->byteOffset() + begin * a->bytesPerElement());
arguments[2] = Encode(newLen);
a = constructor->callAsConstructor(arguments, 3);
- if (!a || a->d()->buffer->isDetachedBuffer())
+ if (!a || a->hasDetachedArrayData())
return scope.engine->throwTypeError();
return a->asReturnedValue();
}
@@ -1575,7 +1541,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_toLocaleString(const Function
{
Scope scope(b);
Scoped<TypedArray> instance(scope, thisObject);
- if (!instance || instance->d()->buffer->isDetachedBuffer())
+ if (!instance || instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
uint len = instance->length();
@@ -1586,14 +1552,29 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_toLocaleString(const Function
ScopedValue v(scope);
ScopedString s(scope);
+ ScopedPropertyKey tolocaleString(scope, scope.engine->id_toLocaleString()->toPropertyKey());
+ Q_ASSERT(!scope.engine->hasException);
+
for (uint k = 0; k < len; ++k) {
- if (instance->d()->buffer->isDetachedBuffer())
+ if (instance->hasDetachedArrayData())
return scope.engine->throwTypeError();
if (k)
R += separator;
v = instance->get(k);
- v = Runtime::CallElement::call(scope.engine, v, *scope.engine->id_toLocaleString(), nullptr, 0);
+ Q_ASSERT(!v->isNullOrUndefined()); // typed array cannot hold null or undefined
+
+ ScopedObject valueAsObject(scope, v->toObject(scope.engine));
+ Q_ASSERT(valueAsObject); // only null or undefined cannot be converted to object
+
+ ScopedFunctionObject function(scope, valueAsObject->get(tolocaleString));
+ if (!function)
+ return scope.engine->throwTypeError();
+
+ v = function->call(valueAsObject, nullptr, 0);
+ if (scope.hasException())
+ return Encode::undefined();
+
s = v->toString(scope.engine);
if (scope.hasException())
return Encode::undefined();
@@ -1617,7 +1598,7 @@ static bool validateTypedArray(const Object *o)
const TypedArray *a = o->as<TypedArray>();
if (!a)
return false;
- if (a->d()->buffer->isDetachedBuffer())
+ if (a->hasDetachedArrayData())
return false;
return true;
}
@@ -1648,6 +1629,157 @@ ReturnedValue IntrinsicTypedArrayCtor::method_of(const FunctionObject *f, const
return newObj->asReturnedValue();
}
+ReturnedValue IntrinsicTypedArrayCtor::method_from(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(f);
+ ScopedObject itemsObject(scope, argv[0]);
+ bool usingIterator = false;
+
+ ScopedFunctionObject mapfn(scope, Value::undefinedValue());
+ Value *mapArguments = nullptr;
+ if (argc > 1) {
+ mapfn = ScopedFunctionObject(scope, argv[1]);
+ if (!mapfn)
+ return scope.engine->throwTypeError(QString::fromLatin1("%1 is not a function").arg(argv[1].toQStringNoThrow()));
+ mapArguments = scope.alloc(2);
+ }
+
+ // Iterator validity check goes after map function validity has been checked.
+ if (itemsObject) {
+ // If the object claims to support iterators, then let's try use them.
+ ScopedValue it(scope, itemsObject->get(scope.engine->symbol_iterator()));
+ CHECK_EXCEPTION();
+ if (!it->isNullOrUndefined()) {
+ ScopedFunctionObject itfunc(scope, it);
+ if (!itfunc)
+ return scope.engine->throwTypeError();
+ usingIterator = true;
+ }
+ }
+
+ ScopedValue thisArg(scope);
+ if (argc > 2)
+ thisArg = argv[2];
+
+ const FunctionObject *C = thisObject->as<FunctionObject>();
+
+ if (usingIterator) {
+ // Item iteration supported, so let's go ahead and try use that.
+ CHECK_EXCEPTION();
+
+ qint64 iterableLength = 0;
+ Value *nextValue = scope.alloc(1);
+ ScopedValue done(scope);
+
+ ScopedObject lengthIterator(scope, Runtime::GetIterator::call(scope.engine, itemsObject, true));
+ CHECK_EXCEPTION(); // symbol_iterator threw; whoops.
+ if (!lengthIterator) {
+ return scope.engine->throwTypeError(); // symbol_iterator wasn't an object.
+ }
+
+ forever {
+ // Here we calculate the length of the iterable range.
+ if (iterableLength > (static_cast<qint64>(1) << 53) - 1) {
+ ScopedValue error(scope, scope.engine->throwTypeError());
+ return Runtime::IteratorClose::call(scope.engine, lengthIterator);
+ }
+ // Retrieve the next value. If the iteration ends, we're done here.
+ done = Value::fromReturnedValue(Runtime::IteratorNext::call(scope.engine, lengthIterator, nextValue));
+ if (scope.hasException())
+ return Runtime::IteratorClose::call(scope.engine, lengthIterator);
+ if (done->toBoolean()) {
+ break;
+ }
+ iterableLength++;
+ }
+
+ // Constructor validity check goes after we have calculated the length, because that calculation can throw
+ // errors that are not type errors and at least the tests expect those rather than type errors.
+ if (!C || !C->isConstructor())
+ return scope.engine->throwTypeError();
+
+ ScopedObject iterator(scope, Runtime::GetIterator::call(scope.engine, itemsObject, true));
+ CHECK_EXCEPTION(); // symbol_iterator can throw.
+ if (!iterator) {
+ return scope.engine->throwTypeError(); // symbol_iterator wasn't an object.
+ }
+
+ ScopedObject a(scope, Value::undefinedValue());
+ ScopedValue ctorArgument(scope, Value::fromReturnedValue(QV4::Encode(int(iterableLength))));
+ a = C->callAsConstructor(ctorArgument, 1);
+ CHECK_EXCEPTION();
+
+ // We check exceptions above, and only after doing so, check the array's validity after construction.
+ if (!::validateTypedArray(a) || (a->getLength() < iterableLength))
+ return scope.engine->throwTypeError();
+
+
+ // The loop below traverses the iterator, and puts elements into the created array.
+ ScopedValue mappedValue(scope, Value::undefinedValue());
+ for (qint64 k = 0; k < iterableLength; ++k) {
+ done = Value::fromReturnedValue(Runtime::IteratorNext::call(scope.engine, iterator, nextValue));
+ if (scope.hasException())
+ return Runtime::IteratorClose::call(scope.engine, iterator);
+
+ if (mapfn) {
+ mapArguments[0] = *nextValue;
+ mapArguments[1] = Value::fromDouble(k);
+ mappedValue = mapfn->call(thisArg, mapArguments, 2);
+ if (scope.hasException())
+ return Runtime::IteratorClose::call(scope.engine, iterator);
+ } else {
+ mappedValue = *nextValue;
+ }
+
+ a->put(k, mappedValue);
+ if (scope.hasException())
+ return Runtime::IteratorClose::call(scope.engine, iterator);
+ }
+ return a.asReturnedValue();
+ } else {
+ // Array-like fallback. We request elements by index, and put them into the created array.
+ ScopedObject arrayLike(scope, argv[0].toObject(scope.engine));
+ if (!arrayLike)
+ return scope.engine->throwTypeError(QString::fromLatin1("Cannot convert %1 to object").arg(argv[0].toQStringNoThrow()));
+
+ int len = arrayLike->getLength();
+ CHECK_EXCEPTION();
+
+ // Getting the length may throw, and must do so before we check the constructor validity.
+ if (!C || !C->isConstructor())
+ return scope.engine->throwTypeError();
+
+ ScopedObject a(scope, Value::undefinedValue());
+ ScopedValue ctorArgument(scope, Value::fromReturnedValue(QV4::Encode(len)));
+ a = C->callAsConstructor(ctorArgument, 1);
+ CHECK_EXCEPTION();
+
+ // We check exceptions above, and only after doing so, check the array's validity after construction.
+ if (!::validateTypedArray(a) || (a->getLength() < len))
+ return scope.engine->throwTypeError();
+
+ ScopedValue mappedValue(scope, Value::undefinedValue());
+ ScopedValue kValue(scope);
+ for (int k = 0; k < len; ++k) {
+ kValue = arrayLike->get(k);
+ CHECK_EXCEPTION();
+
+ if (mapfn) {
+ mapArguments[0] = kValue;
+ mapArguments[1] = Value::fromDouble(k);
+ mappedValue = mapfn->call(thisArg, mapArguments, 2);
+ CHECK_EXCEPTION();
+ } else {
+ mappedValue = kValue;
+ }
+
+ a->put(k, mappedValue);
+ CHECK_EXCEPTION();
+ }
+ return a.asReturnedValue();
+ }
+}
+
void IntrinsicTypedArrayPrototype::init(ExecutionEngine *engine, IntrinsicTypedArrayCtor *ctor)
{
Scope scope(engine);
@@ -1657,6 +1789,8 @@ void IntrinsicTypedArrayPrototype::init(ExecutionEngine *engine, IntrinsicTypedA
ctor->defineReadonlyConfigurableProperty(engine->id_name(), s);
s = scope.engine->newString(QStringLiteral("of"));
ctor->defineDefaultProperty(s, IntrinsicTypedArrayCtor::method_of);
+ s = scope.engine->newString(QStringLiteral("from"));
+ ctor->defineDefaultProperty(s, IntrinsicTypedArrayCtor::method_from, 1);
ctor->addSymbolSpecies();
defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, nullptr);
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index 64792f23a2..9747eac411 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4TYPEDARRAY_H
#define QV4TYPEDARRAY_H
@@ -116,7 +80,7 @@ namespace Heap {
Member(class, NoMark, uint, arrayType)
DECLARE_HEAP_OBJECT(TypedArray, Object) {
- DECLARE_MARKOBJECTS(TypedArray);
+ DECLARE_MARKOBJECTS(TypedArray)
using Type = TypedArrayType;
void init(Type t);
@@ -142,25 +106,24 @@ struct TypedArrayPrototype : Object {
}
-struct Q_QML_PRIVATE_EXPORT TypedArray : Object
+struct Q_QML_EXPORT TypedArray : Object
{
V4_OBJECT2(TypedArray, Object)
static Heap::TypedArray *create(QV4::ExecutionEngine *e, Heap::TypedArray::Type t);
- uint byteLength() const {
- return d()->byteLength;
- }
-
- uint length() const {
- return d()->byteLength/d()->type->bytesPerElement;
- }
+ uint byteOffset() const noexcept { return d()->byteOffset; }
+ uint byteLength() const noexcept { return d()->byteLength; }
+ int bytesPerElement() const noexcept { return d()->type->bytesPerElement; }
+ uint length() const noexcept { return d()->byteLength / d()->type->bytesPerElement; }
- QTypedArrayData<char> *arrayData() {
- return d()->buffer->data;
- }
+ char *arrayData() noexcept { return d()->buffer->arrayData(); }
+ const char *constArrayData() const noexcept { return d()->buffer->constArrayData(); }
+ bool hasDetachedArrayData() const noexcept { return d()->buffer->hasDetachedArrayData(); }
+ uint arrayDataLength() const noexcept { return d()->buffer->arrayDataLength(); }
- Heap::TypedArray::Type arrayType() const {
+ Heap::TypedArray::Type arrayType() const noexcept
+ {
return static_cast<Heap::TypedArray::Type>(d()->arrayType);
}
using Object::get;
@@ -181,6 +144,7 @@ struct IntrinsicTypedArrayCtor: FunctionObject
static constexpr VTable::Call virtualCall = nullptr;
static ReturnedValue method_of(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_from(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
struct TypedArrayCtor: FunctionObject
diff --git a/src/qml/jsruntime/qv4urlobject.cpp b/src/qml/jsruntime/qv4urlobject.cpp
new file mode 100644
index 0000000000..4ece91a2a2
--- /dev/null
+++ b/src/qml/jsruntime/qv4urlobject.cpp
@@ -0,0 +1,1539 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qv4arrayiterator_p.h"
+#include "qv4urlobject_p.h"
+
+#include <QtCore/QUrl>
+
+#include <qv4jscall_p.h>
+#include <qv4objectiterator_p.h>
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(UrlObject);
+DEFINE_OBJECT_VTABLE(UrlCtor);
+
+DEFINE_OBJECT_VTABLE(UrlSearchParamsObject);
+DEFINE_OBJECT_VTABLE(UrlSearchParamsCtor);
+
+
+void Heap::UrlCtor::init(QV4::ExecutionContext *scope)
+{
+ Heap::FunctionObject::init(scope, QLatin1String("URL"));
+}
+
+void UrlPrototype::init(ExecutionEngine *engine, Object *ctor)
+{
+ Q_UNUSED(ctor);
+
+ Scope scope(engine);
+ ScopedObject o(scope);
+
+ defineDefaultProperty(QLatin1String("toString"), method_getHref);
+ defineDefaultProperty(QLatin1String("toJSON"), method_getHref);
+
+ defineAccessorProperty(QLatin1String("hash"), method_getHash, method_setHash);
+ defineAccessorProperty(QLatin1String("host"), method_getHost, method_setHost);
+ defineAccessorProperty(QLatin1String("hostname"), method_getHostname, method_setHostname);
+ defineAccessorProperty(QLatin1String("href"), method_getHref, method_setHref);
+ defineAccessorProperty(QLatin1String("origin"), method_getOrigin, nullptr);
+ defineAccessorProperty(QLatin1String("password"), method_getPassword, method_setPassword);
+ defineAccessorProperty(QLatin1String("pathname"), method_getPathname, method_setPathname);
+ defineAccessorProperty(QLatin1String("port"), method_getPort, method_setPort);
+ defineAccessorProperty(QLatin1String("protocol"), method_getProtocol, method_setProtocol);
+ defineAccessorProperty(QLatin1String("search"), method_getSearch, method_setSearch);
+ defineAccessorProperty(QLatin1String("searchParams"), method_getSearchParams, nullptr);
+ defineAccessorProperty(QLatin1String("username"), method_getUsername, method_setUsername);
+}
+
+bool UrlObject::setHash(QString hash)
+{
+ if (hash.startsWith(QLatin1Char('#')))
+ hash = hash.mid(1);
+
+ QUrl url = toQUrl();
+ url.setFragment(hash);
+
+ if (!url.isValid())
+ return false;
+
+ d()->hash.set(engine(), engine()->newString(url.fragment()));
+ d()->href.set(engine(), engine()->newString(url.toString()));
+
+ return true;
+}
+
+bool UrlObject::setHostname(QString host)
+{
+ QUrl url = toQUrl();
+ url.setHost(host);
+
+ if (!url.isValid())
+ return false;
+
+ d()->hostname.set(engine(), engine()->newString(url.host()));
+ d()->href.set(engine(), engine()->newString(url.toString()));
+
+ updateOrigin();
+ updateHost();
+
+ return true;
+}
+
+bool UrlObject::setHost(QString hostname)
+{
+ int port = -1;
+
+ if (hostname.contains(QLatin1Char(':'))) {
+ const QStringList list = hostname.split(QLatin1Char(':'));
+ hostname = list[0];
+ port = list[1].toInt();
+ }
+
+ QUrl url = toQUrl();
+ url.setHost(hostname);
+ url.setPort(port);
+
+ if (!url.isValid())
+ return false;
+
+ if (url.port() != -1)
+ d()->port.set(engine(), engine()->newString(QString::number(url.port())));
+
+ d()->hostname.set(engine(), engine()->newString(url.host()));
+ d()->href.set(engine(), engine()->newString(url.toString()));
+
+ updateOrigin();
+ updateHost();
+
+ return true;
+}
+
+bool UrlObject::setHref(QString href)
+{
+ const QUrl url(href);
+ if (!url.isValid() || url.isRelative())
+ return false;
+
+ setUrl(url);
+ return true;
+}
+
+void UrlObject::setUrl(const QUrl &url)
+{
+ d()->hash.set(engine(), engine()->newString(url.fragment()));
+ d()->hostname.set(engine(), engine()->newString(url.host()));
+ d()->href.set(engine(), engine()->newString(url.toString(QUrl::ComponentFormattingOptions(QUrl::ComponentFormattingOption::FullyEncoded))));
+ d()->password.set(engine(), engine()->newString(url.password()));
+ d()->pathname.set(engine(), engine()->newString(url.path()));
+ d()->port.set(engine(),
+ engine()->newString(url.port() == -1 ? QLatin1String("")
+ : QString::number(url.port())));
+ d()->protocol.set(engine(), engine()->newString(url.scheme() + QLatin1Char(':')));
+ d()->search.set(engine(), engine()->newString(url.query(QUrl::ComponentFormattingOptions(QUrl::ComponentFormattingOption::FullyEncoded))));
+ d()->username.set(engine(), engine()->newString(url.userName()));
+
+ updateOrigin();
+ updateHost();
+}
+
+bool UrlObject::setPassword(QString password)
+{
+ QUrl url = toQUrl();
+ url.setPassword(password);
+
+ if (!url.isValid())
+ return false;
+
+ d()->password.set(engine(), engine()->newString(url.password()));
+ d()->href.set(engine(), engine()->newString(url.toString()));
+
+ return true;
+}
+
+bool UrlObject::setPathname(QString pathname)
+{
+ QUrl url = toQUrl();
+ url.setPath(pathname);
+
+ if (!url.isValid())
+ return false;
+
+ d()->pathname.set(engine(), engine()->newString(url.path()));
+ d()->href.set(engine(), engine()->newString(url.toString()));
+
+ return true;
+}
+
+bool UrlObject::setPort(QString port)
+{
+ QUrl url = toQUrl();
+ url.setPort(port.isEmpty() ? -1 : port.toInt());
+
+ if (!url.isValid())
+ return false;
+
+ d()->port.set(engine(),
+ engine()->newString(url.port() == -1 ? QLatin1String("")
+ : QString::number(url.port())));
+ d()->href.set(engine(), engine()->newString(url.toString()));
+
+ updateOrigin();
+ updateHost();
+
+ return true;
+}
+
+bool UrlObject::setProtocol(QString protocolOrScheme)
+{
+ QUrl url = toQUrl();
+ // If there is one or several ':' in the protocolOrScheme,
+ // everything from the first colon is removed.
+
+ qsizetype firstColonPos = protocolOrScheme.indexOf(QLatin1Char(':'));
+
+ if (firstColonPos != -1)
+ protocolOrScheme.truncate(firstColonPos);
+
+ url.setScheme(protocolOrScheme);
+
+ if (!url.isValid())
+ return false;
+
+ d()->protocol.set(engine(), engine()->newString(url.scheme() + QLatin1Char(':')));
+ d()->href.set(engine(), engine()->newString(url.toString()));
+
+ updateOrigin();
+ updateHost();
+
+ return true;
+}
+
+bool UrlObject::setSearch(QString search)
+{
+ QUrl url = toQUrl();
+
+ if (search.startsWith(QLatin1Char('?')))
+ search = search.mid(1);
+
+ url.setQuery(search);
+
+ if (!url.isValid())
+ return false;
+
+ d()->search.set(engine(), engine()->newString(url.query()));
+ d()->href.set(engine(), engine()->newString(url.toString()));
+
+ return true;
+}
+
+bool UrlObject::setUsername(QString username)
+{
+ QUrl url = toQUrl();
+ url.setUserName(username);
+
+ if (!url.isValid())
+ return false;
+
+ d()->username.set(engine(), engine()->newString(url.userName()));
+ d()->href.set(engine(), engine()->newString(url.toString()));
+
+ return true;
+}
+
+QString UrlObject::search() const
+{
+ auto url = QUrl(href());
+ if (auto url = QUrl(href()); !url.hasQuery() || url.query().isEmpty())
+ return QLatin1String("");
+
+ constexpr auto options = QUrl::ComponentFormattingOption::EncodeSpaces
+ | QUrl::ComponentFormattingOption::EncodeUnicode
+ | QUrl::ComponentFormattingOption::EncodeReserved;
+ return u'?' + url.query(options);
+}
+
+QUrl UrlObject::toQUrl() const
+{
+ return QUrl(href());
+}
+
+void UrlObject::updateOrigin()
+{
+ QUrl url = toQUrl();
+
+ QString proto = url.scheme();
+
+ // A blob's origin is the origin of the URL that it points to
+ if (proto == QLatin1String("blob")) {
+ url = QUrl(url.path());
+ proto = url.scheme();
+ }
+
+ QString origin;
+ if (proto == QLatin1String("http") || proto == QLatin1String("https")
+ || proto == QLatin1String("ftp")) {
+ origin = QLatin1String("%1://%2").arg(url.scheme(), url.host());
+
+ if (url.port() != -1)
+ origin.append(QLatin1String(":") + QString::number(url.port()));
+ }
+
+ d()->origin.set(engine(), engine()->newString(origin));
+}
+
+void UrlObject::updateHost()
+{
+ QUrl url = toQUrl();
+
+ QString host = url.host();
+
+ if (url.port() != -1)
+ host.append(QLatin1String(":") + QString::number(url.port()));
+
+ d()->host.set(engine(), engine()->newString(host));
+}
+
+static bool checkUrlObjectType(ExecutionEngine *v4, const Scoped<UrlObject> &r)
+{
+ if (r)
+ return true;
+
+ v4->throwTypeError(QStringLiteral("Value of \"this\" must be of type URL"));
+ return false;
+}
+
+ReturnedValue UrlPrototype::method_getHash(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ return Encode(v4->newString(r->hash()));
+}
+
+ReturnedValue UrlPrototype::method_setHash(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ ScopedValue arg(scope, argv[0]);
+ String *stringValue = arg->stringValue();
+
+ if (stringValue == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid parameter provided"));
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ r->setHash(stringValue->toQString());
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlPrototype::method_getHost(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ return Encode(v4->newString(r->host()));
+}
+
+ReturnedValue UrlPrototype::method_setHost(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ ScopedValue arg(scope, argv[0]);
+ String *stringValue = arg->stringValue();
+
+ if (stringValue == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid parameter provided"));
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ QString host = stringValue->toQString();
+ if (!r->setHost(host))
+ return v4->throwTypeError(QLatin1String("Invalid host: %1").arg(host));
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlPrototype::method_getHostname(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ return Encode(v4->newString(r->hostname()));
+}
+
+ReturnedValue UrlPrototype::method_setHostname(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ ScopedValue arg(scope, argv[0]);
+ String *stringValue = arg->stringValue();
+
+ if (stringValue == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid parameter provided"));
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ QString hostname = stringValue->toQString();
+ if (!r->setHostname(hostname))
+ return v4->throwTypeError(QLatin1String("Invalid hostname: %1").arg(hostname));
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlPrototype::method_getHref(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ return Encode(v4->newString(r->href()));
+}
+
+ReturnedValue UrlPrototype::method_setHref(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ ScopedValue arg(scope, argv[0]);
+ String *stringValue = arg->stringValue();
+
+ if (stringValue == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid parameter provided"));
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ QString href = stringValue->toQString();
+ if (!r->setHref(href))
+ return v4->throwTypeError(QLatin1String("Invalid URL: %1").arg(href));
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlPrototype::method_getOrigin(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ return Encode(v4->newString(r->origin()));
+}
+
+ReturnedValue UrlPrototype::method_getPassword(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ return Encode(v4->newString(r->password()));
+}
+
+ReturnedValue UrlPrototype::method_setPassword(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ ScopedValue arg(scope, argv[0]);
+ String *stringValue = arg->stringValue();
+
+ if (stringValue == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid parameter provided"));
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ r->setPassword(stringValue->toQString());
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlPrototype::method_getPathname(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ return Encode(v4->newString(r->pathname()));
+}
+
+ReturnedValue UrlPrototype::method_setPathname(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ ScopedValue arg(scope, argv[0]);
+ String *stringValue = arg->stringValue();
+
+ if (stringValue == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid parameter provided"));
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ r->setPathname(stringValue->toQString());
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlPrototype::method_getPort(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ return Encode(v4->newString(r->port()));
+}
+
+ReturnedValue UrlPrototype::method_setPort(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ ScopedValue arg(scope, argv[0]);
+ String *stringValue = arg->stringValue();
+
+ QString port;
+
+ if (stringValue != nullptr)
+ port = stringValue->toQString();
+ else if (arg->isInt32())
+ port = QString::number(arg->toInt32());
+ else
+ return v4->throwTypeError(QLatin1String("Invalid parameter provided"));
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ if (!r->setPort(port))
+ return v4->throwTypeError(QLatin1String("Invalid port: %1").arg(port));
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlPrototype::method_getProtocol(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ return Encode(v4->newString(r->protocol()));
+}
+
+ReturnedValue UrlPrototype::method_setProtocol(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ ScopedValue arg(scope, argv[0]);
+ String *stringValue = arg->stringValue();
+
+ if (stringValue == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid parameter provided"));
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ r->setProtocol(stringValue->toQString());
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlPrototype::method_getSearch(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ return Encode(v4->newString(r->search()));
+}
+
+ReturnedValue UrlPrototype::method_setSearch(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ ScopedValue arg(scope, argv[0]);
+ String *stringValue = arg->stringValue();
+
+ if (stringValue == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid parameter provided"));
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ r->setSearch(stringValue->toQString());
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlPrototype::method_getUsername(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ return Encode(v4->newString(r->username()));
+}
+
+ReturnedValue UrlPrototype::method_setUsername(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ ScopedValue arg(scope, argv[0]);
+ String *stringValue = arg->stringValue();
+
+ if (stringValue == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid parameter provided"));
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ r->setUsername(stringValue->toQString());
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlPrototype::method_getSearchParams(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlObject> r(scope, thisObject);
+ if (!checkUrlObjectType(v4, r))
+ return Encode::undefined();
+
+ Scoped<UrlSearchParamsObject> usp(scope, v4->newUrlSearchParamsObject());
+
+ usp->setUrlObject(thisObject->as<UrlObject>());
+ usp->initializeParams(r->search());
+
+ return usp->asReturnedValue();
+}
+
+ReturnedValue UrlCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv,
+ int argc, const Value *newTarget)
+{
+ ExecutionEngine *v4 = that->engine();
+
+ if (argc < 1 || argc > 2)
+ return v4->throwError(QLatin1String("Invalid amount of arguments"));
+
+ Scope scope(v4);
+
+ ScopedValue arg1(scope, argv[0]);
+
+ QString arg1String = arg1->toQString();
+ QString urlString;
+
+ if (argc == 2) {
+ ScopedValue arg2(scope, argv[1]);
+ String *arg2StringValue = arg2->stringValue();
+
+ if (arg2StringValue == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid parameter provided"));
+
+ QUrl url = QUrl(arg2StringValue->toQString());
+ QUrl relativeUrl = QUrl(arg1String);
+
+ QString baseUrlPath = url.path();
+ QString relativePath = relativeUrl.path();
+
+ // If the base URL contains a path the last section of it is discarded
+ int lastSlash = baseUrlPath.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash != -1)
+ baseUrlPath.truncate(lastSlash);
+
+ if (!relativePath.startsWith(QLatin1Char('/')))
+ relativePath = relativePath.prepend(QLatin1Char('/'));
+
+ url.setPath(baseUrlPath + relativePath);
+ url.setFragment(relativeUrl.fragment());
+ url.setQuery(relativeUrl.query());
+
+ urlString = url.toString();
+ } else {
+ urlString = arg1String;
+ }
+
+ ReturnedValue o = Encode(v4->newUrlObject());
+
+ if (!newTarget)
+ return o;
+
+ ScopedObject obj(scope, o);
+ obj->setProtoFromNewTarget(newTarget);
+
+ UrlObject *urlObject = obj->as<UrlObject>();
+
+ if (!urlObject->setHref(urlString))
+ return v4->throwTypeError(QLatin1String("Invalid URL: %1").arg(urlString));
+
+ return obj->asReturnedValue();
+}
+
+
+void Heap::UrlSearchParamsCtor::init(QV4::ExecutionContext *scope)
+{
+ Heap::FunctionObject::init(scope, QLatin1String("URLSearchParams"));
+}
+
+void UrlSearchParamsPrototype::init(ExecutionEngine *engine, Object *ctor)
+{
+ Q_UNUSED(ctor);
+
+ Scope scope(engine);
+ ScopedObject o(scope);
+
+ defineDefaultProperty(QLatin1String("toString"), method_toString);
+ defineDefaultProperty(QLatin1String("sort"), method_sort);
+ defineDefaultProperty(QLatin1String("append"), method_append);
+ defineDefaultProperty(QLatin1String("delete"), method_delete);
+ defineDefaultProperty(QLatin1String("has"), method_has);
+ defineDefaultProperty(QLatin1String("set"), method_set);
+ defineDefaultProperty(QLatin1String("get"), method_get);
+ defineDefaultProperty(QLatin1String("getAll"), method_getAll);
+ defineDefaultProperty(QLatin1String("forEach"), method_forEach);
+ defineDefaultProperty(QLatin1String("entries"), method_entries);
+ defineDefaultProperty(QLatin1String("keys"), method_keys);
+ defineDefaultProperty(QLatin1String("values"), method_values);
+}
+
+ReturnedValue UrlSearchParamsCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv,
+ int argc, const Value *newTarget)
+{
+ ExecutionEngine *v4 = that->engine();
+
+ if (argc > 1)
+ return v4->throwError(QLatin1String("Invalid amount of arguments"));
+
+ Scope scope(v4);
+
+ ScopedValue arg(scope, argv[0]);
+ ArrayObject *argArrayObject = arg->as<ArrayObject>();
+ Object *argObject = arg->as<Object>();
+
+ ReturnedValue o = Encode(v4->newUrlSearchParamsObject());
+
+ if (!newTarget)
+ return o;
+
+ ScopedObject obj(scope, o);
+ obj->setProtoFromNewTarget(newTarget);
+
+ UrlSearchParamsObject *urlSearchParamsObject = obj->as<UrlSearchParamsObject>();
+
+ if (argArrayObject != nullptr) {
+ ScopedArrayObject argArray(scope, argArrayObject);
+
+ uint len = argArray->getLength();
+
+ for (uint i = 0; i < len; i++) {
+ QV4::Value pair = argArray->get(i);
+ auto *pairArrayObject = pair.as<ArrayObject>();
+
+ if (pairArrayObject == nullptr) {
+ return v4->throwTypeError(
+ QLatin1String("element %1 is not a pair").arg(QString::number(i)));
+ }
+
+
+ ScopedArrayObject pairArray(scope, pairArrayObject);
+
+
+ uint pairLen = pairArray->getLength();
+
+
+ if (pairLen != 2) {
+ return v4->throwTypeError(QLatin1String("pair %1 has %2 elements instead of 2")
+ .arg(QString::number(i))
+ .arg(QString::number(pairLen)));
+ }
+ }
+
+ urlSearchParamsObject->initializeParams(argArray);
+ } else if (argObject != nullptr) {
+ ScopedObject scopedObject(scope, argObject);
+ urlSearchParamsObject->initializeParams(scopedObject);
+ } else {
+ QString value = argc > 0 ? arg->toQString() : QLatin1String("");
+ urlSearchParamsObject->initializeParams(value);
+ }
+
+ return obj->asReturnedValue();
+}
+
+void UrlSearchParamsObject::initializeParams()
+{
+ auto *arrayObject = engine()->newArrayObject(0);
+ auto *keys = engine()->newArrayObject(0);
+ auto *values = engine()->newArrayObject(0);
+
+ d()->params.set(engine(), arrayObject);
+ d()->keys.set(engine(), keys);
+ d()->values.set(engine(), values);
+}
+
+void UrlSearchParamsObject::initializeParams(QString value)
+{
+ Q_ASSERT(d()->params == nullptr);
+
+ initializeParams();
+
+ if (value.startsWith(QLatin1Char('?')))
+ value = value.mid(1);
+
+ const QStringList params = value.split(QLatin1Char('&'));
+
+ for (const QString& param : params) {
+ if (param.isEmpty())
+ continue;
+
+ QString key, value;
+
+ int equalsIndex = param.indexOf(QLatin1Char('='));
+ if (equalsIndex != -1) {
+ key = param.left(equalsIndex);
+ value = param.mid(equalsIndex+1);
+ } else {
+ key = param;
+ }
+
+ append(engine()->newString(key), engine()->newString(value));
+ }
+}
+
+void UrlSearchParamsObject::initializeParams(ScopedArrayObject& params)
+{
+ Q_ASSERT(d()->params == nullptr);
+
+ Scope scope(engine());
+
+ uint len = params->getLength();
+ auto *keys = engine()->newArrayObject(len);
+ auto *values = engine()->newArrayObject(len);
+
+ ScopedArrayObject scopedKeys(scope, keys);
+ ScopedArrayObject scopedValues(scope, values);
+
+ for (uint i = 0; i < len; i++)
+ {
+ QV4::Value pair = params->get(i);
+ auto *pairArrayObject = pair.as<ArrayObject>();
+
+ QV4::Value key = pairArrayObject->get(uint(0));
+ QV4::Value value = pairArrayObject->get(uint(1));
+
+ scopedKeys->put(i, key);
+ scopedValues->put(i, value);
+ }
+
+
+ d()->params.set(engine(), params->d());
+ d()->keys.set(engine(), keys);
+ d()->values.set(engine(), values);
+}
+
+void UrlSearchParamsObject::initializeParams(ScopedObject& params)
+{
+ Q_ASSERT(d()->params == nullptr);
+
+ initializeParams();
+
+ Scope scope(engine());
+ ObjectIterator it(scope, params, ObjectIterator::EnumerableOnly);
+
+ ScopedValue name(scope);
+ ScopedValue val(scope);
+
+ while (true) {
+ name = it.nextPropertyNameAsString(val);
+ if (name->isNull())
+ break;
+
+ Heap::String *nameStr = name->as<String>()->d();
+ Heap::String *valStr = val->toString(engine());
+
+ append(nameStr, valStr);
+ }
+}
+
+void UrlSearchParamsObject::setParams(QList<QStringList> params)
+{
+ auto *arrayObject = engine()->newArrayObject(0);
+ auto *keys = engine()->newArrayObject(0);
+ auto *values = engine()->newArrayObject(0);
+
+ Scope scope(engine());
+
+ ScopedArrayObject scopedArray(scope, arrayObject);
+
+ ScopedArrayObject scopedKeys(scope, keys);
+ ScopedArrayObject scopedValues(scope, values);
+
+ uint len = 0;
+
+ for (const QStringList& param : params) {
+
+ auto *valuePair = engine()->newArrayObject(2);
+
+ ScopedArrayObject valuePairObject(scope, valuePair);
+
+ ScopedValue key(scope, Value::fromHeapObject(engine()->newString(param[0])));
+ ScopedValue value(scope, Value::fromHeapObject(engine()->newString(param[1])));
+ valuePairObject->put(uint(0), key);
+ valuePairObject->put(uint(1), value);
+
+ scopedKeys->put(len, key);
+ scopedValues->put(len, value);
+
+ scopedArray->put(len, valuePairObject);
+ len++;
+ }
+
+ d()->params.set(engine(), arrayObject);
+ d()->keys.set(engine(), keys);
+ d()->values.set(engine(), values);
+}
+
+void UrlSearchParamsObject::setUrlObject(const UrlObject *url)
+{
+ d()->url.set(engine(), url->d());
+}
+
+void UrlSearchParamsObject::append(Heap::String *name, Heap::String *value)
+{
+ Scope scope(engine());
+
+ ScopedArrayObject scopedArray(scope, d()->params);
+ ScopedArrayObject scopedKeys(scope, d()->keys);
+ ScopedArrayObject scopedValues(scope, d()->values);
+
+ auto *valuePair = engine()->newArrayObject(2);
+
+ ScopedArrayObject valuePairObject(scope, valuePair);
+
+ ScopedValue keyScoped(scope, Value::fromHeapObject(name));
+ ScopedValue valueScoped(scope, Value::fromHeapObject(value));
+ valuePairObject->put(uint(0), keyScoped);
+ valuePairObject->put(uint(1), valueScoped);
+
+ uint len = scopedArray->getLength();
+
+ scopedKeys->put(len, keyScoped);
+ scopedValues->put(len, valueScoped);
+
+ scopedArray->put(len, valuePairObject);
+}
+
+QList<QStringList> UrlSearchParamsObject::params() const
+{
+ auto *arrayObject = d()->params.get();
+ Scope scope(engine());
+ ScopedArrayObject scopedArray(scope, arrayObject);
+
+ QList<QStringList> result;
+
+ uint len = scopedArray->getLength();
+
+ for (uint i = 0; i < len; i++) {
+ QV4::Value pair = scopedArray->get(i);
+ auto *pairArrayObject = pair.as<ArrayObject>();
+
+ QV4::Value key = pairArrayObject->get(uint(0));
+ QV4::Value value = pairArrayObject->get(uint(1));
+
+ result << QStringList { key.toQString(), value.toQString() };
+ }
+
+ return result;
+}
+
+Heap::UrlObject *UrlSearchParamsObject::urlObject() const
+{
+ return d()->url.get();
+}
+
+QString UrlSearchParamsObject::searchString() const
+{
+ QString search = QLatin1String("");
+ auto params = this->params();
+ auto len = params.size();
+ for (int i = 0; i < len; ++i) {
+ const QStringList &param = params[i];
+ search += param[0] + QLatin1Char('=') + param[1];
+ if (i != len - 1)
+ search += QLatin1Char('&');
+ }
+ return search;
+}
+
+int UrlSearchParamsObject::length() const
+{
+ auto *arrayObject = d()->params.get();
+ Scope scope(engine());
+ ScopedArrayObject scopedArray(scope, arrayObject);
+
+ return scopedArray->getLength();
+}
+
+int UrlSearchParamsObject::indexOf(QString name, int last) const
+{
+ auto *arrayObject = d()->params.get();
+ Scope scope(engine());
+ ScopedArrayObject scopedArray(scope, arrayObject);
+
+ int len = scopedArray->getLength();
+
+ for (int i = last + 1; i < len; i++) {
+ QV4::Value pair = scopedArray->get(i);
+ auto *pairArrayObject = pair.as<ArrayObject>();
+
+ QV4::Value key = pairArrayObject->get(uint(0));
+
+ if (key.toQString() == name)
+ return i;
+ }
+
+ return -1;
+}
+
+QString UrlSearchParamsObject::stringAt(int index, int pairIndex) const
+{
+ auto *arrayObject = d()->params.get();
+ Scope scope(engine());
+ ScopedArrayObject scopedArray(scope, arrayObject);
+
+ if (index >= scopedArray->getLength())
+ return {};
+
+ QV4::Value pair = scopedArray->get(index);
+ auto *pairArrayObject = pair.as<ArrayObject>();
+
+ QV4::Value value = pairArrayObject->get(pairIndex);
+
+ return value.toQString();
+}
+
+QV4::Heap::String * UrlSearchParamsObject::stringAtRaw(int index, int pairIndex) const
+{
+ auto *arrayObject = d()->params.get();
+ Scope scope(engine());
+ ScopedArrayObject scopedArray(scope, arrayObject);
+
+ if (index >= scopedArray->getLength())
+ return nullptr;
+
+ QV4::Value pair = scopedArray->get(index);
+ auto *pairArrayObject = pair.as<ArrayObject>();
+
+ QV4::Value value = pairArrayObject->get(pairIndex);
+
+ return value.as<String>()->d();
+}
+
+QString UrlSearchParamsObject::nameAt(int index) const
+{
+ return stringAt(index, 0);
+}
+
+QV4::Heap::String * UrlSearchParamsObject::nameAtRaw(int index) const
+{
+ return stringAtRaw(index, 0);
+}
+
+
+QString UrlSearchParamsObject::valueAt(int index) const
+{
+ return stringAt(index, 1);
+}
+
+QV4::Heap::String * UrlSearchParamsObject::valueAtRaw(int index) const
+{
+ return stringAtRaw(index, 1);
+}
+
+
+struct UrlSearchParamsObjectOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
+{
+ ~UrlSearchParamsObjectOwnPropertyKeyIterator() override = default;
+ PropertyKey next(const QV4::Object *o, Property *pd = nullptr,
+ PropertyAttributes *attrs = nullptr) override;
+};
+
+PropertyKey UrlSearchParamsObjectOwnPropertyKeyIterator::next(const QV4::Object *o, Property *pd,
+ PropertyAttributes *attrs)
+{
+ const UrlSearchParamsObject *usp = static_cast<const UrlSearchParamsObject *>(o);
+
+ Scope scope(usp);
+
+ uint len = usp->length();
+ if (arrayIndex < len) {
+ uint index = arrayIndex;
+ ++arrayIndex;
+ if (attrs)
+ *attrs = Attr_NotConfigurable | Attr_NotWritable;
+ if (pd)
+ pd->value = usp->engine()->newString(usp->nameAt(index));
+ return PropertyKey::fromArrayIndex(index);
+ }
+
+ return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
+}
+
+OwnPropertyKeyIterator *UrlSearchParamsObject::virtualOwnPropertyKeys(const Object *m,
+ Value *target)
+{
+ *target = *m;
+ return new UrlSearchParamsObjectOwnPropertyKeyIterator;
+}
+
+PropertyAttributes UrlSearchParamsObject::virtualGetOwnProperty(const Managed *m, PropertyKey id,
+ Property *p)
+{
+ PropertyAttributes attributes = Object::virtualGetOwnProperty(m, id, p);
+ if (attributes != Attr_Invalid)
+ return attributes;
+
+ if (id.isArrayIndex()) {
+ const int index = id.asArrayIndex();
+ const auto usp = static_cast<const UrlSearchParamsObject *>(m);
+ if (index < usp->length()) {
+ if (p)
+ p->value = usp->engine()->newString(usp->nameAt(index));
+ return Attr_NotConfigurable | Attr_NotWritable;
+ }
+ }
+
+ return Object::virtualGetOwnProperty(m, id, p);
+}
+
+static bool checkSearchParamsType(ExecutionEngine *v4, const Scoped<UrlSearchParamsObject> &o)
+{
+ if (o)
+ return true;
+
+ v4->throwTypeError(QStringLiteral("Value of \"this\" must be of type URLSearchParams"));
+ return false;
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_toString(
+ const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject);
+ if (!checkSearchParamsType(v4, o))
+ return Encode::undefined();
+
+ auto params = o->params();
+
+ QString value;
+
+ for (const QStringList &pair : params)
+ value += QLatin1String("%1=%2&").arg(QString::fromUtf8(QUrl::toPercentEncoding(pair[0])),
+ QString::fromUtf8(QUrl::toPercentEncoding(pair[1])));
+
+ value.chop(1);
+
+ return Encode(v4->newString(value));
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_sort(const FunctionObject *b, const Value *thisObject,
+ const Value *, int)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject);
+ if (!checkSearchParamsType(v4, o))
+ return Encode::undefined();
+
+ QList<QStringList> params = o->params();
+ std::stable_sort(params.begin(), params.end(), [](QStringList a, QStringList b) { return a[0] < b[0]; });
+
+ o->setParams(params);
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_append(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 2)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argName(scope, argv[0]);
+ ScopedValue argValue(scope, argv[1]);
+
+ String *argNameString = argName->stringValue();
+
+ if (argNameString == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument provided"));
+
+ ScopedString name(scope, argName->as<String>());
+ ScopedString value(scope, argValue->toString(v4));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject);
+ if (!checkSearchParamsType(v4, o))
+ return Encode::undefined();
+
+ o->append(name->d(), value->d());
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_delete(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 1)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argName(scope, argv[0]);
+
+ String *argNameString = argName->stringValue();
+
+ if (argNameString == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument provided"));
+
+ QString name = argNameString->toQString();
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject);
+ if (!checkSearchParamsType(v4, o))
+ return Encode::undefined();
+
+ QList<QStringList> params = o->params();
+ params.removeIf([&name](const auto &pair) { return pair.at(0) == name; });
+
+ o->setParams(params);
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_has(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 1)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argName(scope, argv[0]);
+
+ String *argNameString = argName->stringValue();
+
+ if (argNameString == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument provided"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject);
+ if (!checkSearchParamsType(v4, o))
+ return Encode::undefined();
+
+ QString name = argNameString->toQString();
+
+ return Encode(o->indexOf(name) != -1);
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_set(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 2)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argName(scope, argv[0]);
+ ScopedValue argValue(scope, argv[1]);
+
+ String *argNameString = argName->stringValue();
+
+ if (argNameString == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument provided"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject);
+ if (!checkSearchParamsType(v4, o))
+ return Encode::undefined();
+
+ QString name = argNameString->toQString();
+ QString value = argValue->toQString();
+
+ auto params = o->params();
+
+ bool matched = false;
+
+ for (auto it = params.begin(); it != params.end();) {
+ QStringList &param = *it;
+ if (param[0] == name) {
+ if (!matched) {
+ param[1] = value;
+ matched = true;
+ } else {
+ it = params.erase(it);
+ continue;
+ }
+ }
+ it++;
+ }
+
+ if (!matched)
+ params << QStringList { name, value };
+
+ o->setParams(params);
+
+ Scoped<UrlObject> scopedUrlObject(scope, o->d()->url.get());
+ if (scopedUrlObject)
+ scopedUrlObject->setSearch(o->searchString());
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_get(const FunctionObject *b, const Value *thisObject,
+ const Value *argv, int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 1)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argName(scope, argv[0]);
+
+ String *argNameString = argName->stringValue();
+
+ if (argNameString == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument provided"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject);
+ if (!checkSearchParamsType(v4, o))
+ return Encode::undefined();
+
+ QString name = argNameString->toQString();
+
+ int index = o->indexOf(name);
+
+ if (index == -1)
+ return Encode::null();
+
+ return Encode(o->valueAtRaw(index));
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_getAll(const FunctionObject *b,
+ const Value *thisObject, const Value *argv,
+ int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 1)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argName(scope, argv[0]);
+
+ String *argNameString = argName->stringValue();
+
+ if (argNameString == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument provided"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject);
+ if (!checkSearchParamsType(v4, o))
+ return Encode::undefined();
+
+ QString name = argNameString->toQString();
+
+ auto *arrayObject = v4->newArrayObject(0);
+ ScopedArrayObject result(scope, arrayObject);
+
+ int i = 0;
+ for (int index = o->indexOf(name); index != -1; index = o->indexOf(name, index)) {
+ ScopedValue value(scope, Value::fromHeapObject(o->valueAtRaw(index)));
+ result->put(i++, value);
+ }
+
+ return Encode(arrayObject);
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_forEach(const FunctionObject *b,
+ const Value *thisObject, const Value *argv,
+ int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 1)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ ScopedValue argFunc(scope, argv[0]);
+
+ FunctionObject *func = argFunc->as<FunctionObject>();
+
+ if (func == nullptr)
+ return v4->throwTypeError(QLatin1String("Invalid argument: must be a function"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject);
+ if (!checkSearchParamsType(v4, o))
+ return Encode::undefined();
+
+ for (int i = 0; i < o->length(); i++) {
+ Scoped<String> name(scope, o->nameAtRaw(i));
+ Scoped<String> value(scope, o->valueAtRaw(i));
+
+ QV4::JSCallArguments calldata(scope, 2);
+
+ calldata.args[0] = value;
+ calldata.args[1] = name;
+
+ func->call(calldata);
+ }
+
+ return Encode::undefined();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_entries(const FunctionObject *b,
+ const Value *thisObject, const Value *,
+ int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 0)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject);
+ if (!checkSearchParamsType(v4, o))
+ return Encode::undefined();
+
+ ScopedObject params(scope, o->d()->params.get());
+
+ Scoped<ArrayIteratorObject> paramsIterator(scope, v4->newArrayIteratorObject(params));
+ paramsIterator->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
+ return paramsIterator->asReturnedValue();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_keys(const FunctionObject *b,
+ const Value *thisObject, const Value *,
+ int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 0)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject);
+ if (!checkSearchParamsType(v4, o))
+ return Encode::undefined();
+
+ ScopedObject keys(scope, o->d()->keys.get());
+
+ Scoped<ArrayIteratorObject> keysIterator(scope, v4->newArrayIteratorObject(keys));
+ keysIterator->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
+ return keysIterator->asReturnedValue();
+}
+
+ReturnedValue UrlSearchParamsPrototype::method_values(const FunctionObject *b,
+ const Value *thisObject, const Value *,
+ int argc)
+{
+ ExecutionEngine *v4 = b->engine();
+ Scope scope(v4);
+
+ if (argc != 0)
+ return v4->throwError(QLatin1String("Bad amount of arguments"));
+
+ Scoped<UrlSearchParamsObject> o(scope, thisObject);
+ if (!checkSearchParamsType(v4, o))
+ return Encode::undefined();
+
+ ScopedObject values(scope, o->d()->values.get());
+
+ Scoped<ArrayIteratorObject> valuesIterator(scope, v4->newArrayIteratorObject(values));
+ valuesIterator->d()->iterationKind = IteratorKind::KeyValueIteratorKind;
+ return valuesIterator->asReturnedValue();
+}
diff --git a/src/qml/jsruntime/qv4urlobject_p.h b/src/qml/jsruntime/qv4urlobject_p.h
new file mode 100644
index 0000000000..d45b74fcaa
--- /dev/null
+++ b/src/qml/jsruntime/qv4urlobject_p.h
@@ -0,0 +1,293 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QV4URLOBJECT_P_H
+#define QV4URLOBJECT_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 "qv4object_p.h"
+#include "qv4functionobject_p.h"
+
+#include <QtCore/QString>
+#include <QtCore/QUrl>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+namespace Heap {
+// clang-format off
+#define UrlObjectMembers(class, Member) \
+ Member(class, Pointer, String *, hash) \
+ Member(class, Pointer, String *, host) \
+ Member(class, Pointer, String *, hostname) \
+ Member(class, Pointer, String *, href) \
+ Member(class, Pointer, String *, origin) \
+ Member(class, Pointer, String *, password) \
+ Member(class, Pointer, String *, pathname) \
+ Member(class, Pointer, String *, port) \
+ Member(class, Pointer, String *, protocol) \
+ Member(class, Pointer, String *, search) \
+ Member(class, Pointer, String *, username)
+// clang-format on
+
+DECLARE_HEAP_OBJECT(UrlObject, Object)
+{
+ DECLARE_MARKOBJECTS(UrlObject)
+ void init() { Object::init(); }
+};
+
+struct UrlCtor : FunctionObject
+{
+ void init(QV4::ExecutionContext *scope);
+};
+
+// clang-format off
+#define UrlSearchParamsObjectMembers(class, Member) \
+ Member(class, Pointer, ArrayObject *, params) \
+ Member(class, Pointer, ArrayObject *, keys) \
+ Member(class, Pointer, ArrayObject *, values) \
+ Member(class, Pointer, UrlObject *, url)
+// clang-format on
+
+DECLARE_HEAP_OBJECT(UrlSearchParamsObject, Object)
+{
+ DECLARE_MARKOBJECTS(UrlSearchParamsObject)
+ void init() { Object::init(); }
+};
+
+struct UrlSearchParamsCtor : FunctionObject
+{
+ void init(QV4::ExecutionContext *scope);
+};
+}
+
+struct UrlObject : Object
+{
+ V4_OBJECT2(UrlObject, Object)
+ Q_MANAGED_TYPE(UrlObject)
+ V4_PROTOTYPE(urlPrototype)
+
+ QString hash() const { return QLatin1String("#") + toQString(d()->hash); }
+ bool setHash(QString hash);
+
+ QString host() const { return toQString(d()->host); }
+ bool setHost(QString host);
+
+ QString hostname() const { return toQString(d()->hostname); }
+ bool setHostname(QString hostname);
+
+ QString href() const { return toQString(d()->href); }
+ bool setHref(QString href);
+
+ QString origin() const { return toQString(d()->origin); }
+
+ QString password() const { return toQString(d()->password); }
+ bool setPassword(QString password);
+
+ QString pathname() const { return toQString(d()->pathname); }
+ bool setPathname(QString pathname);
+
+ QString port() const { return toQString(d()->port); }
+ bool setPort(QString port);
+
+ QString protocol() const { return toQString(d()->protocol); }
+ bool setProtocol(QString protocol);
+
+ Q_QML_AUTOTEST_EXPORT QString search() const;
+ bool setSearch(QString search);
+
+ QString username() const { return toQString(d()->username); }
+ bool setUsername(QString username);
+
+ QUrl toQUrl() const;
+ void setUrl(const QUrl &url);
+
+private:
+ static QString toQString(const Heap::String *string)
+ {
+ return string ? string->toQString() : QString();
+ }
+
+ void updateOrigin();
+ void updateHost();
+};
+
+template<>
+inline const UrlObject *Value::as() const
+{
+ return isManaged() && m()->internalClass->vtable->type == Managed::Type_UrlObject
+ ? static_cast<const UrlObject *>(this)
+ : nullptr;
+}
+
+struct UrlCtor : FunctionObject
+{
+ V4_OBJECT2(UrlCtor, FunctionObject)
+
+ static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv,
+ int argc, const Value *);
+};
+
+struct UrlPrototype : Object
+{
+ V4_PROTOTYPE(objectPrototype)
+
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_getHash(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_setHash(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+
+ static ReturnedValue method_getHost(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_setHost(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+
+ static ReturnedValue method_getHostname(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_setHostname(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+
+ static ReturnedValue method_getHref(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_setHref(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+
+ static ReturnedValue method_getOrigin(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+
+ static ReturnedValue method_getPassword(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_setPassword(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+
+ static ReturnedValue method_getPathname(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_setPathname(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+
+ static ReturnedValue method_getPort(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_setPort(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+
+ static ReturnedValue method_getProtocol(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_setProtocol(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+
+ static ReturnedValue method_getSearch(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_setSearch(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+
+ static ReturnedValue method_getUsername(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_setUsername(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+
+ static ReturnedValue method_getSearchParams(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+};
+
+struct UrlSearchParamsObject : Object
+{
+ V4_OBJECT2(UrlSearchParamsObject, Object)
+ Q_MANAGED_TYPE(UrlSearchParamsObject)
+ V4_PROTOTYPE(urlSearchParamsPrototype)
+
+ void initializeParams();
+ void initializeParams(QString params);
+ void initializeParams(ScopedArrayObject& params);
+ void initializeParams(ScopedObject& params);
+
+ QList<QStringList> params() const;
+ void setParams(QList<QStringList> params);
+ Heap::UrlObject *urlObject() const;
+ void setUrlObject(const UrlObject *url);
+
+ QString searchString() const;
+
+ QString nameAt(int index) const;
+ Heap::String * nameAtRaw(int index) const;
+ QString valueAt(int index) const;
+ Heap::String * valueAtRaw(int index) const;
+
+ void append(Heap::String *name, Heap::String *value);
+
+ int indexOf(QString name, int last = -1) const;
+ int length() const;
+
+ using Object::getOwnProperty;
+protected:
+ static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
+ static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p);
+private:
+ QString stringAt(int index, int pairIndex) const;
+ Heap::String * stringAtRaw(int index, int pairIndex) const;
+};
+
+template<>
+inline const UrlSearchParamsObject *Value::as() const
+{
+ return isManaged() && m()->internalClass->vtable->type == Managed::Type_UrlSearchParamsObject
+ ? static_cast<const UrlSearchParamsObject *>(this)
+ : nullptr;
+}
+
+struct UrlSearchParamsCtor : FunctionObject
+{
+ V4_OBJECT2(UrlSearchParamsCtor, FunctionObject)
+
+ static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv,
+ int argc, const Value *);
+};
+
+struct UrlSearchParamsPrototype : Object
+{
+ V4_PROTOTYPE(objectPrototype)
+
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_sort(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_append(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_delete(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_has(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_set(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_get(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_getAll(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_forEach(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_entries(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_keys(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+ static ReturnedValue method_values(const FunctionObject *, const Value *thisObject,
+ const Value *argv, int argc);
+
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4URLOBJECT_P_H
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index d29b060b9e..223a004602 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qv4runtime_p.h>
#include <qv4propertykey_p.h>
@@ -109,7 +73,7 @@ double Value::toNumberImpl(Value val)
Scope scope(val.objectValue()->engine());
ScopedValue protectThis(scope, val);
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(val, NUMBER_HINT));
- if (scope.engine->hasException)
+ if (scope.hasException())
return 0;
return prim->toNumber();
}
@@ -122,100 +86,122 @@ double Value::toNumberImpl(Value val)
}
}
-QString Value::toQStringNoThrow() const
+static QString primitiveToQString(const Value *value)
{
- switch (type()) {
+ switch (value->type()) {
case Value::Empty_Type:
Q_ASSERT(!"empty Value encountered");
- Q_UNREACHABLE();
+ Q_UNREACHABLE_RETURN(QString());
case Value::Undefined_Type:
return QStringLiteral("undefined");
case Value::Null_Type:
return QStringLiteral("null");
case Value::Boolean_Type:
- if (booleanValue())
+ if (value->booleanValue())
return QStringLiteral("true");
else
return QStringLiteral("false");
case Value::Managed_Type:
+ Q_UNREACHABLE_RETURN(QString());
+ case Value::Integer_Type: {
+ QString str;
+ RuntimeHelpers::numberToString(&str, (double)value->int_32(), 10);
+ return str;
+ }
+ case Value::Double_Type: {
+ QString str;
+ RuntimeHelpers::numberToString(&str, value->doubleValue(), 10);
+ return str;
+ }
+ } // switch
+
+ Q_UNREACHABLE_RETURN(QString());
+}
+
+
+QString Value::toQStringNoThrow() const
+{
+ if (isManaged()) {
if (String *s = stringValue())
return s->toQString();
if (Symbol *s = symbolValue())
return s->descriptiveString();
- {
- Q_ASSERT(isObject());
- Scope scope(objectValue()->engine());
- ScopedValue ex(scope);
- bool caughtException = false;
- ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
+
+ Q_ASSERT(isObject());
+ Scope scope(objectValue()->engine());
+ ScopedValue ex(scope);
+ bool caughtException = false;
+ ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
+ if (scope.hasException()) {
+ ex = scope.engine->catchException();
+ caughtException = true;
+ } else if (prim->isPrimitive()) {
+ return prim->toQStringNoThrow();
+ }
+
+ // Can't nest try/catch due to CXX ABI limitations for foreign exception nesting.
+ if (caughtException) {
+ ScopedValue prim(scope, RuntimeHelpers::toPrimitive(ex, STRING_HINT));
if (scope.hasException()) {
ex = scope.engine->catchException();
- caughtException = true;
} else if (prim->isPrimitive()) {
- return prim->toQStringNoThrow();
- }
- // Can't nest try/catch due to CXX ABI limitations for foreign exception nesting.
- if (caughtException) {
- ScopedValue prim(scope, RuntimeHelpers::toPrimitive(ex, STRING_HINT));
- if (scope.hasException()) {
- ex = scope.engine->catchException();
- } else if (prim->isPrimitive()) {
- return prim->toQStringNoThrow();
- }
+ return prim->toQStringNoThrow();
}
- return QString();
}
- case Value::Integer_Type: {
- QString str;
- RuntimeHelpers::numberToString(&str, (double)int_32(), 10);
- return str;
- }
- default: { // double
- QString str;
- RuntimeHelpers::numberToString(&str, doubleValue(), 10);
- return str;
+
+ return QString();
}
- } // switch
+
+ return primitiveToQString(this);
}
QString Value::toQString() const
{
- switch (type()) {
- case Value::Empty_Type:
- Q_ASSERT(!"empty Value encountered");
- Q_UNREACHABLE();
- case Value::Undefined_Type:
- return QStringLiteral("undefined");
- case Value::Null_Type:
- return QStringLiteral("null");
- case Value::Boolean_Type:
- if (booleanValue())
- return QStringLiteral("true");
- else
- return QStringLiteral("false");
- case Value::Managed_Type:
- if (String *s = stringValue()) {
+ if (isManaged()) {
+ if (String *s = stringValue())
return s->toQString();
- } else if (isSymbol()) {
+
+ if (isSymbol()) {
static_cast<const Managed *>(this)->engine()->throwTypeError();
return QString();
- } else {
- Q_ASSERT(isObject());
- Scope scope(objectValue()->engine());
- ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
- return prim->toQString();
}
- case Value::Integer_Type: {
- QString str;
- RuntimeHelpers::numberToString(&str, (double)int_32(), 10);
- return str;
+
+ Q_ASSERT(isObject());
+ Scope scope(objectValue()->engine());
+ ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
+ return prim->toQString();
}
- default: { // double
- QString str;
- RuntimeHelpers::numberToString(&str, doubleValue(), 10);
- return str;
+
+ return primitiveToQString(this);
+}
+
+QString Value::toQString(bool *ok) const
+{
+ if (isManaged()) {
+ if (String *s = stringValue()) {
+ *ok = true;
+ return s->toQString();
+ }
+
+ if (isSymbol()) {
+ static_cast<const Managed *>(this)->engine()->throwTypeError();
+ *ok = false;
+ return QString();
+ }
+
+ Q_ASSERT(isObject());
+ Scope scope(objectValue()->engine());
+ ScopedValue prim(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
+
+ if (scope.hasException()) {
+ *ok = false;
+ return QString();
+ }
+
+ return prim->toQString(ok);
}
- } // switch
+
+ return primitiveToQString(this);
}
QV4::PropertyKey Value::toPropertyKey(ExecutionEngine *e) const
@@ -250,6 +236,8 @@ bool Value::sameValue(Value other) const {
if (isDouble() && other.isInteger())
return other.int_32() ? (doubleValue() == double(other.int_32()))
: (doubleValue() == 0 && !std::signbit(doubleValue()));
+ if (isManaged())
+ return other.isManaged() && cast<Managed>()->isEqualTo(other.cast<Managed>());
return false;
}
@@ -269,6 +257,8 @@ bool Value::sameValueZero(Value other) const {
return true;
}
}
+ if (isManaged())
+ return other.isManaged() && cast<Managed>()->isEqualTo(other.cast<Managed>());
return false;
}
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 4e901721cb..f2d01c56cd 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4VALUE_P_H
#define QV4VALUE_P_H
@@ -70,9 +34,8 @@ namespace Heap {
struct Base;
}
-struct Q_QML_PRIVATE_EXPORT Value : public StaticValue
+struct Q_QML_EXPORT Value : public StaticValue
{
- using HeapBasePtr = Heap::Base *;
using ManagedPtr = Managed *;
Value() = default;
@@ -83,53 +46,6 @@ struct Q_QML_PRIVATE_EXPORT Value : public StaticValue
return {staticValue._val};
}
-#if QT_POINTER_SIZE == 8
- QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
- {
- HeapBasePtr b;
-#ifdef __ia64
-// Restore bits 49-47 to bits 63-61, undoing the workaround explained in
-// setM below.
- quint64 _tmp;
-
- _tmp = _val & (7L << 47); // 0x3800000000000
- _tmp = (_tmp << 14) | (_val ^ _tmp);
- memcpy(&b, &_tmp, 8);
-#else
- memcpy(&b, &_val, 8);
-#endif
- return b;
- }
- QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b)
- {
- memcpy(&_val, &b, 8);
-#ifdef __ia64
-// On ia64, bits 63-61 in a 64-bit pointer are used to store the virtual region
-// number. Since this implementation is not 64-bit clean, we move bits 63-61
-// to bits 49-47 and hope for the best. This is undone in *m(), above.
- _val |= ((_val & (7L << 61)) >> 14);
- _val &= ((1L << 50)-1);
-#endif
- }
-#elif QT_POINTER_SIZE == 4
- QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
- {
- Q_STATIC_ASSERT(sizeof(HeapBasePtr) == sizeof(quint32));
- HeapBasePtr b;
- quint32 v = value();
- memcpy(&b, &v, 4);
- return b;
- }
- QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b)
- {
- quint32 v;
- memcpy(&v, &b, 4);
- setTagValue(Managed_Type_Internal, v);
- }
-#else
-# error "unsupported pointer size"
-#endif
-
inline bool isString() const;
inline bool isStringOrSymbol() const;
inline bool isSymbol() const;
@@ -190,8 +106,11 @@ struct Q_QML_PRIVATE_EXPORT Value : public StaticValue
inline double toNumber() const;
static double toNumberImpl(Value v);
double toNumberImpl() const { return toNumberImpl(*this); }
+
QString toQStringNoThrow() const;
QString toQString() const;
+ QString toQString(bool *ok) const;
+
Heap::String *toString(ExecutionEngine *e) const {
if (isString())
return reinterpret_cast<Heap::String *>(m());
@@ -308,7 +227,7 @@ struct Q_QML_PRIVATE_EXPORT Value : public StaticValue
template<typename T>
Value &operator=(const Scoped<T> &t);
};
-Q_STATIC_ASSERT(std::is_trivial<Value>::value);
+Q_STATIC_ASSERT(std::is_trivial_v<Value>);
Q_STATIC_ASSERT(sizeof(Value) == sizeof(StaticValue));
template<>
@@ -434,9 +353,9 @@ inline int Value::toInt32() const
return int_32();
if (Q_LIKELY(isDouble()))
- return Double::toInt32(doubleValue());
+ return QJSNumberCoercion::toInteger(doubleValue());
- return Double::toInt32(toNumberImpl());
+ return QJSNumberCoercion::toInteger(toNumberImpl());
}
inline unsigned int Value::toUInt32() const
@@ -480,7 +399,7 @@ inline double Value::toInteger() const
template <size_t o>
struct HeapValue : Value {
- static Q_CONSTEXPR size_t offset = o;
+ static constexpr size_t offset = o;
HeapBasePtr base() {
HeapBasePtr base = reinterpret_cast<HeapBasePtr>(this) - (offset/sizeof(Heap::Base));
Q_ASSERT(base->inUse());
@@ -497,7 +416,7 @@ struct HeapValue : Value {
template <size_t o>
struct ValueArray {
- static Q_CONSTEXPR size_t offset = o;
+ static constexpr size_t offset = o;
uint size;
uint alloc;
Value values[1];
@@ -523,41 +442,9 @@ struct ValueArray {
return values;
}
- void insertData(EngineBase *e, uint index, Value v) {
- for (uint i = size - 1; i > index; --i) {
- values[i] = values[i - 1];
- }
- set(e, index, v);
- }
- void removeData(EngineBase *e, uint index, int n = 1) {
- Q_UNUSED(e);
- for (uint i = index; i < size - n; ++i) {
- values[i] = values[i + n];
- }
- }
-
void mark(MarkStack *markStack) {
- Value *v = values;
- const Value *end = v + alloc;
- if (alloc > 32*1024) {
- // drain from time to time to avoid overflows in the js stack
- Value::HeapBasePtr *currentBase = markStack->top;
- while (v < end) {
- v->mark(markStack);
- ++v;
- if (markStack->top >= currentBase + 32*1024) {
- Value::HeapBasePtr *oldBase = markStack->base;
- markStack->base = currentBase;
- markStack->drain();
- markStack->base = oldBase;
- }
- }
- } else {
- while (v < end) {
- v->mark(markStack);
- ++v;
- }
- }
+ for (Value *v = values, *end = values + alloc; v < end; ++v)
+ v->mark(markStack);
}
};
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index e117e509ab..62e21a120c 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -1,45 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4variantobject_p.h"
#include "qv4functionobject_p.h"
-#include "qv4objectproto_p.h"
#include <private/qqmlvaluetypewrapper_p.h>
#include <private/qv4qobjectwrapper_p.h>
@@ -55,18 +18,18 @@ void Heap::VariantObject::init()
scarceData = new ExecutionEngine::ScarceResourceData;
}
-void Heap::VariantObject::init(const QVariant &value)
+void Heap::VariantObject::init(const QMetaType type, const void *data)
{
Object::init();
- scarceData = new ExecutionEngine::ScarceResourceData(value);
+ scarceData = new ExecutionEngine::ScarceResourceData(type, data);
if (isScarce())
removeVmePropertyReference();
}
bool VariantObject::Data::isScarce() const
{
- QVariant::Type t = data().type();
- return t == QVariant::Pixmap || t == QVariant::Image;
+ int t = data().userType();
+ return t == QMetaType::QPixmap || t == QMetaType::QImage;
}
bool VariantObject::virtualIsEqualTo(Managed *m, Managed *other)
@@ -139,7 +102,7 @@ ReturnedValue VariantPrototype::method_toString(const FunctionObject *b, const V
RETURN_UNDEFINED();
const QVariant variant = o->d()->data();
QString result = variant.toString();
- if (result.isEmpty() && !variant.canConvert(QVariant::String)) {
+ if (result.isEmpty() && !variant.canConvert(QMetaType(QMetaType::QString))) {
QDebug dbg(&result);
dbg << variant;
// QDebug appends a space, we're not interested in continuing the stream so we chop it off.
@@ -154,21 +117,32 @@ ReturnedValue VariantPrototype::method_valueOf(const FunctionObject *b, const Va
const VariantObject *o = thisObject->as<QV4::VariantObject>();
if (o) {
QVariant v = o->d()->data();
- switch (v.type()) {
- case QVariant::Invalid:
+ switch (v.userType()) {
+ case QMetaType::UnknownType:
return Encode::undefined();
- case QVariant::String:
+ case QMetaType::QString:
return Encode(b->engine()->newString(v.toString()));
- case QVariant::Int:
+ case QMetaType::Int:
return Encode(v.toInt());
- case QVariant::Double:
- case QVariant::UInt:
+ case QMetaType::Double:
+ case QMetaType::UInt:
return Encode(v.toDouble());
- case QVariant::Bool:
+ case QMetaType::Bool:
return Encode(v.toBool());
default:
- if (QMetaType::typeFlags(v.userType()) & QMetaType::IsEnumeration)
- RETURN_RESULT(Encode(v.toInt()));
+ if (QMetaType(v.metaType()).flags() & QMetaType::IsEnumeration)
+ if (v.metaType().sizeOf() <= qsizetype(sizeof(int)))
+ return Encode(v.toInt());
+ if (v.canConvert<double>())
+ return Encode(v.toDouble());
+ if (v.canConvert<int>())
+ return Encode(v.toInt());
+ if (v.canConvert<uint>())
+ return Encode(v.toUInt());
+ if (v.canConvert<bool>())
+ return Encode(v.toBool());
+ if (v.canConvert<QString>())
+ return Encode(b->engine()->newString(v.toString()));
break;
}
}
diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h
index 78e0a5373a..f2394ce9a2 100644
--- a/src/qml/jsruntime/qv4variantobject_p.h
+++ b/src/qml/jsruntime/qv4variantobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4VARIANTOBJECT_P_H
#define QV4VARIANTOBJECT_P_H
@@ -67,7 +31,7 @@ namespace Heap {
struct VariantObject : Object
{
void init();
- void init(const QVariant &value);
+ void init(const QMetaType type, const void *data);
void destroy() {
Q_ASSERT(scarceData);
if (isScarce())
@@ -90,7 +54,7 @@ private:
}
-struct VariantObject : Object
+struct Q_QML_EXPORT VariantObject : Object
{
V4_OBJECT2(VariantObject, Object)
V4_PROTOTYPE(variantPrototype)
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 27d518f5c6..096b9a6299 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4vme_moth_p.h"
#include <QtCore/qjsondocument.h>
#include <QtCore/qjsonobject.h>
+#include <private/qv4alloca_p.h>
#include <private/qv4instr_moth_p.h>
#include <private/qv4value_p.h>
#include <private/qv4debugging_p.h>
@@ -58,6 +23,8 @@
#include <private/qv4generatorobject_p.h>
#include <private/qv4alloca_p.h>
#include <private/qqmljavascriptexpression_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <QtQml/private/qv4runtime_p.h>
#include <iostream>
#if QT_CONFIG(qml_jit)
@@ -68,6 +35,9 @@
#undef COUNT_INSTRUCTIONS
+Q_TRACE_POINT(qtqml, QQmlV4_function_call_entry, const QV4::ExecutionEngine *engine, const QString &function, const QString &fileName, int line, int column)
+Q_TRACE_POINT(qtqml, QQmlV4_function_call_exit)
+
enum { ShowWhenDeoptimiationHappens = 0 };
extern "C" {
@@ -341,14 +311,24 @@ static struct InstrCount {
}
#endif
-#define STACK_VALUE(temp) stack[temp]
+static inline QV4::Value &stackValue(QV4::Value *stack, size_t slot, const JSTypesStackFrame *frame)
+{
+ Q_ASSERT(slot < CallData::HeaderSize() / sizeof(QV4::StaticValue)
+ + frame->jsFrame->argc()
+ + frame->v4Function->compiledFunction->nRegisters);
+ Q_UNUSED(frame);
+
+ return stack[slot];
+}
+
+#define STACK_VALUE(temp) stackValue(stack, temp, frame)
// qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro
#ifdef CHECK_EXCEPTION
#undef CHECK_EXCEPTION
#endif
#define CHECK_EXCEPTION \
- if (engine->hasException || engine->isInterrupted.loadAcquire()) \
+ if (engine->hasException || engine->isInterrupted.loadRelaxed()) \
goto handleUnwind
static inline Heap::CallContext *getScope(QV4::Value *stack, int level)
@@ -364,26 +344,24 @@ static inline Heap::CallContext *getScope(QV4::Value *stack, int level)
static inline const QV4::Value &constant(Function *function, int index)
{
- return function->compilationUnit->constants[index].asValue<Value>();
+ return function->compilationUnit->constants[index].asValue<QV4::Value>();
}
static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs)
{
redo:
- switch (lhs.quickType()) {
- case QV4::Value::QT_ManagedOrUndefined:
- if (lhs.isUndefined())
- return false;
- Q_FALLTHROUGH();
- case QV4::Value::QT_ManagedOrUndefined1:
- case QV4::Value::QT_ManagedOrUndefined2:
- case QV4::Value::QT_ManagedOrUndefined3:
+ if (lhs.isUndefined())
+ return false;
+ if (lhs.isManagedOrUndefined()) {
// LHS: Managed
if (lhs.m()->internalClass->vtable->isString)
return RuntimeHelpers::stringToNumber(static_cast<String &>(lhs).toQString()) == rhs;
accumulator = lhs;
lhs = QV4::Value::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(accumulator), PREFERREDTYPE_HINT));
goto redo;
+ }
+
+ switch (lhs.quickType()) {
case QV4::Value::QT_Empty:
Q_UNREACHABLE();
case QV4::Value::QT_Null:
@@ -413,26 +391,81 @@ static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs)
d = val.toNumberImpl(); \
CHECK_EXCEPTION; \
} \
- i = Double::toInt32(d); \
+ i = QJSNumberCoercion::toInteger(d); \
} \
} while (false)
-ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
+struct AOTCompiledMetaMethod
+{
+public:
+ AOTCompiledMetaMethod(const Function::AOTCompiledFunction *aotCompiledFunction)
+ : aotCompiledFunction(aotCompiledFunction)
+ {}
+
+ int parameterCount() const { return aotCompiledFunction->types.size() - 1; }
+ QMetaType returnMetaType() const { return aotCompiledFunction->types[0]; }
+ QMetaType parameterMetaType(int i) const { return aotCompiledFunction->types[i + 1]; }
+
+private:
+ const Function::AOTCompiledFunction *aotCompiledFunction = nullptr;
+};
+
+void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine)
+{
+ qt_v4ResolvePendingBreakpointsHook();
+ if (engine->checkStackLimits()) {
+ frame->setReturnValueUndefined();
+ return;
+ }
+ ExecutionEngineCallDepthRecorder executionEngineCallDepthRecorder(engine);
+
+ Function *function = frame->v4Function;
+ Q_ASSERT(function->aotCompiledCode);
+ Q_TRACE_SCOPE(QQmlV4_function_call, engine, function->name()->toQString(),
+ function->executableCompilationUnit()->fileName(),
+ function->compiledFunction->location.line(),
+ function->compiledFunction->location.column());
+ Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling
+
+ const AOTCompiledMetaMethod method(&function->aotCompiledFunction);
+ QV4::coerceAndCall(
+ engine, &method, frame->returnAndArgValues(),
+ frame->returnAndArgTypes(), frame->argc(),
+ [frame, engine, function](void **argv, int argc) {
+ Q_UNUSED(argc);
+
+ QQmlPrivate::AOTCompiledContext aotContext;
+ if (auto context = QV4::ExecutionEngine::qmlContext(frame->context()->d())) {
+ QV4::Heap::QQmlContextWrapper *wrapper = static_cast<Heap::QmlContext *>(context)->qml();
+ aotContext.qmlScopeObject = wrapper->scopeObject;
+ aotContext.qmlContext = wrapper->context;
+ }
+
+ aotContext.engine = engine->jsEngine();
+ aotContext.compilationUnit = function->executableCompilationUnit();
+ function->aotCompiledCode(&aotContext, argv);
+ });
+}
+
+ReturnedValue VME::exec(JSTypesStackFrame *frame, ExecutionEngine *engine)
{
qt_v4ResolvePendingBreakpointsHook();
CHECK_STACK_LIMITS(engine);
Function *function = frame->v4Function;
Q_TRACE_SCOPE(QQmlV4_function_call, engine, function->name()->toQString(),
- function->compilationUnit->fileName(),
- function->compiledFunction->location.line,
- function->compiledFunction->location.column);
+ function->executableCompilationUnit()->fileName(),
+ function->compiledFunction->location.line(),
+ function->compiledFunction->location.column());
Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling
QV4::Debugging::Debugger *debugger = engine->debugger();
#if QT_CONFIG(qml_jit)
if (debugger == nullptr) {
- if (function->jittedCode == nullptr) {
+ // Check for codeRef here. In rare cases the JIT compilation may fail, which leaves us
+ // with a (useless) codeRef, but no jittedCode. In that case, don't try to JIT again every
+ // time we execute the function, but just interpret instead.
+ if (function->codeRef == nullptr) {
if (engine->canJIT(function))
QV4::JIT::BaselineJIT(function).generate();
else
@@ -446,6 +479,7 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
debugger->enteringFunction();
ReturnedValue result;
+ Q_ASSERT(function->kind != Function::AotCompiled);
if (function->jittedCode != nullptr && debugger == nullptr) {
result = function->jittedCode(frame, engine);
} else {
@@ -459,7 +493,7 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
return result;
}
-QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, const char *code)
+QV4::ReturnedValue VME::interpret(JSTypesStackFrame *frame, ExecutionEngine *engine, const char *code)
{
QV4::Function *function = frame->v4Function;
QV4::Value &accumulator = frame->jsFrame->accumulator.asValue<Value>();
@@ -521,14 +555,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_END_INSTR(LoadImport)
MOTH_BEGIN_INSTR(LoadLocal)
- auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
+ auto cc = static_cast<Heap::CallContext *>(STACK_VALUE(CallData::Context).m());
Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
acc = cc->locals[index].asReturnedValue();
MOTH_END_INSTR(LoadLocal)
MOTH_BEGIN_INSTR(StoreLocal)
CHECK_EXCEPTION;
- auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m());
+ auto cc = static_cast<Heap::CallContext *>(STACK_VALUE(CallData::Context).m());
Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext);
QV4::WriteBarrier::write(engine, cc, cc->locals.values[index].data_ptr(), acc);
MOTH_END_INSTR(StoreLocal)
@@ -611,6 +645,18 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
CHECK_EXCEPTION;
MOTH_END_INSTR(LoadProperty)
+ MOTH_BEGIN_INSTR(LoadOptionalProperty)
+ STORE_IP();
+ STORE_ACC();
+ if (accumulator.isNullOrUndefined()) {
+ acc = Encode::undefined();
+ code += offset;
+ } else {
+ acc = Runtime::LoadProperty::call(engine, accumulator, name);
+ }
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(LoadOptionalProperty)
+
MOTH_BEGIN_INSTR(GetLookup)
STORE_IP();
STORE_ACC();
@@ -629,6 +675,20 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
CHECK_EXCEPTION;
MOTH_END_INSTR(GetLookup)
+ MOTH_BEGIN_INSTR(GetOptionalLookup)
+ STORE_IP();
+ STORE_ACC();
+
+ QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index;
+
+ if (accumulator.isNullOrUndefined()) {
+ code += offset;
+ } else {
+ acc = l->getter(l, engine, accumulator);
+ }
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(GetOptionalLookup)
+
MOTH_BEGIN_INSTR(StoreProperty)
STORE_IP();
STORE_ACC();
@@ -659,14 +719,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_END_INSTR(StoreSuperProperty)
MOTH_BEGIN_INSTR(Yield)
- frame->yield = code;
- frame->yieldIsIterator = false;
+ frame->setYield(code);
+ frame->setYieldIsIterator(false);
return acc;
MOTH_END_INSTR(Yield)
MOTH_BEGIN_INSTR(YieldStar)
- frame->yield = code;
- frame->yieldIsIterator = true;
+ frame->setYield(code);
+ frame->setYieldIsIterator(true);
return acc;
MOTH_END_INSTR(YieldStar)
@@ -686,7 +746,8 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(IteratorNextForYieldStar)
STORE_ACC();
acc = Runtime::IteratorNextForYieldStar::call(engine, accumulator, STACK_VALUE(iterator), &STACK_VALUE(object));
- CHECK_EXCEPTION;
+ if (ACC.toBoolean())
+ code += offset;
MOTH_END_INSTR(IteratorNextForYieldStar)
MOTH_BEGIN_INSTR(CallValue)
@@ -714,7 +775,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(CallProperty)
STORE_IP();
- acc = Runtime::CallProperty::call(engine, stack[base], name, stack + argv, argc);
+ acc = Runtime::CallProperty::call(engine, STACK_VALUE(base), name, stack + argv, argc);
CHECK_EXCEPTION;
MOTH_END_INSTR(CallProperty)
@@ -722,35 +783,33 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
STORE_IP();
Lookup *l = function->executableCompilationUnit()->runtimeLookups + lookupIndex;
- if (stack[base].isNullOrUndefined()) {
+ if (STACK_VALUE(base).isNullOrUndefined()) {
QString message = QStringLiteral("Cannot call method '%1' of %2")
.arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
- .arg(stack[base].toQStringNoThrow());
+ .arg(STACK_VALUE(base).toQStringNoThrow());
acc = engine->throwTypeError(message);
goto handleUnwind;
}
// ok to have the value on the stack here
- Value f = Value::fromReturnedValue(l->getter(l, engine, stack[base]));
+ Value f = Value::fromReturnedValue(l->getter(l, engine, STACK_VALUE(base)));
- if (Q_UNLIKELY(!f.isFunctionObject())) {
- QString message = QStringLiteral("Property '%1' of object %2 is not a function")
- .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
- .arg(stack[base].toQStringNoThrow());
+ if (Q_LIKELY(f.isFunctionObject())) {
+ acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc);
+ } else if (QmlSignalHandler *handler = f.as<QmlSignalHandler>()) {
+ acc = handler->call(stack + base, stack + argv, argc);
+ } else {
+ const QString message = QStringLiteral("Property '%1' of object %2 is not a function")
+ .arg(engine->currentStackFrame->v4Function->compilationUnit
+ ->runtimeStrings[l->nameIndex]->toQString())
+ .arg(STACK_VALUE(base).toQStringNoThrow());
acc = engine->throwTypeError(message);
goto handleUnwind;
}
- acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc);
CHECK_EXCEPTION;
MOTH_END_INSTR(CallPropertyLookup)
- MOTH_BEGIN_INSTR(CallElement)
- STORE_IP();
- acc = Runtime::CallElement::call(engine, stack[base], STACK_VALUE(index), stack + argv, argc);
- CHECK_EXCEPTION;
- MOTH_END_INSTR(CallElement)
-
MOTH_BEGIN_INSTR(CallName)
STORE_IP();
acc = Runtime::CallName::call(engine, name, stack + argv, argc);
@@ -864,7 +923,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(PushWithContext)
STORE_IP();
STORE_ACC();
- acc = Runtime::PushWithContext::call(engine, stack[CallData::Accumulator]);
+ acc = Runtime::PushWithContext::call(engine, STACK_VALUE(CallData::Accumulator));
CHECK_EXCEPTION;
MOTH_END_INSTR(PushWithContext)
@@ -902,15 +961,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
STORE_IP();
STORE_ACC();
acc = Runtime::IteratorNext::call(engine, accumulator, &STACK_VALUE(value));
- STACK_VALUE(done) = acc;
- CHECK_EXCEPTION;
+ if (ACC.toBoolean())
+ code += offset;
MOTH_END_INSTR(IteratorNext)
MOTH_BEGIN_INSTR(IteratorClose)
STORE_IP();
STORE_ACC();
- acc = Runtime::IteratorClose::call(engine, accumulator, STACK_VALUE(done));
- CHECK_EXCEPTION;
+ acc = Runtime::IteratorClose::call(engine, accumulator);
MOTH_END_INSTR(IteratorClose)
MOTH_BEGIN_INSTR(DestructureRestElement)
@@ -971,12 +1029,13 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(ConvertThisToObject)
STORE_ACC();
- stack[CallData::This] = Runtime::ConvertThisToObject::call(engine, stack[CallData::This]);
+ stack[CallData::This] = Runtime::ConvertThisToObject::call(
+ engine, STACK_VALUE(CallData::This));
CHECK_EXCEPTION;
MOTH_END_INSTR(ConvertThisToObject)
MOTH_BEGIN_INSTR(LoadSuperConstructor)
- acc = Runtime::LoadSuperConstructor::call(engine, stack[CallData::Function]);
+ acc = Runtime::LoadSuperConstructor::call(engine, STACK_VALUE(CallData::Function));
CHECK_EXCEPTION;
MOTH_END_INSTR(LoadSuperConstructor)
@@ -1149,6 +1208,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_END_INSTR(CmpStrictNotEqual)
MOTH_BEGIN_INSTR(CmpIn)
+ STORE_IP();
STORE_ACC();
acc = Runtime::In::call(engine, STACK_VALUE(lhs), accumulator);
CHECK_EXCEPTION;
@@ -1244,14 +1304,17 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
}
MOTH_END_INSTR(Sub)
+ MOTH_BEGIN_INSTR(As)
+ const Value left = STACK_VALUE(lhs);
+ STORE_ACC();
+ acc = Runtime::As::call(engine, left, accumulator);
+ MOTH_END_INSTR(As)
+
MOTH_BEGIN_INSTR(Exp)
const Value left = STACK_VALUE(lhs);
double base = left.toNumber();
double exp = ACC.toNumber();
- if (qIsInf(exp) && (base == 1 || base == -1))
- acc = Encode(qQNaN());
- else
- acc = Encode(pow(base,exp));
+ acc = Encode(QQmlPrivate::jsExponentiate(base, exp));
MOTH_END_INSTR(Exp)
MOTH_BEGIN_INSTR(Mul)
@@ -1377,7 +1440,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
// We do start the exception handler in case of isInterrupted. The exception handler will
// immediately abort, due to the same isInterrupted. We don't skip the exception handler
// because the current behavior is easier to implement in the JIT.
- Q_ASSERT(engine->hasException || engine->isInterrupted.loadAcquire() || frame->unwindLevel);
+ Q_ASSERT(engine->hasException || engine->isInterrupted.loadRelaxed() || frame->unwindLevel);
if (!frame->unwindHandler) {
acc = Encode::undefined();
return acc;
diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h
index b3944f5454..786fc3880d 100644
--- a/src/qml/jsruntime/qv4vme_moth_p.h
+++ b/src/qml/jsruntime/qv4vme_moth_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4VME_MOTH_P_H
#define QV4VME_MOTH_P_H
@@ -66,8 +30,10 @@ public:
QV4::Function *function;
const QV4::ExecutionContext *scope;
};
- static QV4::ReturnedValue exec(CppStackFrame *frame, ExecutionEngine *engine);
- static QV4::ReturnedValue interpret(CppStackFrame *frame, ExecutionEngine *engine, const char *codeEntry);
+
+ static void exec(MetaTypesStackFrame *frame, ExecutionEngine *engine);
+ static QV4::ReturnedValue exec(JSTypesStackFrame *frame, ExecutionEngine *engine);
+ static QV4::ReturnedValue interpret(JSTypesStackFrame *frame, ExecutionEngine *engine, const char *codeEntry);
};
} // namespace Moth
diff --git a/src/qml/jsruntime/qv4vtable_p.h b/src/qml/jsruntime/qv4vtable_p.h
index 9dda104cd1..8ec8c87a31 100644
--- a/src/qml/jsruntime/qv4vtable_p.h
+++ b/src/qml/jsruntime/qv4vtable_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4VTABLE_P_H
#define QV4VTABLE_P_H
@@ -51,14 +15,16 @@
//
#include "qv4global_p.h"
+#include <QtCore/qmetaobject.h>
QT_BEGIN_NAMESPACE
+class QObject;
namespace QV4 {
struct Lookup;
-struct Q_QML_PRIVATE_EXPORT OwnPropertyKeyIterator {
+struct Q_QML_EXPORT OwnPropertyKeyIterator {
virtual ~OwnPropertyKeyIterator() = 0;
virtual PropertyKey next(const Object *o, Property *p = nullptr, PropertyAttributes *attrs = nullptr) = 0;
};
@@ -84,11 +50,14 @@ struct VTable
typedef ReturnedValue (*InstanceOf)(const Object *typeObject, const Value &var);
typedef ReturnedValue (*Call)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ typedef void (*CallWithMetaTypes)(const FunctionObject *, QObject *, void **, const QMetaType *, int);
typedef ReturnedValue (*CallAsConstructor)(const FunctionObject *, const Value *argv, int argc, const Value *newTarget);
typedef ReturnedValue (*ResolveLookupGetter)(const Object *, ExecutionEngine *, Lookup *);
typedef bool (*ResolveLookupSetter)(Object *, ExecutionEngine *, Lookup *, const Value &);
+ typedef int (*Metacall)(Object *, QMetaObject::Call, int, void **);
+
const VTable * const parent;
quint16 inlinePropertyOffset;
quint16 nInlineProperties;
@@ -123,11 +92,65 @@ struct VTable
Call call;
CallAsConstructor callAsConstructor;
+ CallWithMetaTypes callWithMetaTypes;
ResolveLookupGetter resolveLookupGetter;
ResolveLookupSetter resolveLookupSetter;
+
+ Metacall metacall;
};
+template<VTable::CallWithMetaTypes call>
+struct VTableCallWithMetaTypesWrapper { constexpr static VTable::CallWithMetaTypes c = call; };
+
+template<VTable::Call call>
+struct VTableCallWrapper { constexpr static VTable::Call c = call; };
+
+template<class Class>
+constexpr VTable::CallWithMetaTypes vtableMetaTypesCallEntry()
+{
+ // If Class overrides virtualCallWithMetaTypes, return that.
+ // Otherwise, if it overrides virtualCall, return nullptr so that we convert calls.
+ // Otherwise, just return whatever the base class had.
+
+ // A simple != is not considered constexpr, so we have to jump through some hoops.
+ if constexpr (!std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>) {
+ return Class::virtualCallWithMetaTypes;
+ }
+
+ if constexpr (!std::is_same_v<
+ VTableCallWrapper<Class::virtualCall>,
+ VTableCallWrapper<Class::SuperClass::virtualCall>>) {
+ return nullptr;
+ }
+
+ return Class::virtualCallWithMetaTypes;
+}
+
+template<class Class>
+constexpr VTable::Call vtableJsTypesCallEntry()
+{
+ // If Class overrides virtualCall, return that.
+ // Otherwise, if it overrides virtualCallWithMetaTypes, return nullptr so that we convert calls.
+ // Otherwise, just return whatever the base class had.
+
+ // A simple != is not considered constexpr, so we have to jump through some hoops.
+ if constexpr (!std::is_same_v<
+ VTableCallWrapper<Class::virtualCall>,
+ VTableCallWrapper<Class::SuperClass::virtualCall>>) {
+ return Class::virtualCall;
+ }
+
+ if constexpr (!std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>) {
+ return nullptr;
+ }
+
+ return Class::virtualCall;
+}
struct VTableBase {
protected:
@@ -150,9 +173,18 @@ protected:
static constexpr VTable::Call virtualCall = nullptr;
static constexpr VTable::CallAsConstructor virtualCallAsConstructor = nullptr;
+ static constexpr VTable::CallWithMetaTypes virtualCallWithMetaTypes = nullptr;
static constexpr VTable::ResolveLookupGetter virtualResolveLookupGetter = nullptr;
static constexpr VTable::ResolveLookupSetter virtualResolveLookupSetter = nullptr;
+
+ static constexpr VTable::Metacall virtualMetacall = nullptr;
+
+ template<class Class>
+ friend constexpr VTable::CallWithMetaTypes vtableMetaTypesCallEntry();
+
+ template<class Class>
+ friend constexpr VTable::Call vtableJsTypesCallEntry();
};
#define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \
@@ -190,11 +222,13 @@ protected:
classname::virtualOwnPropertyKeys, \
classname::virtualInstanceOf, \
\
- classname::virtualCall, \
- classname::virtualCallAsConstructor, \
+ QV4::vtableJsTypesCallEntry<classname>(), \
+ classname::virtualCallAsConstructor, \
+ QV4::vtableMetaTypesCallEntry<classname>(), \
\
classname::virtualResolveLookupGetter, \
- classname::virtualResolveLookupSetter \
+ classname::virtualResolveLookupSetter, \
+ classname::virtualMetacall \
}
#define DEFINE_MANAGED_VTABLE(classname) \
@@ -202,7 +236,7 @@ const QV4::VTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname,
#define V4_OBJECT2(DataClass, superClass) \
private: \
- DataClass() Q_DECL_EQ_DELETE; \
+ DataClass() = delete; \
Q_DISABLE_COPY(DataClass) \
public: \
Q_MANAGED_CHECK \
@@ -217,7 +251,7 @@ const QV4::VTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname,
dptr->_checkIsInitialized(); \
return dptr; \
} \
- Q_STATIC_ASSERT(std::is_trivial< QV4::Heap::DataClass >::value);
+ Q_STATIC_ASSERT(std::is_trivial_v<QV4::Heap::DataClass>);
#define V4_PROTOTYPE(p) \
static QV4::Object *defaultPrototype(QV4::ExecutionEngine *e) \
diff --git a/src/qml/memory/design.md b/src/qml/memory/design.md
new file mode 100644
index 0000000000..1b4eb8eac4
--- /dev/null
+++ b/src/qml/memory/design.md
@@ -0,0 +1,125 @@
+The V4 Garbage Collector
+========================
+
+ChangeLog
+---------
+- < 6.8: There was little documentation, and the gc was STW mark&sweep
+- 6.8: The gc became incremental (with a stop-the-world sweep phase)
+- 6.8: Sweep was made incremental, too
+
+
+Glossary:
+------------
+- V4: The ECMAScript engine used in Qt (qtdeclarative)
+- gc: abbreviation for garbage collector
+- mutator: the actual user application (in constrast to the collector)
+- roots: A set of pointers from which the gc process starts
+- fast roots: A subset of the roots which are not protected by a barrier
+- write barrier: A set of instructions executed on each write
+- stop the world: not concurrent
+- concurrent gc: gc and mutator can run "at the same time"; this can either mean
+ + incremental: collector and mutator run in the same thread, but in certain time intervals the mutator is paused, a chunk of the collector is executed, and then the mutator resumes. Repeats until the gc cycle is finished
+ + parallel: gc and mutator operations run in different threads
+- precise: a gc is precise if for every value it can know whether it's a pointer to a heap object (a non-precise gc can't in general distinguish pointers from pointer-sized numbers)
+- floating garbage: items that are not live, but nevertheless end up surviving the gc cycle
+- generational: generational refers to dividing objects into different "generations" based on how many collection cycles they survived. This technique is used in garbage collection to improve performance by focusing on collecting the most recently created objects first.
+- moving: A gc is moving if it can relocate objects in memory. Care must be taken to update pointers pointing to them.
+
+
+Overview:
+---------
+
+Since Qt 6.8, V4 uses an incremental, precise mark-and-sweep gc algorithm. It is neither generational nor moving.
+
+In the mark phase, each heap-item can be in one of three states:
+1. unvisited ("white"): The gc has not seen this item at all
+2. seen ("grey"): All grey items have been discovered by the gc, but items directly reachable from them have (potentially) not been visited.
+3. finished ("black"): Not only has the item been seen, but also all items directly reachable from it have been seen.
+
+Items are black if they have their corresponding bit set in the black-object bitmap. They are grey if they are stored at least once in the MarkStack, a stack data structure. Items are white if they are neither grey nor black. Note that black items must never be pushed to the MarkStack (otherwise we could easily end up with endless cycles), but items already _on_ the MarkStack can be black:
+If an item has been pushed multiple times before it has been popped, this can happen. It causes some additional work to revisit its fields, but that is safe, as after popping the item will be black, and thus we won't keep on repeatedly pushing the same item on the mark stack.
+
+The roots consist of
+- the engine-global objects (namely the internal classes for the JS globals)
+- all strings (and symbols) stored in the identifier table and
+- all actively linked compilation units.
+- Moreover, the values on the JS stack are also treated as roots; more precisely as fast roots.
+- Additionally, all persistent values (everything stored in a QJSValue as well as all bound functions of QQmlBindings) are added to the roots.
+- Lastly, all QObjectWrapper of QObjects with C++ ownership, or which are rooted in or parented to a QObject with C++ ownership are added to the root set.
+
+All roots are added to the MarkStack. Then, during mark phase, entries are:
+1. popped from the markstack
+2. All heap-objects reachable from them are added to the MarkStack (unless they are already black)
+
+To avoid that values that were on the heap during the start of the gc cycle, then moved to the stack before they could be visited and consequently freed even though they are still live, the stack is rescanned before the sweep phase.
+
+To avoid that unmarked heap-items are moved from one heap item (or the stack) to an already marked heap-item (and consequently end up hidden from the gc), we employ a Dijkstra style write barrier: Any item that becomes reachable from another heap-item is marked grey (unless already black).
+
+While a gc cycle is ongoing, allocations are black, meaning every allocated object is considered to be live (until the next gc cycle is started).
+This is currently required as compilation units linked to the engine while the gc is running are not protected by the write barrier or another mechanism. It also helps to reduce the amount of work to be done when rescanning the JS stack (as it helps to ensure that most items are already black at that point).
+
+
+The gc state machine
+--------------------
+
+To facilitate incremental garbage collection, the gc algorithm is divided into the following stages:
+
+1. markStart, the atomic initialization phase, in which the MarkStack is initialized, and a flag is set on the engine indicating that incremental gc is active
+2. markGlobalObject, an atomic phase in which the global object, the engine's identifier table and the currently linked compilation units are marked
+3. markJSStack, an atomic phase in which the JS stack is marked
+4. initMarkPersistentValues: Atomic phase. If there are persistent values, some setup is done for the next phase.
+5. markPersistentValues: An interruptible phase in which all persistent values are marked.
+6. initMarkWeakValues: Atomic phase. If there are weak values, some setup is done for the next phase
+7. markWeakValues: An interruptible phase which takes care of marking the QObjectWrappers
+8. markDrain: An interrupible phase. While the MarkStack is not empty, the marking algorithm runs.
+9. markReady: An atomic phase which currently does nothing, but could be used for e.g. logging statistics
+10. initCallDestroyObjects: An atomic phase, in which the stack is rescanned, the MarkStack is drained once more. This ensures that all live objects are really marked.
+ Afterwards, the iteration over all the QObjectWrappers is prepared.
+11. callDestroyObject: An interruptible phase, were we call destroyObject of all non-marked QObjectWrapper.
+12. freeWeakMaps: An atomic phase in which we remove references to dead objects from live weak maps.
+13. freeWeakSets: Same as the last phase, but for weak sets
+14: handleQObjectWrappers: An atomic phase in which pending references to QObjectWrappers are cleared
+15. multiple sweep phases: Atomic phases, in which do the actual sweeping to free up memory. Note that this will also call destroy on objects marked with `V4_NEEDS_DESTROY`. There is one phase for the various allocators (identifier table, block allocator, huge item allocator, IC allocator)
+16. updateMetaData: Updates the black bitmaps, the usage statistics, and marks the gc cycle as done.
+17. invalid, the "not-running" stage of the state machine.
+
+To avoid constantly having to query the timer, even interruptible phases run for a fixed amount of steps before checking whether there's a timemout.
+
+Most steps are straight-forward, only the persistent and weak value phases require some explanation as to why it's safe to interrupt the process: The important thing to note is that we never remove elements from the structure while we're undergoing gc, and that we only ever append at the end. So we will see any new values that might be added.
+
+Persistent Values
+-----------------
+As shown in the diagram above, the handling of persistent values is interruptible (both for "real" persistent values, and also for weak vaules which also are stored in a `PersistentValueStorage` data structure.
+This is done by storing the `PersistentValueStorage::Iterator` in the gc state machine. That in turn raises two questions: Is the iterator safe against invalidation? And do we actually keep track of newly added persistent values?
+
+The latter part is easy to answer: Any newly added weak value is marked when we are in a gc cycle, so the marking part is handled. Sweeping only cares about unmarked values, so that's safe too.
+To answer the question about iterator validity, we have to look at the `PersistentValueStorage` data structure. Conceptionally, it's a forward-list of `Page`s (arrays of `QV4::Value`). Pages are ref-counted, and only unliked from the list if the ref-count reaches zero. Moreover, iterators also increase the ref-count.
+Therefore, as long as we iterate over the list, we don't risk having the pointer point to a deleted `Page` – even if all values in it have been freed. Freeing values is unproblematic for the gc – it will simply encounter `undefined` values, something it is already prepared to handle.
+Pages are also kept in the list while they are not deleted, so iteration works as expected. The only adjustment we need to do is to disable an optimization: When searching for a Page with an empty slot, we have
+to (potentially) travese the whole `PersistentValueStorage`. To avoid that, the first Page with empty slots is normally moved to the front of the list. However, that would mean that we could potentially skip over it during the marking phase. We sidestep that issue by simply disabling the optimization. This area could
+easily be improved in the future by keeping track of the first page with free slots in a different way.
+
+Custom marking
+---------------
+
+Some parts of the engine have to deviate from the general scheme described in the overview, as they don't integrate with the normal WriteBarrier. They are wrapped in the callback of the `QV4::WriteBarrier::markCustom` function, so that they can easily be found via "Find references".
+
+1. `QJSValue::encode`. QJSValues act as roots, and don't act as normal heap-items. When the current value of a QJSValue is overwritten with another heap-item, we also mark the new object. That aligns nicely with the gc barrier.
+2. The same applies to `PersistentValue::set`.
+3. The identifier table is another root; if a new string is inserted there during gc, it is (conservatively) marked black.
+4. PropertyKeys should for all intents and purposes use a write barrier (and have a deleted operator=). But them being an ad-hoc union type of numbers, Strings and Symbols, which has the additional requirements of having to be trivial, it turned out to be easier to simply mark them in `SharedInternalClassDataPrivate<PropertyKey>::set` (for PropertyKeys that had already been allocated), and on the fact that we allocate black for newly created PropertyKeys.
+5. `QV4::Heap::InternalClass` also requires special handling, as it uses plain members to Heap objects, notably to the prototype and to the parent internal class. As the class is somewhat special in any case (due to the usage of `SharedInternalClassData` and especially due to the usage of `SharedInternalClassData<PropertyKey>`, see notes on PropertyKey above), we use some bespoke sections for now. This could probably be cleaned up.
+
+Motivation for using a Dijkstra style barrier:
+----------------------------------------------
+- Deletion barriers are hard to support with the current PropertyKey design
+- Steele style barriers cause more work (have to revisit more objects), and as long as we have black allocations it doesn't make much sense to optimize for a minimal amount of floating garbage.
+
+Sweep Phase and finalizers:
+---------------------------
+A story for another day
+
+Allocator design:
+-----------------
+Your explanation is in another castle.
+
diff --git a/src/qml/memory/memory.pri b/src/qml/memory/memory.pri
deleted file mode 100644
index 0bc8e90d27..0000000000
--- a/src/qml/memory/memory.pri
+++ /dev/null
@@ -1,11 +0,0 @@
-INCLUDEPATH += $$PWD
-INCLUDEPATH += $$OUT_PWD
-
-SOURCES += \
- $$PWD/qv4mm.cpp \
-
-HEADERS += \
- $$PWD/qv4mm_p.h \
- $$PWD/qv4mmdefs_p.h \
- $$PWD/qv4writebarrier_p.h \
- $$PWD/qv4heap_p.h
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h
index d7cfa193e6..41150fd9e1 100644
--- a/src/qml/memory/qv4heap_p.h
+++ b/src/qml/memory/qv4heap_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4HEAP_P_H
#define QV4HEAP_P_H
@@ -50,12 +14,11 @@
// We mean it.
//
-#include <QtCore/QString>
#include <private/qv4global_p.h>
#include <private/qv4mmdefs_p.h>
#include <private/qv4writebarrier_p.h>
#include <private/qv4vtable_p.h>
-#include <QSharedPointer>
+#include <QtCore/QSharedPointer>
// To check if Heap::Base::init is called (meaning, all subclasses did their init and called their
// parent's init all up the inheritance chain), define QML_CHECK_INIT_DESTROY_CALLS below.
@@ -69,7 +32,7 @@ namespace Heap {
template <typename T, size_t o>
struct Pointer {
- static Q_CONSTEXPR size_t offset = o;
+ static constexpr size_t offset = o;
T operator->() const { return get(); }
operator T () const { return get(); }
@@ -90,7 +53,7 @@ private:
Base *ptr;
};
typedef Pointer<char *, 0> V4PointerCheck;
-Q_STATIC_ASSERT(std::is_trivial< V4PointerCheck >::value);
+Q_STATIC_ASSERT(std::is_trivial_v<V4PointerCheck>);
struct Q_QML_EXPORT Base {
void *operator new(size_t) = delete;
@@ -114,12 +77,6 @@ struct Q_QML_EXPORT Base {
Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
return Chunk::setBit(c->blackBitmap, h - c->realBase());
}
- inline void setGrayBit() {
- const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
- Chunk *c = h->chunk();
- Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
- return Chunk::setBit(c->grayBitmap, h - c->realBase());
- }
inline bool inUse() const {
const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
@@ -169,7 +126,7 @@ struct Q_QML_EXPORT Base {
Q_ALWAYS_INLINE void _setDestroyed() {}
#endif
};
-Q_STATIC_ASSERT(std::is_trivial< Base >::value);
+Q_STATIC_ASSERT(std::is_trivial_v<Base>);
// This class needs to consist only of pointer sized members to allow
// for a size/offset translation when cross-compiling between 32- and
// 64-bit.
@@ -204,11 +161,11 @@ Base *Pointer<T, o>::base() {
#ifdef QT_NO_QOBJECT
template <class T>
-struct QQmlQPointer {
+struct QV4QPointer {
};
#else
template <class T>
-struct QQmlQPointer {
+struct QV4QPointer {
void init()
{
d = nullptr;
@@ -238,23 +195,29 @@ struct QQmlQPointer {
}
operator T*() const { return data(); }
inline T* operator->() const { return data(); }
- QQmlQPointer &operator=(T *o)
+ QV4QPointer &operator=(T *o)
{
if (d)
destroy();
init(o);
return *this;
}
- bool isNull() const Q_DECL_NOTHROW
+
+ bool isNull() const noexcept
+ {
+ return !isValid() || d->strongref.loadRelaxed() == 0;
+ }
+
+ bool isValid() const noexcept
{
- return d == nullptr || qObject == nullptr || d->strongref.loadRelaxed() == 0;
+ return d != nullptr && qObject != nullptr;
}
private:
QtSharedPointer::ExternalRefCountData *d;
QObject *qObject;
};
-Q_STATIC_ASSERT(std::is_trivial< QQmlQPointer<QObject> >::value);
+Q_STATIC_ASSERT(std::is_trivial_v<QV4QPointer<QObject>>);
#endif
}
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 3465036c86..8f6a6503fc 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -1,45 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qv4engine_p.h"
#include "qv4object_p.h"
-#include "qv4objectproto_p.h"
#include "qv4mm_p.h"
#include "qv4qobjectwrapper_p.h"
#include "qv4identifiertable_p.h"
@@ -50,8 +13,6 @@
#include <qqmlengine.h>
#include "PageReservation.h"
#include "PageAllocation.h"
-#include "PageAllocationAligned.h"
-#include "StdLibExtras.h"
#include <QElapsedTimer>
#include <QMap>
@@ -63,7 +24,8 @@
#include "qv4profiling_p.h"
#include "qv4mapobject_p.h"
#include "qv4setobject_p.h"
-#include "qv4writebarrier_p.h"
+
+#include <chrono>
//#define MM_STATS
@@ -122,7 +84,7 @@ struct MemorySegment {
MemorySegment(size_t size)
{
- size += Chunk::ChunkSize; // make sure we can get enough 64k aligment memory
+ size += Chunk::ChunkSize; // make sure we can get enough 64k alignment memory
if (size < SegmentSize)
size = SegmentSize;
@@ -311,9 +273,6 @@ bool Chunk::sweep(ExecutionEngine *engine)
HeapItem *o = realBase();
bool lastSlotFree = false;
for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) {
-#if WRITEBARRIER(none)
- Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects
-#endif
quintptr toFree = objectBitmap[i] ^ blackBitmap[i];
Q_ASSERT((toFree & objectBitmap[i]) == toFree); // check all black objects are marked as being used
quintptr e = extendsBitmap[i];
@@ -357,7 +316,6 @@ bool Chunk::sweep(ExecutionEngine *engine)
- (blackBitmap[i] | e)) * Chunk::SlotSize,
Profiling::SmallItem);
objectBitmap[i] = blackBitmap[i];
- grayBitmap[i] = 0;
hasUsedSlots |= (blackBitmap[i] != 0);
extendsBitmap[i] = e;
lastSlotFree = !((objectBitmap[i]|extendsBitmap[i]) >> (sizeof(quintptr)*8 - 1));
@@ -407,7 +365,6 @@ void Chunk::freeAll(ExecutionEngine *engine)
Q_V4_PROFILE_DEALLOC(engine, (qPopulationCount(objectBitmap[i]|extendsBitmap[i])
- qPopulationCount(e)) * Chunk::SlotSize, Profiling::SmallItem);
objectBitmap[i] = 0;
- grayBitmap[i] = 0;
extendsBitmap[i] = e;
o += Chunk::Bits;
}
@@ -419,36 +376,6 @@ void Chunk::resetBlackBits()
memset(blackBitmap, 0, sizeof(blackBitmap));
}
-void Chunk::collectGrayItems(MarkStack *markStack)
-{
- // DEBUG << "sweeping chunk" << this << (*freeList);
- HeapItem *o = realBase();
- for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) {
-#if WRITEBARRIER(none)
- Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects
-#endif
- quintptr toMark = blackBitmap[i] & grayBitmap[i]; // correct for a Steele type barrier
- Q_ASSERT((toMark & objectBitmap[i]) == toMark); // check all black objects are marked as being used
- // DEBUG << hex << " index=" << i << toFree;
- while (toMark) {
- uint index = qCountTrailingZeroBits(toMark);
- quintptr bit = (static_cast<quintptr>(1) << index);
-
- toMark ^= bit; // mask out marked slot
- // DEBUG << " index" << hex << index << toFree;
-
- HeapItem *itemToFree = o + index;
- Heap::Base *b = *itemToFree;
- Q_ASSERT(b->inUse());
- markStack->push(b);
- }
- grayBitmap[i] = 0;
- o += Chunk::Bits;
- }
- // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots.";
-
-}
-
void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
{
// qDebug() << "sortIntoBins:";
@@ -479,12 +406,15 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
uint freeStart = i*Bits + index;
usedSlots &= ~((static_cast<quintptr>(1) << index) - 1);
while (!usedSlots) {
- ++i;
- if (i == EntriesInBitmap) {
- usedSlots = (quintptr)-1;
+ if (++i < EntriesInBitmap) {
+ usedSlots = (objectBitmap[i]|extendsBitmap[i]);
+ } else {
+ Q_ASSERT(i == EntriesInBitmap);
+ // Overflows to 0 when counting trailing zeroes above in next iteration.
+ // Then, all the bits are zeroes and we break.
+ usedSlots = std::numeric_limits<quintptr>::max();
break;
}
- usedSlots = (objectBitmap[i]|extendsBitmap[i]);
#ifndef QT_NO_DEBUG
allocatedSlots += qPopulationCount(usedSlots);
// qDebug() << hex << " i=" << i << "used=" << usedSlots;
@@ -594,6 +524,14 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) {
if (!m) {
if (!forceAllocation)
return nullptr;
+ if (nFree) {
+ // Save any remaining slots of the current chunk
+ // for later, smaller allocations.
+ size_t bin = binForSlots(nFree);
+ nextFree->freeData.next = freeBins[bin];
+ nextFree->freeData.availableSlots = nFree;
+ freeBins[bin] = nextFree;
+ }
Chunk *newChunk = chunkAllocator->allocate();
Q_V4_PROFILE_ALLOC(engine, Chunk::DataSize, Profiling::HeapPage);
chunks.push_back(newChunk);
@@ -658,13 +596,6 @@ void BlockAllocator::resetBlackBits()
c->resetBlackBits();
}
-void BlockAllocator::collectGrayItems(MarkStack *markStack)
-{
- for (auto c : chunks)
- c->collectGrayItems(markStack);
-
-}
-
HeapItem *HugeItemAllocator::allocate(size_t size) {
MemorySegment *m = nullptr;
Chunk *c = nullptr;
@@ -734,18 +665,6 @@ void HugeItemAllocator::resetBlackBits()
Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase());
}
-void HugeItemAllocator::collectGrayItems(MarkStack *markStack)
-{
- for (auto c : chunks)
- // Correct for a Steele type barrier
- if (Chunk::testBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase()) &&
- Chunk::testBit(c.chunk->grayBitmap, c.chunk->first() - c.chunk->realBase())) {
- HeapItem *i = c.chunk->first();
- Heap::Base *b = *i;
- b->mark(markStack);
- }
-}
-
void HugeItemAllocator::freeAll()
{
for (auto &c : chunks) {
@@ -754,6 +673,229 @@ void HugeItemAllocator::freeAll()
}
}
+namespace {
+using ExtraData = GCStateInfo::ExtraData;
+GCState markStart(GCStateMachine *that, ExtraData &)
+{
+ //Initialize the mark stack
+ that->mm->m_markStack = std::make_unique<MarkStack>(that->mm->engine);
+ that->mm->engine->isGCOngoing = true;
+ return MarkGlobalObject;
+}
+
+GCState markGlobalObject(GCStateMachine *that, ExtraData &)
+{
+ that->mm->engine->markObjects(that->mm->m_markStack.get());
+ return MarkJSStack;
+}
+
+GCState markJSStack(GCStateMachine *that, ExtraData &)
+{
+ that->mm->collectFromJSStack(that->mm->markStack());
+ return InitMarkPersistentValues;
+}
+
+GCState initMarkPersistentValues(GCStateMachine *that, ExtraData &stateData)
+{
+ if (!that->mm->m_persistentValues)
+ return InitMarkWeakValues; // no persistent values to mark
+ stateData = GCIteratorStorage { that->mm->m_persistentValues->begin() };
+ return MarkPersistentValues;
+}
+
+static constexpr int markLoopIterationCount = 1024;
+
+bool wasDrainNecessary(MarkStack *ms, QDeadlineTimer deadline)
+{
+ if (ms->remainingBeforeSoftLimit() > markLoopIterationCount)
+ return false;
+ // drain
+ ms->drain(deadline);
+ return true;
+}
+
+GCState markPersistentValues(GCStateMachine *that, ExtraData &stateData) {
+ auto markStack = that->mm->markStack();
+ if (wasDrainNecessary(markStack, that->deadline) && that->deadline.hasExpired())
+ return MarkPersistentValues;
+ PersistentValueStorage::Iterator& it = get<GCIteratorStorage>(stateData).it;
+ // avoid repeatedly hitting the timer constantly by batching iterations
+ for (int i = 0; i < markLoopIterationCount; ++i) {
+ if (!it.p)
+ return InitMarkWeakValues;
+ if (Managed *m = (*it).as<Managed>())
+ m->mark(markStack);
+ ++it;
+ }
+ return MarkPersistentValues;
+}
+
+GCState initMarkWeakValues(GCStateMachine *that, ExtraData &stateData)
+{
+ stateData = GCIteratorStorage { that->mm->m_weakValues->begin() };
+ return MarkWeakValues;
+}
+
+GCState markWeakValues(GCStateMachine *that, ExtraData &stateData)
+{
+ auto markStack = that->mm->markStack();
+ if (wasDrainNecessary(markStack, that->deadline) && that->deadline.hasExpired())
+ return MarkWeakValues;
+ PersistentValueStorage::Iterator& it = get<GCIteratorStorage>(stateData).it;
+ // avoid repeatedly hitting the timer constantly by batching iterations
+ for (int i = 0; i < markLoopIterationCount; ++i) {
+ if (!it.p)
+ return MarkDrain;
+ QObjectWrapper *qobjectWrapper = (*it).as<QObjectWrapper>();
+ ++it;
+ if (!qobjectWrapper)
+ continue;
+ QObject *qobject = qobjectWrapper->object();
+ if (!qobject)
+ continue;
+ bool keepAlive = QQmlData::keepAliveDuringGarbageCollection(qobject);
+
+ if (!keepAlive) {
+ if (QObject *parent = qobject->parent()) {
+ while (parent->parent())
+ parent = parent->parent();
+ keepAlive = QQmlData::keepAliveDuringGarbageCollection(parent);
+ }
+ }
+
+ if (keepAlive)
+ qobjectWrapper->mark(that->mm->markStack());
+ }
+ return MarkWeakValues;
+}
+
+GCState markDrain(GCStateMachine *that, ExtraData &)
+{
+ if (that->deadline.isForever()) {
+ that->mm->markStack()->drain();
+ return MarkReady;
+ }
+ auto drainState = that->mm->m_markStack->drain(that->deadline);
+ return drainState == MarkStack::DrainState::Complete
+ ? MarkReady
+ : MarkDrain;
+}
+
+GCState markReady(GCStateMachine *, ExtraData &)
+{
+ //Possibility to do some clean up, stat printing, etc...
+ return InitCallDestroyObjects;
+}
+
+/** \!internal
+collects new references from the stack, then drains the mark stack again
+*/
+void redrain(GCStateMachine *that)
+{
+ that->mm->collectFromJSStack(that->mm->markStack());
+ that->mm->m_markStack->drain();
+}
+
+GCState initCallDestroyObjects(GCStateMachine *that, ExtraData &stateData)
+{
+ // as we don't have a deletion barrier, we need to rescan the stack
+ redrain(that);
+ if (!that->mm->m_weakValues)
+ return FreeWeakMaps; // no need to call destroy objects
+ stateData = GCIteratorStorage { that->mm->m_weakValues->begin() };
+ return CallDestroyObjects;
+}
+GCState callDestroyObject(GCStateMachine *that, ExtraData &stateData)
+{
+ PersistentValueStorage::Iterator& it = get<GCIteratorStorage>(stateData).it;
+ // destroyObject might call user code, which really shouldn't call back into the gc
+ auto oldState = std::exchange(that->mm->gcBlocked, QV4::MemoryManager::Blockness::InCriticalSection);
+ auto cleanup = qScopeGuard([&]() {
+ that->mm->gcBlocked = oldState;
+ });
+ // avoid repeatedly hitting the timer constantly by batching iterations
+ for (int i = 0; i < markLoopIterationCount; ++i) {
+ if (!it.p)
+ return FreeWeakMaps;
+ Managed *m = (*it).managed();
+ ++it;
+ if (!m || m->markBit())
+ continue;
+ // we need to call destroyObject on qobjectwrappers now, so that they can emit the destroyed
+ // signal before we start sweeping the heap
+ if (QObjectWrapper *qobjectWrapper = m->as<QObjectWrapper>())
+ qobjectWrapper->destroyObject(/*lastSweep =*/false);
+ }
+ return CallDestroyObjects;
+}
+
+void freeWeakMaps(MemoryManager *mm)
+{
+ for (auto [map, lastMap] = std::tuple {mm->weakMaps, &mm->weakMaps }; map; map = map->nextWeakMap) {
+ if (!map->isMarked())
+ continue;
+ map->removeUnmarkedKeys();
+ *lastMap = map;
+ lastMap = &map->nextWeakMap;
+ }
+}
+
+GCState freeWeakMaps(GCStateMachine *that, ExtraData &)
+{
+ freeWeakMaps(that->mm);
+ return FreeWeakSets;
+}
+
+void freeWeakSets(MemoryManager *mm)
+{
+ for (auto [set, lastSet] = std::tuple {mm->weakSets, &mm->weakSets}; set; set = set->nextWeakSet) {
+
+ if (!set->isMarked())
+ continue;
+ set->removeUnmarkedKeys();
+ *lastSet = set;
+ lastSet = &set->nextWeakSet;
+ }
+}
+
+GCState freeWeakSets(GCStateMachine *that, ExtraData &)
+{
+ freeWeakSets(that->mm);
+ return HandleQObjectWrappers;
+}
+
+GCState handleQObjectWrappers(GCStateMachine *that, ExtraData &)
+{
+ that->mm->cleanupDeletedQObjectWrappersInSweep();
+ return DoSweep;
+}
+
+GCState doSweep(GCStateMachine *that, ExtraData &)
+{
+ auto mm = that->mm;
+
+ mm->engine->identifierTable->sweep();
+ mm->blockAllocator.sweep();
+ mm->hugeItemAllocator.sweep(that->mm->gcCollectorStats ? increaseFreedCountForClass : nullptr);
+ mm->icAllocator.sweep();
+
+ // reset all black bits
+ mm->blockAllocator.resetBlackBits();
+ mm->hugeItemAllocator.resetBlackBits();
+ mm->icAllocator.resetBlackBits();
+
+ mm->usedSlotsAfterLastFullSweep = mm->blockAllocator.usedSlotsAfterLastSweep + mm->icAllocator.usedSlotsAfterLastSweep;
+ mm->gcBlocked = MemoryManager::Unblocked;
+ mm->m_markStack.reset();
+ mm->engine->isGCOngoing = false;
+
+ mm->updateUnmanagedHeapSizeGCLimit();
+
+ return Invalid;
+}
+
+}
+
MemoryManager::MemoryManager(ExecutionEngine *engine)
: engine(engine)
@@ -774,6 +916,70 @@ MemoryManager::MemoryManager(ExecutionEngine *engine)
memset(statistics.allocations, 0, sizeof(statistics.allocations));
if (gcStats)
blockAllocator.allocationStats = statistics.allocations;
+
+ gcStateMachine = std::make_unique<GCStateMachine>();
+ gcStateMachine->mm = this;
+
+ gcStateMachine->stateInfoMap[GCState::MarkStart] = {
+ markStart,
+ false,
+ };
+ gcStateMachine->stateInfoMap[GCState::MarkGlobalObject] = {
+ markGlobalObject,
+ false,
+ };
+ gcStateMachine->stateInfoMap[GCState::MarkJSStack] = {
+ markJSStack,
+ false,
+ };
+ gcStateMachine->stateInfoMap[GCState::InitMarkPersistentValues] = {
+ initMarkPersistentValues,
+ false,
+ };
+ gcStateMachine->stateInfoMap[GCState::MarkPersistentValues] = {
+ markPersistentValues,
+ false,
+ };
+ gcStateMachine->stateInfoMap[GCState::InitMarkWeakValues] = {
+ initMarkWeakValues,
+ false,
+ };
+ gcStateMachine->stateInfoMap[GCState::MarkWeakValues] = {
+ markWeakValues,
+ false,
+ };
+ gcStateMachine->stateInfoMap[GCState::MarkDrain] = {
+ markDrain,
+ false,
+ };
+ gcStateMachine->stateInfoMap[GCState::MarkReady] = {
+ markReady,
+ false,
+ };
+ gcStateMachine->stateInfoMap[GCState::InitCallDestroyObjects] = {
+ initCallDestroyObjects,
+ false,
+ };
+ gcStateMachine->stateInfoMap[GCState::CallDestroyObjects] = {
+ callDestroyObject,
+ false,
+ };
+ gcStateMachine->stateInfoMap[GCState::FreeWeakMaps] = {
+ freeWeakMaps,
+ false,
+ };
+ gcStateMachine->stateInfoMap[GCState::FreeWeakSets] = {
+ freeWeakSets,
+ true, // ensure that handleQObjectWrappers runs in isolation
+ };
+ gcStateMachine->stateInfoMap[GCState::HandleQObjectWrappers] = {
+ handleQObjectWrappers,
+ false,
+ };
+ gcStateMachine->stateInfoMap[GCState::DoSweep] = {
+ doSweep,
+ false,
+ };
}
Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
@@ -848,16 +1054,19 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(const QV4::VTable *vtable
static uint markStackSize = 0;
MarkStack::MarkStack(ExecutionEngine *engine)
- : engine(engine)
+ : m_engine(engine)
{
- base = (Heap::Base **)engine->gcStack->base();
- top = base;
- limit = base + engine->maxGCStackSize()/sizeof(Heap::Base)*3/4;
+ m_base = (Heap::Base **)engine->gcStack->base();
+ m_top = m_base;
+ const size_t size = engine->maxGCStackSize() / sizeof(Heap::Base);
+ m_hardLimit = m_base + size;
+ m_softLimit = m_base + size * 3 / 4;
}
void MarkStack::drain()
{
- while (top > base) {
+ // we're not calling drain(QDeadlineTimer::Forever) as that has higher overhead
+ while (m_top > m_base) {
Heap::Base *h = pop();
++markStackSize;
Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen.
@@ -865,96 +1074,85 @@ void MarkStack::drain()
}
}
-void MemoryManager::collectRoots(MarkStack *markStack)
+MarkStack::DrainState MarkStack::drain(QDeadlineTimer deadline)
{
- engine->markObjects(markStack);
-
-// qDebug() << " mark stack after engine->mark" << (engine->jsStackTop - markBase);
-
- collectFromJSStack(markStack);
-
-// qDebug() << " mark stack after js stack collect" << (engine->jsStackTop - markBase);
- m_persistentValues->mark(markStack);
-
-// qDebug() << " mark stack after persistants" << (engine->jsStackTop - markBase);
-
- // Preserve QObject ownership rules within JavaScript: A parent with c++ ownership
- // keeps all of its children alive in JavaScript.
-
- // Do this _after_ collectFromStack to ensure that processing the weak
- // managed objects in the loop down there doesn't make then end up as leftovers
- // on the stack and thus always get collected.
- for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) {
- QObjectWrapper *qobjectWrapper = (*it).as<QObjectWrapper>();
- if (!qobjectWrapper)
- continue;
- QObject *qobject = qobjectWrapper->object();
- if (!qobject)
- continue;
- bool keepAlive = QQmlData::keepAliveDuringGarbageCollection(qobject);
-
- if (!keepAlive) {
- if (QObject *parent = qobject->parent()) {
- while (parent->parent())
- parent = parent->parent();
-
- keepAlive = QQmlData::keepAliveDuringGarbageCollection(parent);
- }
+ do {
+ for (int i = 0; i <= markLoopIterationCount * 10; ++i) {
+ if (m_top == m_base)
+ return DrainState::Complete;
+ Heap::Base *h = pop();
+ ++markStackSize;
+ Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen.
+ h->internalClass->vtable->markObjects(h, this);
}
-
- if (keepAlive)
- qobjectWrapper->mark(markStack);
-
- if (markStack->top >= markStack->limit)
- markStack->drain();
- }
+ } while (!deadline.hasExpired());
+ return DrainState::Ongoing;
}
-void MemoryManager::mark()
+void MemoryManager::onEventLoop()
{
- markStackSize = 0;
+ if (engine->inShutdown)
+ return;
+ if (gcBlocked == InCriticalSection) {
+ QMetaObject::invokeMethod(engine->publicEngine, [this]{
+ onEventLoop();
+ }, Qt::QueuedConnection);
+ return;
+ }
+ if (gcStateMachine->inProgress()) {
+ gcStateMachine->step();
+ }
+}
- MarkStack markStack(engine);
- collectRoots(&markStack);
- markStack.drain();
+void MemoryManager::setGCTimeLimit(int timeMs)
+{
+ gcStateMachine->timeLimit = std::chrono::milliseconds(timeMs);
}
void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPtr)
{
+
for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) {
Managed *m = (*it).managed();
if (!m || m->markBit())
continue;
// we need to call destroyObject on qobjectwrappers now, so that they can emit the destroyed
// signal before we start sweeping the heap
- if (QObjectWrapper *qobjectWrapper = (*it).as<QObjectWrapper>())
+ if (QObjectWrapper *qobjectWrapper = (*it).as<QObjectWrapper>()) {
qobjectWrapper->destroyObject(lastSweep);
- }
-
- // remove objects from weak maps and sets
- Heap::MapObject *map = weakMaps;
- Heap::MapObject **lastMap = &weakMaps;
- while (map) {
- if (map->isMarked()) {
- map->removeUnmarkedKeys();
- *lastMap = map;
- lastMap = &map->nextWeakMap;
}
- map = map->nextWeakMap;
}
- Heap::SetObject *set = weakSets;
- Heap::SetObject **lastSet = &weakSets;
- while (set) {
- if (set->isMarked()) {
- set->removeUnmarkedKeys();
- *lastSet = set;
- lastSet = &set->nextWeakSet;
- }
- set = set->nextWeakSet;
+ freeWeakMaps(this);
+ freeWeakSets(this);
+
+ cleanupDeletedQObjectWrappersInSweep();
+
+ if (!lastSweep) {
+ engine->identifierTable->sweep();
+ blockAllocator.sweep(/*classCountPtr*/);
+ hugeItemAllocator.sweep(classCountPtr);
+ icAllocator.sweep(/*classCountPtr*/);
}
+ // reset all black bits
+ blockAllocator.resetBlackBits();
+ hugeItemAllocator.resetBlackBits();
+ icAllocator.resetBlackBits();
+
+ usedSlotsAfterLastFullSweep = blockAllocator.usedSlotsAfterLastSweep + icAllocator.usedSlotsAfterLastSweep;
+ updateUnmanagedHeapSizeGCLimit();
+ gcBlocked = MemoryManager::Unblocked;
+}
+
+/*
+ \internal
+ Helper function used in sweep to clean up the (to-be-freed) QObjectWrapper
+ Used both in MemoryManager::sweep, and the corresponding gc statemachine phase
+*/
+void MemoryManager::cleanupDeletedQObjectWrappersInSweep()
+{
// onDestruction handlers may have accessed other QObject wrappers and reset their value, so ensure
// that they are all set to undefined.
for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) {
@@ -965,7 +1163,7 @@ void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPt
}
// Now it is time to free QV4::QObjectWrapper Value, we must check the Value's tag to make sure its object has been destroyed
- const int pendingCount = m_pendingFreedObjectWrapperValue.count();
+ const int pendingCount = m_pendingFreedObjectWrapperValue.size();
if (pendingCount) {
QVector<Value *> remainingWeakQObjectWrappers;
remainingWeakQObjectWrappers.reserve(pendingCount);
@@ -981,20 +1179,12 @@ void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPt
if (MultiplyWrappedQObjectMap *multiplyWrappedQObjects = engine->m_multiplyWrappedQObjects) {
for (MultiplyWrappedQObjectMap::Iterator it = multiplyWrappedQObjects->begin(); it != multiplyWrappedQObjects->end();) {
- if (!it.value().isNullOrUndefined())
+ if (it.value().isNullOrUndefined())
it = multiplyWrappedQObjects->erase(it);
else
++it;
}
}
-
-
- if (!lastSweep) {
- engine->identifierTable->sweep();
- blockAllocator.sweep(/*classCountPtr*/);
- hugeItemAllocator.sweep(classCountPtr);
- icAllocator.sweep(/*classCountPtr*/);
- }
}
bool MemoryManager::shouldRunGC() const
@@ -1034,15 +1224,44 @@ static size_t dumpBins(BlockAllocator *b, const char *title)
return totalSlotMem*Chunk::SlotSize;
}
+/*!
+ \internal
+ Precondition: Incremental garbage collection must be currently active
+ Finishes incremental garbage collection, unless in a critical section
+ Code entering a critical section is expected to check if we need to
+ force a gc completion, and to trigger the gc again if necessary
+ when exiting the critcial section.
+ Returns \c true if the gc cycle completed, false otherwise.
+ */
+bool MemoryManager::tryForceGCCompletion()
+{
+ if (gcBlocked == InCriticalSection)
+ return false;
+ const bool incrementalGCIsAlreadyRunning = m_markStack != nullptr;
+ Q_ASSERT(incrementalGCIsAlreadyRunning);
+ auto oldTimeLimit = std::exchange(gcStateMachine->timeLimit, std::chrono::microseconds::max());
+ while (gcStateMachine->inProgress()) {
+ gcStateMachine->step();
+ }
+ gcStateMachine->timeLimit = oldTimeLimit;
+ return true;
+}
+
+void MemoryManager::runFullGC()
+{
+ runGC();
+ const bool incrementalGCStillRunning = m_markStack != nullptr;
+ if (incrementalGCStillRunning)
+ tryForceGCCompletion();
+}
+
void MemoryManager::runGC()
{
- if (gcBlocked) {
-// qDebug() << "Not running GC.";
+ if (gcBlocked != Unblocked) {
return;
}
- QScopedValueRollback<bool> gcBlocker(gcBlocked, true);
-// qDebug() << "runGC";
+ gcBlocked = MemoryManager::NormalBlocked;
if (gcStats) {
statistics.maxReservedMem = qMax(statistics.maxReservedMem, getAllocatedMem());
@@ -1050,8 +1269,7 @@ void MemoryManager::runGC()
}
if (!gcCollectorStats) {
- mark();
- sweep();
+ gcStateMachine->step();
} else {
bool triggeredByUnmanagedHeap = (unmanagedHeapSize > unmanagedHeapSizeGCLimit);
size_t oldUnmanagedSize = unmanagedHeapSize;
@@ -1075,13 +1293,11 @@ void MemoryManager::runGC()
QElapsedTimer t;
t.start();
- mark();
+ gcStateMachine->step();
qint64 markTime = t.nsecsElapsed()/1000;
t.restart();
- sweep(false, increaseFreedCountForClass);
const size_t usedAfter = getUsedMem();
const size_t largeItemsAfter = getLargeItemsMem();
- qint64 sweepTime = t.nsecsElapsed()/1000;
if (triggeredByUnmanagedHeap) {
qDebug(stats) << "triggered by unmanaged heap:";
@@ -1093,14 +1309,13 @@ void MemoryManager::runGC()
+ dumpBins(&icAllocator, "InternalClasss");
qDebug(stats) << "Marked object in" << markTime << "us.";
qDebug(stats) << " " << markStackSize << "objects marked";
- qDebug(stats) << "Sweeped object in" << sweepTime << "us.";
// sort our object types by number of freed instances
MMStatsHash freedObjectStats;
std::swap(freedObjectStats, *freedObjectStatsGlobal());
typedef std::pair<const char*, int> ObjectStatInfo;
std::vector<ObjectStatInfo> freedObjectsSorted;
- freedObjectsSorted.reserve(freedObjectStats.count());
+ freedObjectsSorted.reserve(freedObjectStats.size());
for (auto it = freedObjectStats.constBegin(); it != freedObjectStats.constEnd(); ++it) {
freedObjectsSorted.push_back(std::make_pair(it.key(), it.value()));
}
@@ -1131,21 +1346,6 @@ void MemoryManager::runGC()
if (gcStats)
statistics.maxUsedMem = qMax(statistics.maxUsedMem, getUsedMem() + getLargeItemsMem());
-
- if (aggressiveGC) {
- // ensure we don't 'loose' any memory
- Q_ASSERT(blockAllocator.allocatedMem()
- == blockAllocator.usedMem() + dumpBins(&blockAllocator, nullptr));
- Q_ASSERT(icAllocator.allocatedMem()
- == icAllocator.usedMem() + dumpBins(&icAllocator, nullptr));
- }
-
- usedSlotsAfterLastFullSweep = blockAllocator.usedSlotsAfterLastSweep + icAllocator.usedSlotsAfterLastSweep;
-
- // reset all black bits
- blockAllocator.resetBlackBits();
- hugeItemAllocator.resetBlackBits();
- icAllocator.resetBlackBits();
}
size_t MemoryManager::getUsedMem() const
@@ -1163,6 +1363,29 @@ size_t MemoryManager::getLargeItemsMem() const
return hugeItemAllocator.usedMem();
}
+void MemoryManager::updateUnmanagedHeapSizeGCLimit()
+{
+ if (3*unmanagedHeapSizeGCLimit <= 4 * unmanagedHeapSize) {
+ // more than 75% full, raise limit
+ unmanagedHeapSizeGCLimit = std::max(unmanagedHeapSizeGCLimit,
+ unmanagedHeapSize) * 2;
+ } else if (unmanagedHeapSize * 4 <= unmanagedHeapSizeGCLimit) {
+ // less than 25% full, lower limit
+ unmanagedHeapSizeGCLimit = qMax(std::size_t(MinUnmanagedHeapSizeGCLimit),
+ unmanagedHeapSizeGCLimit/2);
+ }
+
+ if (aggressiveGC && !engine->inShutdown) {
+ // ensure we don't 'loose' any memory
+ // but not during shutdown, because than we skip parts of sweep
+ // and use freeAll instead
+ Q_ASSERT(blockAllocator.allocatedMem()
+ == blockAllocator.usedMem() + dumpBins(&blockAllocator, nullptr));
+ Q_ASSERT(icAllocator.allocatedMem()
+ == icAllocator.usedMem() + dumpBins(&icAllocator, nullptr));
+ }
+}
+
void MemoryManager::registerWeakMap(Heap::MapObject *map)
{
map->nextWeakMap = weakMaps;
@@ -1178,10 +1401,22 @@ void MemoryManager::registerWeakSet(Heap::SetObject *set)
MemoryManager::~MemoryManager()
{
delete m_persistentValues;
-
dumpStats();
+ // do one last non-incremental sweep to clean up C++ objects
+ // first, abort any on-going incremental gc operation
+ setGCTimeLimit(-1);
+ if (engine->isGCOngoing) {
+ engine->isGCOngoing = false;
+ m_markStack.reset();
+ gcStateMachine->state = GCState::Invalid;
+ blockAllocator.resetBlackBits();
+ hugeItemAllocator.resetBlackBits();
+ icAllocator.resetBlackBits();
+ }
+ // then sweep
sweep(/*lastSweep*/true);
+
blockAllocator.freeAll();
hugeItemAllocator.freeAll();
icAllocator.freeAll();
@@ -1225,6 +1460,49 @@ void MemoryManager::collectFromJSStack(MarkStack *markStack) const
}
}
+GCStateMachine::GCStateMachine()
+{
+ // base assumption: target 60fps, use at most 1/3 of time for gc
+ timeLimit = std::chrono::milliseconds { (1000 / 60) / 3 };
+}
+
+void GCStateMachine::transition() {
+ if (timeLimit.count() > 0) {
+ deadline = QDeadlineTimer(timeLimit);
+ bool deadlineExpired = false;
+ while (!(deadlineExpired = deadline.hasExpired()) && state != GCState::Invalid) {
+ if (state > GCState::InitCallDestroyObjects) {
+ /* initCallDestroyObjects is the last action which drains the mark
+ stack by default. But as our write-barrier might end up putting
+ objects on the markStack which still reference other objects.
+ Especially when we call user code triggered by Component.onDestruction,
+ but also when we run into a timeout.
+ We don't redrain before InitCallDestroyObjects, as that would
+ potentially lead to useless busy-work (e.g., if the last referencs
+ to objects are removed while the mark phase is running)
+ */
+ redrain(this);
+ }
+ GCStateInfo& stateInfo = stateInfoMap[int(state)];
+ state = stateInfo.execute(this, stateData);
+ if (stateInfo.breakAfter)
+ break;
+ }
+ if (deadlineExpired)
+ handleTimeout(state);
+ if (state != GCState::Invalid)
+ QMetaObject::invokeMethod(mm->engine->publicEngine, [this]{
+ mm->onEventLoop();
+ }, Qt::QueuedConnection);
+ } else {
+ deadline = QDeadlineTimer::Forever;
+ while (state != GCState::Invalid) {
+ GCStateInfo& stateInfo = stateInfoMap[int(state)];
+ state = stateInfo.execute(this, stateData);
+ }
+ }
+}
+
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index 6dfdd81cb2..ef0cd0c36c 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4GC_H
#define QV4GC_H
@@ -58,16 +22,79 @@
#include <private/qv4mmdefs_p.h>
#include <QVector>
-#define QV4_MM_MAXBLOCK_SHIFT "QV4_MM_MAXBLOCK_SHIFT"
-#define QV4_MM_MAX_CHUNK_SIZE "QV4_MM_MAX_CHUNK_SIZE"
-#define QV4_MM_STATS "QV4_MM_STATS"
-
#define MM_DEBUG 0
QT_BEGIN_NAMESPACE
namespace QV4 {
+enum GCState {
+ MarkStart = 0,
+ MarkGlobalObject,
+ MarkJSStack,
+ InitMarkPersistentValues,
+ MarkPersistentValues,
+ InitMarkWeakValues,
+ MarkWeakValues,
+ MarkDrain,
+ MarkReady,
+ InitCallDestroyObjects,
+ CallDestroyObjects,
+ FreeWeakMaps,
+ FreeWeakSets,
+ HandleQObjectWrappers,
+ DoSweep,
+ Invalid,
+ Count,
+};
+
+struct GCData { virtual ~GCData(){};};
+
+struct GCIteratorStorage {
+ PersistentValueStorage::Iterator it{nullptr, 0};
+};
+struct GCStateMachine;
+
+struct GCStateInfo {
+ using ExtraData = std::variant<std::monostate, GCIteratorStorage>;
+ GCState (*execute)(GCStateMachine *, ExtraData &) = nullptr; // Function to execute for this state, returns true if ready to transition
+ bool breakAfter{false};
+};
+
+struct GCStateMachine {
+ using ExtraData = GCStateInfo::ExtraData;
+ GCState state{GCState::Invalid};
+ std::chrono::microseconds timeLimit{};
+ QDeadlineTimer deadline;
+ std::array<GCStateInfo, GCState::Count> stateInfoMap;
+ MemoryManager *mm = nullptr;
+ ExtraData stateData; // extra date for specific states
+
+ GCStateMachine();
+
+ inline void step() {
+ if (!inProgress()) {
+ reset();
+ }
+ transition();
+ }
+
+ inline bool inProgress() {
+ return state != GCState::Invalid;
+ }
+
+ inline void reset() {
+ state = GCState::MarkStart;
+ }
+
+ Q_QML_EXPORT void transition();
+
+ inline void handleTimeout(GCState state) {
+ Q_UNUSED(state);
+ }
+};
+
+
struct ChunkAllocator;
struct MemorySegment;
@@ -103,7 +130,6 @@ struct BlockAllocator {
void sweep();
void freeAll();
void resetBlackBits();
- void collectGrayItems(MarkStack *markStack);
// bump allocations
HeapItem *nextFree = nullptr;
@@ -125,7 +151,6 @@ struct HugeItemAllocator {
void sweep(ClassDestroyStatsCallback classCountPtr);
void freeAll();
void resetBlackBits();
- void collectGrayItems(MarkStack *markStack);
size_t usedMem() const {
size_t used = 0;
@@ -154,15 +179,26 @@ public:
MemoryManager(ExecutionEngine *engine);
~MemoryManager();
+ template <typename ToBeMarked>
+ friend struct GCCriticalSection;
+
// TODO: this is only for 64bit (and x86 with SSE/AVX), so exend it for other architectures to be slightly more efficient (meaning, align on 8-byte boundaries).
// Note: all occurrences of "16" in alloc/dealloc are also due to the alignment.
- Q_DECL_CONSTEXPR static inline std::size_t align(std::size_t size)
+ constexpr static inline std::size_t align(std::size_t size)
{ return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); }
+ /* NOTE: allocManaged comes in various overloads. If size is not passed explicitly
+ sizeof(ManagedType::Data) is used for size. However, there are quite a few cases
+ where we allocate more than sizeof(ManagedType::Data); that's generally the case
+ when the Object has a ValueArray member.
+ If no internal class pointer is provided, ManagedType::defaultInternalClass(engine)
+ will be used as the internal class.
+ */
+
template<typename ManagedType>
inline typename ManagedType::Data *allocManaged(std::size_t size, Heap::InternalClass *ic)
{
- Q_STATIC_ASSERT(std::is_trivial< typename ManagedType::Data >::value);
+ Q_STATIC_ASSERT(std::is_trivial_v<typename ManagedType::Data>);
size = align(size);
typename ManagedType::Data *d = static_cast<typename ManagedType::Data *>(allocData(size));
d->internalClass.set(engine, ic);
@@ -172,12 +208,24 @@ public:
}
template<typename ManagedType>
+ inline typename ManagedType::Data *allocManaged(Heap::InternalClass *ic)
+ {
+ return allocManaged<ManagedType>(sizeof(typename ManagedType::Data), ic);
+ }
+
+ template<typename ManagedType>
inline typename ManagedType::Data *allocManaged(std::size_t size, InternalClass *ic)
{
return allocManaged<ManagedType>(size, ic->d());
}
template<typename ManagedType>
+ inline typename ManagedType::Data *allocManaged(InternalClass *ic)
+ {
+ return allocManaged<ManagedType>(sizeof(typename ManagedType::Data), ic);
+ }
+
+ template<typename ManagedType>
inline typename ManagedType::Data *allocManaged(std::size_t size)
{
Scope scope(engine);
@@ -185,6 +233,15 @@ public:
return allocManaged<ManagedType>(size, ic);
}
+ template<typename ManagedType>
+ inline typename ManagedType::Data *allocManaged()
+ {
+ auto constexpr size = sizeof(typename ManagedType::Data);
+ Scope scope(engine);
+ Scoped<InternalClass> ic(scope, ManagedType::defaultInternalClass(engine));
+ return allocManaged<ManagedType>(size, ic);
+ }
+
template <typename ObjectType>
typename ObjectType::Data *allocateObject(Heap::InternalClass *ic)
{
@@ -212,50 +269,52 @@ public:
}
template <typename ManagedType, typename Arg1>
- typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1)
+ typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 &&arg1)
{
typename ManagedType::Data *o = reinterpret_cast<typename ManagedType::Data *>(allocString(unmanagedSize));
o->internalClass.set(engine, ManagedType::defaultInternalClass(engine));
Q_ASSERT(o->internalClass && o->internalClass->vtable);
- o->init(arg1);
+ o->init(std::forward<Arg1>(arg1));
return o;
}
template <typename ObjectType, typename... Args>
- typename ObjectType::Data *allocObject(Heap::InternalClass *ic, Args... args)
+ typename ObjectType::Data *allocObject(Heap::InternalClass *ic, Args&&... args)
{
typename ObjectType::Data *d = allocateObject<ObjectType>(ic);
- d->init(args...);
+ d->init(std::forward<Args>(args)...);
return d;
}
template <typename ObjectType, typename... Args>
- typename ObjectType::Data *allocObject(InternalClass *ic, Args... args)
+ typename ObjectType::Data *allocObject(InternalClass *ic, Args&&... args)
{
typename ObjectType::Data *d = allocateObject<ObjectType>(ic);
- d->init(args...);
+ d->init(std::forward<Args>(args)...);
return d;
}
template <typename ObjectType, typename... Args>
- typename ObjectType::Data *allocate(Args... args)
+ typename ObjectType::Data *allocate(Args&&... args)
{
Scope scope(engine);
Scoped<ObjectType> t(scope, allocateObject<ObjectType>());
- t->d_unchecked()->init(args...);
+ t->d_unchecked()->init(std::forward<Args>(args)...);
return t->d();
}
template <typename ManagedType, typename... Args>
- typename ManagedType::Data *alloc(Args... args)
+ typename ManagedType::Data *alloc(Args&&... args)
{
Scope scope(engine);
- Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data)));
- t->d_unchecked()->init(args...);
+ Scoped<ManagedType> t(scope, allocManaged<ManagedType>());
+ t->d_unchecked()->init(std::forward<Args>(args)...);
return t->d();
}
void runGC();
+ bool tryForceGCCompletion();
+ void runFullGC();
void dumpStats() const;
@@ -267,6 +326,9 @@ public:
// and InternalClassDataPrivate<PropertyAttributes>.
void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; }
+ // called at the end of a gc cycle
+ void updateUnmanagedHeapSizeGCLimit();
+
template<typename ManagedType>
typename ManagedType::Data *allocIC()
{
@@ -277,6 +339,12 @@ public:
void registerWeakMap(Heap::MapObject *map);
void registerWeakSet(Heap::SetObject *set);
+ void onEventLoop();
+
+ //GC related methods
+ void setGCTimeLimit(int timeMs);
+ MarkStack* markStack() { return m_markStack.get(); }
+
protected:
/// expects size to be aligned
Heap::Base *allocString(std::size_t unmanagedSize);
@@ -288,33 +356,34 @@ private:
MinUnmanagedHeapSizeGCLimit = 128 * 1024
};
+public:
void collectFromJSStack(MarkStack *markStack) const;
- void mark();
void sweep(bool lastSweep = false, ClassDestroyStatsCallback classCountPtr = nullptr);
+ void cleanupDeletedQObjectWrappersInSweep();
+ bool isAboveUnmanagedHeapLimit()
+ {
+ const bool incrementalGCIsAlreadyRunning = m_markStack != nullptr;
+ const bool aboveUnmanagedHeapLimit = incrementalGCIsAlreadyRunning
+ ? unmanagedHeapSize > 3 * unmanagedHeapSizeGCLimit / 2
+ : unmanagedHeapSize > unmanagedHeapSizeGCLimit;
+ return aboveUnmanagedHeapLimit;
+ }
+private:
bool shouldRunGC() const;
- void collectRoots(MarkStack *markStack);
HeapItem *allocate(BlockAllocator *allocator, std::size_t size)
{
+ const bool incrementalGCIsAlreadyRunning = m_markStack != nullptr;
+
bool didGCRun = false;
if (aggressiveGC) {
- runGC();
+ runFullGC();
didGCRun = true;
}
- if (unmanagedHeapSize > unmanagedHeapSizeGCLimit) {
+ if (isAboveUnmanagedHeapLimit()) {
if (!didGCRun)
- runGC();
-
- if (3*unmanagedHeapSizeGCLimit <= 4 * unmanagedHeapSize) {
- // more than 75% full, raise limit
- unmanagedHeapSizeGCLimit = std::max(unmanagedHeapSizeGCLimit,
- unmanagedHeapSize) * 2;
- } else if (unmanagedHeapSize * 4 <= unmanagedHeapSizeGCLimit) {
- // less than 25% full, lower limit
- unmanagedHeapSizeGCLimit = qMax(std::size_t(MinUnmanagedHeapSizeGCLimit),
- unmanagedHeapSizeGCLimit/2);
- }
+ incrementalGCIsAlreadyRunning ? (void) tryForceGCCompletion() : runGC();
didGCRun = true;
}
@@ -342,11 +411,15 @@ public:
Heap::MapObject *weakMaps = nullptr;
Heap::SetObject *weakSets = nullptr;
+ std::unique_ptr<GCStateMachine> gcStateMachine{nullptr};
+ std::unique_ptr<MarkStack> m_markStack{nullptr};
+
std::size_t unmanagedHeapSize = 0; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items.
std::size_t unmanagedHeapSizeGCLimit;
std::size_t usedSlotsAfterLastFullSweep = 0;
- bool gcBlocked = false;
+ enum Blockness : quint8 {Unblocked, NormalBlocked, InCriticalSection };
+ Blockness gcBlocked = Unblocked;
bool aggressiveGC = false;
bool gcStats = false;
bool gcCollectorStats = false;
@@ -362,6 +435,51 @@ public:
} statistics;
};
+/*!
+ \internal
+ GCCriticalSection prevets the gc from running, until it is destructed.
+ In its dtor, it runs a check whether we've reached the unmanaegd heap limit,
+ and triggers a gc run if necessary.
+ Lastly, it can optionally mark an object passed to it before runnig the gc.
+ */
+template <typename ToBeMarked = void>
+struct GCCriticalSection {
+ Q_DISABLE_COPY_MOVE(GCCriticalSection)
+
+ Q_NODISCARD_CTOR GCCriticalSection(QV4::ExecutionEngine *engine, ToBeMarked *toBeMarked = nullptr)
+ : m_engine(engine)
+ , m_oldState(std::exchange(engine->memoryManager->gcBlocked, MemoryManager::InCriticalSection))
+ , m_toBeMarked(toBeMarked)
+ {
+ // disallow nested critical sections
+ Q_ASSERT(m_oldState != MemoryManager::InCriticalSection);
+ }
+ ~GCCriticalSection()
+ {
+ m_engine->memoryManager->gcBlocked = m_oldState;
+ if (m_oldState != MemoryManager::Unblocked)
+ if constexpr (!std::is_same_v<ToBeMarked, void>)
+ if (m_toBeMarked)
+ m_toBeMarked->markObjects(m_engine->memoryManager->markStack());
+ /* because we blocked the gc, we might be using too much memoryon the unmanaged heap
+ and did not run the normal fixup logic. So recheck again, and trigger a gc run
+ if necessary*/
+ if (!m_engine->memoryManager->isAboveUnmanagedHeapLimit())
+ return;
+ if (!m_engine->isGCOngoing) {
+ m_engine->memoryManager->runGC();
+ } else {
+ [[maybe_unused]] bool gcFinished = m_engine->memoryManager->tryForceGCCompletion();
+ Q_ASSERT(gcFinished);
+ }
+ }
+
+private:
+ QV4::ExecutionEngine *m_engine;
+ MemoryManager::Blockness m_oldState;
+ ToBeMarked *m_toBeMarked;
+};
+
}
QT_END_NAMESPACE
diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h
index 8a53492822..b77b615e6c 100644
--- a/src/qml/memory/qv4mmdefs_p.h
+++ b/src/qml/memory/qv4mmdefs_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4MMDEFS_P_H
#define QV4MMDEFS_P_H
@@ -53,10 +17,12 @@
#include <private/qv4global_p.h>
#include <private/qv4runtimeapi_p.h>
#include <QtCore/qalgorithms.h>
-#include <qdebug.h>
+#include <QtCore/qmath.h>
QT_BEGIN_NAMESPACE
+class QDeadlineTimer;
+
namespace QV4 {
struct MarkStack;
@@ -95,7 +61,7 @@ struct Chunk {
SlotSizeShift = 5,
NumSlots = ChunkSize/SlotSize,
BitmapSize = NumSlots/8,
- HeaderSize = 4*BitmapSize,
+ HeaderSize = 3*BitmapSize,
DataSize = ChunkSize - HeaderSize,
AvailableSlots = DataSize/SlotSize,
#if QT_POINTER_SIZE == 8
@@ -107,7 +73,6 @@ struct Chunk {
#endif
EntriesInBitmap = BitmapSize/sizeof(quintptr)
};
- quintptr grayBitmap[BitmapSize/sizeof(quintptr)];
quintptr blackBitmap[BitmapSize/sizeof(quintptr)];
quintptr objectBitmap[BitmapSize/sizeof(quintptr)];
quintptr extendsBitmap[BitmapSize/sizeof(quintptr)];
@@ -188,7 +153,6 @@ struct Chunk {
bool sweep(ClassDestroyStatsCallback classCountPtr);
void resetBlackBits();
- void collectGrayItems(QV4::MarkStack *markStack);
bool sweep(ExecutionEngine *engine);
void freeAll(ExecutionEngine *engine);
@@ -212,19 +176,14 @@ struct HeapItem {
return reinterpret_cast<Chunk *>(reinterpret_cast<quintptr>(this) >> Chunk::ChunkShift << Chunk::ChunkShift);
}
- bool isGray() const {
- Chunk *c = chunk();
- uint index = this - c->realBase();
- return Chunk::testBit(c->grayBitmap, index);
- }
bool isBlack() const {
Chunk *c = chunk();
- uint index = this - c->realBase();
+ std::ptrdiff_t index = this - c->realBase();
return Chunk::testBit(c->blackBitmap, index);
}
bool isInUse() const {
Chunk *c = chunk();
- uint index = this - c->realBase();
+ std::ptrdiff_t index = this - c->realBase();
return Chunk::testBit(c->objectBitmap, index);
}
@@ -243,10 +202,10 @@ struct HeapItem {
// Doesn't report correctly for huge items
size_t size() const {
Chunk *c = chunk();
- uint index = this - c->realBase();
+ std::ptrdiff_t index = this - c->realBase();
Q_ASSERT(Chunk::testBit(c->objectBitmap, index));
// ### optimize me
- uint end = index + 1;
+ std::ptrdiff_t end = index + 1;
while (end < Chunk::NumSlots && Chunk::testBit(c->extendsBitmap, end))
++end;
return (end - index)*sizeof(HeapItem);
@@ -270,22 +229,52 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize);
Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits);
Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits);
-struct MarkStack {
+struct Q_QML_EXPORT MarkStack {
MarkStack(ExecutionEngine *engine);
- Heap::Base **top = nullptr;
- Heap::Base **base = nullptr;
- Heap::Base **limit = nullptr;
- ExecutionEngine *engine;
+ ~MarkStack() { /* we drain manually */ }
+
void push(Heap::Base *m) {
- *top = m;
- ++top;
+ *(m_top++) = m;
+
+ if (m_top < m_softLimit)
+ return;
+
+ // If at or above soft limit, partition the remaining space into at most 64 segments and
+ // allow one C++ recursion of drain() per segment, plus one for the fence post.
+ const quintptr segmentSize = qNextPowerOfTwo(quintptr(m_hardLimit - m_softLimit) / 64u);
+ if (m_drainRecursion * segmentSize <= quintptr(m_top - m_softLimit)) {
+ ++m_drainRecursion;
+ drain();
+ --m_drainRecursion;
+ } else if (m_top == m_hardLimit) {
+ qFatal("GC mark stack overrun. Either simplify your application or"
+ "increase QV4_GC_MAX_STACK_SIZE");
+ }
}
- Heap::Base *pop() {
- --top;
- return *top;
+
+ bool isEmpty() const { return m_top == m_base; }
+
+ qptrdiff remainingBeforeSoftLimit() const
+ {
+ return m_softLimit - m_top;
}
+
+ ExecutionEngine *engine() const { return m_engine; }
+
void drain();
+ enum class DrainState { Ongoing, Complete };
+ DrainState drain(QDeadlineTimer deadline);
+private:
+ Heap::Base *pop() { return *(--m_top); }
+
+ Heap::Base **m_top = nullptr;
+ Heap::Base **m_base = nullptr;
+ Heap::Base **m_softLimit = nullptr;
+ Heap::Base **m_hardLimit = nullptr;
+
+ ExecutionEngine *m_engine = nullptr;
+ quintptr m_drainRecursion = 0;
};
// Some helper to automate the generation of our
@@ -329,7 +318,7 @@ struct MarkStack {
struct name##SizeStruct : base, name##OffsetStruct {}; \
struct name##Data { \
typedef base SuperClass; \
- static Q_CONSTEXPR size_t baseOffset = sizeof(name##SizeStruct) - sizeof(name##OffsetStruct); \
+ static constexpr size_t baseOffset = sizeof(name##SizeStruct) - sizeof(name##OffsetStruct); \
name##Members(name, HEAP_OBJECT_MEMBER_EXPANSION) \
}; \
Q_STATIC_ASSERT(sizeof(name##SizeStruct) == sizeof(name##Data) + name##Data::baseOffset); \
diff --git a/src/qml/memory/qv4stacklimits.cpp b/src/qml/memory/qv4stacklimits.cpp
new file mode 100644
index 0000000000..288a6fd347
--- /dev/null
+++ b/src/qml/memory/qv4stacklimits.cpp
@@ -0,0 +1,382 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qv4stacklimits_p.h>
+#include <private/qobject_p.h>
+#include <private/qthread_p.h>
+
+#include <QtCore/qfile.h>
+
+#if defined(Q_OS_UNIX)
+# include <pthread.h>
+#endif
+
+#ifdef Q_OS_WIN
+# include <QtCore/qt_windows.h>
+#elif defined(Q_OS_FREEBSD_KERNEL) || defined(Q_OS_OPENBSD)
+# include <pthread_np.h>
+#elif defined(Q_OS_LINUX)
+# include <unistd.h>
+# include <sys/resource.h> // for getrlimit()
+# include <sys/syscall.h> // for SYS_gettid
+# if defined(__GLIBC__) && QT_CONFIG(dlopen)
+# include <dlfcn.h>
+# endif
+#elif defined(Q_OS_DARWIN)
+# include <sys/resource.h> // for getrlimit()
+#elif defined(Q_OS_QNX)
+# include <devctl.h>
+# include <sys/procfs.h>
+# include <sys/types.h>
+# include <unistd.h>
+#elif defined(Q_OS_INTEGRITY)
+# include <INTEGRITY.h>
+#elif defined(Q_OS_VXWORKS)
+# include <taskLib.h>
+#elif defined(Q_OS_WASM)
+# include <emscripten/stack.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+enum StackDefaults : qsizetype {
+ // Default safety margin at the end of the usable stack.
+ // Since we don't check the stack on every instruction, we might overrun our soft limit.
+ DefaultSafetyMargin = 128 * 1024,
+#if defined(Q_OS_IOS)
+ PlatformStackSize = 1024 * 1024,
+ PlatformSafetyMargin = DefaultSafetyMargin,
+#elif defined(Q_OS_MACOS)
+ PlatformStackSize = 8 * 1024 * 1024,
+ PlatformSafetyMargin = DefaultSafetyMargin,
+#elif defined(Q_OS_ANDROID)
+ // Android appears to have 1MB stacks.
+ PlatformStackSize = 1024 * 1024,
+ PlatformSafetyMargin = DefaultSafetyMargin,
+#elif defined(Q_OS_LINUX)
+ // On linux, we assume 8MB stacks if rlimit doesn't work.
+ PlatformStackSize = 8 * 1024 * 1024,
+ PlatformSafetyMargin = DefaultSafetyMargin,
+#elif defined(Q_OS_QNX)
+ // QNX's stack is only 512k by default
+ PlatformStackSize = 512 * 1024,
+ PlatformSafetyMargin = DefaultSafetyMargin,
+#else
+ // We try to claim 512k if we don't know anything else.
+ PlatformStackSize = 512 * 1024,
+ PlatformSafetyMargin = DefaultSafetyMargin,
+#endif
+};
+
+// We may not be able to take the negative of the type
+// used to represent stack size, but we can always add
+// or subtract it to/from a quint8 pointer.
+
+template<typename Size>
+static void *incrementStackPointer(void *base, Size amount)
+{
+#if Q_STACK_GROWTH_DIRECTION > 0
+ return static_cast<quint8 *>(base) + amount;
+#else
+ return static_cast<quint8 *>(base) - amount;
+#endif
+}
+
+template<typename Size>
+static void *decrementStackPointer(void *base, Size amount)
+{
+#if Q_STACK_GROWTH_DIRECTION > 0
+ return static_cast<quint8 *>(base) - amount;
+#else
+ return static_cast<quint8 *>(base) + amount;
+#endif
+}
+
+static StackProperties createStackProperties(void *base, qsizetype size = PlatformStackSize)
+{
+ return StackProperties {
+ base,
+ incrementStackPointer(base, size - PlatformSafetyMargin),
+ incrementStackPointer(base, size),
+ };
+}
+
+#if defined(Q_OS_DARWIN) || defined(Q_OS_LINUX)
+
+// On linux and darwin, on the main thread, the pthread functions
+// may not return the true stack size since the main thread stack
+// may grow. Use rlimit instead. rlimit does not work for secondary
+// threads, though. If getrlimit fails, we assume the platform
+// stack size.
+static qsizetype getMainStackSizeFromRlimit()
+{
+ rlimit limit;
+ return (getrlimit(RLIMIT_STACK, &limit) == 0 && limit.rlim_cur != RLIM_INFINITY)
+ ? qsizetype(limit.rlim_cur)
+ : qsizetype(PlatformStackSize);
+}
+#endif
+
+#if defined(Q_OS_INTEGRITY)
+
+StackProperties stackProperties()
+{
+ Address stackLow, stackHigh;
+ CheckSuccess(GetTaskStackLimits(CurrentTask(), &stackLow, &stackHigh));
+# if Q_STACK_GROWTH_DIRECTION < 0
+ return createStackProperties(reinterpret_cast<void *>(stackHigh), stackHigh - stackLow);
+# else
+ return createStackProperties(reinterpret_cast<void *>(stackLow), stackHigh - stackLow);
+# endif
+}
+
+#elif defined(Q_OS_DARWIN)
+
+StackProperties stackProperties()
+{
+ pthread_t thread = pthread_self();
+ return createStackProperties(
+ pthread_get_stackaddr_np(thread),
+ pthread_main_np()
+ ? getMainStackSizeFromRlimit()
+ : qsizetype(pthread_get_stacksize_np(thread)));
+}
+
+#elif defined(Q_OS_WIN)
+
+static_assert(Q_STACK_GROWTH_DIRECTION < 0);
+StackProperties stackProperties()
+{
+ // MinGW complains about out of bounds array access in compiler headers
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_GCC("-Warray-bounds")
+
+ // Get the stack base.
+# ifdef _WIN64
+ PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb());
+# else
+ PNT_TIB pTib = reinterpret_cast<PNT_TIB>(NtCurrentTeb());
+# endif
+
+ QT_WARNING_POP
+
+ quint8 *stackBase = reinterpret_cast<quint8 *>(pTib->StackBase);
+
+ // Get the stack limit. tib->StackLimit is the size of the
+ // currently mapped stack. The address space is larger.
+ MEMORY_BASIC_INFORMATION mbi = {};
+ if (!VirtualQuery(&mbi, &mbi, sizeof(mbi)))
+ qFatal("Could not retrieve memory information for stack.");
+
+ quint8 *stackLimit = reinterpret_cast<quint8 *>(mbi.AllocationBase);
+ return createStackProperties(stackBase, qsizetype(stackBase - stackLimit));
+}
+
+#elif defined(Q_OS_OPENBSD)
+
+StackProperties stackProperties()
+{
+ // From the OpenBSD docs:
+ //
+ // The pthread_stackseg_np() function returns information about the given thread's stack.
+ // A stack_t is the same as a struct sigaltstack (see sigaltstack(2)) except the ss_sp
+ // variable points to the top of the stack instead of the base.
+ //
+ // Since the example in the sigaltstack(2) documentation shows ss_sp being assigned the result
+ // of a malloc() call, we can assume that "top of the stack" means "the highest address", not
+ // the logical top of the stack.
+
+ stack_t ss;
+ rc = pthread_stackseg_np(pthread_self, &ss);
+#if Q_STACK_GROWTH_DIRECTION < 0
+ return createStackProperties(ss.ss_sp);
+#else
+ return createStackProperties(decrementStackPointer(ss.ss_sp, ss.ss_size));
+#endif
+}
+
+#elif defined(Q_OS_QNX)
+
+StackProperties stackProperties()
+{
+ const auto tid = pthread_self();
+ procfs_status status;
+ status.tid = tid;
+
+ const int fd = open("/proc/self/ctl", O_RDONLY);
+ if (fd == -1)
+ qFatal("Could not open /proc/self/ctl");
+ const auto guard = qScopeGuard([fd]() { close(fd); });
+
+ if (devctl(fd, DCMD_PROC_TIDSTATUS, &status, sizeof(status), 0) != EOK)
+ qFatal("Could not query thread status for current thread");
+
+ if (status.tid != tid)
+ qFatal("Thread status query returned garbage");
+
+#if Q_STACK_GROWTH_DIRECTION < 0
+ return createStackProperties(
+ decrementStackPointer(reinterpret_cast<void *>(status.stkbase), status.stksize),
+ status.stksize);
+#else
+ return createStackProperties(reinterpret_cast<void *>(status.stkbase), status.stksize);
+#endif
+}
+
+#elif defined(Q_OS_WASM)
+
+StackProperties stackProperties()
+{
+ const uintptr_t base = emscripten_stack_get_base();
+ const uintptr_t end = emscripten_stack_get_end();
+ const size_t size = base - end;
+ return createStackProperties(reinterpret_cast<void *>(base), size);
+}
+
+#elif defined(Q_OS_VXWORKS)
+
+StackProperties stackProperties()
+{
+ TASK_DESC taskDescription;
+ taskInfoGet(taskIdSelf(), &taskDescription);
+ return createStackProperties(taskDescription.td_pStackBase, taskDescription.td_stackSize);
+}
+
+#else
+
+StackProperties stackPropertiesGeneric(qsizetype stackSize = 0)
+{
+ // If stackSize is given, do not trust the stack size returned by pthread_attr_getstack
+
+ pthread_t thread = pthread_self();
+ pthread_attr_t sattr;
+# if defined(PTHREAD_NP_H) || defined(_PTHREAD_NP_H_) || defined(Q_OS_NETBSD)
+ pthread_attr_init(&sattr);
+ pthread_attr_get_np(thread, &sattr);
+# else
+ pthread_getattr_np(thread, &sattr);
+# endif
+
+ // pthread_attr_getstack returns the address of the memory region, which is the physical
+ // base of the stack, not the logical one.
+ void *stackBase;
+ size_t regionSize;
+ int rc = pthread_attr_getstack(&sattr, &stackBase, &regionSize);
+ pthread_attr_destroy(&sattr);
+
+ if (rc)
+ qFatal("Cannot find stack base");
+
+# if Q_STACK_GROWTH_DIRECTION < 0
+ stackBase = decrementStackPointer(stackBase, regionSize);
+# endif
+
+ return createStackProperties(stackBase, stackSize ? stackSize : regionSize);
+}
+
+#if defined(Q_OS_LINUX)
+
+static void *stackBaseFromLibc()
+{
+#if defined(__GLIBC__) && QT_CONFIG(dlopen)
+ void **libcStackEnd = static_cast<void **>(dlsym(RTLD_DEFAULT, "__libc_stack_end"));
+ if (!libcStackEnd)
+ return nullptr;
+ if (void *stackBase = *libcStackEnd)
+ return stackBase;
+#endif
+ return nullptr;
+}
+
+struct StackSegment {
+ quintptr base;
+ quintptr limit;
+};
+
+static StackSegment stackSegmentFromProc()
+{
+ QFile maps(QStringLiteral("/proc/self/maps"));
+ if (!maps.open(QIODevice::ReadOnly))
+ return {0, 0};
+
+ const quintptr stackAddr = reinterpret_cast<quintptr>(&maps);
+
+ char buffer[1024];
+ while (true) {
+ const qint64 length = maps.readLine(buffer, 1024);
+ if (length <= 0)
+ break;
+
+ const QByteArrayView line(buffer, length);
+ bool ok = false;
+
+ const qsizetype boundary = line.indexOf('-');
+ if (boundary < 0)
+ continue;
+
+ const quintptr base = line.sliced(0, boundary).toULongLong(&ok, 16);
+ if (!ok || base > stackAddr)
+ continue;
+
+ const qsizetype end = line.indexOf(' ', boundary);
+ if (end < 0)
+ continue;
+
+ const quintptr limit = line.sliced(boundary + 1, end - boundary - 1).toULongLong(&ok, 16);
+ if (!ok || limit <= stackAddr)
+ continue;
+
+ return {base, limit};
+ }
+
+ return {0, 0};
+}
+
+StackProperties stackProperties()
+{
+ if (getpid() != static_cast<pid_t>(syscall(SYS_gettid)))
+ return stackPropertiesGeneric();
+
+ // On linux (including android), the pthread functions are expensive
+ // and unreliable on the main thread.
+
+ // First get the stack size from rlimit
+ const qsizetype stackSize = getMainStackSizeFromRlimit();
+
+ // If we have glibc and libdl, we can query a special symbol in glibc to find the base.
+ // That is extremely cheap, compared to all other options.
+ if (stackSize) {
+ if (void *base = stackBaseFromLibc())
+ return createStackProperties(base, stackSize);
+ }
+
+ // Try to read the stack segment from /proc/self/maps if possible.
+ const StackSegment segment = stackSegmentFromProc();
+ if (segment.base) {
+# if Q_STACK_GROWTH_DIRECTION > 0
+ void *stackBase = reinterpret_cast<void *>(segment.base);
+# else
+ void *stackBase = reinterpret_cast<void *>(segment.limit);
+# endif
+ return createStackProperties(
+ stackBase, stackSize ? stackSize : segment.limit - segment.base);
+ }
+
+ // If we can't read /proc/self/maps, use the pthread functions after all, but
+ // override the stackSize. The main thread can grow its stack, and the pthread
+ // functions typically return the currently allocated stack size.
+ return stackPropertiesGeneric(stackSize);
+}
+
+#else // Q_OS_LINUX
+
+StackProperties stackProperties() { return stackPropertiesGeneric(); }
+
+#endif // Q_OS_LINUX
+#endif
+
+} // namespace QV4
+
+QT_END_NAMESPACE
diff --git a/src/qml/memory/qv4stacklimits_p.h b/src/qml/memory/qv4stacklimits_p.h
new file mode 100644
index 0000000000..9e7fdb279b
--- /dev/null
+++ b/src/qml/memory/qv4stacklimits_p.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QV4STACKLIMITS_P_H
+#define QV4STACKLIMITS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtqmlglobal_p.h>
+
+#ifndef Q_STACK_GROWTH_DIRECTION
+# ifdef Q_PROCESSOR_HPPA
+# define Q_STACK_GROWTH_DIRECTION (1)
+# else
+# define Q_STACK_GROWTH_DIRECTION (-1)
+# endif
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+// Note: This does not return a completely accurate stack pointer.
+// Depending on whether this function is inlined or not, we may get the address of
+// this function's stack frame or the caller's stack frame.
+// Always use a safety margin when determining stack limits.
+inline const void *currentStackPointer()
+{
+ // TODO: How often do we actually need the assembler mess below? Is that worth it?
+
+ void *stackPointer;
+#if defined(Q_CC_GNU) || __has_builtin(__builtin_frame_address)
+ stackPointer = __builtin_frame_address(0);
+#elif defined(Q_CC_MSVC)
+ stackPointer = &stackPointer;
+#elif defined(Q_PROCESSOR_X86_64)
+ __asm__ __volatile__("movq %%rsp, %0" : "=r"(stackPointer) : :);
+#elif defined(Q_PROCESSOR_X86)
+ __asm__ __volatile__("movl %%esp, %0" : "=r"(stackPointer) : :);
+#elif defined(Q_PROCESSOR_ARM_64) && defined(__ILP32__)
+ quint64 stackPointerRegister = 0;
+ __asm__ __volatile__("mov %0, sp" : "=r"(stackPointerRegister) : :);
+ stackPointer = reinterpret_cast<void *>(stackPointerRegister);
+#elif defined(Q_PROCESSOR_ARM_64) || defined(Q_PROCESSOR_ARM_32)
+ __asm__ __volatile__("mov %0, sp" : "=r"(stackPointer) : :);
+#else
+ stackPointer = &stackPointer;
+#endif
+ return stackPointer;
+}
+
+struct StackProperties
+{
+ const void *base = nullptr;
+ const void *softLimit = nullptr;
+ const void *hardLimit = nullptr;
+};
+
+StackProperties stackProperties();
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4STACKLIMITS_P_H
diff --git a/src/qml/memory/qv4writebarrier.cpp b/src/qml/memory/qv4writebarrier.cpp
new file mode 100644
index 0000000000..d7e56212ca
--- /dev/null
+++ b/src/qml/memory/qv4writebarrier.cpp
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include <private/qv4value_p.h>
+#include <private/qv4mm_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+ void markHeapBase(QV4::MarkStack* markStack, QV4::Heap::Base *base){
+ if (!base)
+ return;
+ base->mark(markStack);
+ }
+}
+namespace QV4 {
+
+void WriteBarrier::write_slowpath(EngineBase *engine, Heap::Base *base, ReturnedValue *slot, ReturnedValue value)
+{
+ Q_UNUSED(base);
+ Q_UNUSED(slot);
+ MarkStack * markStack = engine->memoryManager->markStack();
+ if constexpr (isInsertionBarrier)
+ markHeapBase(markStack, Value::fromReturnedValue(value).heapObject());
+}
+
+void WriteBarrier::write_slowpath(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value)
+{
+ Q_UNUSED(base);
+ Q_UNUSED(slot);
+ MarkStack * markStack = engine->memoryManager->markStack();
+ if constexpr (isInsertionBarrier)
+ markHeapBase(markStack, value);
+}
+
+}
+QT_END_NAMESPACE
diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h
index c65cfc0269..ddee183982 100644
--- a/src/qml/memory/qv4writebarrier_p.h
+++ b/src/qml/memory/qv4writebarrier_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4WRITEBARRIER_P_H
#define QV4WRITEBARRIER_P_H
@@ -51,57 +15,115 @@
//
#include <private/qv4global_p.h>
+#include <private/qv4enginebase_p.h>
QT_BEGIN_NAMESPACE
-#define WRITEBARRIER_none 1
-
-#define WRITEBARRIER(x) (1/WRITEBARRIER_##x == 1)
-
namespace QV4 {
struct EngineBase;
-
-namespace WriteBarrier {
-
-enum Type {
- NoBarrier,
- Barrier
+typedef quint64 ReturnedValue;
+
+struct WriteBarrier {
+
+ static constexpr bool isInsertionBarrier = true;
+
+ Q_ALWAYS_INLINE static void write(EngineBase *engine, Heap::Base *base, ReturnedValue *slot, ReturnedValue value)
+ {
+ if (engine->isGCOngoing)
+ write_slowpath(engine, base, slot, value);
+ *slot = value;
+ }
+ Q_QML_EXPORT Q_NEVER_INLINE static void write_slowpath(
+ EngineBase *engine, Heap::Base *base,
+ ReturnedValue *slot, ReturnedValue value);
+
+ Q_ALWAYS_INLINE static void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value)
+ {
+ if (engine->isGCOngoing)
+ write_slowpath(engine, base, slot, value);
+ *slot = value;
+ }
+ Q_QML_EXPORT Q_NEVER_INLINE static void write_slowpath(
+ EngineBase *engine, Heap::Base *base,
+ Heap::Base **slot, Heap::Base *value);
+
+ // MemoryManager isn't a complete type here, so make Engine a template argument
+ // so that we can still call engine->memoryManager->markStack()
+ template<typename F, typename Engine = EngineBase>
+ static void markCustom(Engine *engine, F &&markFunction) {
+ if (engine->isGCOngoing)
+ (std::forward<F>(markFunction))(engine->memoryManager->markStack());
+ }
+
+ // HeapObjectWrapper(Base) are helper classes to ensure that
+ // we always use a WriteBarrier when setting heap-objects
+ // they are also trivial; if triviality is not required, use Pointer instead
+ struct HeapObjectWrapperBase
+ {
+ // enum class avoids accidental construction via brace-init
+ enum class PointerWrapper : quintptr {};
+ PointerWrapper wrapped;
+
+ void clear() { wrapped = PointerWrapper(quintptr(0)); }
+ };
+
+ template<typename HeapType>
+ struct HeapObjectWrapperCommon : HeapObjectWrapperBase
+ {
+ HeapType *get() const { return reinterpret_cast<HeapType *>(wrapped); }
+ operator HeapType *() const { return get(); }
+ HeapType * operator->() const { return get(); }
+
+ template <typename ConvertibleToHeapType>
+ void set(QV4::EngineBase *engine, ConvertibleToHeapType *heapObject)
+ {
+ WriteBarrier::markCustom(engine, [heapObject](QV4::MarkStack *ms){
+ if (heapObject)
+ heapObject->mark(ms);
+ });
+ wrapped = static_cast<HeapObjectWrapperBase::PointerWrapper>(quintptr(heapObject));
+ }
+ };
+
+ // all types are trivial; we however want to block copies bypassing the write barrier
+ // therefore, all members use a PhantomTag to reduce the likelihood
+ template<typename HeapType, int PhantomTag>
+ struct HeapObjectWrapper : HeapObjectWrapperCommon<HeapType> {};
+
+ /* similar Heap::Pointer, but without the Base conversion (and its inUse assert)
+ and for storing references in engine classes stored on the native heap
+ Stores a "non-owning" reference to a heap-item (in the C++ sense), but should
+ generally mark the heap-item; therefore set goes through a write-barrier
+ */
+ template<typename T>
+ struct Pointer
+ {
+ Pointer() = default;
+ ~Pointer() = default;
+ Q_DISABLE_COPY_MOVE(Pointer)
+ T* operator->() const { return get(); }
+ operator T* () const { return get(); }
+
+ void set(EngineBase *e, T *newVal) {
+ WriteBarrier::markCustom(e, [newVal](QV4::MarkStack *ms) {
+ if (newVal)
+ newVal->mark(ms);
+ });
+ ptr = newVal;
+ }
+
+ T* get() const { return ptr; }
+
+
+
+ private:
+ T *ptr = nullptr;
+ };
};
-enum NewValueType {
- Primitive,
- Object,
- Unknown
-};
-
-// ### this needs to be filled with a real memory fence once marking is concurrent
+ // ### this needs to be filled with a real memory fence once marking is concurrent
Q_ALWAYS_INLINE void fence() {}
-#if WRITEBARRIER(none)
-
-template <NewValueType type>
-static Q_CONSTEXPR inline bool isRequired() {
- return false;
-}
-
-inline void write(EngineBase *engine, Heap::Base *base, ReturnedValue *slot, ReturnedValue value)
-{
- Q_UNUSED(engine);
- Q_UNUSED(base);
- *slot = value;
-}
-
-inline void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value)
-{
- Q_UNUSED(engine);
- Q_UNUSED(base);
- *slot = value;
-}
-
-#endif
-
-}
-
}
QT_END_NAMESPACE
diff --git a/src/qml/parser/parser.pri b/src/qml/parser/parser.pri
deleted file mode 100644
index e15730f5d1..0000000000
--- a/src/qml/parser/parser.pri
+++ /dev/null
@@ -1,25 +0,0 @@
-HEADERS += \
- $$PWD/qqmljsast_p.h \
- $$PWD/qqmljsastfwd_p.h \
- $$PWD/qqmljsastvisitor_p.h \
- $$PWD/qqmljsengine_p.h \
- $$PWD/qqmljslexer_p.h \
- $$PWD/qqmljsglobal_p.h \
- $$PWD/qqmljskeywords_p.h \
- $$PWD/qqmljsengine_p.h \
- $$PWD/qqmljssourcelocation_p.h
-
-SOURCES += \
- $$PWD/qqmljsast.cpp \
- $$PWD/qqmljsastvisitor.cpp \
- $$PWD/qqmljsengine_p.cpp \
- $$PWD/qqmljslexer.cpp \
-
-CONFIG += qlalr
-QLALRSOURCES = $$PWD/qqmljs.g
-QMAKE_QLALRFLAGS = --no-debug --qt
-
-OTHER_FILES += $$QLALRSOURCES
-
-# make sure we install the headers generated by qlalr
-private_headers.CONFIG += no_check_exist
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index e28899883f..32b609f5ff 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -1,41 +1,5 @@
-----------------------------------------------------------------------------
---
-- Copyright (C) 2016 The Qt Company Ltd.
--- Contact: http://www.qt.io/licensing/
---
--- This file is part of the QtQml module of the Qt Toolkit.
---
--- $QT_BEGIN_LICENSE:LGPL$
--- Commercial License Usage
--- Licensees holding valid commercial Qt licenses may use this file in
--- accordance with the commercial license agreement provided with the
--- Software or, alternatively, in accordance with the terms contained in
--- a written agreement between you and The Qt Company. For licensing terms
--- and conditions see https://www.qt.io/terms-conditions. For further
--- information use the contact form at https://www.qt.io/contact-us.
---
--- GNU Lesser General Public License Usage
--- Alternatively, this file may be used under the terms of the GNU Lesser
--- General Public License version 3 as published by the Free Software
--- Foundation and appearing in the file LICENSE.LGPL3 included in the
--- packaging of this file. Please review the following information to
--- ensure the GNU Lesser General Public License version 3 requirements
--- will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
---
--- GNU General Public License Usage
--- Alternatively, this file may be used under the terms of the GNU
--- General Public License version 2.0 or (at your option) the GNU General
--- Public license version 3 or any later version approved by the KDE Free
--- Qt Foundation. The licenses are as published by the Free Software
--- Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
--- included in the packaging of this file. Please review the following
--- information to ensure the GNU General Public License requirements will
--- be met: https://www.gnu.org/licenses/gpl-2.0.html and
--- https://www.gnu.org/licenses/gpl-3.0.html.
---
--- $QT_END_LICENSE$
---
-----------------------------------------------------------------------------
+-- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
%parser QQmlJSGrammar
%decl qqmljsparser_p.h
@@ -73,13 +37,15 @@
%token T_VAR "var" T_VOID "void" T_WHILE "while"
%token T_WITH "with" T_XOR "^" T_XOR_EQ "^="
%token T_NULL "null" T_TRUE "true" T_FALSE "false"
-%token T_CONST "const" T_LET "let"
+%token T_CONST "const" T_LET "let" T_AT "@"
%token T_DEBUGGER "debugger"
%token T_RESERVED_WORD "reserved word"
%token T_MULTILINE_STRING_LITERAL "multiline string literal"
%token T_COMMENT "comment"
%token T_COMPATIBILITY_SEMICOLON
%token T_ARROW "=>"
+%token T_QUESTION_QUESTION "??"
+%token T_QUESTION_DOT "?."
%token T_ENUM "enum"
%token T_ELLIPSIS "..."
%token T_YIELD "yield"
@@ -90,6 +56,7 @@
%token T_EXPORT "export"
%token T_FROM "from"
%token T_REQUIRED "required"
+%token T_COMPONENT "component"
--- template strings
%token T_NO_SUBSTITUTION_TEMPLATE"(no subst template)"
@@ -106,8 +73,19 @@
%token T_GET "get"
%token T_SET "set"
+-- token representing no token
+%token T_NONE
+
%token T_ERROR
+-- states for line by line parsing
+%token T_EOL
+%token T_PARTIAL_COMMENT "non closed multiline comment"
+%token T_PARTIAL_SINGLE_QUOTE_STRING_LITERAL "multiline single quote string literal"
+%token T_PARTIAL_DOUBLE_QUOTE_STRING_LITERAL "multiline double quote string literal"
+%token T_PARTIAL_TEMPLATE_HEAD "(template head)"
+%token T_PARTIAL_TEMPLATE_MIDDLE "(template middle)"
+
--- feed tokens
%token T_FEED_UI_PROGRAM
%token T_FEED_UI_OBJECT_MEMBER
@@ -122,50 +100,16 @@
%token T_FOR_LOOKAHEAD_OK "(for lookahead ok)"
--%left T_PLUS T_MINUS
-%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY T_ON T_SET T_GET T_OF T_STATIC T_FROM T_AS T_REQUIRED
+%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY T_ON T_SET T_GET T_OF T_STATIC T_FROM T_AS T_REQUIRED T_COMPONENT
%nonassoc REDUCE_HERE
%right T_THEN T_ELSE
+%right T_WITHOUTAS T_AS
%start TopLevel
-/./****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+/.// Copyright (C) 2016 The Qt Company Ltd.
+// Contact: https://www.qt.io/licensing/
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmljsengine_p.h>
#include <private/qqmljslexer_p.h>
@@ -179,44 +123,9 @@
./
-/:/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+/:// Copyright (C) 2016 The Qt Company Ltd.
+// Contact: https://www.qt.io/licensing/
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
@@ -303,14 +212,15 @@ public:
AST::ExportClause *ExportClause;
AST::ExportDeclaration *ExportDeclaration;
AST::TypeAnnotation *TypeAnnotation;
- AST::TypeArgumentList *TypeArgumentList;
AST::Type *Type;
AST::UiProgram *UiProgram;
AST::UiHeaderItemList *UiHeaderItemList;
+ AST::UiPragmaValueList *UiPragmaValueList;
AST::UiPragma *UiPragma;
AST::UiImport *UiImport;
AST::UiParameterList *UiParameterList;
+ AST::UiPropertyAttributes *UiPropertyAttributes;
AST::UiPublicMember *UiPublicMember;
AST::UiObjectDefinition *UiObjectDefinition;
AST::UiObjectInitializer *UiObjectInitializer;
@@ -323,6 +233,8 @@ public:
AST::UiQualifiedId *UiQualifiedId;
AST::UiEnumMemberList *UiEnumMemberList;
AST::UiVersionSpecifier *UiVersionSpecifier;
+ AST::UiAnnotation *UiAnnotation;
+ AST::UiAnnotationList *UiAnnotationList;
};
public:
@@ -385,10 +297,22 @@ public:
{ return diagnosticMessage().message; }
inline int errorLineNumber() const
- { return diagnosticMessage().line; }
+ { return diagnosticMessage().loc.startLine; }
inline int errorColumnNumber() const
- { return diagnosticMessage().column; }
+ { return diagnosticMessage().loc.startColumn; }
+
+ inline bool identifierInsertionEnabled() const
+ { return m_identifierInsertionEnabled; }
+
+ inline void setIdentifierInsertionEnabled(bool enable)
+ { m_identifierInsertionEnabled = enable; }
+
+ inline bool incompleteBindingsEnabled() const
+ { return m_incompleteBindingsEnabled; }
+
+ inline void setIncompleteBindingsEnabled(bool enable)
+ { m_incompleteBindingsEnabled = enable; }
protected:
bool parse(int startToken);
@@ -398,35 +322,35 @@ protected:
inline Value &sym(int index)
{ return sym_stack [tos + index - 1]; }
- inline QStringRef &stringRef(int index)
+ inline QStringView &stringRef(int index)
{ return string_stack [tos + index - 1]; }
- inline QStringRef &rawStringRef(int index)
+ inline QStringView &rawStringRef(int index)
{ return rawString_stack [tos + index - 1]; }
- inline AST::SourceLocation &loc(int index)
+ inline SourceLocation &loc(int index)
{ return location_stack [tos + index - 1]; }
AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
void pushToken(int token);
+ void pushTokenWithEmptyLocation(int token);
int lookaheadToken(Lexer *lexer);
- static DiagnosticMessage compileError(const AST::SourceLocation &location,
+ static DiagnosticMessage compileError(const SourceLocation &location,
const QString &message, QtMsgType kind = QtCriticalMsg)
{
DiagnosticMessage error;
- error.line = location.startLine;
- error.column = location.startColumn;
+ error.loc = location;
error.message = message;
error.type = kind;
return error;
}
- void syntaxError(const AST::SourceLocation &location, const char *message) {
+ void syntaxError(const SourceLocation &location, const char *message) {
diagnostic_messages.append(compileError(location, QLatin1String(message)));
}
- void syntaxError(const AST::SourceLocation &location, const QString &message) {
+ void syntaxError(const SourceLocation &location, const QString &message) {
diagnostic_messages.append(compileError(location, message));
}
@@ -439,9 +363,9 @@ protected:
int stack_size = 0;
Value *sym_stack = nullptr;
int *state_stack = nullptr;
- AST::SourceLocation *location_stack = nullptr;
- QVector<QStringRef> string_stack;
- QVector<QStringRef> rawString_stack;
+ SourceLocation *location_stack = nullptr;
+ std::vector<QStringView> string_stack;
+ std::vector<QStringView> rawString_stack;
AST::Node *program = nullptr;
@@ -451,33 +375,37 @@ protected:
struct SavedToken {
int token;
double dval;
- AST::SourceLocation loc;
- QStringRef spell;
- QStringRef raw;
+ SourceLocation loc;
+ QStringView spell;
+ QStringView raw;
};
int yytoken = -1;
double yylval = 0.;
- QStringRef yytokenspell;
- QStringRef yytokenraw;
- AST::SourceLocation yylloc;
- AST::SourceLocation yyprevlloc;
+ QStringView yytokenspell;
+ QStringView yytokenraw;
+ SourceLocation yylloc;
+ SourceLocation yyprevlloc;
+ int yyprevtoken = -1;
SavedToken token_buffer[TOKEN_BUFFER_SIZE];
SavedToken *first_token = nullptr;
SavedToken *last_token = nullptr;
int functionNestingLevel = 0;
+ int classNestingLevel = 0;
enum CoverExpressionType {
CE_Invalid,
CE_ParenthesizedExpression,
CE_FormalParameterList
};
- AST::SourceLocation coverExpressionErrorLocation;
+ SourceLocation coverExpressionErrorLocation;
CoverExpressionType coverExpressionType = CE_Invalid;
QList<DiagnosticMessage> diagnostic_messages;
+ bool m_identifierInsertionEnabled = false;
+ bool m_incompleteBindingsEnabled = false;
};
} // end of namespace QQmlJS
@@ -519,7 +447,7 @@ void Parser::reallocateStack()
sym_stack = reinterpret_cast<Value*> (realloc(sym_stack, stack_size * sizeof(Value)));
state_stack = reinterpret_cast<int*> (realloc(state_stack, stack_size * sizeof(int)));
- location_stack = reinterpret_cast<AST::SourceLocation*> (realloc(location_stack, stack_size * sizeof(AST::SourceLocation)));
+ location_stack = reinterpret_cast<SourceLocation*> (realloc(location_stack, stack_size * sizeof(SourceLocation)));
string_stack.resize(stack_size);
rawString_stack.resize(stack_size);
}
@@ -539,9 +467,9 @@ Parser::~Parser()
}
}
-static inline AST::SourceLocation location(Lexer *lexer)
+static inline SourceLocation location(Lexer *lexer)
{
- AST::SourceLocation loc;
+ SourceLocation loc;
loc.offset = lexer->tokenOffset();
loc.length = lexer->tokenLength();
loc.startLine = lexer->tokenStartLine();
@@ -551,13 +479,15 @@ static inline AST::SourceLocation location(Lexer *lexer)
AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
{
- QVarLengthArray<QStringRef, 4> nameIds;
- QVarLengthArray<AST::SourceLocation, 4> locations;
+ QVarLengthArray<QStringView, 4> nameIds;
+ QVarLengthArray<SourceLocation, 4> locations;
+ QVarLengthArray<SourceLocation, 4> dotLocations;
AST::ExpressionNode *it = expr;
while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) {
nameIds.append(m->name);
locations.append(m->identifierToken);
+ dotLocations.append(m->dotToken);
it = m->base;
}
@@ -569,6 +499,7 @@ AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
for (int i = nameIds.size() - 1; i != -1; --i) {
currentId = new (pool) AST::UiQualifiedId(currentId, nameIds[i]);
currentId->identifierToken = locations[i];
+ currentId->dotToken = dotLocations[i];
}
return currentId->finish();
@@ -590,9 +521,19 @@ void Parser::pushToken(int token)
yytoken = token;
}
+void Parser::pushTokenWithEmptyLocation(int token)
+{
+ pushToken(token);
+ yylloc = yyprevlloc;
+ yylloc.offset += yylloc.length;
+ yylloc.startColumn += yylloc.length;
+ yylloc.length = 0;
+}
+
int Parser::lookaheadToken(Lexer *lexer)
{
if (yytoken < 0) {
+ yyprevtoken = yytoken;
yytoken = lexer->lex();
yylval = lexer->tokenValue();
yytokenspell = lexer->tokenSpell();
@@ -688,6 +629,7 @@ bool Parser::parse(int startToken)
#endif
if (action > 0) {
if (action != ACCEPT_STATE) {
+ yyprevtoken = yytoken;
yytoken = -1;
sym(1).dval = yylval;
stringRef(1) = yytokenspell;
@@ -736,7 +678,7 @@ TopLevel: T_FEED_JS_EXPRESSION Expression;
} break;
./
-TopLevel: T_FEED_UI_OBJECT_MEMBER UiObjectMember;
+TopLevel: T_FEED_UI_OBJECT_MEMBER UiAnnotatedObjectMember;
/.
case $rule_number: {
sym(1).Node = sym(2).Node;
@@ -805,20 +747,56 @@ UiHeaderItemList: UiHeaderItemList UiImport;
./
PragmaId: JsIdentifier;
+PragmaValue: JsIdentifier
+ | T_STRING_LITERAL;
Semicolon: T_AUTOMATIC_SEMICOLON;
Semicolon: T_SEMICOLON;
+UiPragmaValueList: PragmaValue;
+/.
+ case $rule_number: {
+ AST::UiPragmaValueList *list
+ = new (pool) AST::UiPragmaValueList(stringRef(1));
+ list->location = loc(1);
+ sym(1).Node = list;
+ } break;
+./
+
+UiPragmaValueList: UiPragmaValueList T_COMMA PragmaValue;
+/.
+ case $rule_number: {
+ AST::UiPragmaValueList *list
+ = new (pool) AST::UiPragmaValueList(sym(1).UiPragmaValueList, stringRef(3));
+ list->location = loc(3);
+ sym(1).Node = list;
+ } break;
+./
+
UiPragma: T_PRAGMA PragmaId Semicolon;
/.
case $rule_number: {
AST::UiPragma *pragma = new (pool) AST::UiPragma(stringRef(2));
pragma->pragmaToken = loc(1);
+ pragma->pragmaIdToken = loc(2);
pragma->semicolonToken = loc(3);
sym(1).Node = pragma;
} break;
./
+UiPragma: T_PRAGMA PragmaId T_COLON UiPragmaValueList Semicolon;
+/.
+ case $rule_number: {
+ AST::UiPragma *pragma = new (pool) AST::UiPragma(
+ stringRef(2), sym(4).UiPragmaValueList->finish());
+ pragma->pragmaToken = loc(1);
+ pragma->pragmaIdToken = loc(2);
+ pragma->colonToken = loc(3);
+ pragma->semicolonToken = loc(5);
+ sym(1).Node = pragma;
+ } break;
+./
+
ImportId: MemberExpression;
UiImport: UiImportHead Semicolon;
@@ -831,7 +809,15 @@ UiImport: UiImportHead Semicolon;
UiVersionSpecifier: T_VERSION_NUMBER T_DOT T_VERSION_NUMBER;
/.
case $rule_number: {
- auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval, sym(3).dval);
+ const int major = sym(1).dval;
+ const int minor = sym(3).dval;
+ if (!QTypeRevision::isValidSegment(major) || !QTypeRevision::isValidSegment(minor)) {
+ diagnostic_messages.append(
+ compileError(loc(1),
+ QLatin1String("Invalid version. Version numbers must be >= 0 and < 255.")));
+ return false;
+ }
+ auto version = new (pool) AST::UiVersionSpecifier(major, minor);
version->majorToken = loc(1);
version->minorToken = loc(3);
sym(1).UiVersionSpecifier = version;
@@ -842,7 +828,14 @@ UiVersionSpecifier: T_VERSION_NUMBER T_DOT T_VERSION_NUMBER;
UiVersionSpecifier: T_VERSION_NUMBER;
/.
case $rule_number: {
- auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval, 0);
+ const int major = sym(1).dval;
+ if (!QTypeRevision::isValidSegment(major)) {
+ diagnostic_messages.append(
+ compileError(loc(1),
+ QLatin1String("Invalid major version. Version numbers must be >= 0 and < 255.")));
+ return false;
+ }
+ auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval);
version->majorToken = loc(1);
sym(1).UiVersionSpecifier = version;
} break;
@@ -910,21 +903,92 @@ Empty: ;
} break;
./
-UiRootMember: UiObjectDefinition;
+UiRootMember: UiAnnotatedObject;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
} break;
./
-UiObjectMemberList: UiObjectMember;
+UiSimpleQualifiedId: T_IDENTIFIER;
+/.
+ case $rule_number: {
+ AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+ } break;
+./
+
+UiSimpleQualifiedId: UiSimpleQualifiedId T_DOT T_IDENTIFIER;
+/.
+ case $rule_number: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+ } break;
+./
+
+UiAnnotationObjectDefinition: UiSimpleQualifiedId UiObjectInitializer;
+/.
+ case $rule_number: {
+ if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) {
+ sym(1).UiQualifiedId = qualifiedId;
+ } else {
+ sym(1).UiQualifiedId = 0;
+
+ diagnostic_messages.append(compileError(loc(1),
+ QLatin1String("Expected a qualified name id")));
+
+ return false;
+ }
+ AST::UiAnnotation *node = new (pool) AST::UiAnnotation(sym(1).UiQualifiedId, sym(2).UiObjectInitializer);
+ sym(1).Node = node;
+ } break;
+./
+
+UiAnnotation: T_AT UiAnnotationObjectDefinition;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+} break;
+./
+
+
+UiAnnotationList: UiAnnotation;
+/.
+ case $rule_number: {
+ sym(1).Node = new (pool) AST::UiAnnotationList(sym(1).UiAnnotation);
+ } break;
+./
+
+UiAnnotationList: UiAnnotationList UiAnnotation;
+/.
+ case $rule_number: {
+ AST::UiAnnotationList *node = new (pool) AST::UiAnnotationList(sym(1).UiAnnotationList, sym(2).UiAnnotation);
+ sym(1).Node = node;
+ } break;
+./
+
+UiAnnotatedObject: UiAnnotationList UiObjectDefinition;
+/.
+ case $rule_number: {
+ AST::UiObjectDefinition *node = sym(2).UiObjectDefinition;
+ node->annotations = sym(1).UiAnnotationList->finish();
+ sym(1).Node = node;
+ } break;
+./
+
+UiAnnotatedObject: UiObjectDefinition;
+
+UiObjectMemberList: UiAnnotatedObjectMember;
/.
case $rule_number: {
sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
} break;
./
-UiObjectMemberList: UiObjectMemberList UiObjectMember;
+UiObjectMemberList: UiObjectMemberList UiAnnotatedObjectMember;
/.
case $rule_number: {
AST::UiObjectMemberList *node = new (pool) AST:: UiObjectMemberList(sym(1).UiObjectMemberList, sym(2).UiObjectMember);
@@ -976,6 +1040,17 @@ UiObjectDefinition: UiQualifiedId UiObjectInitializer;
} break;
./
+UiAnnotatedObjectMember: UiAnnotationList UiObjectMember;
+/.
+ case $rule_number: {
+ AST::UiObjectMember *node = sym(2).UiObjectMember;
+ node->annotations = sym(1).UiAnnotationList->finish();
+ sym(1).Node = sym(2).Node;
+ } break;
+./
+
+UiAnnotatedObjectMember: UiObjectMember;
+
UiObjectMember: UiObjectDefinition;
UiObjectMember: UiQualifiedId T_COLON ExpressionStatementLookahead T_LBRACKET UiArrayMemberList T_RBRACKET;
@@ -1011,15 +1086,27 @@ UiObjectMember: UiQualifiedId T_ON UiQualifiedId UiObjectInitializer;
./
-UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_RBRACE;
-/. case $rule_number: Q_FALLTHROUGH(); ./
-UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_COMMA T_RBRACE;
+UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_RBRACE Semicolon;
/.
case $rule_number: {
AST::ObjectPattern *l = new (pool) AST::ObjectPattern(sym(3).PatternPropertyList->finish());
l->lbraceToken = loc(1);
l->rbraceToken = loc(4);
AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(l);
+ node->semicolonToken = loc(5);
+ sym(1).Node = node;
+ } break;
+./
+
+
+UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_COMMA T_RBRACE Semicolon;
+/.
+ case $rule_number: {
+ AST::ObjectPattern *l = new (pool) AST::ObjectPattern(sym(3).PatternPropertyList->finish());
+ l->lbraceToken = loc(1);
+ l->rbraceToken = loc(5);
+ AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(l);
+ node->semicolonToken = loc(6);
sym(1).Node = node;
} break;
./
@@ -1064,6 +1151,20 @@ case $rule_number:
} break;
./
+UiObjectMember: UiQualifiedId Semicolon;
+/.
+ case $rule_number: {
+ if (!m_incompleteBindingsEnabled) {
+ diagnostic_messages.append(compileError(loc(1), QLatin1String("Incomplete binding, expected token `:` or `{`")));
+ return false;
+ }
+ AST::EmptyStatement *statement = new (pool) AST::EmptyStatement;
+ statement->semicolonToken = loc(2);
+ AST::UiScriptBinding *node = new (pool) AST::UiScriptBinding(sym(1).UiQualifiedId, statement);
+ sym(1).Node = node;
+ } break;
+./
+
UiPropertyType: T_VAR;
/. case $rule_number: Q_FALLTHROUGH(); ./
UiPropertyType: T_RESERVED_WORD;
@@ -1100,10 +1201,10 @@ UiParameterListOpt: UiParameterList;
} break;
./
-UiParameterList: QmlIdentifier T_COLON UiPropertyType;
+UiParameterList: QmlIdentifier T_COLON Type;
/.
case $rule_number: {
- AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(3).UiQualifiedId->finish(), stringRef(1));
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(3).Type, stringRef(1));
node->identifierToken = loc(1);
node->colonToken = loc(2);
node->propertyTypeToken = loc(3);
@@ -1111,20 +1212,20 @@ UiParameterList: QmlIdentifier T_COLON UiPropertyType;
} break;
./
-UiParameterList: UiPropertyType QmlIdentifier;
+UiParameterList: Type QmlIdentifier;
/.
case $rule_number: {
- AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiQualifiedId->finish(), stringRef(2));
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).Type, stringRef(2));
node->propertyTypeToken = loc(1);
node->identifierToken = loc(2);
sym(1).Node = node;
} break;
./
-UiParameterList: UiParameterList T_COMMA QmlIdentifier T_COLON UiPropertyType;
+UiParameterList: UiParameterList T_COMMA QmlIdentifier T_COLON Type;
/.
case $rule_number: {
- AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(5).UiQualifiedId->finish(), stringRef(3));
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(5).Type, stringRef(3));
node->propertyTypeToken = loc(5);
node->commaToken = loc(2);
node->identifierToken = loc(3);
@@ -1133,10 +1234,10 @@ UiParameterList: UiParameterList T_COMMA QmlIdentifier T_COLON UiPropertyType;
} break;
./
-UiParameterList: UiParameterList T_COMMA UiPropertyType QmlIdentifier;
+UiParameterList: UiParameterList T_COMMA Type QmlIdentifier;
/.
case $rule_number: {
- AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(3).UiQualifiedId->finish(), stringRef(4));
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(3).Type, stringRef(4));
node->propertyTypeToken = loc(3);
node->commaToken = loc(2);
node->identifierToken = loc(4);
@@ -1149,7 +1250,7 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN Semic
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
node->type = AST::UiPublicMember::Signal;
- node->propertyToken = loc(1);
+ node->setPropertyToken(loc(1));
node->typeToken = loc(2);
node->identifierToken = loc(2);
node->parameters = sym(4).UiParameterList;
@@ -1163,7 +1264,7 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER Semicolon;
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2));
node->type = AST::UiPublicMember::Signal;
- node->propertyToken = loc(1);
+ node->setPropertyToken(loc(1));
node->typeToken = loc(2);
node->identifierToken = loc(2);
node->semicolonToken = loc(3);
@@ -1171,89 +1272,124 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER Semicolon;
} break;
./
-UiObjectMemberListPropertyNoInitialiser: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
+-------------------------------------------------------------------------------
+-- There is some ambiguity in whether required default property should be parsed
+-- as required (default (property)) or as ((required (default)) property)
+-- by reducing after each attribute modifier, we ensure that T_PROPERTY (which
+-- is always available is used as the base case (so we only have to allocate the
+-- node in the T_PROPERY case, and all other rules can assume that the node is
+-- already available).
+--------------------------------------------------------------------------------
+
+AttrRequired: T_REQUIRED %prec REDUCE_HERE;
+AttrReadonly: T_READONLY %prec REDUCE_HERE;
+AttrDefault: T_DEFAULT %prec REDUCE_HERE;
+
+UiPropertyAttributes: AttrRequired UiPropertyAttributes;
/.
case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
- node->typeModifier = stringRef(2);
- node->propertyToken = loc(1);
- node->typeModifierToken = loc(2);
- node->typeToken = loc(4);
- node->identifierToken = loc(6);
- node->semicolonToken = loc(7);
- sym(1).Node = node;
+ AST::UiPropertyAttributes *node = sym(2).UiPropertyAttributes;
+ if (node->isRequired())
+ diagnostic_messages.append(compileError(node->requiredToken(), QLatin1String("Duplicated 'required' attribute is not allowed."), QtCriticalMsg));
+ node->m_requiredToken = loc(1);
+ sym(1).UiPropertyAttributes = node;
} break;
./
-UiObjectMember: UiObjectMemberListPropertyNoInitialiser;
-
-UiObjectMember: T_READONLY UiObjectMemberListPropertyNoInitialiser;
+UiPropertyAttributes: AttrDefault UiPropertyAttributes;
/.
case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isReadonlyMember = true;
- node->readonlyToken = loc(1);
- sym(1).Node = node;
+ AST::UiPropertyAttributes *node = sym(2).UiPropertyAttributes;
+ if (node->isDefaultMember())
+ diagnostic_messages.append(compileError(node->requiredToken(), QLatin1String("Duplicated 'default' attribute is not allowed."), QtCriticalMsg));
+ node->m_defaultToken = loc(1);
+ sym(1).UiPropertyAttributes = node;
} break;
./
-UiObjectMemberPropertyNoInitialiser: T_PROPERTY UiPropertyType QmlIdentifier Semicolon;
+UiPropertyAttributes: AttrReadonly UiPropertyAttributes;
/.
case $rule_number: {
- AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
- node->propertyToken = loc(1);
- node->typeToken = loc(2);
- node->identifierToken = loc(3);
- node->semicolonToken = loc(4);
- sym(1).Node = node;
+ AST::UiPropertyAttributes *node = sym(2).UiPropertyAttributes;
+ if (node->isReadonly())
+ diagnostic_messages.append(compileError(node->requiredToken(), QLatin1String("Duplicated 'readonly' attribute is not allowed."), QtCriticalMsg));
+ node->m_readonlyToken = loc(1);
+ sym(1).UiPropertyAttributes = node;
} break;
./
+UiPropertyAttributes: T_PROPERTY;
+/.
+ case $rule_number: {
+ AST::UiPropertyAttributes *node = new (pool) AST::UiPropertyAttributes();
+ node->m_propertyToken = loc(1);
+ sym(1).UiPropertyAttributes = node;
+ } break;
+./
-UiObjectMember: UiObjectMemberPropertyNoInitialiser;
-
-UiObjectMember: T_DEFAULT UiObjectMemberPropertyNoInitialiser;
+UiObjectMemberListPropertyNoInitialiser: UiPropertyAttributes T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon;
/.
case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
+ auto attributes = sym(1).UiPropertyAttributes;
+ node->setAttributes(attributes);
+ if (attributes->isReadonly())
+ diagnostic_messages.append(compileError(attributes->readonlyToken(), QLatin1String("Read-only properties require an initializer."), QtWarningMsg));
+ node->typeModifier = stringRef(2);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7);
sym(1).Node = node;
} break;
./
-UiObjectMember: T_DEFAULT UiObjectMemberListPropertyNoInitialiser;
+UiObjectMember: UiObjectMemberListPropertyNoInitialiser;
+
+UiObjectMemberPropertyNoInitialiser: UiPropertyAttributes UiPropertyType QmlIdentifier Semicolon;
/.
case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
+ auto attributes = sym(1).UiPropertyAttributes;
+ if (attributes->isReadonly())
+ diagnostic_messages.append(compileError(attributes->readonlyToken(), QLatin1String("Read-only properties require an initializer."), QtCriticalMsg));
+ node->setAttributes(attributes);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4);
sym(1).Node = node;
} break;
./
+
+UiObjectMember: UiObjectMemberPropertyNoInitialiser;
+
OptionalSemicolon: | Semicolon;
/.
/* we need OptionalSemicolon because UiScriptStatement might already parse the last semicolon
and then we would miss a semicolon (see tests/auto/quick/qquickvisualdatamodel/data/objectlist.qml)*/
./
-UiObjectMember: T_REQUIRED UiObjectMemberPropertyNoInitialiser;
+UiRequired: T_REQUIRED QmlIdentifier Semicolon;
/.
case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
+ AST::UiRequired *node = new (pool) AST::UiRequired(stringRef(2));
node->requiredToken = loc(1);
- node->isRequired = true;
+ node->semicolonToken = loc(3);
sym(1).Node = node;
} break;
./
+UiObjectMember: UiRequired;
-UiObjectMemberWithScriptStatement: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
+UiObjectMemberWithScriptStatement: UiPropertyAttributes UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3), sym(5).Statement);
- node->propertyToken = loc(1);
+ auto attributes = sym(1).UiPropertyAttributes;
+ if (attributes->isRequired())
+ diagnostic_messages.append(compileError(attributes->requiredToken(), QLatin1String("Required properties with initializer do not make sense."), QtCriticalMsg));
+ node->setAttributes(attributes);
node->typeToken = loc(2);
node->identifierToken = loc(3);
node->colonToken = loc(4);
@@ -1261,47 +1397,48 @@ UiObjectMemberWithScriptStatement: T_PROPERTY UiPropertyType QmlIdentifier T_COL
} break;
./
-UiObjectMember: UiObjectMemberWithScriptStatement;
-
-UiObjectMember: T_READONLY UiObjectMemberWithScriptStatement;
+UiObjectMemberWithScriptStatement: UiPropertyAttributes T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isReadonlyMember = true;
- node->readonlyToken = loc(1);
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6), sym(8).Statement);
+ node->typeModifier = stringRef(2);
+ auto attributes = sym(1).UiPropertyAttributes;
+ if (attributes->isRequired())
+ diagnostic_messages.append(compileError(attributes->requiredToken(), QLatin1String("Required properties with initializer do not make sense."), QtCriticalMsg));
+ node->setAttributes(attributes);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->colonToken = loc(7);
sym(1).Node = node;
} break;
./
-UiObjectMember: T_DEFAULT UiObjectMemberWithScriptStatement;
-/.
- case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isDefaultMember = true;
- node->defaultToken = loc(1);
- sym(1).Node = node;
- } break;
-./
+UiObjectMember: UiObjectMemberWithScriptStatement;
-UiObjectMemberWithArray: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
+UiObjectMemberWithArray: UiPropertyAttributes T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON ExpressionStatementLookahead T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
+ auto attributes = sym(1).UiPropertyAttributes;
+ if (attributes->isRequired())
+ diagnostic_messages.append(compileError(attributes->requiredToken(), QLatin1String("Required properties with initializer do not make sense."), QtCriticalMsg));
+ node->setAttributes(attributes);
node->typeModifier = stringRef(2);
- node->propertyToken = loc(1);
node->typeModifierToken = loc(2);
node->typeToken = loc(4);
node->identifierToken = loc(6);
node->semicolonToken = loc(7); // insert a fake ';' before ':'
+ node->colonToken = loc(7);
AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(6));
propertyName->identifierToken = loc(6);
- propertyName->next = 0;
+ propertyName->next = nullptr;
- AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(propertyName, sym(9).UiArrayMemberList->finish());
+ AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(propertyName, sym(10).UiArrayMemberList->finish());
binding->colonToken = loc(7);
- binding->lbracketToken = loc(8);
- binding->rbracketToken = loc(10);
+ binding->lbracketToken = loc(9);
+ binding->rbracketToken = loc(11);
node->binding = binding;
@@ -1311,28 +1448,22 @@ UiObjectMemberWithArray: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIde
UiObjectMember: UiObjectMemberWithArray;
-UiObjectMember: T_READONLY UiObjectMemberWithArray;
-/.
- case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isReadonlyMember = true;
- node->readonlyToken = loc(1);
- sym(1).Node = node;
- } break;
-./
-
-UiObjectMemberExpressionStatementLookahead: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
+UiObjectMemberExpressionStatementLookahead: UiPropertyAttributes UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
- node->propertyToken = loc(1);
+ auto attributes = sym(1).UiPropertyAttributes;
+ if (attributes->isRequired())
+ diagnostic_messages.append(compileError(attributes->requiredToken(), QLatin1String("Required properties with initializer do not make sense."), QtWarningMsg));
+ node->setAttributes(attributes);
node->typeToken = loc(2);
node->identifierToken = loc(3);
node->semicolonToken = loc(4); // insert a fake ';' before ':'
+ node->colonToken = loc(4);
AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(3));
propertyName->identifierToken = loc(3);
- propertyName->next = 0;
+ propertyName->next = nullptr;
AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding(
propertyName, sym(6).UiQualifiedId, sym(7).UiObjectInitializer);
@@ -1346,16 +1477,6 @@ UiObjectMemberExpressionStatementLookahead: T_PROPERTY UiPropertyType QmlIdentif
UiObjectMember: UiObjectMemberExpressionStatementLookahead;
-UiObjectMember: T_READONLY UiObjectMemberExpressionStatementLookahead;
-/.
- case $rule_number: {
- AST::UiPublicMember *node = sym(2).UiPublicMember;
- node->isReadonlyMember = true;
- node->readonlyToken = loc(1);
- sym(1).Node = node;
- } break;
-./
-
UiObjectMember: GeneratorDeclaration;
/.
case $rule_number: {
@@ -1406,12 +1527,28 @@ UiObjectMember: T_ENUM T_IDENTIFIER T_LBRACE EnumMemberList T_RBRACE;
case $rule_number: {
AST::UiEnumDeclaration *enumDeclaration = new (pool) AST::UiEnumDeclaration(stringRef(2), sym(4).UiEnumMemberList->finish());
enumDeclaration->enumToken = loc(1);
+ enumDeclaration->identifierToken = loc(2);
+ enumDeclaration->lbraceToken = loc(3);
enumDeclaration->rbraceToken = loc(5);
sym(1).Node = enumDeclaration;
break;
}
./
+UiObjectMember: T_COMPONENT T_IDENTIFIER T_COLON UiObjectDefinition;
+/.
+ case $rule_number: {
+ if (!stringRef(2).front().isUpper()) {
+ diagnostic_messages.append(compileError(loc(2),
+ QLatin1String("Type name must be upper case"), QtWarningMsg));
+ }
+ auto inlineComponent = new (pool) AST::UiInlineComponent(stringRef(2), sym(4).UiObjectDefinition);
+ inlineComponent->componentToken = loc(1);
+ inlineComponent->identifierToken = loc(2);
+ sym(1).Node = inlineComponent;
+ } break;
+./
+
EnumMemberList: T_IDENTIFIER;
/.
case $rule_number: {
@@ -1433,6 +1570,18 @@ EnumMemberList: T_IDENTIFIER T_EQ T_NUMERIC_LITERAL;
}
./
+
+EnumMemberList: T_IDENTIFIER T_EQ T_MINUS T_NUMERIC_LITERAL;
+/.
+ case $rule_number: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(stringRef(1), -sym(4).dval);
+ node->memberToken = loc(1);
+ node->valueToken = combine(loc(3), loc(4));
+ sym(1).Node = node;
+ break;
+ }
+./
+
EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER;
/.
case $rule_number: {
@@ -1454,29 +1603,43 @@ EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER T_EQ T_NUMERIC_LITERAL;
}
./
-QmlIdentifier: T_IDENTIFIER;
-QmlIdentifier: T_PROPERTY;
-QmlIdentifier: T_SIGNAL;
-QmlIdentifier: T_READONLY;
-QmlIdentifier: T_ON;
-QmlIdentifier: T_GET;
-QmlIdentifier: T_SET;
-QmlIdentifier: T_FROM;
-QmlIdentifier: T_OF;
-QmlIdentifier: T_REQUIRED;
-
-JsIdentifier: T_IDENTIFIER;
-JsIdentifier: T_PROPERTY;
-JsIdentifier: T_SIGNAL;
-JsIdentifier: T_READONLY;
-JsIdentifier: T_ON;
-JsIdentifier: T_GET;
-JsIdentifier: T_SET;
-JsIdentifier: T_FROM;
-JsIdentifier: T_STATIC;
-JsIdentifier: T_OF;
-JsIdentifier: T_AS;
-JsIdentifier: T_REQUIRED;
+
+EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER T_EQ T_MINUS T_NUMERIC_LITERAL;
+/.
+ case $rule_number: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(sym(1).UiEnumMemberList, stringRef(3), -sym(6).dval);
+ node->memberToken = loc(3);
+ node->valueToken = combine(loc(5), loc(6));
+ sym(1).Node = node;
+ break;
+ }
+./
+
+QmlIdentifier: T_IDENTIFIER
+ | T_PROPERTY
+ | T_SIGNAL
+ | T_READONLY
+ | T_ON
+ | T_GET
+ | T_SET
+ | T_FROM
+ | T_OF
+ | T_REQUIRED
+ | T_COMPONENT;
+
+JsIdentifier: T_IDENTIFIER
+ | T_PROPERTY
+ | T_SIGNAL
+ | T_READONLY
+ | T_ON
+ | T_GET
+ | T_SET
+ | T_FROM
+ | T_STATIC
+ | T_OF
+ | T_AS
+ | T_REQUIRED
+ | T_COMPONENT;
IdentifierReference: JsIdentifier;
BindingIdentifier: IdentifierReference;
@@ -1485,28 +1648,35 @@ BindingIdentifier: IdentifierReference;
-- Types
--------------------------------------------------------------------------------------------------------
-TypeArguments: Type;
+Type: UiQualifiedId T_LT SimpleType T_GT;
/.
case $rule_number: {
- sym(1).TypeArgumentList = new (pool) AST::TypeArgumentList(sym(1).Type);
+ sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId, sym(3).Type);
} break;
./
-TypeArguments: TypeArguments T_COMMA Type;
+Type: SimpleType;
+
+SimpleType: T_RESERVED_WORD;
/.
case $rule_number: {
- sym(1).TypeArgumentList = new (pool) AST::TypeArgumentList(sym(1).TypeArgumentList, sym(3).Type);
+ 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 T_LT TypeArguments T_GT;
+SimpleType: UiQualifiedId;
/.
case $rule_number: {
- sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId, sym(3).TypeArgumentList->finish());
+ sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId);
} break;
./
-Type: T_RESERVED_WORD;
+SimpleType: T_VAR;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+
+SimpleType: T_VOID;
/.
case $rule_number: {
AST::UiQualifiedId *id = new (pool) AST::UiQualifiedId(stringRef(1));
@@ -1515,13 +1685,6 @@ Type: T_RESERVED_WORD;
} break;
./
-Type: UiQualifiedId;
-/.
- case $rule_number: {
- sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId);
- } break;
-./
-
TypeAnnotation: T_COLON Type;
/.
case $rule_number: {
@@ -1893,7 +2056,6 @@ PropertyDefinition: IdentifierReference;
AST::IdentifierExpression *expr = new (pool) AST::IdentifierExpression(stringRef(1));
expr->identifierToken = loc(1);
AST::PatternProperty *node = new (pool) AST::PatternProperty(name, expr);
- node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
@@ -1914,8 +2076,8 @@ CoverInitializedName: IdentifierReference Initializer_In;
if (auto *c = asAnonymousClassDefinition(sym(2).Expression))
c->name = stringRef(1);
AST::BinaryExpression *assignment = new (pool) AST::BinaryExpression(left, QSOperator::Assign, sym(2).Expression);
+ assignment->operatorToken = loc(2);
AST::PatternProperty *node = new (pool) AST::PatternProperty(name, assignment);
- node->colonToken = loc(1);
sym(1).Node = node;
} break;
@@ -2028,7 +2190,9 @@ Initializer: T_EQ AssignmentExpression;
Initializer_In: T_EQ AssignmentExpression_In;
/.
case $rule_number: {
- sym(1) = sym(2);
+ auto node = new (pool) AST::InitializerExpression(sym(2).Expression);
+ node->equalToken = loc(1);
+ sym(1).Expression = node;
} break;
./
@@ -2046,7 +2210,14 @@ InitializerOpt: Initializer;
InitializerOpt_In: Initializer_In;
TemplateLiteral: T_NO_SUBSTITUTION_TEMPLATE;
-/. case $rule_number: Q_FALLTHROUGH(); ./
+/.
+ case $rule_number: {
+ AST::TemplateLiteral *node = new (pool) AST::TemplateLiteral(stringRef(1), rawStringRef(1), nullptr);
+ node->literalToken = loc(1);
+ node->hasNoSubstitution = true;
+ sym(1).Node = node;
+ } break;
+./
TemplateSpans: T_TEMPLATE_TAIL;
/.
@@ -2094,7 +2265,16 @@ MemberExpression: MemberExpression T_LBRACKET Expression_In T_RBRACKET;
sym(1).Node = node;
} break;
./
-
+MemberExpression: MemberExpression T_QUESTION_DOT T_LBRACKET Expression_In T_RBRACKET;
+/.
+ case $rule_number: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(4).Expression);
+ node->lbracketToken = loc(3);
+ node->rbracketToken = loc(5);
+ node->isOptional = true;
+ sym(1).Node = node;
+ } break;
+./
-- the identifier has to be "target", catched at codegen time
NewTarget: T_NEW T_DOT T_IDENTIFIER;
@@ -2117,6 +2297,17 @@ MemberExpression: MemberExpression T_DOT IdentifierName;
} break;
./
+MemberExpression: MemberExpression T_QUESTION_DOT IdentifierName;
+/.
+ case $rule_number: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ node->isOptional = true;
+ sym(1).Node = node;
+ } break;
+./
+
MemberExpression: MetaProperty;
MemberExpression: T_NEW MemberExpression T_LPAREN Arguments T_RPAREN;
@@ -2165,6 +2356,17 @@ CallExpression: MemberExpression T_LPAREN Arguments T_RPAREN;
} break;
./
+CallExpression: MemberExpression T_QUESTION_DOT T_LPAREN Arguments T_RPAREN;
+/.
+ case $rule_number: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(4).ArgumentList);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->isOptional = true;
+ sym(1).Node = node;
+ } break;
+./
+
CallExpression: Super T_LPAREN Arguments T_RPAREN;
/. case $rule_number: Q_FALLTHROUGH(); ./
CallExpression: CallExpression T_LPAREN Arguments T_RPAREN;
@@ -2177,6 +2379,18 @@ CallExpression: CallExpression T_LPAREN Arguments T_RPAREN;
} break;
./
+CallExpression: CallExpression T_QUESTION_DOT T_LPAREN Arguments T_RPAREN;
+/.
+ case $rule_number: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(4).ArgumentList);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->isOptional = true;
+ sym(1).Node = node;
+ } break;
+./
+
+
CallExpression: CallExpression T_LBRACKET Expression_In T_RBRACKET;
/.
case $rule_number: {
@@ -2187,6 +2401,17 @@ CallExpression: CallExpression T_LBRACKET Expression_In T_RBRACKET;
} break;
./
+CallExpression: CallExpression T_QUESTION_DOT T_LBRACKET Expression_In T_RBRACKET;
+/.
+ case $rule_number: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(4).Expression);
+ node->lbracketToken = loc(3);
+ node->rbracketToken = loc(5);
+ node->isOptional = true;
+ sym(1).Node = node;
+ } break;
+./
+
CallExpression: CallExpression T_DOT IdentifierName;
/.
case $rule_number: {
@@ -2197,6 +2422,17 @@ CallExpression: CallExpression T_DOT IdentifierName;
} break;
./
+CallExpression: CallExpression T_QUESTION_DOT IdentifierName;
+/.
+ case $rule_number: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ node->isOptional = true;
+ sym(1).Node = node;
+ } break;
+./
+
Arguments: ;
/.
case $rule_number: {
@@ -2490,6 +2726,12 @@ RelationalOperator: T_INSTANCEOF;
sym(1).ival = QSOperator::InstanceOf;
} break;
./
+RelationalOperator: T_AS;
+/.
+ case $rule_number: {
+ sym(1).ival = QSOperator::As;
+ } break;
+./
RelationalExpression_In: RelationalExpression_In T_IN ShiftExpression;
/.
@@ -2611,13 +2853,48 @@ LogicalORExpression_In: LogicalORExpression_In T_OR_OR LogicalANDExpression_In;
} break;
./
+CoalesceExpression: LogicalORExpression;
+CoalesceExpression_In: LogicalORExpression_In;
+
+CoalesceExpression: CoalesceExpression T_QUESTION_QUESTION LogicalORExpression;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+CoalesceExpression_In: CoalesceExpression_In T_QUESTION_QUESTION LogicalORExpression_In;
+/.
+ case $rule_number: {
+
+ auto *lhs = sym(1).Expression;
+ auto *rhs = sym(3).Expression;
-ConditionalExpression: LogicalORExpression;
-ConditionalExpression_In: LogicalORExpression_In;
+ // Check if lhs or rhs contain || or &&
-ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression;
+ if (lhs->binaryExpressionCast() != nullptr) {
+ auto *binaryExpr = lhs->binaryExpressionCast();
+ if (binaryExpr->op == QSOperator::And || binaryExpr->op == QSOperator::Or) {
+ syntaxError(binaryExpr->operatorToken, "Left-hand side may not contain || or &&");
+ return false;
+ }
+ }
+
+ if (rhs->binaryExpressionCast() != nullptr) {
+ auto *binaryExpr = rhs->binaryExpressionCast();
+ if (binaryExpr->op == QSOperator::And || binaryExpr->op == QSOperator::Or) {
+ syntaxError(binaryExpr->operatorToken, "Right-hand side may not contain || or &&");
+ return false;
+ }
+ }
+
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(lhs, QSOperator::Coalesce, rhs);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+ } break;
+./
+
+ConditionalExpression: CoalesceExpression;
+ConditionalExpression_In: CoalesceExpression_In;
+
+ConditionalExpression: CoalesceExpression T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression;
/. case $rule_number: Q_FALLTHROUGH(); ./
-ConditionalExpression_In: LogicalORExpression_In T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression_In;
+ConditionalExpression_In: CoalesceExpression_In T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression_In;
/.
case $rule_number: {
AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression, sym(3).Expression, sym(5).Expression);
@@ -2641,9 +2918,12 @@ AssignmentExpression: LeftHandSideExpression T_EQ AssignmentExpression;
AssignmentExpression_In: LeftHandSideExpression T_EQ AssignmentExpression_In;
/.
case $rule_number: {
+ if (sym(1).Expression->containsOptionalChain()) {
+ syntaxError(loc(1), QStringLiteral("Optional chains are not permitted on the left-hand-side in assignments"));
+ }
// need to convert the LHS to an AssignmentPattern if it was an Array/ObjectLiteral
if (AST::Pattern *p = sym(1).Expression->patternCast()) {
- AST::SourceLocation errorLoc;
+ SourceLocation errorLoc;
QString errorMsg;
if (!p->convertLiteralToAssignmentPattern(pool, &errorLoc, &errorMsg)) {
syntaxError(errorLoc, errorMsg);
@@ -2671,6 +2951,9 @@ AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpres
AssignmentExpression_In: LeftHandSideExpression AssignmentOperator AssignmentExpression_In;
/.
case $rule_number: {
+ if (sym(1).Expression->containsOptionalChain()) {
+ syntaxError(loc(1), QStringLiteral("Optional chains are not permitted on the left-hand-side in assignments"));
+ }
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
@@ -3099,14 +3382,15 @@ BindingElisionElement: ElisionOpt BindingElement;
BindingProperty: BindingIdentifier InitializerOpt_In;
/.
case $rule_number: {
- AST::StringLiteralPropertyName *name = new (pool) AST::StringLiteralPropertyName(stringRef(1));
+ AST::IdentifierPropertyName *name = new (pool) AST::IdentifierPropertyName(stringRef(1));
name->propertyNameToken = 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))
f->name = stringRef(1);
if (auto *c = asAnonymousClassDefinition(sym(2).Expression))
c->name = stringRef(1);
- sym(1).Node = new (pool) AST::PatternProperty(name, stringRef(1), sym(2).Expression);
+ AST::PatternProperty *node = new (pool) AST::PatternProperty(name, stringRef(1), sym(2).Expression);
+ sym(1).Node = node;
} break;
./
@@ -3114,6 +3398,8 @@ BindingProperty: PropertyName T_COLON BindingIdentifier InitializerOpt_In;
/.
case $rule_number: {
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, stringRef(3), sym(4).Expression);
+ node->colonToken = loc(2);
+ node->identifierToken = loc(3);
sym(1).Node = node;
} break;
./
@@ -3122,6 +3408,7 @@ BindingProperty: PropertyName T_COLON BindingPattern InitializerOpt_In;
/.
case $rule_number: {
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, sym(3).Pattern, sym(4).Expression);
+ node->colonToken = loc(2);
sym(1).Node = node;
} break;
./
@@ -3281,6 +3568,11 @@ IterationStatement: T_FOR T_LPAREN LexicalDeclaration T_SEMICOLON ExpressionOpt_
AST::ForStatement *node = new (pool) AST::ForStatement(
static_cast<AST::VariableStatement *>(sym(3).Node)->declarations, sym(5).Expression,
sym(7).Expression, sym(9).Statement);
+ if (node->declarations) {
+ AST::PatternElement *pe = node->declarations->declaration;
+ pe->isForDeclaration = true;
+ pe->declarationKindToken = loc(3);
+ }
node->forToken = loc(1);
node->lparenToken = loc(2);
node->firstSemicolonToken = loc(4);
@@ -3309,7 +3601,7 @@ IterationStatement: T_FOR T_LPAREN LeftHandSideExpression InOrOf Expression_In T
case $rule_number: {
// need to convert the LHS to an AssignmentPattern if it was an Array/ObjectLiteral
if (AST::Pattern *p = sym(3).Expression->patternCast()) {
- AST::SourceLocation errorLoc;
+ SourceLocation errorLoc;
QString errorMsg;
if (!p->convertLiteralToAssignmentPattern(pool, &errorLoc, &errorMsg)) {
syntaxError(errorLoc, errorMsg);
@@ -3352,6 +3644,7 @@ ForDeclaration: Var BindingIdentifier TypeAnnotationOpt;
node->identifierToken = loc(2);
node->scope = sym(1).scope;
node->isForDeclaration = true;
+ node->declarationKindToken = loc(1);
sym(1).Node = node;
} break;
./
@@ -3364,6 +3657,7 @@ ForDeclaration: Var BindingPattern;
auto *node = new (pool) AST::PatternElement(sym(2).Pattern, nullptr);
node->scope = sym(1).scope;
node->isForDeclaration = true;
+ node->declarationKindToken = loc(1);
sym(1).Node = node;
} break;
./
@@ -3392,7 +3686,7 @@ ContinueStatement: T_CONTINUE IdentifierReference Semicolon;
BreakStatement: T_BREAK Semicolon;
/.
case $rule_number: {
- AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef());
+ AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringView());
node->breakToken = loc(1);
node->semicolonToken = loc(2);
sym(1).Node = node;
@@ -3666,7 +3960,7 @@ FunctionDeclaration_Default: Function T_LPAREN FormalParameters T_RPAREN TypeAnn
case $rule_number: {
if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, sym(3).FormalParameterList))
return false;
- AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringRef(), sym(3).FormalParameterList, sym(7).StatementList,
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringView(), sym(3).FormalParameterList, sym(7).StatementList,
/*type annotation*/nullptr);
node->functionToken = loc(1);
node->lparenToken = loc(2);
@@ -3700,7 +3994,7 @@ FunctionExpression: T_FUNCTION T_LPAREN FormalParameters T_RPAREN TypeAnnotation
case $rule_number: {
if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, sym(3).FormalParameterList))
return false;
- AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(7).StatementList,
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringView(), sym(3).FormalParameterList, sym(7).StatementList,
/*type annotation*/nullptr);
node->functionToken = loc(1);
node->lparenToken = loc(2);
@@ -3787,14 +4081,14 @@ ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead AssignmentExpress
/.
case $rule_number: {
AST::ReturnStatement *ret = new (pool) AST::ReturnStatement(sym(4).Expression);
- ret->returnToken = sym(4).Node->firstSourceLocation();
- ret->semicolonToken = sym(4).Node->lastSourceLocation();
+ ret->returnToken = sym(4).Node->firstSourceLocation().startZeroLengthLocation();
+ ret->semicolonToken = sym(4).Node->lastSourceLocation().endZeroLengthLocation(driver->code());
AST::StatementList *statements = (new (pool) AST::StatementList(ret))->finish();
- AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringRef(), sym(1).FormalParameterList, statements);
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringView(), sym(1).FormalParameterList, statements);
f->isArrowFunction = true;
- f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation() : loc(1);
- f->lbraceToken = sym(4).Node->firstSourceLocation();
- f->rbraceToken = sym(4).Node->lastSourceLocation();
+ f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation().startZeroLengthLocation() : loc(1).startZeroLengthLocation();
+ f->lbraceToken = sym(4).Node->firstSourceLocation().startZeroLengthLocation();
+ f->rbraceToken = sym(4).Node->lastSourceLocation().endZeroLengthLocation(driver->code());
sym(1).Node = f;
} break;
./
@@ -3804,10 +4098,10 @@ ArrowFunction: ArrowParameters T_ARROW ConciseBodyLookahead T_FORCE_BLOCK Functi
ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead T_FORCE_BLOCK FunctionLBrace FunctionBody FunctionRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringRef(), sym(1).FormalParameterList, sym(6).StatementList);
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringView(), sym(1).FormalParameterList, sym(6).StatementList);
f->isArrowFunction = true;
- f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation() : loc(1);
- f->lbraceToken = loc(6);
+ f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation().startZeroLengthLocation() : loc(1).startZeroLengthLocation();
+ f->lbraceToken = loc(5);
f->rbraceToken = loc(7);
sym(1).Node = f;
} break;
@@ -3880,7 +4174,6 @@ MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_R
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);
sym(1).Node = node;
} break;
./
@@ -3898,7 +4191,6 @@ MethodDefinition: T_GET PropertyName T_LPAREN T_RPAREN TypeAnnotationOpt Functio
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;
./
@@ -3915,7 +4207,6 @@ MethodDefinition: T_SET PropertyName T_LPAREN PropertySetParameterList T_RPAREN
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;
} break;
./
@@ -3965,7 +4256,7 @@ GeneratorDeclaration_Default: GeneratorDeclaration;
GeneratorDeclaration_Default: FunctionStar GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
/.
case $rule_number: {
- AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringRef(), sym(3).FormalParameterList, sym(6).StatementList);
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringView(), sym(3).FormalParameterList, sym(6).StatementList);
node->functionToken = loc(1);
node->lparenToken = loc(2);
node->rparenToken = loc(4);
@@ -3995,7 +4286,7 @@ GeneratorExpression: T_FUNCTION_STAR BindingIdentifier GeneratorLParen FormalPar
GeneratorExpression: T_FUNCTION_STAR GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
/.
case $rule_number: {
- AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).StatementList);
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringView(), sym(3).FormalParameterList, sym(6).StatementList);
node->functionToken = loc(1);
node->lparenToken = loc(2);
node->rparenToken = loc(4);
@@ -4070,7 +4361,7 @@ ClassExpression: T_CLASS BindingIdentifier ClassHeritageOpt ClassLBrace ClassBod
ClassDeclaration_Default: T_CLASS ClassHeritageOpt ClassLBrace ClassBodyOpt ClassRBrace;
/.
case $rule_number: {
- AST::ClassDeclaration *node = new (pool) AST::ClassDeclaration(QStringRef(), sym(2).Expression, sym(4).ClassElementList);
+ AST::ClassDeclaration *node = new (pool) AST::ClassDeclaration(QStringView(), sym(2).Expression, sym(4).ClassElementList);
node->classToken = loc(1);
node->lbraceToken = loc(3);
node->rbraceToken = loc(5);
@@ -4081,7 +4372,7 @@ ClassDeclaration_Default: T_CLASS ClassHeritageOpt ClassLBrace ClassBodyOpt Clas
ClassExpression: T_CLASS ClassHeritageOpt ClassLBrace ClassBodyOpt ClassRBrace;
/.
case $rule_number: {
- AST::ClassExpression *node = new (pool) AST::ClassExpression(QStringRef(), sym(2).Expression, sym(4).ClassElementList);
+ AST::ClassExpression *node = new (pool) AST::ClassExpression(QStringView(), sym(2).Expression, sym(4).ClassElementList);
node->classToken = loc(1);
node->lbraceToken = loc(3);
node->rbraceToken = loc(5);
@@ -4094,16 +4385,16 @@ ClassDeclaration_Default: ClassDeclaration;
ClassLBrace: T_LBRACE;
/.
case $rule_number: {
- lexer->setStaticIsKeyword(true);
+ if (++classNestingLevel == 1)
+ lexer->setStaticIsKeyword(true);
} break;
./
ClassRBrace: T_RBRACE;
-/. case $rule_number: ./
-ClassStaticQualifier: T_STATIC;
/.
case $rule_number: {
- lexer->setStaticIsKeyword(false);
+ if (--classNestingLevel == 0)
+ lexer->setStaticIsKeyword(false);
} break;
./
@@ -4158,10 +4449,9 @@ ClassElement: MethodDefinition;
} break;
./
-ClassElement: ClassStaticQualifier MethodDefinition;
+ClassElement: T_STATIC MethodDefinition;
/.
case $rule_number: {
- lexer->setStaticIsKeyword(true);
AST::ClassElementList *node = new (pool) AST::ClassElementList(sym(2).PatternProperty, true);
sym(1).Node = node;
} break;
@@ -4356,7 +4646,10 @@ ImportsList: ImportsList T_COMMA ImportSpecifier;
} break;
./
-ImportSpecifier: ImportedBinding;
+-- When enconutering an IdentifierReference it can resolve to both ImportedBinding and IdentifierName
+-- Using %right and %prec, we tell qlalr that it should not reduce immediately, but rather shift
+-- so that we have a chance of actually parsing the correct rule if there is an "as" identifier
+ImportSpecifier: ImportedBinding %prec T_WITHOUTAS;
/.
case $rule_number: {
auto importSpecifier = new (pool) AST::ImportSpecifier(stringRef(1));
@@ -4543,35 +4836,26 @@ ExportSpecifier: IdentifierName T_AS IdentifierName;
if (first_token == last_token) {
const int errorState = state_stack[tos];
+ // automatic insertion of missing identifiers after dots
+ if (yytoken != -1 && m_identifierInsertionEnabled && t_action(errorState, T_IDENTIFIER) && yyprevtoken == T_DOT) {
+#ifdef PARSER_DEBUG
+ qDebug() << "Inserting missing identifier between" << spell[yyprevtoken] << "and"
+ << spell[yytoken];
+#endif
+ pushTokenWithEmptyLocation(T_IDENTIFIER);
+ action = errorState;
+ goto _Lcheck_token;
+ }
+
+
// automatic insertion of `;'
if (yytoken != -1 && ((t_action(errorState, T_AUTOMATIC_SEMICOLON) && lexer->canInsertAutomaticSemicolon(yytoken))
|| t_action(errorState, T_COMPATIBILITY_SEMICOLON))) {
#ifdef PARSER_DEBUG
qDebug() << "Inserting automatic semicolon.";
#endif
- SavedToken &tk = token_buffer[0];
- tk.token = yytoken;
- tk.dval = yylval;
- tk.spell = yytokenspell;
- tk.raw = yytokenraw;
- tk.loc = yylloc;
-
- yylloc = yyprevlloc;
- yylloc.offset += yylloc.length;
- yylloc.startColumn += yylloc.length;
- yylloc.length = 0;
-
- //const QString msg = QCoreApplication::translate("QQmlParser", "Missing `;'");
- //diagnostic_messages.append(compileError(yyloc, msg, QtWarningMsg));
-
- first_token = &token_buffer[0];
- last_token = &token_buffer[1];
-
- yytoken = T_SEMICOLON;
- yylval = 0;
-
+ pushTokenWithEmptyLocation(T_SEMICOLON);
action = errorState;
-
goto _Lcheck_token;
}
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index 03355b3e38..8f13ad193e 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -1,45 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include <QString>
+#include <QLocale>
+#include "common/qqmljssourcelocation_p.h"
#include "qqmljsast_p.h"
#include "qqmljsastvisitor_p.h"
+#include <qlocale.h>
+
+#include <algorithm>
+#include <array>
QT_BEGIN_NAMESPACE
@@ -116,6 +87,44 @@ ExpressionNode *ExpressionNode::expressionCast()
return this;
}
+bool ExpressionNode::containsOptionalChain() const
+{
+ for (const Node *node = this;;) {
+ switch (node->kind) {
+ case Kind_FieldMemberExpression: {
+ const auto *fme = AST::cast<const FieldMemberExpression*>(node);
+ if (fme->isOptional)
+ return true;
+ node = fme->base;
+ break;
+ }
+ case Kind_ArrayMemberExpression: {
+ const auto *ame = AST::cast<const ArrayMemberExpression*>(node);
+ if (ame->isOptional)
+ return true;
+ node = ame->base;
+ break;
+ }
+ case Kind_CallExpression: {
+ const auto *ce = AST::cast<const CallExpression*>(node);
+ if (ce->isOptional)
+ return true;
+ node = ce->base;
+ break;
+ }
+ case Kind_NestedExpression: {
+ const auto *ne = AST::cast<const NestedExpression*>(node);
+ node = ne->expression;
+ break;
+ }
+ default:
+ // These unhandled nodes lead to invalid lvalues anyway, so they do not need to be handled here.
+ return false;
+ }
+ }
+ return false;
+}
+
FormalParameterList *ExpressionNode::reparseAsFormalParameterList(MemoryPool *pool)
{
AST::ExpressionNode *expr = this;
@@ -157,6 +166,12 @@ BinaryExpression *BinaryExpression::binaryExpressionCast()
return this;
}
+void TypeExpression::accept0(BaseVisitor *visitor)
+{
+ visitor->visit(this);
+ visitor->endVisit(this);
+}
+
Statement *Statement::statementCast()
{
return this;
@@ -167,7 +182,7 @@ UiObjectMember *UiObjectMember::uiObjectMemberCast()
return this;
}
-void NestedExpression::accept0(Visitor *visitor)
+void NestedExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -185,7 +200,7 @@ ClassExpression *NestedExpression::asClassDefinition()
return expression->asClassDefinition();
}
-void ThisExpression::accept0(Visitor *visitor)
+void ThisExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -193,7 +208,7 @@ void ThisExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void IdentifierExpression::accept0(Visitor *visitor)
+void IdentifierExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -201,7 +216,7 @@ void IdentifierExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void NullExpression::accept0(Visitor *visitor)
+void NullExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -209,7 +224,7 @@ void NullExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void TrueLiteral::accept0(Visitor *visitor)
+void TrueLiteral::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -217,7 +232,7 @@ void TrueLiteral::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void FalseLiteral::accept0(Visitor *visitor)
+void FalseLiteral::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -225,7 +240,7 @@ void FalseLiteral::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void SuperLiteral::accept0(Visitor *visitor)
+void SuperLiteral::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -234,7 +249,7 @@ void SuperLiteral::accept0(Visitor *visitor)
}
-void StringLiteral::accept0(Visitor *visitor)
+void StringLiteral::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -242,7 +257,7 @@ void StringLiteral::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void TemplateLiteral::accept0(Visitor *visitor)
+void TemplateLiteral::accept0(BaseVisitor *visitor)
{
bool accepted = true;
for (TemplateLiteral *it = this; it && accepted; it = it->next) {
@@ -251,7 +266,7 @@ void TemplateLiteral::accept0(Visitor *visitor)
}
}
-void NumericLiteral::accept0(Visitor *visitor)
+void NumericLiteral::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -259,7 +274,7 @@ void NumericLiteral::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void RegExpLiteral::accept0(Visitor *visitor)
+void RegExpLiteral::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -267,7 +282,7 @@ void RegExpLiteral::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ArrayPattern::accept0(Visitor *visitor)
+void ArrayPattern::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this))
accept(elements, visitor);
@@ -287,7 +302,7 @@ bool ArrayPattern::isValidArrayLiteral(SourceLocation *errorLocation) const {
return true;
}
-void ObjectPattern::accept0(Visitor *visitor)
+void ObjectPattern::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(properties, visitor);
@@ -462,7 +477,7 @@ bool PatternProperty::convertLiteralToAssignmentPattern(MemoryPool *pool, Source
}
-void Elision::accept0(Visitor *visitor)
+void Elision::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
// ###
@@ -471,7 +486,7 @@ void Elision::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void IdentifierPropertyName::accept0(Visitor *visitor)
+void IdentifierPropertyName::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -479,7 +494,7 @@ void IdentifierPropertyName::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void StringLiteralPropertyName::accept0(Visitor *visitor)
+void StringLiteralPropertyName::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -487,7 +502,7 @@ void StringLiteralPropertyName::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void NumericLiteralPropertyName::accept0(Visitor *visitor)
+void NumericLiteralPropertyName::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -517,7 +532,7 @@ QString NumericLiteralPropertyName::asString()const
return locale.toString(id, 'g', 16);
}
-void ArrayMemberExpression::accept0(Visitor *visitor)
+void ArrayMemberExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(base, visitor);
@@ -527,7 +542,7 @@ void ArrayMemberExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void FieldMemberExpression::accept0(Visitor *visitor)
+void FieldMemberExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(base, visitor);
@@ -536,7 +551,7 @@ void FieldMemberExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void NewMemberExpression::accept0(Visitor *visitor)
+void NewMemberExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(base, visitor);
@@ -546,7 +561,7 @@ void NewMemberExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void NewExpression::accept0(Visitor *visitor)
+void NewExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -555,7 +570,7 @@ void NewExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void CallExpression::accept0(Visitor *visitor)
+void CallExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(base, visitor);
@@ -565,7 +580,7 @@ void CallExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ArgumentList::accept0(Visitor *visitor)
+void ArgumentList::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
for (ArgumentList *it = this; it; it = it->next) {
@@ -576,7 +591,7 @@ void ArgumentList::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void PostIncrementExpression::accept0(Visitor *visitor)
+void PostIncrementExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(base, visitor);
@@ -585,7 +600,7 @@ void PostIncrementExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void PostDecrementExpression::accept0(Visitor *visitor)
+void PostDecrementExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(base, visitor);
@@ -594,7 +609,7 @@ void PostDecrementExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void DeleteExpression::accept0(Visitor *visitor)
+void DeleteExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -603,7 +618,7 @@ void DeleteExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void VoidExpression::accept0(Visitor *visitor)
+void VoidExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -612,7 +627,7 @@ void VoidExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void TypeOfExpression::accept0(Visitor *visitor)
+void TypeOfExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -621,7 +636,7 @@ void TypeOfExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void PreIncrementExpression::accept0(Visitor *visitor)
+void PreIncrementExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -630,7 +645,7 @@ void PreIncrementExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void PreDecrementExpression::accept0(Visitor *visitor)
+void PreDecrementExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -639,7 +654,7 @@ void PreDecrementExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void UnaryPlusExpression::accept0(Visitor *visitor)
+void UnaryPlusExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -648,7 +663,7 @@ void UnaryPlusExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void UnaryMinusExpression::accept0(Visitor *visitor)
+void UnaryMinusExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -657,7 +672,7 @@ void UnaryMinusExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void TildeExpression::accept0(Visitor *visitor)
+void TildeExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -666,7 +681,7 @@ void TildeExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void NotExpression::accept0(Visitor *visitor)
+void NotExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -675,7 +690,7 @@ void NotExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void BinaryExpression::accept0(Visitor *visitor)
+void BinaryExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(left, visitor);
@@ -685,7 +700,7 @@ void BinaryExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ConditionalExpression::accept0(Visitor *visitor)
+void ConditionalExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -696,7 +711,7 @@ void ConditionalExpression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void Expression::accept0(Visitor *visitor)
+void Expression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(left, visitor);
@@ -706,7 +721,7 @@ void Expression::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void Block::accept0(Visitor *visitor)
+void Block::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(statements, visitor);
@@ -715,7 +730,7 @@ void Block::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void StatementList::accept0(Visitor *visitor)
+void StatementList::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
for (StatementList *it = this; it; it = it->next) {
@@ -726,7 +741,7 @@ void StatementList::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void VariableStatement::accept0(Visitor *visitor)
+void VariableStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(declarations, visitor);
@@ -735,7 +750,7 @@ void VariableStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void VariableDeclarationList::accept0(Visitor *visitor)
+void VariableDeclarationList::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
for (VariableDeclarationList *it = this; it; it = it->next) {
@@ -746,7 +761,7 @@ void VariableDeclarationList::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void EmptyStatement::accept0(Visitor *visitor)
+void EmptyStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -754,7 +769,7 @@ void EmptyStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ExpressionStatement::accept0(Visitor *visitor)
+void ExpressionStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -763,7 +778,7 @@ void ExpressionStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void IfStatement::accept0(Visitor *visitor)
+void IfStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -774,7 +789,7 @@ void IfStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void DoWhileStatement::accept0(Visitor *visitor)
+void DoWhileStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(statement, visitor);
@@ -784,7 +799,7 @@ void DoWhileStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void WhileStatement::accept0(Visitor *visitor)
+void WhileStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -794,7 +809,7 @@ void WhileStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ForStatement::accept0(Visitor *visitor)
+void ForStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(initialiser, visitor);
@@ -807,7 +822,7 @@ void ForStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ForEachStatement::accept0(Visitor *visitor)
+void ForEachStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(lhs, visitor);
@@ -818,7 +833,7 @@ void ForEachStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ContinueStatement::accept0(Visitor *visitor)
+void ContinueStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -826,7 +841,7 @@ void ContinueStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void BreakStatement::accept0(Visitor *visitor)
+void BreakStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -834,7 +849,7 @@ void BreakStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ReturnStatement::accept0(Visitor *visitor)
+void ReturnStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -843,7 +858,7 @@ void ReturnStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void YieldExpression::accept0(Visitor *visitor)
+void YieldExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -853,7 +868,7 @@ void YieldExpression::accept0(Visitor *visitor)
}
-void WithStatement::accept0(Visitor *visitor)
+void WithStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -863,7 +878,7 @@ void WithStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void SwitchStatement::accept0(Visitor *visitor)
+void SwitchStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -873,7 +888,7 @@ void SwitchStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void CaseBlock::accept0(Visitor *visitor)
+void CaseBlock::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(clauses, visitor);
@@ -884,7 +899,7 @@ void CaseBlock::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void CaseClauses::accept0(Visitor *visitor)
+void CaseClauses::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
for (CaseClauses *it = this; it; it = it->next) {
@@ -895,7 +910,7 @@ void CaseClauses::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void CaseClause::accept0(Visitor *visitor)
+void CaseClause::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -905,7 +920,7 @@ void CaseClause::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void DefaultClause::accept0(Visitor *visitor)
+void DefaultClause::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(statements, visitor);
@@ -914,7 +929,7 @@ void DefaultClause::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void LabelledStatement::accept0(Visitor *visitor)
+void LabelledStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(statement, visitor);
@@ -923,7 +938,7 @@ void LabelledStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ThrowStatement::accept0(Visitor *visitor)
+void ThrowStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -932,7 +947,7 @@ void ThrowStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void TryStatement::accept0(Visitor *visitor)
+void TryStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(statement, visitor);
@@ -943,7 +958,7 @@ void TryStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void Catch::accept0(Visitor *visitor)
+void Catch::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(patternElement, visitor);
@@ -953,7 +968,7 @@ void Catch::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void Finally::accept0(Visitor *visitor)
+void Finally::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(statement, visitor);
@@ -962,7 +977,7 @@ void Finally::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void FunctionDeclaration::accept0(Visitor *visitor)
+void FunctionDeclaration::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(formals, visitor);
@@ -973,7 +988,7 @@ void FunctionDeclaration::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void FunctionExpression::accept0(Visitor *visitor)
+void FunctionExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(formals, visitor);
@@ -1001,7 +1016,9 @@ BoundNames FormalParameterList::formals() const
// change the name of the earlier argument to enforce the lookup semantics from the spec
formals[duplicateIndex].id += QLatin1String("#") + QString::number(i);
}
- formals += {name, it->element->typeAnnotation};
+ formals += { name, it->element->firstSourceLocation(), it->element->typeAnnotation,
+ it->element->isInjectedSignalParameter ? BoundName::Injected
+ : BoundName::Declared };
}
++i;
}
@@ -1018,7 +1035,7 @@ BoundNames FormalParameterList::boundNames() const
return names;
}
-void FormalParameterList::accept0(Visitor *visitor)
+void FormalParameterList::accept0(BaseVisitor *visitor)
{
bool accepted = true;
for (FormalParameterList *it = this; it && accepted; it = it->next) {
@@ -1029,21 +1046,14 @@ void FormalParameterList::accept0(Visitor *visitor)
}
}
-FormalParameterList *FormalParameterList::finish(QQmlJS::MemoryPool *pool)
+FormalParameterList *FormalParameterList::finish(QQmlJS::MemoryPool *)
{
FormalParameterList *front = next;
next = nullptr;
-
- int i = 0;
- for (const FormalParameterList *it = this; it; it = it->next) {
- if (it->element && it->element->bindingIdentifier.isEmpty())
- it->element->bindingIdentifier = pool->newString(QLatin1String("arg#") + QString::number(i));
- ++i;
- }
return front;
}
-void Program::accept0(Visitor *visitor)
+void Program::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(statements, visitor);
@@ -1052,7 +1062,7 @@ void Program::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ImportSpecifier::accept0(Visitor *visitor)
+void ImportSpecifier::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
@@ -1060,7 +1070,7 @@ void ImportSpecifier::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ImportsList::accept0(Visitor *visitor)
+void ImportsList::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
for (ImportsList *it = this; it; it = it->next) {
@@ -1071,7 +1081,7 @@ void ImportsList::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void NamedImports::accept0(Visitor *visitor)
+void NamedImports::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(importsList, visitor);
@@ -1080,7 +1090,7 @@ void NamedImports::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void FromClause::accept0(Visitor *visitor)
+void FromClause::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -1088,7 +1098,7 @@ void FromClause::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void NameSpaceImport::accept0(Visitor *visitor)
+void NameSpaceImport::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -1096,7 +1106,7 @@ void NameSpaceImport::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ImportClause::accept0(Visitor *visitor)
+void ImportClause::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(nameSpaceImport, visitor);
@@ -1106,7 +1116,7 @@ void ImportClause::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ImportDeclaration::accept0(Visitor *visitor)
+void ImportDeclaration::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(importClause, visitor);
@@ -1116,7 +1126,7 @@ void ImportDeclaration::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ExportSpecifier::accept0(Visitor *visitor)
+void ExportSpecifier::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
@@ -1125,7 +1135,7 @@ void ExportSpecifier::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ExportsList::accept0(Visitor *visitor)
+void ExportsList::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
for (ExportsList *it = this; it; it = it->next) {
@@ -1136,7 +1146,7 @@ void ExportsList::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ExportClause::accept0(Visitor *visitor)
+void ExportClause::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(exportsList, visitor);
@@ -1145,18 +1155,18 @@ void ExportClause::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ExportDeclaration::accept0(Visitor *visitor)
+void ExportDeclaration::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
- accept(fromClause, visitor);
accept(exportClause, visitor);
+ accept(fromClause, visitor);
accept(variableStatementOrDeclaration, visitor);
}
visitor->endVisit(this);
}
-void ESModule::accept0(Visitor *visitor)
+void ESModule::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(body, visitor);
@@ -1165,7 +1175,7 @@ void ESModule::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void DebuggerStatement::accept0(Visitor *visitor)
+void DebuggerStatement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -1173,7 +1183,7 @@ void DebuggerStatement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void UiProgram::accept0(Visitor *visitor)
+void UiProgram::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(headers, visitor);
@@ -1183,19 +1193,23 @@ void UiProgram::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void UiPublicMember::accept0(Visitor *visitor)
+void UiPublicMember::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
+ // accept(annotations, visitor); // accept manually in visit if interested
+ // accept(memberType, visitor); // accept manually in visit if interested
accept(statement, visitor);
accept(binding, visitor);
+ // accept(parameters, visitor); // accept manually in visit if interested
}
visitor->endVisit(this);
}
-void UiObjectDefinition::accept0(Visitor *visitor)
+void UiObjectDefinition::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
+ // accept(annotations, visitor); // accept manually in visit if interested
accept(qualifiedTypeNameId, visitor);
accept(initializer, visitor);
}
@@ -1203,7 +1217,7 @@ void UiObjectDefinition::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void UiObjectInitializer::accept0(Visitor *visitor)
+void UiObjectInitializer::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(members, visitor);
@@ -1212,16 +1226,18 @@ void UiObjectInitializer::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void UiParameterList::accept0(Visitor *visitor)
+void UiParameterList::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
+ // accept(type, visitor); // accept manually in visit if interested
}
visitor->endVisit(this);
}
-void UiObjectBinding::accept0(Visitor *visitor)
+void UiObjectBinding::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
+ // accept(annotations, visitor); // accept manually in visit if interested
accept(qualifiedId, visitor);
accept(qualifiedTypeNameId, visitor);
accept(initializer, visitor);
@@ -1230,9 +1246,10 @@ void UiObjectBinding::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void UiScriptBinding::accept0(Visitor *visitor)
+void UiScriptBinding::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
+ // accept(annotations, visitor); // accept manually in visit if interested
accept(qualifiedId, visitor);
accept(statement, visitor);
}
@@ -1240,9 +1257,10 @@ void UiScriptBinding::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void UiArrayBinding::accept0(Visitor *visitor)
+void UiArrayBinding::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
+ // accept(annotations, visitor); // accept manually in visit if interested
accept(qualifiedId, visitor);
accept(members, visitor);
}
@@ -1250,7 +1268,7 @@ void UiArrayBinding::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void UiObjectMemberList::accept0(Visitor *visitor)
+void UiObjectMemberList::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
for (UiObjectMemberList *it = this; it; it = it->next)
@@ -1260,7 +1278,7 @@ void UiObjectMemberList::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void UiArrayMemberList::accept0(Visitor *visitor)
+void UiArrayMemberList::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
for (UiArrayMemberList *it = this; it; it = it->next)
@@ -1270,53 +1288,54 @@ void UiArrayMemberList::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void UiQualifiedId::accept0(Visitor *visitor)
+void UiQualifiedId::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
+ // accept(next, visitor) // accept manually in visit if interested
}
visitor->endVisit(this);
}
-void Type::accept0(Visitor *visitor)
+void Type::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(typeId, visitor);
- accept(typeArguments, visitor);
+ accept(typeArgument, visitor);
}
visitor->endVisit(this);
}
-void TypeArgumentList::accept0(Visitor *visitor)
+void TypeAnnotation::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
- for (TypeArgumentList *it = this; it; it = it->next)
- accept(it->typeId, visitor);
+ accept(type, visitor);
}
visitor->endVisit(this);
}
-void TypeAnnotation::accept0(Visitor *visitor)
+void UiImport::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
- accept(type, visitor);
+ accept(importUri, visitor);
+ // accept(version, visitor); // accept manually in visit if interested
}
visitor->endVisit(this);
}
-void UiImport::accept0(Visitor *visitor)
+void UiPragmaValueList::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
- accept(importUri, visitor);
}
visitor->endVisit(this);
}
-void UiPragma::accept0(Visitor *visitor)
+
+void UiPragma::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -1324,7 +1343,7 @@ void UiPragma::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void UiHeaderItemList::accept0(Visitor *visitor)
+void UiHeaderItemList::accept0(BaseVisitor *visitor)
{
bool accepted = true;
for (UiHeaderItemList *it = this; it && accepted; it = it->next) {
@@ -1337,25 +1356,27 @@ void UiHeaderItemList::accept0(Visitor *visitor)
}
-void UiSourceElement::accept0(Visitor *visitor)
+void UiSourceElement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
+ // accept(annotations, visitor); // accept manually in visit if interested
accept(sourceElement, visitor);
}
visitor->endVisit(this);
}
-void UiEnumDeclaration::accept0(Visitor *visitor)
+void UiEnumDeclaration::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
+ // accept(annotations, visitor); // accept manually in visit if interested
accept(members, visitor);
}
visitor->endVisit(this);
}
-void UiEnumMemberList::accept0(Visitor *visitor)
+void UiEnumMemberList::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -1363,7 +1384,7 @@ void UiEnumMemberList::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void TaggedTemplate::accept0(Visitor *visitor)
+void TaggedTemplate::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(base, visitor);
@@ -1373,7 +1394,12 @@ void TaggedTemplate::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void PatternElement::accept0(Visitor *visitor)
+void InitializerExpression::accept0(BaseVisitor *visitor)
+{
+ expression->accept0(visitor);
+}
+
+void PatternElement::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(bindingTarget, visitor);
@@ -1392,11 +1418,12 @@ void PatternElement::boundNames(BoundNames *names)
else if (PatternPropertyList *p = propertyList())
p->boundNames(names);
} else {
- names->append({bindingIdentifier.toString(), typeAnnotation});
+ names->append({ bindingIdentifier.toString(), firstSourceLocation(), typeAnnotation,
+ isInjectedSignalParameter ? BoundName::Injected : BoundName::Declared });
}
}
-void PatternElementList::accept0(Visitor *visitor)
+void PatternElementList::accept0(BaseVisitor *visitor)
{
bool accepted = true;
for (PatternElementList *it = this; it && accepted; it = it->next) {
@@ -1417,7 +1444,7 @@ void PatternElementList::boundNames(BoundNames *names)
}
}
-void PatternProperty::accept0(Visitor *visitor)
+void PatternProperty::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(name, visitor);
@@ -1434,7 +1461,7 @@ void PatternProperty::boundNames(BoundNames *names)
PatternElement::boundNames(names);
}
-void PatternPropertyList::accept0(Visitor *visitor)
+void PatternPropertyList::accept0(BaseVisitor *visitor)
{
bool accepted = true;
for (PatternPropertyList *it = this; it && accepted; it = it->next) {
@@ -1451,7 +1478,7 @@ void PatternPropertyList::boundNames(BoundNames *names)
it->property->boundNames(names);
}
-void ComputedPropertyName::accept0(Visitor *visitor)
+void ComputedPropertyName::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(expression, visitor);
@@ -1460,7 +1487,7 @@ void ComputedPropertyName::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ClassExpression::accept0(Visitor *visitor)
+void ClassExpression::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(heritage, visitor);
@@ -1475,7 +1502,7 @@ ClassExpression *ClassExpression::asClassDefinition()
return this;
}
-void ClassDeclaration::accept0(Visitor *visitor)
+void ClassDeclaration::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
accept(heritage, visitor);
@@ -1485,7 +1512,7 @@ void ClassDeclaration::accept0(Visitor *visitor)
visitor->endVisit(this);
}
-void ClassElementList::accept0(Visitor *visitor)
+void ClassElementList::accept0(BaseVisitor *visitor)
{
bool accepted = true;
for (ClassElementList *it = this; it && accepted; it = it->next) {
@@ -1514,7 +1541,7 @@ LeftHandSideExpression *LeftHandSideExpression::leftHandSideExpressionCast()
return this;
}
-void UiVersionSpecifier::accept0(Visitor *visitor)
+void UiVersionSpecifier::accept0(BaseVisitor *visitor)
{
if (visitor->visit(this)) {
}
@@ -1530,21 +1557,67 @@ QString Type::toString() const
void Type::toString(QString *out) const
{
- for (QQmlJS::AST::UiQualifiedId *it = typeId; it; it = it->next) {
- out->append(it->name);
+ typeId->toString(out);
- if (it->next)
- out->append(QLatin1Char('.'));
- }
-
- if (typeArguments) {
+ if (typeArgument) {
out->append(QLatin1Char('<'));
- if (auto subType = static_cast<TypeArgumentList*>(typeArguments)->typeId)
- subType->toString(out);
+ typeArgument->toString(out);
out->append(QLatin1Char('>'));
};
}
+void UiInlineComponent::accept0(BaseVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ // accept(annotations, visitor); // accept manually in visit if interested
+ accept(component, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiRequired::accept0(BaseVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiAnnotationList::accept0(BaseVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (UiAnnotationList *it = this; it; it = it->next)
+ accept(it->annotation, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiAnnotation::accept0(BaseVisitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedTypeNameId, visitor);
+ accept(initializer, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+SourceLocation UiPropertyAttributes::firstSourceLocation() const
+{
+ std::array<const SourceLocation *, 4> tokens {&m_propertyToken, &m_defaultToken, &m_readonlyToken, &m_requiredToken};
+ const auto it = std::min_element(tokens.begin(), tokens.end(), compareLocationsByBegin<true>);
+ return **it;
+}
+
+SourceLocation UiPropertyAttributes::lastSourceLocation() const
+{
+ std::array<const SourceLocation *, 4> tokens {&m_propertyToken, &m_defaultToken, &m_readonlyToken, &m_requiredToken};
+ const auto it = std::max_element(tokens.begin(), tokens.end(), compareLocationsByBegin<false>);
+ return **it;
+}
+
} } // namespace QQmlJS::AST
QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index e436c4673d..bfeab7518c 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSAST_P_H
#define QQMLJSAST_P_H
@@ -56,10 +20,19 @@
#include <private/qqmljsmemorypool_p.h>
-#include <QtCore/qstring.h>
+#include <QtCore/qtaggedpointer.h>
+#include <QtCore/qversionnumber.h>
+
+#include <type_traits>
QT_BEGIN_NAMESPACE
+class QString;
+
+namespace QQmlJS {
+ class Parser;
+}
+
#define QQMLJS_DECLARE_AST_NODE(name) \
enum { K = Kind_##name };
@@ -104,6 +77,8 @@ enum Op {
URShift,
InplaceURightShift,
InplaceXor,
+ As,
+ Coalesce,
Invalid
};
@@ -123,10 +98,10 @@ enum class VariableScope {
template <typename T1, typename T2>
T1 cast(T2 *ast)
{
- if (ast && ast->kind == static_cast<T1>(0)->K)
+ if (ast && ast->kind == std::remove_pointer_t<T1>::K)
return static_cast<T1>(ast);
- return 0;
+ return nullptr;
}
FunctionExpression *asAnonymousFunctionDefinition(AST::Node *n);
@@ -174,6 +149,7 @@ public:
Kind_ClassDeclaration,
Kind_IdentifierExpression,
Kind_IdentifierPropertyName,
+ Kind_InitializerExpression,
Kind_ComputedPropertyName,
Kind_IfStatement,
Kind_LabelledStatement,
@@ -214,6 +190,7 @@ public:
Kind_SwitchStatement,
Kind_TemplateLiteral,
Kind_TaggedTemplate,
+ Kind_TypeExpression,
Kind_ThisExpression,
Kind_ThrowStatement,
Kind_TildeExpression,
@@ -235,19 +212,22 @@ public:
Kind_PatternProperty,
Kind_PatternPropertyList,
Kind_Type,
- Kind_TypeArgumentList,
+ Kind_TypeArgument,
Kind_TypeAnnotation,
Kind_UiArrayBinding,
Kind_UiImport,
Kind_UiObjectBinding,
Kind_UiObjectDefinition,
+ Kind_UiInlineComponent,
Kind_UiObjectInitializer,
Kind_UiObjectMemberList,
Kind_UiArrayMemberList,
+ Kind_UiPragmaValueList,
Kind_UiPragma,
Kind_UiProgram,
Kind_UiParameterList,
+ Kind_UiPropertyAttributes,
Kind_UiPublicMember,
Kind_UiQualifiedId,
Kind_UiScriptBinding,
@@ -255,7 +235,10 @@ public:
Kind_UiHeaderItemList,
Kind_UiEnumDeclaration,
Kind_UiEnumMemberList,
- Kind_UiVersionSpecifier
+ Kind_UiVersionSpecifier,
+ Kind_UiRequired,
+ Kind_UiAnnotation,
+ Kind_UiAnnotationList
};
inline Node() {}
@@ -277,9 +260,9 @@ public:
bool ignoreRecursionDepth() const;
- inline void accept(Visitor *visitor)
+ inline void accept(BaseVisitor *visitor)
{
- Visitor::RecursionDepthCheck recursionCheck(visitor);
+ BaseVisitor::RecursionDepthCheck recursionCheck(visitor);
// Stack overflow is uncommon, ignoreRecursionDepth() only returns true if
// QV4_CRASH_ON_STACKOVERFLOW is set, and ignoreRecursionDepth() needs to be out of line.
@@ -293,19 +276,13 @@ public:
}
}
- inline static void accept(Node *node, Visitor *visitor)
+ inline static void accept(Node *node, BaseVisitor *visitor)
{
if (node)
node->accept(visitor);
}
- // ### Remove when we can. This is part of the qmldevtools library, though.
- inline static void acceptChild(Node *node, Visitor *visitor)
- {
- return accept(node, visitor);
- }
-
- virtual void accept0(Visitor *visitor) = 0;
+ virtual void accept0(BaseVisitor *visitor) = 0;
virtual SourceLocation firstSourceLocation() const = 0;
virtual SourceLocation lastSourceLocation() const = 0;
@@ -327,11 +304,11 @@ class QML_PARSER_EXPORT UiQualifiedId: public Node
public:
QQMLJS_DECLARE_AST_NODE(UiQualifiedId)
- UiQualifiedId(const QStringRef &name)
+ UiQualifiedId(QStringView name)
: next(this), name(name)
{ kind = K; }
- UiQualifiedId(UiQualifiedId *previous, const QStringRef &name)
+ UiQualifiedId(UiQualifiedId *previous, QStringView name)
: name(name)
{
kind = K;
@@ -346,18 +323,39 @@ public:
return head;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return identifierToken; }
SourceLocation lastSourceLocation() const override
- { return lastListElement(this)->identifierToken; }
+ {
+ return lastListElement(this)->lastOwnSourceLocation();
+ }
+
+ SourceLocation lastOwnSourceLocation() const { return identifierToken; }
+
+ QString toString() const
+ {
+ QString result;
+ toString(&result);
+ return result;
+ }
+
+ void toString(QString *out) const
+ {
+ for (const UiQualifiedId *it = this; it; it = it->next) {
+ out->append(it->name);
+ if (it->next)
+ out->append(QLatin1Char('.'));
+ }
+ }
// attributes
UiQualifiedId *next;
- QStringRef name;
+ QStringView name;
SourceLocation identifierToken;
+ SourceLocation dotToken;
};
class QML_PARSER_EXPORT Type: public Node
@@ -365,64 +363,25 @@ class QML_PARSER_EXPORT Type: public Node
public:
QQMLJS_DECLARE_AST_NODE(Type)
- Type(UiQualifiedId *typeId, Node *typeArguments = nullptr)
+ Type(UiQualifiedId *typeId, Type *typeArgument = nullptr)
: typeId(typeId)
- , typeArguments(typeArguments)
+ , typeArgument(typeArgument ? typeArgument->typeId : nullptr)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return typeId->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return typeArguments ? typeArguments->lastSourceLocation() : typeId->lastSourceLocation(); }
+ { return typeArgument ? typeArgument->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 lastListElement(this)->typeId->lastSourceLocation(); }
-
- inline TypeArgumentList *finish()
- {
- TypeArgumentList *front = next;
- next = nullptr;
- return front;
- }
-
-// attributes
- Type *typeId;
- TypeArgumentList *next;
+ UiQualifiedId *typeArgument;
};
class QML_PARSER_EXPORT TypeAnnotation: public Node
@@ -434,7 +393,7 @@ public:
: type(type)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return colonToken; }
@@ -452,6 +411,7 @@ public:
ExpressionNode() {}
ExpressionNode *expressionCast() override;
+ bool containsOptionalChain() const;
AST::FormalParameterList *reparseAsFormalParameterList(MemoryPool *pool);
@@ -479,7 +439,7 @@ public:
: expression(expression)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return lparenToken; }
@@ -497,6 +457,26 @@ public:
SourceLocation rparenToken;
};
+
+class QML_PARSER_EXPORT TypeExpression : public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TypeExpression)
+ TypeExpression(Type *t) : m_type(t) { kind = K; }
+
+ void accept0(BaseVisitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override {
+ return m_type->firstSourceLocation();
+ }
+
+ SourceLocation lastSourceLocation() const override {
+ return m_type->lastSourceLocation();
+ }
+
+ Type *m_type;
+};
+
class QML_PARSER_EXPORT ThisExpression: public LeftHandSideExpression
{
public:
@@ -504,7 +484,7 @@ public:
ThisExpression() { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return thisToken; }
@@ -521,10 +501,10 @@ class QML_PARSER_EXPORT IdentifierExpression: public LeftHandSideExpression
public:
QQMLJS_DECLARE_AST_NODE(IdentifierExpression)
- IdentifierExpression(const QStringRef &n):
+ IdentifierExpression(QStringView n):
name (n) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return identifierToken; }
@@ -533,7 +513,7 @@ public:
{ return identifierToken; }
// attributes
- QStringRef name;
+ QStringView name;
SourceLocation identifierToken;
};
@@ -544,7 +524,7 @@ public:
NullExpression() { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return nullToken; }
@@ -563,7 +543,7 @@ public:
TrueLiteral() { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return trueToken; }
@@ -582,7 +562,7 @@ public:
FalseLiteral() { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return falseToken; }
@@ -601,7 +581,7 @@ public:
SuperLiteral() { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return superToken; }
@@ -622,7 +602,7 @@ public:
NumericLiteral(double v):
value(v) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return literalToken; }
@@ -640,9 +620,17 @@ class QML_PARSER_EXPORT UiVersionSpecifier : public Node
public:
QQMLJS_DECLARE_AST_NODE(UiVersionSpecifier)
- UiVersionSpecifier(int majorum, int minorum) : majorVersion(majorum), minorVersion(minorum) { kind = K; }
+ UiVersionSpecifier(int majorum) : version(QTypeRevision::fromMajorVersion(majorum))
+ {
+ kind = K;
+ }
+
+ UiVersionSpecifier(int majorum, int minorum) : version(QTypeRevision::fromVersion(majorum, minorum))
+ {
+ kind = K;
+ }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override { return majorToken; }
@@ -652,8 +640,7 @@ public:
}
// attributes:
- int majorVersion;
- int minorVersion;
+ QTypeRevision version;
SourceLocation majorToken;
SourceLocation minorToken;
};
@@ -663,10 +650,10 @@ class QML_PARSER_EXPORT StringLiteral : public LeftHandSideExpression
public:
QQMLJS_DECLARE_AST_NODE(StringLiteral)
- StringLiteral(const QStringRef &v):
+ StringLiteral(QStringView v):
value (v) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return literalToken; }
@@ -675,7 +662,7 @@ public:
{ return literalToken; }
// attributes:
- QStringRef value;
+ QStringView value;
SourceLocation literalToken;
};
@@ -684,7 +671,7 @@ class QML_PARSER_EXPORT TemplateLiteral : public LeftHandSideExpression
public:
QQMLJS_DECLARE_AST_NODE(TemplateLiteral)
- TemplateLiteral(const QStringRef &str, const QStringRef &raw, ExpressionNode *e)
+ TemplateLiteral(QStringView str, QStringView raw, ExpressionNode *e)
: value(str), rawValue(raw), expression(e), next(nullptr)
{ kind = K; }
@@ -697,10 +684,11 @@ public:
return (last->expression ? last->expression->lastSourceLocation() : last->literalToken);
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
- QStringRef value;
- QStringRef rawValue;
+ bool hasNoSubstitution = false;
+ QStringView value;
+ QStringView rawValue;
ExpressionNode *expression;
TemplateLiteral *next;
SourceLocation literalToken;
@@ -711,10 +699,10 @@ class QML_PARSER_EXPORT RegExpLiteral: public LeftHandSideExpression
public:
QQMLJS_DECLARE_AST_NODE(RegExpLiteral)
- RegExpLiteral(const QStringRef &p, int f):
+ RegExpLiteral(QStringView p, int f):
pattern (p), flags (f) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return literalToken; }
@@ -723,7 +711,7 @@ public:
{ return literalToken; }
// attributes:
- QStringRef pattern;
+ QStringView pattern;
int flags;
SourceLocation literalToken;
};
@@ -749,7 +737,7 @@ public:
: elements(elts)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return lbracketToken; }
@@ -780,7 +768,7 @@ public:
: properties(plist)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return lbraceToken; }
@@ -811,7 +799,7 @@ public:
previous->next = this;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return commaToken; }
@@ -852,13 +840,21 @@ public:
struct QML_PARSER_EXPORT BoundName
{
+ enum Type {
+ Declared,
+ Injected,
+ };
+
QString id;
- TypeAnnotation *typeAnnotation = nullptr;
- BoundName(const QString &id, TypeAnnotation *typeAnnotation)
- : id(id), typeAnnotation(typeAnnotation)
+ QQmlJS::SourceLocation location;
+ QTaggedPointer<TypeAnnotation, Type> typeAnnotation;
+ BoundName(const QString &id, const QQmlJS::SourceLocation &location,
+ TypeAnnotation *typeAnnotation, Type type = Declared)
+ : id(id), location(location), typeAnnotation(typeAnnotation, type)
{}
BoundName() = default;
- QString typeName() const { return typeAnnotation ? typeAnnotation->type->toString() : QString(); }
+
+ bool isInjected() const { return typeAnnotation.tag() == Injected; }
};
struct BoundNames : public QVector<BoundName>
@@ -878,6 +874,39 @@ struct BoundNames : public QVector<BoundName>
}
};
+/*!
+\internal
+This class is needed to pass the information about the equalToken in the parser, and is only needed
+during AST construction. It behaves exactly like the expression it contains: that avoids changing
+all the usages in qqmljs.g from ExpressionNode to InitializerExpression for every rule expecting a
+InitializerOpt_In or InitializerOpt.
+*/
+class QML_PARSER_EXPORT InitializerExpression : public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(InitializerExpression)
+
+ InitializerExpression(ExpressionNode *e) : expression(e) { kind = K; }
+
+ void accept0(BaseVisitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return equalToken; }
+
+ SourceLocation lastSourceLocation() const override { return expression->lastSourceLocation(); }
+
+ FunctionExpression *asFunctionDefinition() override
+ {
+ return expression->asFunctionDefinition();
+ }
+
+ ClassExpression *asClassDefinition() override { return expression->asClassDefinition(); }
+
+ // attributes
+ ExpressionNode *expression;
+ SourceLocation equalToken;
+};
+
class QML_PARSER_EXPORT PatternElement : public Node
{
public:
@@ -898,16 +927,36 @@ public:
Binding,
};
+private:
+ /*!
+ \internal
+ Hide InitializerExpression from the AST. InitializerExpression is only needed during parsing for
+ the AST construction, and it is not possible for the parser to directly embed the location of
+ equal tokens inside the PatternElement without the InitializerExpression.
+ */
+ void unwrapInitializer()
+ {
+ if (auto unwrapped = AST::cast<InitializerExpression *>(initializer)) {
+ equalToken = unwrapped->equalToken;
+ initializer = unwrapped->expression;
+ }
+ }
+public:
+
PatternElement(ExpressionNode *i = nullptr, Type t = Literal)
: initializer(i), type(t)
- { kind = K; }
+ {
+ kind = K;
+ unwrapInitializer();
+ }
- PatternElement(const QStringRef &n, TypeAnnotation *typeAnnotation = nullptr, ExpressionNode *i = nullptr, Type t = Binding)
+ PatternElement(QStringView n, TypeAnnotation *typeAnnotation = nullptr, ExpressionNode *i = nullptr, Type t = Binding)
: bindingIdentifier(n), initializer(i), type(t)
, typeAnnotation(typeAnnotation)
{
Q_ASSERT(t >= RestElement);
kind = K;
+ unwrapInitializer();
}
PatternElement(Pattern *pattern, ExpressionNode *i = nullptr, Type t = Binding)
@@ -915,9 +964,10 @@ public:
{
Q_ASSERT(t >= RestElement);
kind = K;
+ unwrapInitializer();
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
virtual bool convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage);
SourceLocation firstSourceLocation() const override
@@ -938,14 +988,17 @@ public:
// attributes
SourceLocation identifierToken;
- QStringRef bindingIdentifier;
+ SourceLocation equalToken;
+ QStringView bindingIdentifier;
ExpressionNode *bindingTarget = nullptr;
ExpressionNode *initializer = nullptr;
Type type = Literal;
TypeAnnotation *typeAnnotation = nullptr;
// when used in a VariableDeclarationList
+ SourceLocation declarationKindToken;
VariableScope scope = VariableScope::NoScope;
bool isForDeclaration = false;
+ bool isInjectedSignalParameter = false;
};
class QML_PARSER_EXPORT PatternElementList : public Node
@@ -970,7 +1023,7 @@ public:
return front;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
void boundNames(BoundNames *names);
@@ -997,7 +1050,7 @@ public:
: PatternElement(i, t), name(name)
{ kind = K; }
- PatternProperty(PropertyName *name, const QStringRef &n, ExpressionNode *i = nullptr)
+ PatternProperty(PropertyName *name, QStringView n, ExpressionNode *i = nullptr)
: PatternElement(n, /*type annotation*/nullptr, i), name(name)
{ kind = K; }
@@ -1005,7 +1058,7 @@ public:
: PatternElement(pattern, i), name(name)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return name->firstSourceLocation(); }
@@ -1041,7 +1094,7 @@ public:
previous->next = this;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
void boundNames(BoundNames *names);
@@ -1062,20 +1115,20 @@ public:
PatternPropertyList *next;
};
-class QML_PARSER_EXPORT IdentifierPropertyName : public PropertyName
+class QML_PARSER_EXPORT IdentifierPropertyName: public PropertyName
{
public:
QQMLJS_DECLARE_AST_NODE(IdentifierPropertyName)
- IdentifierPropertyName(const QStringRef &n):
+ IdentifierPropertyName(QStringView n):
id (n) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
QString asString() const override { return id.toString(); }
// attributes
- QStringRef id;
+ QStringView id;
};
class QML_PARSER_EXPORT StringLiteralPropertyName: public PropertyName
@@ -1083,15 +1136,15 @@ class QML_PARSER_EXPORT StringLiteralPropertyName: public PropertyName
public:
QQMLJS_DECLARE_AST_NODE(StringLiteralPropertyName)
- StringLiteralPropertyName(const QStringRef &n):
+ StringLiteralPropertyName(QStringView n):
id (n) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
QString asString() const override { return id.toString(); }
// attributes
- QStringRef id;
+ QStringView id;
};
class QML_PARSER_EXPORT NumericLiteralPropertyName: public PropertyName
@@ -1102,7 +1155,7 @@ public:
NumericLiteralPropertyName(double n):
id (n) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
QString asString() const override;
@@ -1119,7 +1172,7 @@ public:
: expression(expression)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
QString asString() const override { return QString(); }
@@ -1143,7 +1196,7 @@ public:
base (b), expression (e)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return base->firstSourceLocation(); }
@@ -1156,6 +1209,7 @@ public:
ExpressionNode *expression;
SourceLocation lbracketToken;
SourceLocation rbracketToken;
+ bool isOptional = false;
};
class QML_PARSER_EXPORT FieldMemberExpression: public LeftHandSideExpression
@@ -1163,11 +1217,11 @@ class QML_PARSER_EXPORT FieldMemberExpression: public LeftHandSideExpression
public:
QQMLJS_DECLARE_AST_NODE(FieldMemberExpression)
- FieldMemberExpression(ExpressionNode *b, const QStringRef &n):
+ FieldMemberExpression(ExpressionNode *b, QStringView n):
base (b), name (n)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return base->firstSourceLocation(); }
@@ -1177,9 +1231,10 @@ public:
// attributes
ExpressionNode *base;
- QStringRef name;
+ QStringView name;
SourceLocation dotToken;
SourceLocation identifierToken;
+ bool isOptional = false;
};
class QML_PARSER_EXPORT TaggedTemplate : public LeftHandSideExpression
@@ -1191,7 +1246,7 @@ public:
: base (b), templateLiteral(t)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return base->firstSourceLocation(); }
@@ -1213,7 +1268,7 @@ public:
base (b), arguments (a)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return newToken; }
@@ -1237,7 +1292,7 @@ public:
NewExpression(ExpressionNode *e):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return newToken; }
@@ -1259,7 +1314,7 @@ public:
base (b), arguments (a)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return base->firstSourceLocation(); }
@@ -1272,6 +1327,7 @@ public:
ArgumentList *arguments;
SourceLocation lparenToken;
SourceLocation rparenToken;
+ bool isOptional = false;
};
class QML_PARSER_EXPORT ArgumentList: public Node
@@ -1291,7 +1347,7 @@ public:
previous->next = this;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return expression->firstSourceLocation(); }
@@ -1325,7 +1381,7 @@ public:
PostIncrementExpression(ExpressionNode *b):
base (b) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return base->firstSourceLocation(); }
@@ -1346,7 +1402,7 @@ public:
PostDecrementExpression(ExpressionNode *b):
base (b) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return base->firstSourceLocation(); }
@@ -1367,7 +1423,7 @@ public:
DeleteExpression(ExpressionNode *e):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return deleteToken; }
@@ -1388,7 +1444,7 @@ public:
VoidExpression(ExpressionNode *e):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return voidToken; }
@@ -1409,7 +1465,7 @@ public:
TypeOfExpression(ExpressionNode *e):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return typeofToken; }
@@ -1430,7 +1486,7 @@ public:
PreIncrementExpression(ExpressionNode *e):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return incrementToken; }
@@ -1451,7 +1507,7 @@ public:
PreDecrementExpression(ExpressionNode *e):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return decrementToken; }
@@ -1472,7 +1528,7 @@ public:
UnaryPlusExpression(ExpressionNode *e):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return plusToken; }
@@ -1493,7 +1549,7 @@ public:
UnaryMinusExpression(ExpressionNode *e):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return minusToken; }
@@ -1514,7 +1570,7 @@ public:
TildeExpression(ExpressionNode *e):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return tildeToken; }
@@ -1535,7 +1591,7 @@ public:
NotExpression(ExpressionNode *e):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return notToken; }
@@ -1559,7 +1615,7 @@ public:
BinaryExpression *binaryExpressionCast() override;
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return left->firstSourceLocation(); }
@@ -1583,7 +1639,7 @@ public:
expression (e), ok (t), ko (f)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return expression->firstSourceLocation(); }
@@ -1607,7 +1663,7 @@ public:
Expression(ExpressionNode *l, ExpressionNode *r):
left (l), right (r) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return left->firstSourceLocation(); }
@@ -1629,7 +1685,7 @@ public:
Block(StatementList *slist):
statements (slist) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return lbraceToken; }
@@ -1659,7 +1715,7 @@ public:
return n;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return statement->firstSourceLocation(); }
@@ -1698,7 +1754,7 @@ public:
previous->next = this;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return declaration->firstSourceLocation(); }
@@ -1736,7 +1792,7 @@ public:
declarations (vlist)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return declarationKindToken; }
@@ -1756,7 +1812,7 @@ public:
EmptyStatement() { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return semicolonToken; }
@@ -1776,13 +1832,13 @@ public:
ExpressionStatement(ExpressionNode *e):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return expression->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
- { return expression->lastSourceLocation(); }
+ { return semicolonToken; }
// attributes
ExpressionNode *expression;
@@ -1798,7 +1854,7 @@ public:
expression (e), ok (t), ko (f)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return ifToken; }
@@ -1830,7 +1886,7 @@ public:
statement (stmt), expression (e)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return doToken; }
@@ -1857,7 +1913,7 @@ public:
expression (e), statement (stmt)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return whileToken; }
@@ -1887,7 +1943,7 @@ public:
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return forToken; }
@@ -1925,7 +1981,7 @@ public:
: lhs(v), expression(e), statement(stmt)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return forToken; }
@@ -1953,10 +2009,10 @@ class QML_PARSER_EXPORT ContinueStatement: public Statement
public:
QQMLJS_DECLARE_AST_NODE(ContinueStatement)
- ContinueStatement(const QStringRef &l = QStringRef()):
+ ContinueStatement(QStringView l = QStringView()):
label (l) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return continueToken; }
@@ -1965,7 +2021,7 @@ public:
{ return semicolonToken; }
// attributes
- QStringRef label;
+ QStringView label;
SourceLocation continueToken;
SourceLocation identifierToken;
SourceLocation semicolonToken;
@@ -1976,10 +2032,10 @@ class QML_PARSER_EXPORT BreakStatement: public Statement
public:
QQMLJS_DECLARE_AST_NODE(BreakStatement)
- BreakStatement(const QStringRef &l):
+ BreakStatement(QStringView l):
label (l) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return breakToken; }
@@ -1988,7 +2044,7 @@ public:
{ return semicolonToken; }
// attributes
- QStringRef label;
+ QStringView label;
SourceLocation breakToken;
SourceLocation identifierToken;
SourceLocation semicolonToken;
@@ -2002,7 +2058,7 @@ public:
ReturnStatement(ExpressionNode *e):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return returnToken; }
@@ -2024,7 +2080,7 @@ public:
YieldExpression(ExpressionNode *e = nullptr):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return yieldToken; }
@@ -2047,7 +2103,7 @@ public:
expression (e), statement (stmt)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return withToken; }
@@ -2072,7 +2128,7 @@ public:
clauses (c), defaultClause (d), moreClauses (r)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return lbraceToken; }
@@ -2097,7 +2153,7 @@ public:
expression (e), block (b)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return switchToken; }
@@ -2122,7 +2178,7 @@ public:
expression (e), statements (slist)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return caseToken; }
@@ -2154,7 +2210,7 @@ public:
previous->next = this;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return clause->firstSourceLocation(); }
@@ -2185,7 +2241,7 @@ public:
statements (slist)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return defaultToken; }
@@ -2204,11 +2260,11 @@ class QML_PARSER_EXPORT LabelledStatement: public Statement
public:
QQMLJS_DECLARE_AST_NODE(LabelledStatement)
- LabelledStatement(const QStringRef &l, Statement *stmt):
+ LabelledStatement(QStringView l, Statement *stmt):
label (l), statement (stmt)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return identifierToken; }
@@ -2217,7 +2273,7 @@ public:
{ return statement->lastSourceLocation(); }
// attributes
- QStringRef label;
+ QStringView label;
Statement *statement;
SourceLocation identifierToken;
SourceLocation colonToken;
@@ -2231,7 +2287,7 @@ public:
ThrowStatement(ExpressionNode *e):
expression (e) { kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return throwToken; }
@@ -2254,7 +2310,7 @@ public:
: patternElement(p), statement(stmt)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return catchToken; }
@@ -2280,7 +2336,7 @@ public:
statement (stmt)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return finallyToken; }
@@ -2310,7 +2366,7 @@ public:
statement (stmt), catchExpression (c), finallyExpression (nullptr)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return tryToken; }
@@ -2337,12 +2393,12 @@ class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode
public:
QQMLJS_DECLARE_AST_NODE(FunctionExpression)
- FunctionExpression(const QStringRef &n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr):
+ FunctionExpression(QStringView n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr):
name (n), formals (f), body (b),
typeAnnotation(typeAnnotation)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return functionToken; }
@@ -2353,7 +2409,7 @@ public:
FunctionExpression *asFunctionDefinition() override;
// attributes
- QStringRef name;
+ QStringView name;
bool isArrowFunction = false;
bool isGenerator = false;
FormalParameterList *formals;
@@ -2372,11 +2428,11 @@ class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression
public:
QQMLJS_DECLARE_AST_NODE(FunctionDeclaration)
- FunctionDeclaration(const QStringRef &n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr):
+ FunctionDeclaration(QStringView n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr):
FunctionExpression(n, f, b, typeAnnotation)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
};
class QML_PARSER_EXPORT FormalParameterList: public Node
@@ -2447,7 +2503,7 @@ public:
BoundNames boundNames() const;
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return element->firstSourceLocation(); }
@@ -2469,11 +2525,11 @@ class QML_PARSER_EXPORT ClassExpression : public ExpressionNode
public:
QQMLJS_DECLARE_AST_NODE(ClassExpression)
- ClassExpression(const QStringRef &n, ExpressionNode *heritage, ClassElementList *elements)
+ ClassExpression(QStringView n, ExpressionNode *heritage, ClassElementList *elements)
: name(n), heritage(heritage), elements(elements)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return classToken; }
@@ -2484,7 +2540,7 @@ public:
ClassExpression *asClassDefinition() override;
// attributes
- QStringRef name;
+ QStringView name;
ExpressionNode *heritage;
ClassElementList *elements;
SourceLocation classToken;
@@ -2498,11 +2554,11 @@ class QML_PARSER_EXPORT ClassDeclaration: public ClassExpression
public:
QQMLJS_DECLARE_AST_NODE(ClassDeclaration)
- ClassDeclaration(const QStringRef &n, ExpressionNode *heritage, ClassElementList *elements)
+ ClassDeclaration(QStringView n, ExpressionNode *heritage, ClassElementList *elements)
: ClassExpression(n, heritage, elements)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
};
@@ -2524,7 +2580,7 @@ public:
return n;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return property->firstSourceLocation(); }
@@ -2552,7 +2608,7 @@ public:
: statements(statements)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return statements ? statements->firstSourceLocation() : SourceLocation(); }
@@ -2569,19 +2625,19 @@ class QML_PARSER_EXPORT ImportSpecifier: public Node
public:
QQMLJS_DECLARE_AST_NODE(ImportSpecifier)
- ImportSpecifier(const QStringRef &importedBinding)
+ ImportSpecifier(QStringView importedBinding)
: importedBinding(importedBinding)
{
kind = K;
}
- ImportSpecifier(const QStringRef &identifier, const QStringRef &importedBinding)
+ ImportSpecifier(QStringView identifier, QStringView importedBinding)
: identifier(identifier), importedBinding(importedBinding)
{
kind = K;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return identifier.isNull() ? importedBindingToken : identifierToken; }
@@ -2591,8 +2647,8 @@ public:
// attributes
SourceLocation identifierToken;
SourceLocation importedBindingToken;
- QStringRef identifier;
- QStringRef importedBinding;
+ QStringView identifier;
+ QStringView importedBinding;
};
class QML_PARSER_EXPORT ImportsList: public Node
@@ -2626,7 +2682,7 @@ public:
return head;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return importSpecifierToken; }
@@ -2658,7 +2714,7 @@ public:
kind = K;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return leftBraceToken; }
@@ -2676,13 +2732,13 @@ class QML_PARSER_EXPORT NameSpaceImport: public Node
public:
QQMLJS_DECLARE_AST_NODE(NameSpaceImport)
- NameSpaceImport(const QStringRef &importedBinding)
+ NameSpaceImport(QStringView importedBinding)
: importedBinding(importedBinding)
{
kind = K;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
virtual SourceLocation firstSourceLocation() const override
{ return starToken; }
@@ -2692,7 +2748,7 @@ public:
// attributes
SourceLocation starToken;
SourceLocation importedBindingToken;
- QStringRef importedBinding;
+ QStringView importedBinding;
};
class QML_PARSER_EXPORT ImportClause: public Node
@@ -2700,7 +2756,7 @@ class QML_PARSER_EXPORT ImportClause: public Node
public:
QQMLJS_DECLARE_AST_NODE(ImportClause)
- ImportClause(const QStringRef &importedDefaultBinding)
+ ImportClause(QStringView importedDefaultBinding)
: importedDefaultBinding(importedDefaultBinding)
{
kind = K;
@@ -2718,21 +2774,21 @@ public:
kind = K;
}
- ImportClause(const QStringRef &importedDefaultBinding, NameSpaceImport *nameSpaceImport)
+ ImportClause(QStringView importedDefaultBinding, NameSpaceImport *nameSpaceImport)
: importedDefaultBinding(importedDefaultBinding)
, nameSpaceImport(nameSpaceImport)
{
kind = K;
}
- ImportClause(const QStringRef &importedDefaultBinding, NamedImports *namedImports)
+ ImportClause(QStringView importedDefaultBinding, NamedImports *namedImports)
: importedDefaultBinding(importedDefaultBinding)
, namedImports(namedImports)
{
kind = K;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
virtual SourceLocation firstSourceLocation() const override
{ return importedDefaultBinding.isNull() ? (nameSpaceImport ? nameSpaceImport->firstSourceLocation() : namedImports->firstSourceLocation()) : importedDefaultBindingToken; }
@@ -2741,7 +2797,7 @@ public:
// attributes
SourceLocation importedDefaultBindingToken;
- QStringRef importedDefaultBinding;
+ QStringView importedDefaultBinding;
NameSpaceImport *nameSpaceImport = nullptr;
NamedImports *namedImports = nullptr;
};
@@ -2751,13 +2807,13 @@ class QML_PARSER_EXPORT FromClause: public Node
public:
QQMLJS_DECLARE_AST_NODE(FromClause)
- FromClause(const QStringRef &moduleSpecifier)
+ FromClause(QStringView moduleSpecifier)
: moduleSpecifier(moduleSpecifier)
{
kind = K;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return fromToken; }
@@ -2768,7 +2824,7 @@ public:
// attributes
SourceLocation fromToken;
SourceLocation moduleSpecifierToken;
- QStringRef moduleSpecifier;
+ QStringView moduleSpecifier;
};
class QML_PARSER_EXPORT ImportDeclaration: public Statement
@@ -2782,13 +2838,13 @@ public:
kind = K;
}
- ImportDeclaration(const QStringRef &moduleSpecifier)
+ ImportDeclaration(QStringView moduleSpecifier)
: moduleSpecifier(moduleSpecifier)
{
kind = K;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return importToken; }
@@ -2799,7 +2855,7 @@ public:
// attributes
SourceLocation importToken;
SourceLocation moduleSpecifierToken;
- QStringRef moduleSpecifier;
+ QStringView moduleSpecifier;
ImportClause *importClause = nullptr;
FromClause *fromClause = nullptr;
};
@@ -2809,19 +2865,19 @@ class QML_PARSER_EXPORT ExportSpecifier: public Node
public:
QQMLJS_DECLARE_AST_NODE(ExportSpecifier)
- ExportSpecifier(const QStringRef &identifier)
+ ExportSpecifier(QStringView identifier)
: identifier(identifier), exportedIdentifier(identifier)
{
kind = K;
}
- ExportSpecifier(const QStringRef &identifier, const QStringRef &exportedIdentifier)
+ ExportSpecifier(QStringView identifier, QStringView exportedIdentifier)
: identifier(identifier), exportedIdentifier(exportedIdentifier)
{
kind = K;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return identifierToken; }
@@ -2831,8 +2887,8 @@ public:
// attributes
SourceLocation identifierToken;
SourceLocation exportedIdentifierToken;
- QStringRef identifier;
- QStringRef exportedIdentifier;
+ QStringView identifier;
+ QStringView exportedIdentifier;
};
class QML_PARSER_EXPORT ExportsList: public Node
@@ -2866,7 +2922,7 @@ public:
return head;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return exportSpecifier->firstSourceLocation(); }
@@ -2894,7 +2950,7 @@ public:
kind = K;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return leftBraceToken; }
@@ -2915,7 +2971,6 @@ public:
ExportDeclaration(FromClause *fromClause)
: fromClause(fromClause)
{
- exportAll = true;
kind = K;
}
@@ -2938,7 +2993,12 @@ public:
kind = K;
}
- void accept0(Visitor *visitor) override;
+ bool exportsAll() const
+ {
+ return fromClause && !exportClause;
+ }
+
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return exportToken; }
@@ -2947,7 +3007,6 @@ public:
// attributes
SourceLocation exportToken;
- bool exportAll = false;
ExportClause *exportClause = nullptr;
FromClause *fromClause = nullptr;
Node *variableStatementOrDeclaration = nullptr;
@@ -2965,7 +3024,7 @@ public:
kind = K;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return body ? body->firstSourceLocation() : SourceLocation(); }
@@ -2985,7 +3044,7 @@ public:
DebuggerStatement()
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return debuggerToken; }
@@ -3003,7 +3062,7 @@ class QML_PARSER_EXPORT UiImport: public Node
public:
QQMLJS_DECLARE_AST_NODE(UiImport)
- UiImport(const QStringRef &fileName)
+ UiImport(QStringView fileName)
: fileName(fileName), importUri(nullptr)
{ kind = K; }
@@ -3011,7 +3070,7 @@ public:
: importUri(uri)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return importToken; }
@@ -3020,9 +3079,9 @@ public:
{ return semicolonToken; }
// attributes
- QStringRef fileName;
+ QStringView fileName;
UiQualifiedId *importUri;
- QStringRef importId;
+ QStringView importId;
SourceLocation importToken;
SourceLocation fileNameToken;
SourceLocation asToken;
@@ -3038,6 +3097,9 @@ public:
SourceLocation lastSourceLocation() const override = 0;
UiObjectMember *uiObjectMemberCast() override;
+
+// attributes
+ UiAnnotationList *annotations = nullptr;
};
class QML_PARSER_EXPORT UiObjectMemberList: public Node
@@ -3057,7 +3119,7 @@ public:
previous->next = this;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return member->firstSourceLocation(); }
@@ -3077,16 +3139,56 @@ public:
UiObjectMember *member;
};
+class QML_PARSER_EXPORT UiPragmaValueList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiPragmaValueList)
+
+ UiPragmaValueList(QStringView value)
+ : value(value)
+ , next(this)
+ {
+ kind = K;
+ }
+
+ UiPragmaValueList(UiPragmaValueList *previous, QStringView value)
+ : value(value)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ void accept0(BaseVisitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return location; }
+
+ SourceLocation lastSourceLocation() const override
+ { return lastListElement(this)->location; }
+
+ UiPragmaValueList *finish()
+ {
+ UiPragmaValueList *head = next;
+ next = nullptr;
+ return head;
+ }
+
+ QStringView value;
+ UiPragmaValueList *next;
+ SourceLocation location;
+};
+
class QML_PARSER_EXPORT UiPragma: public Node
{
public:
QQMLJS_DECLARE_AST_NODE(UiPragma)
- UiPragma(QStringRef name)
- : name(name)
+ UiPragma(QStringView name, UiPragmaValueList *values = nullptr)
+ : name(name), values(values)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return pragmaToken; }
@@ -3095,8 +3197,33 @@ public:
{ return semicolonToken; }
// attributes
- QStringRef name;
+ QStringView name;
+ UiPragmaValueList *values;
SourceLocation pragmaToken;
+ SourceLocation pragmaIdToken;
+ SourceLocation colonToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT UiRequired: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiRequired)
+
+ UiRequired(QStringView name)
+ :name(name)
+ { kind = K; }
+
+ void accept0(BaseVisitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return requiredToken; }
+
+ SourceLocation lastSourceLocation() const override
+ { return semicolonToken; }
+
+ QStringView name;
+ SourceLocation requiredToken;
SourceLocation semicolonToken;
};
@@ -3136,7 +3263,7 @@ public:
return head;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return headerItem->firstSourceLocation(); }
@@ -3158,7 +3285,7 @@ public:
: headers(headers), members(members)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{
@@ -3200,7 +3327,7 @@ public:
previous->next = this;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return member->firstSourceLocation(); }
@@ -3230,7 +3357,7 @@ public:
: members(members)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return lbraceToken; }
@@ -3249,11 +3376,11 @@ class QML_PARSER_EXPORT UiParameterList: public Node
public:
QQMLJS_DECLARE_AST_NODE(UiParameterList)
- UiParameterList(UiQualifiedId *t, const QStringRef &n):
+ UiParameterList(Type *t, QStringView n):
type (t), name (n), next (this)
{ kind = K; }
- UiParameterList(UiParameterList *previous, UiQualifiedId *t, const QStringRef &n):
+ UiParameterList(UiParameterList *previous, Type *t, QStringView n):
type (t), name (n)
{
kind = K;
@@ -3261,7 +3388,7 @@ public:
previous->next = this;
}
- void accept0(Visitor *) override;
+ void accept0(BaseVisitor *) override;
SourceLocation firstSourceLocation() const override
{ return colonToken.isValid() ? identifierToken : propertyTypeToken; }
@@ -3269,7 +3396,12 @@ public:
SourceLocation lastSourceLocation() const override
{
auto last = lastListElement(this);
- return (last->colonToken.isValid() ? last->propertyTypeToken : last->identifierToken);
+ return last->lastOwnSourceLocation();
+ }
+
+ SourceLocation lastOwnSourceLocation() const
+ {
+ return (colonToken.isValid() ? propertyTypeToken : identifierToken);
}
inline UiParameterList *finish ()
@@ -3280,8 +3412,8 @@ public:
}
// attributes
- UiQualifiedId *type;
- QStringRef name;
+ Type *type;
+ QStringView name;
UiParameterList *next;
SourceLocation commaToken;
SourceLocation propertyTypeToken;
@@ -3289,34 +3421,70 @@ public:
SourceLocation colonToken;
};
+class QML_PARSER_EXPORT UiPropertyAttributes : public Node
+{
+ QQMLJS_DECLARE_AST_NODE(UiPropertyAttributes)
+public:
+ UiPropertyAttributes() { kind = K; }
+
+ SourceLocation defaultToken() const { return m_defaultToken; }
+ bool isDefaultMember() const { return defaultToken().isValid(); }
+ SourceLocation requiredToken() const { return m_requiredToken; }
+ bool isRequired() const { return requiredToken().isValid(); }
+ SourceLocation readonlyToken() const { return m_readonlyToken; }
+ bool isReadonly() const { return readonlyToken().isValid(); }
+
+ SourceLocation propertyToken() const { return m_propertyToken; }
+
+ template <bool InvalidIsLargest = true>
+ static bool compareLocationsByBegin(const SourceLocation *& lhs, const SourceLocation *& rhs)
+ {
+ if (lhs->isValid() && rhs->isValid())
+ return lhs->begin() < rhs->begin();
+ else if (lhs->isValid())
+ return InvalidIsLargest;
+ else
+ return !InvalidIsLargest;
+ }
+
+ void accept0(BaseVisitor *) override {} // intentionally do nothing
+
+ SourceLocation firstSourceLocation() const override;
+
+ SourceLocation lastSourceLocation() const override;
+
+private:
+ friend class QQmlJS::Parser;
+ SourceLocation m_defaultToken;
+ SourceLocation m_readonlyToken;
+ SourceLocation m_requiredToken;
+ SourceLocation m_propertyToken;
+};
+
class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember
{
public:
QQMLJS_DECLARE_AST_NODE(UiPublicMember)
UiPublicMember(UiQualifiedId *memberType,
- const QStringRef &name)
- : type(Property), memberType(memberType), name(name), statement(nullptr), binding(nullptr), isDefaultMember(false), isReadonlyMember(false), parameters(nullptr)
+ QStringView name)
+ : type(Property), memberType(memberType), name(name), statement(nullptr), binding(nullptr), parameters(nullptr)
{ kind = K; }
UiPublicMember(UiQualifiedId *memberType,
- const QStringRef &name,
+ QStringView name,
Statement *statement)
- : type(Property), memberType(memberType), name(name), statement(statement), binding(nullptr), isDefaultMember(false), isReadonlyMember(false), parameters(nullptr)
+ : type(Property), memberType(memberType), name(name), statement(statement), binding(nullptr), parameters(nullptr)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{
- if (defaultToken.isValid())
- return defaultToken;
- else if (readonlyToken.isValid())
- return readonlyToken;
- else if (requiredToken.isValid())
- return requiredToken;
-
- return propertyToken;
+ if (hasAttributes)
+ return m_attributes->firstSourceLocation();
+ else
+ return m_propertyToken;
}
SourceLocation lastSourceLocation() const override
@@ -3329,27 +3497,61 @@ public:
return semicolonToken;
}
+ SourceLocation defaultToken() const
+ {
+ return hasAttributes ? m_attributes->defaultToken() : SourceLocation {};
+ }
+ bool isDefaultMember() const { return defaultToken().isValid(); }
+
+ SourceLocation requiredToken() const
+ {
+ return hasAttributes ? m_attributes->requiredToken() : SourceLocation {};
+ }
+ bool isRequired() const { return requiredToken().isValid(); }
+
+ SourceLocation readonlyToken() const
+ {
+ return hasAttributes ? m_attributes->readonlyToken() : SourceLocation {};
+ }
+ bool isReadonly() const { return readonlyToken().isValid(); }
+
+ void setAttributes(UiPropertyAttributes *attributes)
+ {
+ m_attributes = attributes;
+ hasAttributes = true;
+ }
+
+ SourceLocation propertyToken() const
+ {
+ return hasAttributes ? m_attributes->propertyToken() : m_propertyToken;
+ }
+
+ void setPropertyToken(SourceLocation token)
+ {
+ m_propertyToken = token;
+ hasAttributes = false;
+ }
+
// attributes
- enum { Signal, Property } type;
- QStringRef typeModifier;
+ enum : bool { Signal, Property } type;
+ bool hasAttributes = false;
+ QStringView typeModifier;
UiQualifiedId *memberType;
- QStringRef name;
+ QStringView name;
Statement *statement; // initialized with a JS expression
UiObjectMember *binding; // initialized with a QML object or array.
- bool isDefaultMember;
- bool isReadonlyMember;
- bool isRequired = false;
UiParameterList *parameters;
// TODO: merge source locations
- SourceLocation defaultToken;
- SourceLocation readonlyToken;
- SourceLocation propertyToken;
- SourceLocation requiredToken;
SourceLocation typeModifierToken;
SourceLocation typeToken;
SourceLocation identifierToken;
SourceLocation colonToken;
SourceLocation semicolonToken;
+private:
+ union {
+ SourceLocation m_propertyToken = SourceLocation {};
+ UiPropertyAttributes *m_attributes;
+ };
};
class QML_PARSER_EXPORT UiObjectDefinition: public UiObjectMember
@@ -3362,7 +3564,7 @@ public:
: qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer)
{ kind = K; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
SourceLocation firstSourceLocation() const override
{ return qualifiedTypeNameId->identifierToken; }
@@ -3375,6 +3577,30 @@ public:
UiObjectInitializer *initializer;
};
+class QML_PARSER_EXPORT UiInlineComponent: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiInlineComponent)
+
+ UiInlineComponent(QStringView inlineComponentName, UiObjectDefinition* inlineComponent)
+ : name(inlineComponentName), component(inlineComponent)
+ { kind = K; }
+
+ SourceLocation lastSourceLocation() const override
+ {return component->lastSourceLocation();}
+
+ SourceLocation firstSourceLocation() const override
+ {return componentToken;}
+
+ void accept0(BaseVisitor *visitor) override;
+
+ // attributes
+ QStringView name;
+ UiObjectDefinition* component;
+ SourceLocation componentToken;
+ SourceLocation identifierToken;
+};
+
class QML_PARSER_EXPORT UiSourceElement: public UiObjectMember
{
public:
@@ -3404,7 +3630,7 @@ public:
return SourceLocation();
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
// attributes
@@ -3436,7 +3662,7 @@ public:
SourceLocation lastSourceLocation() const override
{ return initializer->rbraceToken; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
// attributes
@@ -3464,7 +3690,7 @@ public:
SourceLocation lastSourceLocation() const override
{ return statement->lastSourceLocation(); }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
// attributes
UiQualifiedId *qualifiedId;
@@ -3484,12 +3710,12 @@ public:
{ kind = K; }
SourceLocation firstSourceLocation() const override
- { return qualifiedId->identifierToken; }
+ { Q_ASSERT(qualifiedId); return qualifiedId->identifierToken; }
SourceLocation lastSourceLocation() const override
{ return rbracketToken; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
// attributes
UiQualifiedId *qualifiedId;
@@ -3503,11 +3729,11 @@ class QML_PARSER_EXPORT UiEnumMemberList: public Node
{
QQMLJS_DECLARE_AST_NODE(UiEnumMemberList)
public:
- UiEnumMemberList(const QStringRef &member, double v = 0.0)
+ UiEnumMemberList(QStringView member, double v = 0.0)
: next(this), member(member), value(v)
{ kind = K; }
- UiEnumMemberList(UiEnumMemberList *previous, const QStringRef &member)
+ UiEnumMemberList(UiEnumMemberList *previous, QStringView member)
: member(member)
{
kind = K;
@@ -3516,7 +3742,7 @@ public:
value = previous->value + 1;
}
- UiEnumMemberList(UiEnumMemberList *previous, const QStringRef &member, double v)
+ UiEnumMemberList(UiEnumMemberList *previous, QStringView member, double v)
: member(member), value(v)
{
kind = K;
@@ -3533,7 +3759,7 @@ public:
return last->valueToken.isValid() ? last->valueToken : last->memberToken;
}
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
UiEnumMemberList *finish()
{
@@ -3544,7 +3770,7 @@ public:
// attributes
UiEnumMemberList *next;
- QStringRef member;
+ QStringView member;
double value;
SourceLocation memberToken;
SourceLocation valueToken;
@@ -3555,7 +3781,7 @@ class QML_PARSER_EXPORT UiEnumDeclaration: public UiObjectMember
public:
QQMLJS_DECLARE_AST_NODE(UiEnumDeclaration)
- UiEnumDeclaration(const QStringRef &name,
+ UiEnumDeclaration(QStringView name,
UiEnumMemberList *members)
: name(name)
, members(members)
@@ -3567,17 +3793,78 @@ public:
SourceLocation lastSourceLocation() const override
{ return rbraceToken; }
- void accept0(Visitor *visitor) override;
+ void accept0(BaseVisitor *visitor) override;
// attributes
SourceLocation enumToken;
+ SourceLocation identifierToken;
+ SourceLocation lbraceToken;
SourceLocation rbraceToken;
- QStringRef name;
+ QStringView name;
UiEnumMemberList *members;
};
-} } // namespace AST
+class QML_PARSER_EXPORT UiAnnotation: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiAnnotation)
+
+ UiAnnotation(UiQualifiedId *qualifiedTypeNameId,
+ UiObjectInitializer *initializer)
+ : qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer)
+ { kind = K; }
+
+ void accept0(BaseVisitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return qualifiedTypeNameId->identifierToken; }
+
+ SourceLocation lastSourceLocation() const override
+ { return initializer->rbraceToken; }
+// attributes
+ UiQualifiedId *qualifiedTypeNameId;
+ UiObjectInitializer *initializer;
+};
+
+class QML_PARSER_EXPORT UiAnnotationList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiAnnotationList)
+
+ UiAnnotationList(UiAnnotation *annotation)
+ : next(this), annotation(annotation)
+ { kind = K; }
+
+ UiAnnotationList(UiAnnotationList *previous, UiAnnotation *annotation)
+ : annotation(annotation)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ void accept0(BaseVisitor *visitor) override;
+
+ SourceLocation firstSourceLocation() const override
+ { return annotation->firstSourceLocation(); }
+
+ SourceLocation lastSourceLocation() const override
+ { return lastListElement(this)->annotation->lastSourceLocation(); }
+
+ UiAnnotationList *finish()
+ {
+ UiAnnotationList *head = next;
+ next = nullptr;
+ return head;
+ }
+
+// attributes
+ UiAnnotationList *next;
+ UiAnnotation *annotation;
+};
+
+} } // namespace AST
QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h
index 05226fd043..c87f67c67e 100644
--- a/src/qml/parser/qqmljsastfwd_p.h
+++ b/src/qml/parser/qqmljsastfwd_p.h
@@ -1,47 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSAST_FWD_P_H
#define QQMLJSAST_FWD_P_H
-#include "qqmljsglobal_p.h"
-#include "qqmljssourcelocation_p.h"
+#include <private/qqmljssourcelocation_p.h>
#include <QtCore/qglobal.h>
@@ -60,10 +23,12 @@ QT_BEGIN_NAMESPACE
namespace QQmlJS { namespace AST {
+class BaseVisitor;
class Visitor;
class Node;
class ExpressionNode;
class Statement;
+class TypeExpression;
class ThisExpression;
class IdentifierExpression;
class NullExpression;
@@ -151,24 +116,24 @@ class NamedImport;
class ImportClause;
class FromClause;
class ImportDeclaration;
-class ModuleItem;
class ESModule;
class DebuggerStatement;
class NestedExpression;
class ClassExpression;
class ClassDeclaration;
class ClassElementList;
-class TypeArgumentList;
class Type;
class TypeAnnotation;
// ui elements
class UiProgram;
+class UiPragmaValueList;
class UiPragma;
class UiImport;
class UiPublicMember;
class UiParameterList;
class UiObjectDefinition;
+class UiInlineComponent;
class UiObjectInitializer;
class UiObjectBinding;
class UiScriptBinding;
@@ -182,6 +147,9 @@ class UiHeaderItemList;
class UiEnumDeclaration;
class UiEnumMemberList;
class UiVersionSpecifier;
+class UiRequired;
+class UiAnnotation;
+class UiAnnotationList;
} // namespace AST
} // namespace QQmlJS
diff --git a/src/qml/parser/qqmljsastvisitor.cpp b/src/qml/parser/qqmljsastvisitor.cpp
index 5ecac36423..21a9e92e2c 100644
--- a/src/qml/parser/qqmljsastvisitor.cpp
+++ b/src/qml/parser/qqmljsastvisitor.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmljsastvisitor_p.h"
@@ -43,11 +7,13 @@ QT_BEGIN_NAMESPACE
namespace QQmlJS { namespace AST {
-Visitor::Visitor(quint16 parentRecursionDepth) : m_recursionDepth(parentRecursionDepth)
+Visitor::Visitor(quint16 parentRecursionDepth) : BaseVisitor(parentRecursionDepth)
{
}
-Visitor::~Visitor()
+BaseVisitor::BaseVisitor(quint16 parentRecursionDepth) : m_recursionDepth(parentRecursionDepth) {}
+
+BaseVisitor::~BaseVisitor()
{
}
diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h
index 7146cd00ac..540d21d725 100644
--- a/src/qml/parser/qqmljsastvisitor_p.h
+++ b/src/qml/parser/qqmljsastvisitor_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSASTVISITOR_P_H
#define QQMLJSASTVISITOR_P_H
@@ -56,9 +20,132 @@
QT_BEGIN_NAMESPACE
+// as done in https://en.wikipedia.org/wiki/X_Macro
+
+#define QQmlJSASTUiClassListToVisit \
+ X(UiProgram) \
+ X(UiHeaderItemList) \
+ X(UiPragmaValueList) \
+ X(UiPragma) \
+ X(UiImport) \
+ X(UiPublicMember) \
+ X(UiSourceElement) \
+ X(UiObjectDefinition) \
+ X(UiObjectInitializer) \
+ X(UiObjectBinding) \
+ X(UiScriptBinding) \
+ X(UiArrayBinding) \
+ X(UiParameterList) \
+ X(UiObjectMemberList) \
+ X(UiArrayMemberList) \
+ X(UiQualifiedId) \
+ X(UiEnumDeclaration) \
+ X(UiEnumMemberList) \
+ X(UiVersionSpecifier) \
+ X(UiInlineComponent) \
+ X(UiAnnotation) \
+ X(UiAnnotationList) \
+ X(UiRequired)
+
+#define QQmlJSASTQQmlJSClassListToVisit \
+ X(TypeExpression) \
+ X(ThisExpression) \
+ X(IdentifierExpression) \
+ X(NullExpression) \
+ X(TrueLiteral) \
+ X(FalseLiteral) \
+ X(SuperLiteral) \
+ X(StringLiteral) \
+ X(TemplateLiteral) \
+ X(NumericLiteral) \
+ X(RegExpLiteral) \
+ X(ArrayPattern) \
+ X(ObjectPattern) \
+ X(PatternElementList) \
+ X(PatternPropertyList) \
+ X(PatternElement) \
+ X(PatternProperty) \
+ X(Elision) \
+ X(NestedExpression) \
+ X(IdentifierPropertyName) \
+ X(StringLiteralPropertyName) \
+ X(NumericLiteralPropertyName) \
+ X(ComputedPropertyName) \
+ X(ArrayMemberExpression) \
+ X(FieldMemberExpression) \
+ X(TaggedTemplate) \
+ X(NewMemberExpression) \
+ X(NewExpression) \
+ X(CallExpression) \
+ X(ArgumentList) \
+ X(PostIncrementExpression) \
+ X(PostDecrementExpression) \
+ X(DeleteExpression) \
+ X(VoidExpression) \
+ X(TypeOfExpression) \
+ X(PreIncrementExpression) \
+ X(PreDecrementExpression) \
+ X(UnaryPlusExpression) \
+ X(UnaryMinusExpression) \
+ X(TildeExpression) \
+ X(NotExpression) \
+ X(BinaryExpression) \
+ X(ConditionalExpression) \
+ X(Expression) \
+ X(Block) \
+ X(StatementList) \
+ X(VariableStatement) \
+ X(VariableDeclarationList) \
+ X(EmptyStatement) \
+ X(ExpressionStatement) \
+ X(IfStatement) \
+ X(DoWhileStatement) \
+ X(WhileStatement) \
+ X(ForStatement) \
+ X(ForEachStatement) \
+ X(ContinueStatement) \
+ X(BreakStatement) \
+ X(ReturnStatement) \
+ X(YieldExpression) \
+ X(WithStatement) \
+ X(SwitchStatement) \
+ X(CaseBlock) \
+ X(CaseClauses) \
+ X(CaseClause) \
+ X(DefaultClause) \
+ X(LabelledStatement) \
+ X(ThrowStatement) \
+ X(TryStatement) \
+ X(Catch) \
+ X(Finally) \
+ X(FunctionDeclaration) \
+ X(FunctionExpression) \
+ X(FormalParameterList) \
+ X(ClassExpression) \
+ X(ClassDeclaration) \
+ X(ClassElementList) \
+ X(Program) \
+ X(NameSpaceImport) \
+ X(ImportSpecifier) \
+ X(ImportsList) \
+ X(NamedImports) \
+ X(FromClause) \
+ X(ImportClause) \
+ X(ImportDeclaration) \
+ X(ExportSpecifier) \
+ X(ExportsList) \
+ X(ExportClause) \
+ X(ExportDeclaration) \
+ X(ESModule) \
+ X(DebuggerStatement) \
+ X(Type) \
+ X(TypeAnnotation)
+
+#define QQmlJSASTClassListToVisit QQmlJSASTUiClassListToVisit QQmlJSASTQQmlJSClassListToVisit
+
namespace QQmlJS { namespace AST {
-class QML_PARSER_EXPORT Visitor
+class QML_PARSER_EXPORT BaseVisitor
{
public:
class RecursionDepthCheck
@@ -68,7 +155,7 @@ public:
RecursionDepthCheck(RecursionDepthCheck &&) = delete;
RecursionDepthCheck &operator=(RecursionDepthCheck &&) = delete;
- RecursionDepthCheck(Visitor *visitor) : m_visitor(visitor)
+ RecursionDepthCheck(BaseVisitor *visitor) : m_visitor(visitor)
{
++(m_visitor->m_recursionDepth);
}
@@ -84,333 +171,20 @@ public:
private:
static const quint16 s_recursionLimit = 4096;
- Visitor *m_visitor;
+ BaseVisitor *m_visitor;
};
- Visitor(quint16 parentRecursionDepth = 0);
- virtual ~Visitor();
-
- virtual bool preVisit(Node *) { return true; }
- virtual void postVisit(Node *) {}
-
- // Ui
- virtual bool visit(UiProgram *) { return true; }
- virtual bool visit(UiHeaderItemList *) { return true; }
- virtual bool visit(UiPragma *) { return true; }
- virtual bool visit(UiImport *) { return true; }
- virtual bool visit(UiPublicMember *) { return true; }
- virtual bool visit(UiSourceElement *) { return true; }
- virtual bool visit(UiObjectDefinition *) { return true; }
- virtual bool visit(UiObjectInitializer *) { return true; }
- virtual bool visit(UiObjectBinding *) { return true; }
- virtual bool visit(UiScriptBinding *) { return true; }
- virtual bool visit(UiArrayBinding *) { return true; }
- virtual bool visit(UiParameterList *) { return true; }
- virtual bool visit(UiObjectMemberList *) { return true; }
- virtual bool visit(UiArrayMemberList *) { return true; }
- virtual bool visit(UiQualifiedId *) { return true; }
- virtual bool visit(UiEnumDeclaration *) { return true; }
- virtual bool visit(UiEnumMemberList *) { return true; }
- virtual bool visit(UiVersionSpecifier *) { return true; }
-
- virtual void endVisit(UiProgram *) {}
- virtual void endVisit(UiImport *) {}
- virtual void endVisit(UiHeaderItemList *) {}
- virtual void endVisit(UiPragma *) {}
- virtual void endVisit(UiPublicMember *) {}
- virtual void endVisit(UiSourceElement *) {}
- virtual void endVisit(UiObjectDefinition *) {}
- virtual void endVisit(UiObjectInitializer *) {}
- virtual void endVisit(UiObjectBinding *) {}
- virtual void endVisit(UiScriptBinding *) {}
- virtual void endVisit(UiArrayBinding *) {}
- virtual void endVisit(UiParameterList *) {}
- virtual void endVisit(UiObjectMemberList *) {}
- virtual void endVisit(UiArrayMemberList *) {}
- virtual void endVisit(UiQualifiedId *) {}
- virtual void endVisit(UiEnumDeclaration *) {}
- virtual void endVisit(UiEnumMemberList *) { }
- virtual void endVisit(UiVersionSpecifier *) {}
-
- // QQmlJS
- virtual bool visit(ThisExpression *) { return true; }
- virtual void endVisit(ThisExpression *) {}
-
- virtual bool visit(IdentifierExpression *) { return true; }
- virtual void endVisit(IdentifierExpression *) {}
-
- virtual bool visit(NullExpression *) { return true; }
- virtual void endVisit(NullExpression *) {}
-
- virtual bool visit(TrueLiteral *) { return true; }
- virtual void endVisit(TrueLiteral *) {}
-
- virtual bool visit(FalseLiteral *) { return true; }
- virtual void endVisit(FalseLiteral *) {}
-
- virtual bool visit(SuperLiteral *) { return true; }
- virtual void endVisit(SuperLiteral *) {}
-
- virtual bool visit(StringLiteral *) { return true; }
- virtual void endVisit(StringLiteral *) {}
-
- virtual bool visit(TemplateLiteral *) { return true; }
- virtual void endVisit(TemplateLiteral *) {}
-
- virtual bool visit(NumericLiteral *) { return true; }
- virtual void endVisit(NumericLiteral *) {}
-
- virtual bool visit(RegExpLiteral *) { return true; }
- virtual void endVisit(RegExpLiteral *) {}
-
- virtual bool visit(ArrayPattern *) { return true; }
- virtual void endVisit(ArrayPattern *) {}
-
- virtual bool visit(ObjectPattern *) { return true; }
- virtual void endVisit(ObjectPattern *) {}
-
- virtual bool visit(PatternElementList *) { return true; }
- virtual void endVisit(PatternElementList *) {}
-
- virtual bool visit(PatternPropertyList *) { return true; }
- virtual void endVisit(PatternPropertyList *) {}
-
- virtual bool visit(PatternElement *) { return true; }
- virtual void endVisit(PatternElement *) {}
-
- virtual bool visit(PatternProperty *) { return true; }
- virtual void endVisit(PatternProperty *) {}
-
- virtual bool visit(Elision *) { return true; }
- virtual void endVisit(Elision *) {}
-
- virtual bool visit(NestedExpression *) { return true; }
- virtual void endVisit(NestedExpression *) {}
-
- virtual bool visit(IdentifierPropertyName *) { return true; }
- virtual void endVisit(IdentifierPropertyName *) {}
-
- virtual bool visit(StringLiteralPropertyName *) { return true; }
- virtual void endVisit(StringLiteralPropertyName *) {}
-
- virtual bool visit(NumericLiteralPropertyName *) { return true; }
- virtual void endVisit(NumericLiteralPropertyName *) {}
-
- virtual bool visit(ComputedPropertyName *) { return true; }
- virtual void endVisit(ComputedPropertyName *) {}
-
- virtual bool visit(ArrayMemberExpression *) { return true; }
- virtual void endVisit(ArrayMemberExpression *) {}
-
- virtual bool visit(FieldMemberExpression *) { return true; }
- virtual void endVisit(FieldMemberExpression *) {}
-
- virtual bool visit(TaggedTemplate *) { return true; }
- virtual void endVisit(TaggedTemplate *) {}
-
- virtual bool visit(NewMemberExpression *) { return true; }
- virtual void endVisit(NewMemberExpression *) {}
-
- virtual bool visit(NewExpression *) { return true; }
- virtual void endVisit(NewExpression *) {}
-
- virtual bool visit(CallExpression *) { return true; }
- virtual void endVisit(CallExpression *) {}
-
- virtual bool visit(ArgumentList *) { return true; }
- virtual void endVisit(ArgumentList *) {}
-
- virtual bool visit(PostIncrementExpression *) { return true; }
- virtual void endVisit(PostIncrementExpression *) {}
-
- virtual bool visit(PostDecrementExpression *) { return true; }
- virtual void endVisit(PostDecrementExpression *) {}
-
- virtual bool visit(DeleteExpression *) { return true; }
- virtual void endVisit(DeleteExpression *) {}
-
- virtual bool visit(VoidExpression *) { return true; }
- virtual void endVisit(VoidExpression *) {}
-
- virtual bool visit(TypeOfExpression *) { return true; }
- virtual void endVisit(TypeOfExpression *) {}
-
- virtual bool visit(PreIncrementExpression *) { return true; }
- virtual void endVisit(PreIncrementExpression *) {}
-
- virtual bool visit(PreDecrementExpression *) { return true; }
- virtual void endVisit(PreDecrementExpression *) {}
-
- virtual bool visit(UnaryPlusExpression *) { return true; }
- virtual void endVisit(UnaryPlusExpression *) {}
-
- virtual bool visit(UnaryMinusExpression *) { return true; }
- virtual void endVisit(UnaryMinusExpression *) {}
-
- virtual bool visit(TildeExpression *) { return true; }
- virtual void endVisit(TildeExpression *) {}
-
- virtual bool visit(NotExpression *) { return true; }
- virtual void endVisit(NotExpression *) {}
-
- virtual bool visit(BinaryExpression *) { return true; }
- virtual void endVisit(BinaryExpression *) {}
-
- virtual bool visit(ConditionalExpression *) { return true; }
- virtual void endVisit(ConditionalExpression *) {}
-
- virtual bool visit(Expression *) { return true; }
- virtual void endVisit(Expression *) {}
-
- virtual bool visit(Block *) { return true; }
- virtual void endVisit(Block *) {}
-
- virtual bool visit(StatementList *) { return true; }
- virtual void endVisit(StatementList *) {}
-
- virtual bool visit(VariableStatement *) { return true; }
- virtual void endVisit(VariableStatement *) {}
-
- virtual bool visit(VariableDeclarationList *) { return true; }
- virtual void endVisit(VariableDeclarationList *) {}
-
- virtual bool visit(EmptyStatement *) { return true; }
- virtual void endVisit(EmptyStatement *) {}
+ BaseVisitor(quint16 parentRecursionDepth = 0);
+ virtual ~BaseVisitor();
- virtual bool visit(ExpressionStatement *) { return true; }
- virtual void endVisit(ExpressionStatement *) {}
+ virtual bool preVisit(Node *) = 0;
+ virtual void postVisit(Node *) = 0;
- virtual bool visit(IfStatement *) { return true; }
- virtual void endVisit(IfStatement *) {}
-
- virtual bool visit(DoWhileStatement *) { return true; }
- virtual void endVisit(DoWhileStatement *) {}
-
- virtual bool visit(WhileStatement *) { return true; }
- virtual void endVisit(WhileStatement *) {}
-
- virtual bool visit(ForStatement *) { return true; }
- virtual void endVisit(ForStatement *) {}
-
- virtual bool visit(ForEachStatement *) { return true; }
- virtual void endVisit(ForEachStatement *) {}
-
- virtual bool visit(ContinueStatement *) { return true; }
- virtual void endVisit(ContinueStatement *) {}
-
- virtual bool visit(BreakStatement *) { return true; }
- virtual void endVisit(BreakStatement *) {}
-
- virtual bool visit(ReturnStatement *) { return true; }
- virtual void endVisit(ReturnStatement *) {}
-
- virtual bool visit(YieldExpression *) { return true; }
- virtual void endVisit(YieldExpression *) {}
-
- virtual bool visit(WithStatement *) { return true; }
- virtual void endVisit(WithStatement *) {}
-
- virtual bool visit(SwitchStatement *) { return true; }
- virtual void endVisit(SwitchStatement *) {}
-
- virtual bool visit(CaseBlock *) { return true; }
- virtual void endVisit(CaseBlock *) {}
-
- virtual bool visit(CaseClauses *) { return true; }
- virtual void endVisit(CaseClauses *) {}
-
- virtual bool visit(CaseClause *) { return true; }
- virtual void endVisit(CaseClause *) {}
-
- virtual bool visit(DefaultClause *) { return true; }
- virtual void endVisit(DefaultClause *) {}
-
- virtual bool visit(LabelledStatement *) { return true; }
- virtual void endVisit(LabelledStatement *) {}
-
- virtual bool visit(ThrowStatement *) { return true; }
- virtual void endVisit(ThrowStatement *) {}
-
- virtual bool visit(TryStatement *) { return true; }
- virtual void endVisit(TryStatement *) {}
-
- virtual bool visit(Catch *) { return true; }
- virtual void endVisit(Catch *) {}
-
- virtual bool visit(Finally *) { return true; }
- virtual void endVisit(Finally *) {}
-
- virtual bool visit(FunctionDeclaration *) { return true; }
- virtual void endVisit(FunctionDeclaration *) {}
-
- virtual bool visit(FunctionExpression *) { return true; }
- virtual void endVisit(FunctionExpression *) {}
-
- virtual bool visit(FormalParameterList *) { return true; }
- virtual void endVisit(FormalParameterList *) {}
-
- virtual bool visit(ClassExpression *) { return true; }
- virtual void endVisit(ClassExpression *) {}
-
- virtual bool visit(ClassDeclaration *) { return true; }
- virtual void endVisit(ClassDeclaration *) {}
-
- virtual bool visit(ClassElementList *) { return true; }
- virtual void endVisit(ClassElementList *) {}
-
- virtual bool visit(Program *) { return true; }
- virtual void endVisit(Program *) {}
-
- virtual bool visit(NameSpaceImport *) { return true; }
- virtual void endVisit(NameSpaceImport *) {}
-
- virtual bool visit(ImportSpecifier *) { return true; }
- virtual void endVisit(ImportSpecifier *) {}
-
- virtual bool visit(ImportsList *) { return true; }
- virtual void endVisit(ImportsList *) {}
-
- virtual bool visit(NamedImports *) { return true; }
- virtual void endVisit(NamedImports *) {}
-
- virtual bool visit(FromClause *) { return true; }
- virtual void endVisit(FromClause *) {}
-
- virtual bool visit(ImportClause *) { return true; }
- virtual void endVisit(ImportClause *) {}
-
- virtual bool visit(ImportDeclaration *) { return true; }
- virtual void endVisit(ImportDeclaration *) {}
-
- virtual bool visit(ExportSpecifier *) { return true; }
- virtual void endVisit(ExportSpecifier *) {}
-
- virtual bool visit(ExportsList *) { return true; }
- virtual void endVisit(ExportsList *) {}
-
- virtual bool visit(ExportClause *) { return true; }
- virtual void endVisit(ExportClause *) {}
-
- virtual bool visit(ExportDeclaration *) { return true; }
- virtual void endVisit(ExportDeclaration *) {}
-
- virtual bool visit(ModuleItem *) { return true; }
- virtual void endVisit(ModuleItem *) {}
-
- virtual bool visit(ESModule *) { return true; }
- virtual void endVisit(ESModule *) {}
-
- 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 *) {}
+#define X(name) \
+ virtual bool visit(name *) = 0; \
+ virtual void endVisit(name *) = 0;
+ QQmlJSASTClassListToVisit
+#undef X
virtual void throwRecursionDepthError() = 0;
@@ -421,6 +195,45 @@ protected:
friend class RecursionDepthCheck;
};
+class QML_PARSER_EXPORT Visitor: public BaseVisitor
+{
+public:
+ Visitor(quint16 parentRecursionDepth = 0);
+
+ bool preVisit(Node *) override { return true; }
+ void postVisit(Node *) override {}
+
+#define X(name) \
+ bool visit(name *) override { return true; } \
+ void endVisit(name *) override { }
+ QQmlJSASTClassListToVisit
+#undef X
+};
+
+class QML_PARSER_EXPORT JSVisitor : public BaseVisitor
+{
+public:
+ JSVisitor() = default;
+
+ bool preVisit(Node *) override { return true; }
+ void postVisit(Node *) override { }
+
+#define X(name) \
+ bool visit(name *) override { return true; } \
+ void endVisit(name *) override { }
+ QQmlJSASTQQmlJSClassListToVisit
+#undef X
+
+#define X(name) \
+ bool visit(name *) override \
+ { \
+ Q_ASSERT(false); \
+ return false; \
+ } \
+ void endVisit(name *) override { }
+ QQmlJSASTUiClassListToVisit
+#undef X
+}; // namespace AST
} } // namespace AST
QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsengine_p.cpp b/src/qml/parser/qqmljsengine_p.cpp
deleted file mode 100644
index bb27f3992e..0000000000
--- a/src/qml/parser/qqmljsengine_p.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmljsengine_p.h"
-#include "qqmljsglobal_p.h"
-
-#include <QtCore/private/qnumeric_p.h>
-#include <QtCore/qhash.h>
-#include <QtCore/qdebug.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QQmlJS {
-
-static inline int toDigit(char c)
-{
- if ((c >= '0') && (c <= '9'))
- return c - '0';
- else if ((c >= 'a') && (c <= 'z'))
- return 10 + c - 'a';
- else if ((c >= 'A') && (c <= 'Z'))
- return 10 + c - 'A';
- return -1;
-}
-
-double integerFromString(const char *buf, int size, int radix)
-{
- if (size == 0)
- return qt_qnan();
-
- double sign = 1.0;
- int i = 0;
- if (buf[0] == '+') {
- ++i;
- } else if (buf[0] == '-') {
- sign = -1.0;
- ++i;
- }
-
- if (((size-i) >= 2) && (buf[i] == '0')) {
- if (((buf[i+1] == 'x') || (buf[i+1] == 'X'))
- && (radix < 34)) {
- if ((radix != 0) && (radix != 16))
- return 0;
- radix = 16;
- i += 2;
- } else {
- if (radix == 0) {
- radix = 8;
- ++i;
- }
- }
- } else if (radix == 0) {
- radix = 10;
- }
-
- int j = i;
- for ( ; i < size; ++i) {
- int d = toDigit(buf[i]);
- if ((d == -1) || (d >= radix))
- break;
- }
- double result;
- if (j == i) {
- if (!qstrcmp(buf, "Infinity"))
- result = qInf();
- else
- result = qt_qnan();
- } else {
- result = 0;
- double multiplier = 1;
- for (--i ; i >= j; --i, multiplier *= radix)
- result += toDigit(buf[i]) * multiplier;
- }
- result *= sign;
- return result;
-}
-
-Engine::Engine()
- : _lexer(nullptr), _directives(nullptr)
-{ }
-
-Engine::~Engine()
-{ }
-
-void Engine::setCode(const QString &code)
-{ _code = code; }
-
-void Engine::addComment(int pos, int len, int line, int col)
-{ if (len > 0) _comments.append(QQmlJS::AST::SourceLocation(pos, len, line, col)); }
-
-QList<QQmlJS::AST::SourceLocation> Engine::comments() const
-{ return _comments; }
-
-Lexer *Engine::lexer() const
-{ return _lexer; }
-
-void Engine::setLexer(Lexer *lexer)
-{ _lexer = lexer; }
-
-Directives *Engine::directives() const
-{ return _directives; }
-
-void Engine::setDirectives(Directives *directives)
-{ _directives = directives; }
-
-MemoryPool *Engine::pool()
-{ return &_pool; }
-
-QStringRef Engine::newStringRef(const QString &text)
-{
- const int pos = _extraCode.length();
- _extraCode += text;
- return _extraCode.midRef(pos, text.length());
-}
-
-QStringRef Engine::newStringRef(const QChar *chars, int size)
-{ return newStringRef(QString(chars, size)); }
-
-} // end of namespace QQmlJS
-
-QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsengine_p.h b/src/qml/parser/qqmljsengine_p.h
index 8a3e2db6a1..37f78a30e1 100644
--- a/src/qml/parser/qqmljsengine_p.h
+++ b/src/qml/parser/qqmljsengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSENGINE_P_H
#define QQMLJSENGINE_P_H
@@ -52,7 +16,7 @@
//
#include "qqmljsglobal_p.h"
-#include "qqmljssourcelocation_p.h"
+#include <private/qqmljssourcelocation_p.h>
#include <private/qqmljsmemorypool_p.h>
@@ -92,40 +56,52 @@ public:
}
};
-class QML_PARSER_EXPORT Engine
+class Engine
{
- Lexer *_lexer;
- Directives *_directives;
+ Lexer *_lexer = nullptr;
+ Directives *_directives = nullptr;
MemoryPool _pool;
- QList<AST::SourceLocation> _comments;
- QString _extraCode;
+ QList<SourceLocation> _comments;
+ QStringList _extraCode;
QString _code;
public:
- Engine();
- ~Engine();
-
- void setCode(const QString &code);
+ void setCode(const QString &code) { _code = code; }
const QString &code() const { return _code; }
- void addComment(int pos, int len, int line, int col);
- QList<AST::SourceLocation> comments() const;
+ void addComment(int pos, int len, int line, int col)
+ {
+ Q_ASSERT(len >= 0);
+ _comments.append(QQmlJS::SourceLocation(pos, len, line, col));
+ }
- Lexer *lexer() const;
- void setLexer(Lexer *lexer);
+ QList<SourceLocation> comments() const { return _comments; }
- Directives *directives() const;
- void setDirectives(Directives *directives);
+ Lexer *lexer() const { return _lexer; }
+ void setLexer(Lexer *lexer) { _lexer = lexer; }
- MemoryPool *pool();
+ Directives *directives() const { return _directives; }
+ void setDirectives(Directives *directives) { _directives = directives; }
- inline QStringRef midRef(int position, int size) { return _code.midRef(position, size); }
+ MemoryPool *pool() { return &_pool; }
+ const MemoryPool *pool() const { return &_pool; }
- QStringRef newStringRef(const QString &s);
- QStringRef newStringRef(const QChar *chars, int size);
-};
+ QStringView midRef(int position, int size)
+ {
+ return QStringView{_code}.mid(position, size);
+ }
-double integerFromString(const char *buf, int size, int radix);
+ QStringView newStringRef(const QString &text)
+ {
+ _extraCode.append(text);
+ return QStringView{_extraCode.last()};
+ }
+
+ QStringView newStringRef(const QChar *chars, int size)
+ {
+ return newStringRef(QString(chars, size));
+ }
+};
} // end of namespace QQmlJS
diff --git a/src/qml/parser/qqmljsglobal_p.h b/src/qml/parser/qqmljsglobal_p.h
index bf8155c6ec..1ca98b2041 100644
--- a/src/qml/parser/qqmljsglobal_p.h
+++ b/src/qml/parser/qqmljsglobal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSGLOBAL_P_H
#define QQMLJSGLOBAL_P_H
@@ -50,31 +14,16 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
-#ifdef QT_CREATOR
-
-# ifdef QDECLARATIVEJS_BUILD_DIR
+#ifndef QT_STATIC
+# if defined(QT_BUILD_QML_LIB)
# define QML_PARSER_EXPORT Q_DECL_EXPORT
-# elif QML_BUILD_STATIC_LIB
-# define QML_PARSER_EXPORT
# else
# define QML_PARSER_EXPORT Q_DECL_IMPORT
-# endif // QQMLJS_BUILD_DIR
-
-#else // !QT_CREATOR
-# ifndef QT_STATIC
-# if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
- // QmlDevTools is a static library
-# define QML_PARSER_EXPORT
-# elif defined(QT_BUILD_QML_LIB)
-# define QML_PARSER_EXPORT Q_DECL_EXPORT
-# else
-# define QML_PARSER_EXPORT Q_DECL_IMPORT
-# endif
-# else
-# define QML_PARSER_EXPORT
# endif
-#endif // QT_CREATOR
+#else
+# define QML_PARSER_EXPORT
+#endif
#endif // QQMLJSGLOBAL_P_H
diff --git a/src/qml/parser/qqmljskeywords_p.h b/src/qml/parser/qqmljskeywords_p.h
index 3eb054341f..72be5822a7 100644
--- a/src/qml/parser/qqmljskeywords_p.h
+++ b/src/qml/parser/qqmljskeywords_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSKEYWORDS_P_H
#define QQMLJSKEYWORDS_P_H
@@ -836,6 +800,25 @@ static inline int classify9(const QChar *s, int parseModeFlags) {
}
}
}
+ else if (s[0].unicode() == 'c') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'm') {
+ if (s[3].unicode() == 'p') {
+ if (s[4].unicode() == 'o') {
+ if (s[5].unicode() == 'n') {
+ if (s[6].unicode() == 'e') {
+ if (s[7].unicode() == 'n') {
+ if (s[8].unicode() == 't') {
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_COMPONENT) : int(Lexer::T_IDENTIFIER);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
return Lexer::T_IDENTIFIER;
}
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index 443e1a7476..cdb3dde5c6 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmljslexer_p.h"
#include "qqmljsengine_p.h"
@@ -43,16 +7,17 @@
#include <private/qqmljsdiagnosticmessage_p.h>
#include <private/qqmljsmemorypool_p.h>
+#include <private/qlocale_tools_p.h>
+
#include <QtCore/qcoreapplication.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qdebug.h>
#include <QtCore/QScopedValueRollback>
-QT_BEGIN_NAMESPACE
-Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
-QT_END_NAMESPACE
+#include <optional>
+QT_BEGIN_NAMESPACE
using namespace QQmlJS;
static inline int regExpFlagFromChar(const QChar &ch)
@@ -82,31 +47,8 @@ static inline QChar convertHex(QChar c1, QChar c2)
return QChar((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
}
-Lexer::Lexer(Engine *engine)
- : _engine(engine)
- , _codePtr(nullptr)
- , _endPtr(nullptr)
- , _tokenStartPtr(nullptr)
- , _char(QLatin1Char('\n'))
- , _errorCode(NoError)
- , _currentLineNumber(0)
- , _currentColumnNumber(0)
- , _tokenValue(0)
- , _parenthesesState(IgnoreParentheses)
- , _parenthesesCount(0)
- , _stackToken(-1)
- , _patternFlags(0)
- , _tokenKind(0)
- , _tokenLength(0)
- , _tokenLine(0)
- , _tokenColumn(0)
- , _validTokenText(false)
- , _prohibitAutomaticSemicolon(false)
- , _restrictedKeyword(false)
- , _terminator(false)
- , _followsClosingBrace(false)
- , _delimited(true)
- , _qmlMode(true)
+Lexer::Lexer(Engine *engine, LexMode lexMode)
+ : _engine(engine), _lexMode(lexMode), _endPtr(nullptr), _qmlMode(true)
{
if (engine)
engine->setLexer(this);
@@ -122,70 +64,70 @@ QString Lexer::code() const
return _code;
}
-void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
+void Lexer::setCode(const QString &code, int lineno, bool qmlMode,
+ Lexer::CodeContinuation codeContinuation)
{
+ if (codeContinuation == Lexer::CodeContinuation::Continue)
+ _currentOffset += _code.size();
+ else
+ _currentOffset = 0;
if (_engine)
_engine->setCode(code);
_qmlMode = qmlMode;
_code = code;
+ _skipLinefeed = false;
+
_tokenText.clear();
_tokenText.reserve(1024);
_errorMessage.clear();
- _tokenSpell = QStringRef();
- _rawString = QStringRef();
+ _tokenSpell = QStringView();
+ _rawString = QStringView();
_codePtr = code.unicode();
- _endPtr = _codePtr + code.length();
+ _endPtr = _codePtr + code.size();
_tokenStartPtr = _codePtr;
- _char = QLatin1Char('\n');
- _errorCode = NoError;
-
- _currentLineNumber = lineno;
+ if (lineno >= 0)
+ _currentLineNumber = lineno;
_currentColumnNumber = 0;
- _tokenValue = 0;
-
- // parentheses state
- _parenthesesState = IgnoreParentheses;
- _parenthesesCount = 0;
-
- _stackToken = -1;
-
- _patternFlags = 0;
- _tokenLength = 0;
- _tokenLine = lineno;
+ _tokenLine = _currentLineNumber;
_tokenColumn = 0;
+ _tokenLength = 0;
- _validTokenText = false;
- _prohibitAutomaticSemicolon = false;
- _restrictedKeyword = false;
- _terminator = false;
- _followsClosingBrace = false;
- _delimited = true;
+ if (codeContinuation == Lexer::CodeContinuation::Reset)
+ _state = State {};
}
void Lexer::scanChar()
{
if (_skipLinefeed) {
- Q_ASSERT(*_codePtr == QLatin1Char('\n'));
+ Q_ASSERT(*_codePtr == u'\n');
++_codePtr;
_skipLinefeed = false;
}
- _char = *_codePtr++;
+ _state.currentChar = *_codePtr++;
++_currentColumnNumber;
if (isLineTerminator()) {
- if (_char == QLatin1Char('\r')) {
- if (_codePtr < _endPtr && *_codePtr == QLatin1Char('\n'))
+ if (_state.currentChar == u'\r') {
+ if (_codePtr < _endPtr && *_codePtr == u'\n')
_skipLinefeed = true;
- _char = QLatin1Char('\n');
+ _state.currentChar = u'\n';
}
++_currentLineNumber;
_currentColumnNumber = 0;
}
}
+QChar Lexer::peekChar()
+{
+ auto peekPtr = _codePtr;
+ if (peekPtr < _endPtr)
+ return *peekPtr;
+ return QChar();
+}
+
namespace {
inline bool isBinop(int tok)
{
@@ -233,19 +175,19 @@ inline bool isBinop(int tok)
int hexDigit(QChar c)
{
- if (c >= QLatin1Char('0') && c <= QLatin1Char('9'))
- return c.unicode() - '0';
- if (c >= QLatin1Char('a') && c <= QLatin1Char('f'))
- return c.unicode() - 'a' + 10;
- if (c >= QLatin1Char('A') && c <= QLatin1Char('F'))
- return c.unicode() - 'A' + 10;
+ if (c >= u'0' && c <= u'9')
+ return c.unicode() - u'0';
+ if (c >= u'a' && c <= u'f')
+ return c.unicode() - u'a' + 10;
+ if (c >= u'A' && c <= u'F')
+ return c.unicode() - u'A' + 10;
return -1;
}
int octalDigit(QChar c)
{
- if (c >= QLatin1Char('0') && c <= QLatin1Char('7'))
- return c.unicode() - '0';
+ if (c >= u'0' && c <= u'7')
+ return c.unicode() - u'0';
return -1;
}
@@ -253,107 +195,184 @@ int octalDigit(QChar c)
int Lexer::lex()
{
- const int previousTokenKind = _tokenKind;
+ const int previousTokenKind = _state.tokenKind;
+ int tokenKind;
+ bool firstPass = true;
again:
- _tokenSpell = QStringRef();
- _rawString = QStringRef();
- _tokenKind = scanToken();
- _tokenLength = _codePtr - _tokenStartPtr - 1;
-
- _delimited = false;
- _restrictedKeyword = false;
- _followsClosingBrace = (previousTokenKind == T_RBRACE);
-
- // update the flags
- switch (_tokenKind) {
- case T_LBRACE:
- if (_bracesCount > 0)
- ++_bracesCount;
- Q_FALLTHROUGH();
- case T_SEMICOLON:
- _importState = ImportState::NoQmlImport;
- Q_FALLTHROUGH();
- case T_QUESTION:
- case T_COLON:
- case T_TILDE:
- _delimited = true;
- break;
- case T_AUTOMATIC_SEMICOLON:
- case T_AS:
- _importState = ImportState::NoQmlImport;
- Q_FALLTHROUGH();
- default:
- if (isBinop(_tokenKind))
- _delimited = true;
- break;
-
- case T_IMPORT:
- if (qmlMode() || (_handlingDirectives && previousTokenKind == T_DOT))
- _importState = ImportState::SawImport;
- if (isBinop(_tokenKind))
- _delimited = true;
- break;
-
- case T_IF:
- case T_FOR:
- case T_WHILE:
- case T_WITH:
- _parenthesesState = CountParentheses;
- _parenthesesCount = 0;
- break;
-
- case T_ELSE:
- case T_DO:
- _parenthesesState = BalancedParentheses;
- break;
-
- case T_CONTINUE:
- case T_BREAK:
- case T_RETURN:
- case T_YIELD:
- case T_THROW:
- _restrictedKeyword = true;
- break;
- case T_RBRACE:
- if (_bracesCount > 0)
- --_bracesCount;
- if (_bracesCount == 0)
- goto again;
- } // switch
+ tokenKind = T_ERROR;
+ _tokenSpell = QStringView();
+ _rawString = QStringView();
+ if (firstPass && _state.stackToken == -1) {
+ firstPass = false;
+ if (_codePtr > _endPtr && _lexMode == LexMode::LineByLine && !_code.isEmpty())
+ return T_EOL;
+
+ if (_state.comments == CommentState::InMultilineComment) {
+ scanChar();
+ _tokenStartPtr = _codePtr - 1;
+ _tokenLine = _currentLineNumber;
+ _tokenColumn = _currentColumnNumber;
+ while (_codePtr <= _endPtr) {
+ if (_state.currentChar == u'*') {
+ scanChar();
+ if (_state.currentChar == u'/') {
+ scanChar();
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2,
+ _codePtr - _tokenStartPtr - 1 - 4,
+ tokenStartLine(), tokenStartColumn() + 2);
+ }
+ tokenKind = T_COMMENT;
+ break;
+ }
+ } else {
+ scanChar();
+ }
+ }
+ if (tokenKind == T_ERROR)
+ tokenKind = T_PARTIAL_COMMENT;
+ } else {
+ // handle multiline continuation
+ std::optional<ScanStringMode> scanMode;
+ switch (previousTokenKind) {
+ case T_PARTIAL_SINGLE_QUOTE_STRING_LITERAL:
+ scanMode = ScanStringMode::SingleQuote;
+ break;
+ case T_PARTIAL_DOUBLE_QUOTE_STRING_LITERAL:
+ scanMode = ScanStringMode::DoubleQuote;
+ break;
+ case T_PARTIAL_TEMPLATE_HEAD:
+ scanMode = ScanStringMode::TemplateHead;
+ break;
+ case T_PARTIAL_TEMPLATE_MIDDLE:
+ scanMode = ScanStringMode::TemplateContinuation;
+ break;
+ default:
+ break;
+ }
+ if (scanMode) {
+ scanChar();
+ _tokenStartPtr = _codePtr - 1;
+ _tokenLine = _currentLineNumber;
+ _tokenColumn = _currentColumnNumber;
+ tokenKind = scanString(*scanMode);
+ }
+ }
+ }
+ if (tokenKind == T_ERROR)
+ tokenKind = scanToken();
+ _tokenLength = _codePtr - _tokenStartPtr - 1;
+ switch (tokenKind) {
+ // end of line and comments should not "overwrite" the old token type...
+ case T_EOL:
+ return tokenKind;
+ case T_COMMENT:
+ _state.comments = CommentState::HadComment;
+ return tokenKind;
+ case T_PARTIAL_COMMENT:
+ _state.comments = CommentState::InMultilineComment;
+ return tokenKind;
+ default:
+ _state.comments = CommentState::NoComment;
+ break;
+ }
+ _state.tokenKind = tokenKind;
+
+ _state.delimited = false;
+ _state.restrictedKeyword = false;
+ _state.followsClosingBrace = (previousTokenKind == T_RBRACE);
+
+ // update the flags
+ switch (_state.tokenKind) {
+ case T_LBRACE:
+ if (_state.bracesCount > 0)
+ ++_state.bracesCount;
+ Q_FALLTHROUGH();
+ case T_SEMICOLON:
+ _state.importState = ImportState::NoQmlImport;
+ Q_FALLTHROUGH();
+ case T_QUESTION:
+ case T_COLON:
+ case T_TILDE:
+ _state.delimited = true;
+ break;
+ case T_AUTOMATIC_SEMICOLON:
+ case T_AS:
+ _state.importState = ImportState::NoQmlImport;
+ Q_FALLTHROUGH();
+ default:
+ if (isBinop(_state.tokenKind))
+ _state.delimited = true;
+ break;
+
+ case T_IMPORT:
+ if (qmlMode() || (_state.handlingDirectives && previousTokenKind == T_DOT))
+ _state.importState = ImportState::SawImport;
+ if (isBinop(_state.tokenKind))
+ _state.delimited = true;
+ break;
+
+ case T_IF:
+ case T_FOR:
+ case T_WHILE:
+ case T_WITH:
+ _state.parenthesesState = CountParentheses;
+ _state.parenthesesCount = 0;
+ break;
+
+ case T_ELSE:
+ case T_DO:
+ _state.parenthesesState = BalancedParentheses;
+ break;
+
+ case T_CONTINUE:
+ case T_BREAK:
+ case T_RETURN:
+ case T_YIELD:
+ case T_THROW:
+ _state.restrictedKeyword = true;
+ break;
+ case T_RBRACE:
+ if (_state.bracesCount > 0)
+ --_state.bracesCount;
+ if (_state.bracesCount == 0)
+ goto again;
+ } // switch
// update the parentheses state
- switch (_parenthesesState) {
- case IgnoreParentheses:
- break;
-
- case CountParentheses:
- if (_tokenKind == T_RPAREN) {
- --_parenthesesCount;
- if (_parenthesesCount == 0)
- _parenthesesState = BalancedParentheses;
- } else if (_tokenKind == T_LPAREN) {
- ++_parenthesesCount;
- }
- break;
-
- case BalancedParentheses:
- if (_tokenKind != T_DO && _tokenKind != T_ELSE)
- _parenthesesState = IgnoreParentheses;
- break;
- } // switch
-
- return _tokenKind;
+ switch (_state.parenthesesState) {
+ case IgnoreParentheses:
+ break;
+
+ case CountParentheses:
+ if (_state.tokenKind == T_RPAREN) {
+ --_state.parenthesesCount;
+ if (_state.parenthesesCount == 0)
+ _state.parenthesesState = BalancedParentheses;
+ } else if (_state.tokenKind == T_LPAREN) {
+ ++_state.parenthesesCount;
+ }
+ break;
+
+ case BalancedParentheses:
+ if (_state.tokenKind != T_DO && _state.tokenKind != T_ELSE)
+ _state.parenthesesState = IgnoreParentheses;
+ break;
+ } // switch
+
+ return _state.tokenKind;
}
uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
{
- Q_ASSERT(_char == QLatin1Char('u'));
+ Q_ASSERT(_state.currentChar == u'u');
scanChar(); // skip u
- if (_codePtr + 4 <= _endPtr && isHexDigit(_char)) {
+ constexpr int distanceFromFirstHexToLastHex = 3;
+ if (_codePtr + distanceFromFirstHexToLastHex <= _endPtr && isHexDigit(_state.currentChar)) {
uint codePoint = 0;
for (int i = 0; i < 4; ++i) {
- int digit = hexDigit(_char);
+ int digit = hexDigit(_state.currentChar);
if (digit < 0)
goto error;
codePoint *= 16;
@@ -363,15 +382,15 @@ uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
*ok = true;
return codePoint;
- } else if (_codePtr < _endPtr && _char == QLatin1Char('{')) {
+ } else if (_codePtr < _endPtr && _state.currentChar == u'{') {
scanChar(); // skip '{'
uint codePoint = 0;
- if (!isHexDigit(_char))
+ if (!isHexDigit(_state.currentChar))
// need at least one hex digit
goto error;
while (_codePtr <= _endPtr) {
- int digit = hexDigit(_char);
+ int digit = hexDigit(_state.currentChar);
if (digit < 0)
break;
codePoint *= 16;
@@ -381,7 +400,7 @@ uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
scanChar();
}
- if (_char != QLatin1Char('}'))
+ if (_state.currentChar != u'}')
goto error;
scanChar(); // skip '}'
@@ -391,8 +410,8 @@ uint Lexer::decodeUnicodeEscapeCharacter(bool *ok)
return codePoint;
}
- error:
- _errorCode = IllegalUnicodeEscapeSequence;
+error:
+ _state.errorCode = IllegalUnicodeEscapeSequence;
_errorMessage = QCoreApplication::translate("QQmlParser", "Illegal unicode escape sequence");
*ok = false;
@@ -404,10 +423,10 @@ QChar Lexer::decodeHexEscapeCharacter(bool *ok)
if (isHexDigit(_codePtr[0]) && isHexDigit(_codePtr[1])) {
scanChar();
- const QChar c1 = _char;
+ const QChar c1 = _state.currentChar;
scanChar();
- const QChar c2 = _char;
+ const QChar c2 = _state.currentChar;
scanChar();
if (ok)
@@ -420,12 +439,46 @@ QChar Lexer::decodeHexEscapeCharacter(bool *ok)
return QChar();
}
+namespace QQmlJS {
+QDebug operator<<(QDebug dbg, const Lexer &l)
+{
+ dbg << "{\n"
+ << " engine:" << qsizetype(l._engine) << ",\n"
+ << " lexMode:" << int(l._lexMode) << ",\n"
+ << " code.size:" << qsizetype(l._code.unicode()) << "+" << l._code.size() << ",\n"
+ << " endPtr: codePtr + " << (l._endPtr - l._codePtr) << ",\n"
+ << " qmlMode:" << l._qmlMode << ",\n"
+ << " staticIsKeyword:" << l._staticIsKeyword << ",\n"
+ << " currentLineNumber:" << l._currentLineNumber << ",\n"
+ << " currentColumnNumber:" << l._currentColumnNumber << ",\n"
+ << " currentOffset:" << l._currentOffset << ",\n"
+ << " tokenLength:" << l._tokenLength << ",\n"
+ << " tokenLine:" << l._tokenLine << ",\n"
+ << " tokenColumn:" << l._tokenColumn << ",\n"
+ << " tokenText:" << l._tokenText << ",\n"
+ << " skipLinefeed:" << l._skipLinefeed << ",\n"
+ << " errorMessage:" << l._errorMessage << ",\n"
+ << " tokenSpell:" << l._tokenSpell << ",\n"
+ << " rawString:" << l._rawString << ",\n";
+ if (l._codePtr)
+ dbg << " codePtr: code.unicode()+" << (l._codePtr - l._code.unicode()) << ",\n";
+ else
+ dbg << " codePtr: *null*,\n";
+ if (l._tokenStartPtr)
+ dbg << " tokenStartPtr: codePtr " << (l._tokenStartPtr - l._codePtr) << ",\n";
+ else
+ dbg << " tokenStartPtr: *null*,\n";
+ dbg << " state:" << l._state << "\n}";
+ return dbg;
+}
+}
+
static inline bool isIdentifierStart(uint ch)
{
// fast path for ascii
- if ((ch >= 'a' && ch <= 'z') ||
- (ch >= 'A' && ch <= 'Z') ||
- ch == '$' || ch == '_')
+ if ((ch >= u'a' && ch <= u'z') ||
+ (ch >= u'A' && ch <= u'Z') ||
+ ch == u'$' || ch == u'_')
return true;
switch (QChar::category(ch)) {
@@ -445,10 +498,10 @@ static inline bool isIdentifierStart(uint ch)
static bool isIdentifierPart(uint ch)
{
// fast path for ascii
- if ((ch >= 'a' && ch <= 'z') ||
- (ch >= 'A' && ch <= 'Z') ||
- (ch >= '0' && ch <= '9') ||
- ch == '$' || ch == '_' ||
+ if ((ch >= u'a' && ch <= u'z') ||
+ (ch >= u'A' && ch <= u'Z') ||
+ (ch >= u'0' && ch <= u'9') ||
+ ch == u'$' || ch == u'_' ||
ch == 0x200c /* ZWNJ */ || ch == 0x200d /* ZWJ */)
return true;
@@ -475,71 +528,36 @@ static bool isIdentifierPart(uint ch)
int Lexer::scanToken()
{
- if (_stackToken != -1) {
- int tk = _stackToken;
- _stackToken = -1;
+ if (_state.stackToken != -1) {
+ int tk = _state.stackToken;
+ _state.stackToken = -1;
return tk;
}
- if (_bracesCount == 0) {
+ if (_state.bracesCount == 0) {
// we're inside a Template string
return scanString(TemplateContinuation);
}
-
- _terminator = false;
+ if (_state.comments == CommentState::NoComment)
+ _state.terminator = false;
again:
- _validTokenText = false;
-
- // handle comment can be called after a '/' has been read
- // and returns true if it actually encountered a comment
- auto handleComment = [this](){
- if (_char == QLatin1Char('*')) {
- scanChar();
- while (_codePtr <= _endPtr) {
- if (_char == QLatin1Char('*')) {
- scanChar();
- if (_char == QLatin1Char('/')) {
- scanChar();
-
- if (_engine) {
- _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 4,
- tokenStartLine(), tokenStartColumn() + 2);
- }
-
- return true;
- }
- } else {
- scanChar();
- }
- }
- } else if (_char == QLatin1Char('/')) {
- while (_codePtr <= _endPtr && !isLineTerminator()) {
- scanChar();
- }
- if (_engine) {
- _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2,
- tokenStartLine(), tokenStartColumn() + 2);
- }
- return true;
- }
- return false;
- };
+ _state.validTokenText = false;
-
- while (_char.isSpace()) {
+ while (_state.currentChar.isSpace()) {
if (isLineTerminator()) {
- if (_restrictedKeyword) {
+ bool isAtEnd = (_codePtr + (_skipLinefeed ? 1 : 0)) == _endPtr;
+ if (_state.restrictedKeyword) {
// automatic semicolon insertion
_tokenLine = _currentLineNumber;
_tokenColumn = _currentColumnNumber;
_tokenStartPtr = _codePtr - 1;
return T_SEMICOLON;
- } else {
- _terminator = true;
+ } else if (_lexMode == LexMode::WholeCode || !isAtEnd) {
+ _state.terminator = true;
syncProhibitAutomaticSemicolon();
- }
+ } // else we will do the previous things at the start of next line...
}
scanChar();
@@ -549,81 +567,102 @@ again:
_tokenLine = _currentLineNumber;
_tokenColumn = _currentColumnNumber;
- if (_codePtr > _endPtr)
- return EOF_SYMBOL;
+ if (_codePtr >= _endPtr) {
+ if (_lexMode == LexMode::LineByLine) {
+ if (!_code.isEmpty()) {
+ _state.currentChar = *(_codePtr - 2);
+ return T_EOL;
+ } else {
+ return EOF_SYMBOL;
+ }
+ } else if (_codePtr > _endPtr) {
+ return EOF_SYMBOL;
+ }
+ }
- const QChar ch = _char;
+ const QChar ch = _state.currentChar;
scanChar();
switch (ch.unicode()) {
- case '~': return T_TILDE;
- case '}': return T_RBRACE;
+ case u'~': return T_TILDE;
+ case u'}': return T_RBRACE;
- case '|':
- if (_char == QLatin1Char('|')) {
+ case u'|':
+ if (_state.currentChar == u'|') {
scanChar();
return T_OR_OR;
- } else if (_char == QLatin1Char('=')) {
+ } else if (_state.currentChar == u'=') {
scanChar();
return T_OR_EQ;
}
return T_OR;
- case '{': return T_LBRACE;
+ case u'{': return T_LBRACE;
- case '^':
- if (_char == QLatin1Char('=')) {
+ case u'^':
+ if (_state.currentChar == u'=') {
scanChar();
return T_XOR_EQ;
}
return T_XOR;
- case ']': return T_RBRACKET;
- case '[': return T_LBRACKET;
- case '?': return T_QUESTION;
+ case u']': return T_RBRACKET;
+ case u'[': return T_LBRACKET;
+ case u'?': {
+ if (_state.currentChar == u'?') {
+ scanChar();
+ return T_QUESTION_QUESTION;
+ }
+ if (_state.currentChar == u'.' && !peekChar().isDigit()) {
+ scanChar();
+ return T_QUESTION_DOT;
+ }
- case '>':
- if (_char == QLatin1Char('>')) {
+ return T_QUESTION;
+ }
+
+ case u'>':
+ if (_state.currentChar == u'>') {
scanChar();
- if (_char == QLatin1Char('>')) {
+ if (_state.currentChar == u'>') {
scanChar();
- if (_char == QLatin1Char('=')) {
+ if (_state.currentChar == u'=') {
scanChar();
return T_GT_GT_GT_EQ;
}
return T_GT_GT_GT;
- } else if (_char == QLatin1Char('=')) {
+ } else if (_state.currentChar == u'=') {
scanChar();
return T_GT_GT_EQ;
}
return T_GT_GT;
- } else if (_char == QLatin1Char('=')) {
+ } else if (_state.currentChar == u'=') {
scanChar();
return T_GE;
}
return T_GT;
- case '=':
- if (_char == QLatin1Char('=')) {
+ case u'=':
+ if (_state.currentChar == u'=') {
scanChar();
- if (_char == QLatin1Char('=')) {
+ if (_state.currentChar == u'=') {
scanChar();
return T_EQ_EQ_EQ;
}
return T_EQ_EQ;
- } else if (_char == QLatin1Char('>')) {
+ } else if (_state.currentChar == u'>') {
scanChar();
return T_ARROW;
}
return T_EQ;
- case '<':
- if (_char == QLatin1Char('=')) {
+ case u'<':
+ if (_state.currentChar == u'=') {
scanChar();
return T_LE;
- } else if (_char == QLatin1Char('<')) {
+ } else if (_state.currentChar == u'<') {
scanChar();
- if (_char == QLatin1Char('=')) {
+ if (_state.currentChar == u'=') {
scanChar();
return T_LT_LT_EQ;
}
@@ -631,45 +670,82 @@ again:
}
return T_LT;
- case ';': return T_SEMICOLON;
- case ':': return T_COLON;
+ case u';': return T_SEMICOLON;
+ case u':': return T_COLON;
- case '/':
- if (handleComment())
- goto again;
- else if (_char == QLatin1Char('=')) {
+ case u'/':
+ switch (_state.currentChar.unicode()) {
+ case u'*':
+ scanChar();
+ while (_codePtr <= _endPtr) {
+ if (_state.currentChar == u'*') {
+ scanChar();
+ if (_state.currentChar == u'/') {
+ scanChar();
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2,
+ _codePtr - _tokenStartPtr - 1 - 4, tokenStartLine(),
+ tokenStartColumn() + 2);
+ }
+ if (_lexMode == LexMode::LineByLine)
+ return T_COMMENT;
+ else
+ goto again;
+ }
+ } else {
+ scanChar();
+ }
+ }
+ if (_lexMode == LexMode::LineByLine)
+ return T_PARTIAL_COMMENT;
+ else
+ goto again;
+ case u'/':
+ while (_codePtr <= _endPtr && !isLineTerminator()) {
+ scanChar();
+ }
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2,
+ tokenStartLine(), tokenStartColumn() + 2);
+ }
+ if (_lexMode == LexMode::LineByLine)
+ return T_COMMENT;
+ else
+ goto again;
+ case u'=':
scanChar();
return T_DIVIDE_EQ;
+ default:
+ return T_DIVIDE_;
}
- return T_DIVIDE_;
-
- case '.':
- if (_importState == ImportState::SawImport)
+ case u'.':
+ if (_state.importState == ImportState::SawImport)
return T_DOT;
- if (isDecimalDigit(_char.unicode()))
+ if (isDecimalDigit(_state.currentChar.unicode()))
return scanNumber(ch);
- if (_char == QLatin1Char('.')) {
+ if (_state.currentChar == u'.') {
scanChar();
- if (_char == QLatin1Char('.')) {
+ if (_state.currentChar == u'.') {
scanChar();
return T_ELLIPSIS;
} else {
- _errorCode = IllegalCharacter;
+ _state.errorCode = IllegalCharacter;
_errorMessage = QCoreApplication::translate("QQmlParser", "Unexpected token '.'");
return T_ERROR;
}
}
return T_DOT;
- case '-':
- if (_char == QLatin1Char('=')) {
+ case u'-':
+ if (_state.currentChar == u'=') {
scanChar();
return T_MINUS_EQ;
- } else if (_char == QLatin1Char('-')) {
+ } else if (_state.currentChar == u'-') {
scanChar();
- if (_terminator && !_delimited && !_prohibitAutomaticSemicolon && _tokenKind != T_LPAREN) {
- _stackToken = T_MINUS_MINUS;
+ if (_state.terminator && !_state.delimited && !_state.prohibitAutomaticSemicolon
+ && _state.tokenKind != T_LPAREN) {
+ _state.stackToken = T_MINUS_MINUS;
return T_SEMICOLON;
}
@@ -677,17 +753,18 @@ again:
}
return T_MINUS;
- case ',': return T_COMMA;
+ case u',': return T_COMMA;
- case '+':
- if (_char == QLatin1Char('=')) {
+ case u'+':
+ if (_state.currentChar == u'=') {
scanChar();
return T_PLUS_EQ;
- } else if (_char == QLatin1Char('+')) {
+ } else if (_state.currentChar == u'+') {
scanChar();
- if (_terminator && !_delimited && !_prohibitAutomaticSemicolon && _tokenKind != T_LPAREN) {
- _stackToken = T_PLUS_PLUS;
+ if (_state.terminator && !_state.delimited && !_state.prohibitAutomaticSemicolon
+ && _state.tokenKind != T_LPAREN) {
+ _state.stackToken = T_PLUS_PLUS;
return T_SEMICOLON;
}
@@ -695,13 +772,13 @@ again:
}
return T_PLUS;
- case '*':
- if (_char == QLatin1Char('=')) {
+ case u'*':
+ if (_state.currentChar == u'=') {
scanChar();
return T_STAR_EQ;
- } else if (_char == QLatin1Char('*')) {
+ } else if (_state.currentChar == u'*') {
scanChar();
- if (_char == QLatin1Char('=')) {
+ if (_state.currentChar == u'=') {
scanChar();
return T_STAR_STAR_EQ;
}
@@ -709,30 +786,32 @@ again:
}
return T_STAR;
- case ')': return T_RPAREN;
- case '(': return T_LPAREN;
+ case u')': return T_RPAREN;
+ case u'(': return T_LPAREN;
- case '&':
- if (_char == QLatin1Char('=')) {
+ case u'@': return T_AT;
+
+ case u'&':
+ if (_state.currentChar == u'=') {
scanChar();
return T_AND_EQ;
- } else if (_char == QLatin1Char('&')) {
+ } else if (_state.currentChar == u'&') {
scanChar();
return T_AND_AND;
}
return T_AND;
- case '%':
- if (_char == QLatin1Char('=')) {
+ case u'%':
+ if (_state.currentChar == u'=') {
scanChar();
return T_REMAINDER_EQ;
}
return T_REMAINDER;
- case '!':
- if (_char == QLatin1Char('=')) {
+ case u'!':
+ if (_state.currentChar == u'=') {
scanChar();
- if (_char == QLatin1Char('=')) {
+ if (_state.currentChar == u'=') {
scanChar();
return T_NOT_EQ_EQ;
}
@@ -740,34 +819,51 @@ again:
}
return T_NOT;
- case '`':
- _outerTemplateBraceCount.push(_bracesCount);
+ case u'`':
+ _state.outerTemplateBraceCount.push(_state.bracesCount);
Q_FALLTHROUGH();
- case '\'':
- case '"':
+ case u'\'':
+ case u'"':
return scanString(ScanStringMode(ch.unicode()));
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- if (_importState == ImportState::SawImport)
+ case u'0':
+ case u'1':
+ case u'2':
+ case u'3':
+ case u'4':
+ case u'5':
+ case u'6':
+ case u'7':
+ case u'8':
+ case u'9':
+ if (_state.importState == ImportState::SawImport)
return scanVersionNumber(ch);
else
return scanNumber(ch);
+ case '#':
+ if (_currentLineNumber == 1 && _currentColumnNumber == 2) {
+ // shebang support
+ while (_codePtr <= _endPtr && !isLineTerminator()) {
+ scanChar();
+ }
+ if (_engine) {
+ _engine->addComment(tokenOffset(), _codePtr - _tokenStartPtr - 1, tokenStartLine(),
+ tokenStartColumn());
+ }
+ if (_lexMode == LexMode::LineByLine)
+ return T_COMMENT;
+ else
+ goto again;
+ }
+ Q_FALLTHROUGH();
+
default: {
uint c = ch.unicode();
bool identifierWithEscapeChars = false;
- if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_char.unicode())) {
- c = QChar::surrogateToUcs4(ushort(c), _char.unicode());
+ if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_state.currentChar.unicode())) {
+ c = QChar::surrogateToUcs4(ushort(c), _state.currentChar.unicode());
scanChar();
- } else if (c == '\\' && _char == QLatin1Char('u')) {
+ } else if (c == '\\' && _state.currentChar == u'u') {
identifierWithEscapeChars = true;
bool ok = false;
c = decodeUnicodeEscapeCharacter(&ok);
@@ -783,19 +879,19 @@ again:
} else {
_tokenText += QChar(c);
}
- _validTokenText = true;
+ _state.validTokenText = true;
}
while (_codePtr <= _endPtr) {
- c = _char.unicode();
+ c = _state.currentChar.unicode();
if (QChar::isHighSurrogate(c) && QChar::isLowSurrogate(_codePtr->unicode())) {
scanChar();
- c = QChar::surrogateToUcs4(ushort(c), _char.unicode());
- } else if (_char == QLatin1Char('\\') && _codePtr[0] == QLatin1Char('u')) {
+ c = QChar::surrogateToUcs4(ushort(c), _state.currentChar.unicode());
+ } else if (_state.currentChar == u'\\' && _codePtr[0] == u'u') {
if (!identifierWithEscapeChars) {
identifierWithEscapeChars = true;
_tokenText.resize(0);
_tokenText.insert(0, _tokenStartPtr, _codePtr - _tokenStartPtr - 1);
- _validTokenText = true;
+ _state.validTokenText = true;
}
scanChar(); // skip '\\'
@@ -807,13 +903,11 @@ again:
if (!isIdentifierPart(c))
break;
- if (identifierWithEscapeChars) {
- if (QChar::requiresSurrogates(c)) {
- _tokenText += QChar(QChar::highSurrogate(c));
- _tokenText += QChar(QChar::lowSurrogate(c));
- } else {
- _tokenText += QChar(c);
- }
+ if (QChar::requiresSurrogates(c)) {
+ _tokenText += QChar(QChar::highSurrogate(c));
+ _tokenText += QChar(QChar::lowSurrogate(c));
+ } else {
+ _tokenText += QChar(c);
}
continue;
}
@@ -841,17 +935,57 @@ again:
if (kind == T_FUNCTION) {
continue_skipping:
- while (_codePtr < _endPtr && _char.isSpace())
- scanChar();
- if (_char == QLatin1Char('*')) {
- _tokenLength = _codePtr - _tokenStartPtr - 1;
- kind = T_FUNCTION_STAR;
- scanChar();
- } else if (_char == QLatin1Char('/')) {
- scanChar();
- if (handleComment())
- goto continue_skipping;
- }
+ while (_codePtr < _endPtr && _state.currentChar.isSpace())
+ scanChar();
+ if (_state.currentChar == u'*') {
+ _tokenLength = _codePtr - _tokenStartPtr - 1;
+ kind = T_FUNCTION_STAR;
+ scanChar();
+ } else if (_state.currentChar == u'/') {
+ scanChar();
+ switch (_state.currentChar.unicode()) {
+ case u'*':
+ scanChar();
+ while (_codePtr <= _endPtr) {
+ if (_state.currentChar == u'*') {
+ scanChar();
+ if (_state.currentChar == u'/') {
+ scanChar();
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2,
+ _codePtr - _tokenStartPtr - 1 - 4,
+ tokenStartLine(),
+ tokenStartColumn() + 2);
+ }
+ if (_lexMode == LexMode::LineByLine)
+ return T_COMMENT;
+ goto continue_skipping;
+ }
+ } else {
+ scanChar();
+ }
+ }
+ if (_lexMode == LexMode::LineByLine)
+ return T_PARTIAL_COMMENT;
+ else
+ goto continue_skipping;
+ case u'/':
+ while (_codePtr <= _endPtr && !isLineTerminator()) {
+ scanChar();
+ }
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2,
+ _codePtr - _tokenStartPtr - 1 - 2,
+ tokenStartLine(), tokenStartColumn() + 2);
+ }
+ if (_lexMode == LexMode::LineByLine)
+ return T_COMMENT;
+ else
+ goto continue_skipping;
+ default:
+ break;
+ }
+ }
}
if (_engine) {
@@ -874,73 +1008,87 @@ again:
int Lexer::scanString(ScanStringMode mode)
{
QChar quote = (mode == TemplateContinuation) ? QChar(TemplateHead) : QChar(mode);
+ // we actually use T_STRING_LITERAL also for multiline strings, should we want to
+ // change that we should set it to:
+ // _state.tokenKind == T_PARTIAL_SINGLE_QUOTE_STRING_LITERAL ||
+ // _state.tokenKind == T_PARTIAL_DOUBLE_QUOTE_STRING_LITERAL
+ // here and uncomment the multilineStringLiteral = true below.
bool multilineStringLiteral = false;
const QChar *startCode = _codePtr - 1;
// in case we just parsed a \r, we need to reset this flag to get things working
// correctly in the loop below and afterwards
_skipLinefeed = false;
+ bool first = true;
if (_engine) {
while (_codePtr <= _endPtr) {
if (isLineTerminator()) {
- if ((quote == QLatin1Char('`') || qmlMode()))
+ if ((quote == u'`' || qmlMode())) {
+ if (first)
+ --_currentLineNumber; // will be read again in scanChar()
break;
- _errorCode = IllegalCharacter;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Stray newline in string literal");
+ }
+ _state.errorCode = IllegalCharacter;
+ _errorMessage = QCoreApplication::translate("QQmlParser",
+ "Stray newline in string literal");
return T_ERROR;
- } else if (_char == QLatin1Char('\\')) {
+ } else if (_state.currentChar == u'\\') {
break;
- } else if (_char == '$' && quote == QLatin1Char('`')) {
+ } else if (_state.currentChar == u'$' && quote == u'`') {
break;
- } else if (_char == quote) {
- _tokenSpell = _engine->midRef(startCode - _code.unicode(), _codePtr - startCode - 1);
+ } else if (_state.currentChar == quote) {
+ _tokenSpell =
+ _engine->midRef(startCode - _code.unicode(), _codePtr - startCode - 1);
_rawString = _tokenSpell;
scanChar();
- if (quote == QLatin1Char('`'))
- _bracesCount = _outerTemplateBraceCount.pop();
-
+ if (quote == u'`')
+ _state.bracesCount = _state.outerTemplateBraceCount.pop();
if (mode == TemplateHead)
return T_NO_SUBSTITUTION_TEMPLATE;
else if (mode == TemplateContinuation)
return T_TEMPLATE_TAIL;
+ else if (multilineStringLiteral)
+ return T_MULTILINE_STRING_LITERAL;
else
return T_STRING_LITERAL;
}
// don't use scanChar() here, that would transform \r sequences and the midRef() call would create the wrong result
- _char = *_codePtr++;
+ _state.currentChar = *_codePtr++;
++_currentColumnNumber;
+ first = false;
}
}
// rewind by one char, so things gets scanned correctly
--_codePtr;
+ --_currentColumnNumber;
- _validTokenText = true;
+ _state.validTokenText = true;
_tokenText = QString(startCode, _codePtr - startCode);
auto setRawString = [&](const QChar *end) {
QString raw(startCode, end - startCode - 1);
raw.replace(QLatin1String("\r\n"), QLatin1String("\n"));
- raw.replace(QLatin1Char('\r'), QLatin1Char('\n'));
+ raw.replace(u'\r', u'\n');
_rawString = _engine->newStringRef(raw);
};
scanChar();
while (_codePtr <= _endPtr) {
- if (_char == quote) {
+ if (_state.currentChar == quote) {
scanChar();
if (_engine) {
_tokenSpell = _engine->newStringRef(_tokenText);
- if (quote == QLatin1Char('`'))
+ if (quote == u'`')
setRawString(_codePtr - 1);
}
- if (quote == QLatin1Char('`'))
- _bracesCount = _outerTemplateBraceCount.pop();
+ if (quote == u'`')
+ _state.bracesCount = _state.outerTemplateBraceCount.pop();
if (mode == TemplateContinuation)
return T_TEMPLATE_TAIL;
@@ -948,29 +1096,30 @@ int Lexer::scanString(ScanStringMode mode)
return T_NO_SUBSTITUTION_TEMPLATE;
return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL;
- } else if (quote == QLatin1Char('`') && _char == QLatin1Char('$') && *_codePtr == '{') {
+ } else if (quote == u'`' && _state.currentChar == u'$' && *_codePtr == u'{') {
scanChar();
scanChar();
- _bracesCount = 1;
+ _state.bracesCount = 1;
if (_engine) {
_tokenSpell = _engine->newStringRef(_tokenText);
setRawString(_codePtr - 2);
}
return (mode == TemplateHead ? T_TEMPLATE_HEAD : T_TEMPLATE_MIDDLE);
- } else if (_char == QLatin1Char('\\')) {
+ } else if (_state.currentChar == u'\\') {
scanChar();
if (_codePtr > _endPtr) {
- _errorCode = IllegalEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "End of file reached at escape sequence");
+ _state.errorCode = IllegalEscapeSequence;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "End of file reached at escape sequence");
return T_ERROR;
}
QChar u;
- switch (_char.unicode()) {
+ switch (_state.currentChar.unicode()) {
// unicode escape sequence
- case 'u': {
+ case u'u': {
bool ok = false;
uint codePoint = decodeUnicodeEscapeCharacter(&ok);
if (!ok)
@@ -980,157 +1129,220 @@ int Lexer::scanString(ScanStringMode mode)
_tokenText += QChar(QChar::highSurrogate(codePoint));
u = QChar::lowSurrogate(codePoint);
} else {
- u = codePoint;
+ u = QChar(codePoint);
}
} break;
// hex escape sequence
- case 'x': {
+ case u'x': {
bool ok = false;
u = decodeHexEscapeCharacter(&ok);
if (!ok) {
- _errorCode = IllegalHexadecimalEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal hexadecimal escape sequence");
+ _state.errorCode = IllegalHexadecimalEscapeSequence;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Illegal hexadecimal escape sequence");
return T_ERROR;
}
} break;
// single character escape sequence
- case '\\': u = QLatin1Char('\\'); scanChar(); break;
- case '\'': u = QLatin1Char('\''); scanChar(); break;
- case '\"': u = QLatin1Char('\"'); scanChar(); break;
- case 'b': u = QLatin1Char('\b'); scanChar(); break;
- case 'f': u = QLatin1Char('\f'); scanChar(); break;
- case 'n': u = QLatin1Char('\n'); scanChar(); break;
- case 'r': u = QLatin1Char('\r'); scanChar(); break;
- case 't': u = QLatin1Char('\t'); scanChar(); break;
- case 'v': u = QLatin1Char('\v'); scanChar(); break;
-
- case '0':
- if (! _codePtr->isDigit()) {
+ case u'\\': u = u'\\'; scanChar(); break;
+ case u'\'': u = u'\''; scanChar(); break;
+ case u'\"': u = u'\"'; scanChar(); break;
+ case u'b': u = u'\b'; scanChar(); break;
+ case u'f': u = u'\f'; scanChar(); break;
+ case u'n': u = u'\n'; scanChar(); break;
+ case u'r': u = u'\r'; scanChar(); break;
+ case u't': u = u'\t'; scanChar(); break;
+ case u'v': u = u'\v'; scanChar(); break;
+
+ case u'0':
+ if (!_codePtr->isDigit()) {
scanChar();
- u = QLatin1Char('\0');
+ u = u'\0';
break;
}
Q_FALLTHROUGH();
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- _errorCode = IllegalEscapeSequence;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Octal escape sequences are not allowed");
+ case u'1':
+ case u'2':
+ case u'3':
+ case u'4':
+ case u'5':
+ case u'6':
+ case u'7':
+ case u'8':
+ case u'9':
+ _state.errorCode = IllegalEscapeSequence;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Octal escape sequences are not allowed");
return T_ERROR;
- case '\r':
- case '\n':
+ case u'\r':
+ case u'\n':
case 0x2028u:
case 0x2029u:
+ // uncomment the following to use T_MULTILINE_STRING_LITERAL
+ // multilineStringLiteral = true;
scanChar();
continue;
default:
// non escape character
- u = _char;
+ u = _state.currentChar;
scanChar();
}
_tokenText += u;
} else {
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
}
}
-
- _errorCode = UnclosedStringLiteral;
+ if (_lexMode == LexMode::LineByLine && !_code.isEmpty()) {
+ if (mode == TemplateContinuation)
+ return T_PARTIAL_TEMPLATE_MIDDLE;
+ else if (mode == TemplateHead)
+ return T_PARTIAL_TEMPLATE_HEAD;
+ else if (mode == SingleQuote)
+ return T_PARTIAL_SINGLE_QUOTE_STRING_LITERAL;
+ return T_PARTIAL_DOUBLE_QUOTE_STRING_LITERAL;
+ }
+ _state.errorCode = UnclosedStringLiteral;
_errorMessage = QCoreApplication::translate("QQmlParser", "Unclosed string at end of line");
return T_ERROR;
}
int Lexer::scanNumber(QChar ch)
{
- if (ch == QLatin1Char('0')) {
- if (_char == QLatin1Char('x') || _char == QLatin1Char('X')) {
- ch = _char; // remember the x or X to use it in the error message below.
+ auto scanOptionalNumericSeparator = [this](auto isNextCharacterValid){
+ if (_state.currentChar == u'_') {
+ if (peekChar() == u'_') {
+ _state.errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser",
+ "There can be at most one numeric separator beetwen digits"
+ );
+ return false;
+ }
+
+ if (!isNextCharacterValid()) {
+ _state.errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser",
+ "A trailing numeric separator is not allowed in numeric literals"
+ );
+ return false;
+ }
+
+ scanChar();
+ }
+
+ return true;
+ };
+
+ if (ch == u'0') {
+ if (_state.currentChar == u'x' || _state.currentChar == u'X') {
+ ch = _state.currentChar; // remember the x or X to use it in the error message below.
// parse hex integer literal
scanChar(); // consume 'x'
- if (!isHexDigit(_char)) {
- _errorCode = IllegalNumber;
- _errorMessage = QCoreApplication::translate("QQmlParser", "At least one hexadecimal digit is required after '0%1'").arg(ch);
+ if (!isHexDigit(_state.currentChar)) {
+ _state.errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser",
+ "At least one hexadecimal digit is required after '0%1'")
+ .arg(ch);
return T_ERROR;
}
double d = 0.;
while (1) {
- int digit = ::hexDigit(_char);
+ int digit = ::hexDigit(_state.currentChar);
if (digit < 0)
break;
d *= 16;
d += digit;
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){ return isHexDigit(peekChar()); }))
+ return T_ERROR;
}
- _tokenValue = d;
+ _state.tokenValue = d;
return T_NUMERIC_LITERAL;
- } else if (_char == QLatin1Char('o') || _char == QLatin1Char('O')) {
- ch = _char; // remember the o or O to use it in the error message below.
+ } else if (_state.currentChar == u'o' || _state.currentChar == u'O') {
+ ch = _state.currentChar; // remember the o or O to use it in the error message below.
// parse octal integer literal
scanChar(); // consume 'o'
- if (!isOctalDigit(_char.unicode())) {
- _errorCode = IllegalNumber;
- _errorMessage = QCoreApplication::translate("QQmlParser", "At least one octal digit is required after '0%1'").arg(ch);
+ if (!isOctalDigit(_state.currentChar.unicode())) {
+ _state.errorCode = IllegalNumber;
+ _errorMessage =
+ QCoreApplication::translate(
+ "QQmlParser", "At least one octal digit is required after '0%1'")
+ .arg(ch);
return T_ERROR;
}
double d = 0.;
while (1) {
- int digit = ::octalDigit(_char);
+ int digit = ::octalDigit(_state.currentChar);
if (digit < 0)
break;
d *= 8;
d += digit;
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){
+ return isOctalDigit(peekChar().unicode());
+ })) {
+ return T_ERROR;
+ }
}
- _tokenValue = d;
+ _state.tokenValue = d;
return T_NUMERIC_LITERAL;
- } else if (_char == QLatin1Char('b') || _char == QLatin1Char('B')) {
- ch = _char; // remember the b or B to use it in the error message below.
+ } else if (_state.currentChar == u'b' || _state.currentChar == u'B') {
+ ch = _state.currentChar; // remember the b or B to use it in the error message below.
// parse binary integer literal
scanChar(); // consume 'b'
- if (_char.unicode() != '0' && _char.unicode() != '1') {
- _errorCode = IllegalNumber;
- _errorMessage = QCoreApplication::translate("QQmlParser", "At least one binary digit is required after '0%1'").arg(ch);
+ if (_state.currentChar.unicode() != u'0' && _state.currentChar.unicode() != u'1') {
+ _state.errorCode = IllegalNumber;
+ _errorMessage =
+ QCoreApplication::translate(
+ "QQmlParser", "At least one binary digit is required after '0%1'")
+ .arg(ch);
return T_ERROR;
}
double d = 0.;
while (1) {
int digit = 0;
- if (_char.unicode() == '1')
+ if (_state.currentChar.unicode() == u'1')
digit = 1;
- else if (_char.unicode() != '0')
+ else if (_state.currentChar.unicode() != u'0')
break;
d *= 2;
d += digit;
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){
+ return peekChar().unicode() == u'0' || peekChar().unicode() == u'1';
+ })) {
+ return T_ERROR;
+ }
}
- _tokenValue = d;
+ _state.tokenValue = d;
return T_NUMERIC_LITERAL;
- } else if (_char.isDigit() && !qmlMode()) {
- _errorCode = IllegalCharacter;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Decimal numbers can't start with '0'");
+ } else if (_state.currentChar.isDigit() && !qmlMode()) {
+ _state.errorCode = IllegalCharacter;
+ _errorMessage = QCoreApplication::translate("QQmlParser",
+ "Decimal numbers can't start with '0'");
return T_ERROR;
}
}
@@ -1139,53 +1351,64 @@ int Lexer::scanNumber(QChar ch)
QVarLengthArray<char,32> chars;
chars.append(ch.unicode());
- if (ch != QLatin1Char('.')) {
- while (_char.isDigit()) {
- chars.append(_char.unicode());
+ if (ch != u'.') {
+ if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); }))
+ return T_ERROR;
+
+ while (_state.currentChar.isDigit()) {
+ chars.append(_state.currentChar.unicode());
scanChar(); // consume the digit
+
+ if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); }))
+ return T_ERROR;
}
- if (_char == QLatin1Char('.')) {
- chars.append(_char.unicode());
+ if (_state.currentChar == u'.') {
+ chars.append(_state.currentChar.unicode());
scanChar(); // consume `.'
}
}
- while (_char.isDigit()) {
- chars.append(_char.unicode());
+ while (_state.currentChar.isDigit()) {
+ chars.append(_state.currentChar.unicode());
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); }))
+ return T_ERROR;
}
- if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
- if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
- _codePtr[1].isDigit())) {
+ if (_state.currentChar == u'e' || _state.currentChar == u'E') {
+ if (_codePtr[0].isDigit()
+ || ((_codePtr[0] == u'+' || _codePtr[0] == u'-') && _codePtr[1].isDigit())) {
- chars.append(_char.unicode());
+ chars.append(_state.currentChar.unicode());
scanChar(); // consume `e'
- if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
- chars.append(_char.unicode());
+ if (_state.currentChar == u'+' || _state.currentChar == u'-') {
+ chars.append(_state.currentChar.unicode());
scanChar(); // consume the sign
}
- while (_char.isDigit()) {
- chars.append(_char.unicode());
+ while (_state.currentChar.isDigit()) {
+ chars.append(_state.currentChar.unicode());
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); }))
+ return T_ERROR;
}
}
}
- chars.append('\0');
-
const char *begin = chars.constData();
const char *end = nullptr;
bool ok = false;
- _tokenValue = qstrtod(begin, &end, &ok);
+ _state.tokenValue = qstrntod(begin, chars.size(), &end, &ok);
- if (end - begin != chars.size() - 1) {
- _errorCode = IllegalExponentIndicator;
- _errorMessage = QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number");
+ if (end - begin != chars.size()) {
+ _state.errorCode = IllegalExponentIndicator;
+ _errorMessage =
+ QCoreApplication::translate("QQmlParser", "Illegal syntax for exponential number");
return T_ERROR;
}
@@ -1194,109 +1417,114 @@ int Lexer::scanNumber(QChar ch)
int Lexer::scanVersionNumber(QChar ch)
{
- if (ch == QLatin1Char('0')) {
- _tokenValue = 0;
+ if (ch == u'0') {
+ _state.tokenValue = 0;
return T_VERSION_NUMBER;
}
int acc = 0;
acc += ch.digitValue();
- while (_char.isDigit()) {
+ while (_state.currentChar.isDigit()) {
acc *= 10;
- acc += _char.digitValue();
+ acc += _state.currentChar.digitValue();
scanChar(); // consume the digit
}
- _tokenValue = acc;
+ _state.tokenValue = acc;
return T_VERSION_NUMBER;
}
bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
{
_tokenText.resize(0);
- _validTokenText = true;
- _patternFlags = 0;
+ _state.validTokenText = true;
+ _state.patternFlags = 0;
if (prefix == EqualPrefix)
- _tokenText += QLatin1Char('=');
+ _tokenText += u'=';
while (true) {
- switch (_char.unicode()) {
- case '/':
+ switch (_state.currentChar.unicode()) {
+ case u'/':
scanChar();
// scan the flags
- _patternFlags = 0;
- while (isIdentLetter(_char)) {
- int flag = regExpFlagFromChar(_char);
- if (flag == 0 || _patternFlags & flag) {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Invalid regular expression flag '%0'")
- .arg(QChar(_char));
+ _state.patternFlags = 0;
+ while (isIdentLetter(_state.currentChar)) {
+ int flag = regExpFlagFromChar(_state.currentChar);
+ if (flag == 0 || _state.patternFlags & flag) {
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Invalid regular expression flag '%0'")
+ .arg(QChar(_state.currentChar));
return false;
}
- _patternFlags |= flag;
+ _state.patternFlags |= flag;
scanChar();
}
_tokenLength = _codePtr - _tokenStartPtr - 1;
return true;
- case '\\':
+ case u'\\':
// regular expression backslash sequence
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
if (_codePtr > _endPtr || isLineTerminator()) {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression backslash sequence");
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Unterminated regular expression backslash sequence");
return false;
}
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
break;
- case '[':
+ case u'[':
// regular expression class
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
- while (_codePtr <= _endPtr && ! isLineTerminator()) {
- if (_char == QLatin1Char(']'))
+ while (_codePtr <= _endPtr && !isLineTerminator()) {
+ if (_state.currentChar == u']')
break;
- else if (_char == QLatin1Char('\\')) {
+ else if (_state.currentChar == u'\\') {
// regular expression backslash sequence
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
if (_codePtr > _endPtr || isLineTerminator()) {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression backslash sequence");
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Unterminated regular expression backslash sequence");
return false;
}
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
} else {
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
}
}
- if (_char != QLatin1Char(']')) {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression class");
+ if (_state.currentChar != u']') {
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Unterminated regular expression class");
return false;
}
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar(); // skip ]
break;
default:
if (_codePtr > _endPtr || isLineTerminator()) {
- _errorMessage = QCoreApplication::translate("QQmlParser", "Unterminated regular expression literal");
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser", "Unterminated regular expression literal");
return false;
} else {
- _tokenText += _char;
+ _tokenText += _state.currentChar;
scanChar();
}
} // switch
@@ -1307,7 +1535,7 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
bool Lexer::isLineTerminator() const
{
- const ushort unicode = _char.unicode();
+ const ushort unicode = _state.currentChar.unicode();
return unicode == 0x000Au
|| unicode == 0x000Du
|| unicode == 0x2028u
@@ -1316,7 +1544,7 @@ bool Lexer::isLineTerminator() const
unsigned Lexer::isLineTerminatorSequence() const
{
- switch (_char.unicode()) {
+ switch (_state.currentChar.unicode()) {
case 0x000Au:
case 0x2028u:
case 0x2029u:
@@ -1335,10 +1563,9 @@ bool Lexer::isIdentLetter(QChar ch)
{
// ASCII-biased, since all reserved words are ASCII, aand hence the
// bulk of content to be parsed.
- if ((ch >= QLatin1Char('a') && ch <= QLatin1Char('z'))
- || (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z'))
- || ch == QLatin1Char('$')
- || ch == QLatin1Char('_'))
+ if ((ch >= u'a' && ch <= u'z')
+ || (ch >= u'A' && ch <= u'Z')
+ || ch == u'$' || ch == u'_')
return true;
if (ch.unicode() < 128)
return false;
@@ -1347,27 +1574,27 @@ bool Lexer::isIdentLetter(QChar ch)
bool Lexer::isDecimalDigit(ushort c)
{
- return (c >= '0' && c <= '9');
+ return (c >= u'0' && c <= u'9');
}
bool Lexer::isHexDigit(QChar c)
{
- return ((c >= QLatin1Char('0') && c <= QLatin1Char('9'))
- || (c >= QLatin1Char('a') && c <= QLatin1Char('f'))
- || (c >= QLatin1Char('A') && c <= QLatin1Char('F')));
+ return ((c >= u'0' && c <= u'9')
+ || (c >= u'a' && c <= u'f')
+ || (c >= u'A' && c <= u'F'));
}
bool Lexer::isOctalDigit(ushort c)
{
- return (c >= '0' && c <= '7');
+ return (c >= u'0' && c <= u'7');
}
QString Lexer::tokenText() const
{
- if (_validTokenText)
+ if (_state.validTokenText)
return _tokenText;
- if (_tokenKind == T_STRING_LITERAL)
+ if (_state.tokenKind == T_STRING_LITERAL)
return QString(_tokenStartPtr + 1, _tokenLength - 2);
return QString(_tokenStartPtr, _tokenLength);
@@ -1375,7 +1602,7 @@ QString Lexer::tokenText() const
Lexer::Error Lexer::errorCode() const
{
- return _errorCode;
+ return _state.errorCode;
}
QString Lexer::errorMessage() const
@@ -1385,33 +1612,31 @@ QString Lexer::errorMessage() const
void Lexer::syncProhibitAutomaticSemicolon()
{
- if (_parenthesesState == BalancedParentheses) {
+ if (_state.parenthesesState == BalancedParentheses) {
// we have seen something like "if (foo)", which means we should
// never insert an automatic semicolon at this point, since it would
// then be expanded into an empty statement (ECMA-262 7.9.1)
- _prohibitAutomaticSemicolon = true;
- _parenthesesState = IgnoreParentheses;
+ _state.prohibitAutomaticSemicolon = true;
+ _state.parenthesesState = IgnoreParentheses;
} else {
- _prohibitAutomaticSemicolon = false;
+ _state.prohibitAutomaticSemicolon = false;
}
}
bool Lexer::prevTerminator() const
{
- return _terminator;
+ return _state.terminator;
}
bool Lexer::followsClosingBrace() const
{
- return _followsClosingBrace;
+ return _state.followsClosingBrace;
}
bool Lexer::canInsertAutomaticSemicolon(int token) const
{
- return token == T_RBRACE
- || token == EOF_SYMBOL
- || _terminator
- || _followsClosingBrace;
+ return token == T_RBRACE || token == EOF_SYMBOL || _state.terminator
+ || _state.followsClosingBrace;
}
static const int uriTokens[] = {
@@ -1471,16 +1696,16 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
{
auto setError = [error, this](QString message) {
error->message = std::move(message);
- error->line = tokenStartLine();
- error->column = tokenStartColumn();
+ error->loc.startLine = tokenStartLine();
+ error->loc.startColumn = tokenStartColumn();
};
- QScopedValueRollback<bool> directivesGuard(_handlingDirectives, true);
+ QScopedValueRollback<bool> directivesGuard(_state.handlingDirectives, true);
Q_ASSERT(!_qmlMode);
lex(); // fetch the first token
- if (_tokenKind != T_DOT)
+ if (_state.tokenKind != T_DOT)
return true;
do {
@@ -1489,7 +1714,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
lex(); // skip T_DOT
- if (! (_tokenKind == T_IDENTIFIER || _tokenKind == T_IMPORT))
+ if (!(_state.tokenKind == T_IDENTIFIER || _state.tokenKind == T_IMPORT))
return true; // expected a valid QML/JS directive
const QString directiveName = tokenText();
@@ -1519,7 +1744,7 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
QString version;
bool fileImport = false; // file or uri import
- if (_tokenKind == T_STRING_LITERAL) {
+ if (_state.tokenKind == T_STRING_LITERAL) {
// .import T_STRING_LITERAL as T_IDENTIFIER
fileImport = true;
@@ -1529,11 +1754,12 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
setError(QCoreApplication::translate("QQmlParser","Imported file must be a script"));
return false;
}
+ lex();
- } else if (_tokenKind == T_IDENTIFIER) {
- // .import T_IDENTIFIER (. T_IDENTIFIER)* T_VERSION_NUMBER . T_VERSION_NUMBER as T_IDENTIFIER
+ } else if (_state.tokenKind == T_IDENTIFIER) {
+ // .import T_IDENTIFIER (. T_IDENTIFIER)* (T_VERSION_NUMBER (. T_VERSION_NUMBER)?)? as T_IDENTIFIER
while (true) {
- if (!isUriToken(_tokenKind)) {
+ if (!isUriToken(_state.tokenKind)) {
setError(QCoreApplication::translate("QQmlParser","Invalid module URI"));
return false;
}
@@ -1545,10 +1771,10 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
setError(QCoreApplication::translate("QQmlParser","Invalid module URI"));
return false;
}
- if (_tokenKind != QQmlJSGrammar::T_DOT)
+ if (_state.tokenKind != QQmlJSGrammar::T_DOT)
break;
- pathOrUri.append(QLatin1Char('.'));
+ pathOrUri.append(u'.');
lex();
if (tokenStartLine() != lineNumber) {
@@ -1557,38 +1783,34 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
}
}
- if (_tokenKind != T_VERSION_NUMBER) {
- setError(QCoreApplication::translate("QQmlParser","Module import requires a version"));
- return false; // expected the module version number
- }
-
- version = tokenText();
- lex();
- if (_tokenKind != T_DOT) {
- setError(QCoreApplication::translate( "QQmlParser", "Module import requires a minor version (missing dot)"));
- return false; // expected the module version number
- }
- version += QLatin1Char('.');
-
- lex();
- if (_tokenKind != T_VERSION_NUMBER) {
- setError(QCoreApplication::translate( "QQmlParser", "Module import requires a minor version (missing number)"));
- return false; // expected the module version number
+ if (_state.tokenKind == T_VERSION_NUMBER) {
+ version = tokenText();
+ lex();
+ if (_state.tokenKind == T_DOT) {
+ version += u'.';
+ lex();
+ if (_state.tokenKind != T_VERSION_NUMBER) {
+ setError(QCoreApplication::translate(
+ "QQmlParser", "Incomplete version number (dot but no minor)"));
+ return false; // expected the module version number
+ }
+ version += tokenText();
+ lex();
+ }
}
- version += tokenText();
}
//
// recognize the mandatory `as' followed by the module name
//
- if (! (lex() == T_AS && tokenStartLine() == lineNumber)) {
+ if (!(_state.tokenKind == T_AS && tokenStartLine() == lineNumber)) {
if (fileImport)
setError(QCoreApplication::translate("QQmlParser", "File import requires a qualifier"));
else
setError(QCoreApplication::translate("QQmlParser", "Module import requires a qualifier"));
if (tokenStartLine() != lineNumber) {
- error->line = lineNumber;
- error->line = column;
+ error->loc.startLine = lineNumber;
+ error->loc.startColumn = column;
}
return false; // expected `as'
}
@@ -1620,7 +1842,56 @@ bool Lexer::scanDirectives(Directives *directives, DiagnosticMessage *error)
// fetch the first token after the .pragma/.import directive
lex();
- } while (_tokenKind == T_DOT);
+ } while (_state.tokenKind == T_DOT);
return true;
}
+
+const Lexer::State &Lexer::state() const
+{
+ return _state;
+}
+void Lexer::setState(const Lexer::State &state)
+{
+ _state = state;
+}
+
+int Lexer::parseModeFlags() const {
+ int flags = 0;
+ if (qmlMode())
+ flags |= QmlMode|StaticIsKeyword;
+ if (yieldIsKeyWord())
+ flags |= YieldIsKeyword;
+ if (_staticIsKeyword)
+ flags |= StaticIsKeyword;
+ return flags;
+}
+
+namespace QQmlJS {
+QDebug operator<<(QDebug dbg, const Lexer::State &s)
+{
+ dbg << "{\n"
+ << " errorCode:" << int(s.errorCode) << ",\n"
+ << " currentChar:" << s.currentChar << ",\n"
+ << " tokenValue:" << s.tokenValue << ",\n"
+ << " parenthesesState:" << s.parenthesesState << ",\n"
+ << " parenthesesCount:" << s.parenthesesCount << ",\n"
+ << " outerTemplateBraceCount:" << s.outerTemplateBraceCount << ",\n"
+ << " bracesCount:" << s.bracesCount << ",\n"
+ << " stackToken:" << s.stackToken << ",\n"
+ << " patternFlags:" << s.patternFlags << ",\n"
+ << " tokenKind:" << s.tokenKind << ",\n"
+ << " importState:" << int(s.importState) << ",\n"
+ << " validTokenText:" << s.validTokenText << ",\n"
+ << " prohibitAutomaticSemicolon:" << s.prohibitAutomaticSemicolon << ",\n"
+ << " restrictedKeyword:" << s.restrictedKeyword << ",\n"
+ << " terminator:" << s.terminator << ",\n"
+ << " followsClosingBrace:" << s.followsClosingBrace << ",\n"
+ << " delimited:" << s.delimited << ",\n"
+ << " handlingDirectives:" << s.handlingDirectives << ",\n"
+ << " generatorLevel:" << s.generatorLevel << "\n}";
+ return dbg;
+}
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h
index e2ee4ae351..b6144e8894 100644
--- a/src/qml/parser/qqmljslexer_p.h
+++ b/src/qml/parser/qqmljslexer_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJSLEXER_P_H
#define QQMLJSLEXER_P_H
@@ -59,6 +23,8 @@
QT_BEGIN_NAMESPACE
+class QDebug;
+
namespace QQmlJS {
class Engine;
@@ -129,52 +95,44 @@ public:
NoQmlImport
};
+ enum class LexMode { WholeCode, LineByLine };
+
+ enum class CodeContinuation { Reset, Continue };
+
public:
- Lexer(Engine *engine);
-
- int parseModeFlags() const {
- int flags = 0;
- if (qmlMode())
- flags |= QmlMode|StaticIsKeyword;
- if (yieldIsKeyWord())
- flags |= YieldIsKeyword;
- if (_staticIsKeyword)
- flags |= StaticIsKeyword;
- return flags;
- }
+ Lexer(Engine *engine, LexMode lexMode = LexMode::WholeCode);
bool qmlMode() const;
- bool yieldIsKeyWord() const { return _generatorLevel != 0; }
+ bool yieldIsKeyWord() const { return _state.generatorLevel != 0; }
void setStaticIsKeyword(bool b) { _staticIsKeyword = b; }
QString code() const;
- void setCode(const QString &code, int lineno, bool qmlMode = true);
+ void setCode(const QString &code, int lineno, bool qmlMode = true,
+ CodeContinuation codeContinuation = CodeContinuation::Reset);
int lex();
bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix);
bool scanDirectives(Directives *directives, DiagnosticMessage *error);
- int regExpFlags() const { return _patternFlags; }
+ int regExpFlags() const { return _state.patternFlags; }
QString regExpPattern() const { return _tokenText; }
- int tokenKind() const { return _tokenKind; }
- int tokenOffset() const { return _tokenStartPtr - _code.unicode(); }
+ int tokenKind() const { return _state.tokenKind; }
+ int tokenOffset() const { return _currentOffset + _tokenStartPtr - _code.unicode(); }
int tokenLength() const { return _tokenLength; }
int tokenStartLine() const { return _tokenLine; }
int tokenStartColumn() const { return _tokenColumn; }
- inline QStringRef tokenSpell() const { return _tokenSpell; }
- inline QStringRef rawString() const { return _rawString; }
- double tokenValue() const { return _tokenValue; }
+ inline QStringView tokenSpell() const { return _tokenSpell; }
+ inline QStringView rawString() const { return _rawString; }
+ double tokenValue() const { return _state.tokenValue; }
QString tokenText() const;
Error errorCode() const;
QString errorMessage() const;
- bool prevTerminator() const;
- bool followsClosingBrace() const;
bool canInsertAutomaticSemicolon(int token) const;
enum ParenthesesState {
@@ -183,14 +141,102 @@ public:
BalancedParentheses
};
- void enterGeneratorBody() { ++_generatorLevel; }
- void leaveGeneratorBody() { --_generatorLevel; }
+ enum class CommentState { NoComment, HadComment, InMultilineComment };
+
+ void enterGeneratorBody() { ++_state.generatorLevel; }
+ void leaveGeneratorBody() { --_state.generatorLevel; }
+
+ struct State
+ {
+ Error errorCode = NoError;
+
+ QChar currentChar = u'\n';
+ double tokenValue = 0;
+
+ // parentheses state
+ ParenthesesState parenthesesState = IgnoreParentheses;
+ int parenthesesCount = 0;
+
+ // template string stack
+ QStack<int> outerTemplateBraceCount;
+ int bracesCount = -1;
+
+ int stackToken = -1;
+
+ int patternFlags = 0;
+ int tokenKind = 0;
+ ImportState importState = ImportState::NoQmlImport;
+
+ bool validTokenText = false;
+ bool prohibitAutomaticSemicolon = false;
+ bool restrictedKeyword = false;
+ bool terminator = false;
+ bool followsClosingBrace = false;
+ bool delimited = true;
+ bool handlingDirectives = false;
+ CommentState comments = CommentState::NoComment;
+ int generatorLevel = 0;
+
+ friend bool operator==(State const &s1, State const &s2)
+ {
+ if (s1.errorCode != s2.errorCode)
+ return false;
+ if (s1.currentChar != s2.currentChar)
+ return false;
+ if (s1.tokenValue != s2.tokenValue)
+ return false;
+ if (s1.parenthesesState != s2.parenthesesState)
+ return false;
+ if (s1.parenthesesCount != s2.parenthesesCount)
+ return false;
+ if (s1.outerTemplateBraceCount != s2.outerTemplateBraceCount)
+ return false;
+ if (s1.bracesCount != s2.bracesCount)
+ return false;
+ if (s1.stackToken != s2.stackToken)
+ return false;
+ if (s1.patternFlags != s2.patternFlags)
+ return false;
+ if (s1.tokenKind != s2.tokenKind)
+ return false;
+ if (s1.importState != s2.importState)
+ return false;
+ if (s1.validTokenText != s2.validTokenText)
+ return false;
+ if (s1.prohibitAutomaticSemicolon != s2.prohibitAutomaticSemicolon)
+ return false;
+ if (s1.restrictedKeyword != s2.restrictedKeyword)
+ return false;
+ if (s1.terminator != s2.terminator)
+ return false;
+ if (s1.followsClosingBrace != s2.followsClosingBrace)
+ return false;
+ if (s1.delimited != s2.delimited)
+ return false;
+ if (s1.handlingDirectives != s2.handlingDirectives)
+ return false;
+ if (s1.generatorLevel != s2.generatorLevel)
+ return false;
+ return true;
+ }
+
+ friend bool operator!=(State const &s1, State const &s2) { return !(s1 == s2); }
+
+ friend QML_PARSER_EXPORT QDebug operator<<(QDebug dbg, State const &s);
+ };
+
+ const State &state() const;
+ void setState(const State &state);
protected:
static int classify(const QChar *s, int n, int parseModeFlags);
private:
+ int parseModeFlags() const;
+ bool prevTerminator() const;
+ bool followsClosingBrace() const;
inline void scanChar();
+ inline QChar peekChar();
int scanToken();
int scanNumber(QChar ch);
int scanVersionNumber(QChar ch);
@@ -213,54 +259,36 @@ private:
uint decodeUnicodeEscapeCharacter(bool *ok);
QChar decodeHexEscapeCharacter(bool *ok);
+ friend QML_PARSER_EXPORT QDebug operator<<(QDebug dbg, const Lexer &l);
+
private:
Engine *_engine;
+ LexMode _lexMode = LexMode::WholeCode;
QString _code;
- QString _tokenText;
- QString _errorMessage;
- QStringRef _tokenSpell;
- QStringRef _rawString;
-
- const QChar *_codePtr;
const QChar *_endPtr;
- const QChar *_tokenStartPtr;
-
- QChar _char;
- Error _errorCode;
-
- int _currentLineNumber;
- int _currentColumnNumber;
- double _tokenValue;
-
- // parentheses state
- ParenthesesState _parenthesesState;
- int _parenthesesCount;
-
- // template string stack
- QStack<int> _outerTemplateBraceCount;
- int _bracesCount = -1;
-
- int _stackToken;
-
- int _patternFlags;
- int _tokenKind;
- int _tokenLength;
- int _tokenLine;
- int _tokenColumn;
- ImportState _importState = ImportState::NoQmlImport;
-
- bool _validTokenText;
- bool _prohibitAutomaticSemicolon;
- bool _restrictedKeyword;
- bool _terminator;
- bool _followsClosingBrace;
- bool _delimited;
bool _qmlMode;
- bool _skipLinefeed = false;
- int _generatorLevel = 0;
bool _staticIsKeyword = false;
- bool _handlingDirectives = false;
+
+ bool _skipLinefeed = false;
+
+ int _currentLineNumber = 0;
+ int _currentColumnNumber = 0;
+ int _currentOffset = 0;
+
+ int _tokenLength = 0;
+ int _tokenLine = 0;
+ int _tokenColumn = 0;
+
+ QString _tokenText;
+ QString _errorMessage;
+ QStringView _tokenSpell;
+ QStringView _rawString;
+
+ const QChar *_codePtr = nullptr;
+ const QChar *_tokenStartPtr = nullptr;
+
+ State _state;
};
} // end of namespace QQmlJS
diff --git a/src/qml/parser/qqmljssourcelocation_p.h b/src/qml/parser/qqmljssourcelocation_p.h
deleted file mode 100644
index d76e701d49..0000000000
--- a/src/qml/parser/qqmljssourcelocation_p.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLJSSOURCELOCATION_P_H
-#define QQMLJSSOURCELOCATION_P_H
-
-#include "qqmljsglobal_p.h"
-
-#include <QtCore/qglobal.h>
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-QT_BEGIN_NAMESPACE
-
-namespace QQmlJS { namespace AST {
-
-class SourceLocation
-{
-public:
- explicit SourceLocation(quint32 offset = 0, quint32 length = 0, quint32 line = 0, quint32 column = 0)
- : offset(offset), length(length),
- startLine(line), startColumn(column)
- { }
-
- bool isValid() const { return length != 0; }
-
- quint32 begin() const { return offset; }
- quint32 end() const { return offset + length; }
-
-// attributes
- // ### encode
- quint32 offset;
- quint32 length;
- quint32 startLine;
- quint32 startColumn;
-};
-
-} } // namespace AST
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
deleted file mode 100644
index 3c889244f4..0000000000
--- a/src/qml/qml.pro
+++ /dev/null
@@ -1,70 +0,0 @@
-TARGET = QtQml
-QT = core-private
-
-qtConfig(qml-network): \
- QT += network
-
-TRACEPOINT_PROVIDER = $$PWD/qtqml.tracepoints
-CONFIG += qt_tracepoints
-
-DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES
-
-msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x66000000
-msvc:DEFINES *= _CRT_SECURE_NO_WARNINGS
-win32:!winrt:LIBS += -lshell32
-solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2
-
-# Ensure this gcc optimization is switched off for mips platforms to avoid trouble with JIT.
-gcc:isEqual(QT_ARCH, "mips"): QMAKE_CXXFLAGS += -fno-reorder-blocks
-
-DEFINES += QT_NO_FOREACH
-
-exists("qqml_enable_gcov") {
- QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage -fno-elide-constructors
- LIBS_PRIVATE += -lgcov
-}
-
-# QTBUG-55238, disable new optimizer for MSVC 2015/Update 3.
-release:msvc:equals(QT_CL_MAJOR_VERSION, 19):equals(QT_CL_MINOR_VERSION, 00): \
- greaterThan(QT_CL_PATCH_VERSION, 24212):QMAKE_CXXFLAGS += -d2SSAOptimizer-
-
-QMAKE_DOCS = $$PWD/doc/qtqml.qdocconf
-
-# 2415: variable "xx" of static storage duration was declared but never referenced
-intel_icc: WERROR += -ww2415
-# unused variable 'xx' [-Werror,-Wunused-const-variable]
-greaterThan(QT_CLANG_MAJOR_VERSION, 3)|greaterThan(QT_CLANG_MINOR_VERSION, 3)| \
- greaterThan(QT_APPLE_CLANG_MAJOR_VERSION, 5)| \
- if(equals(QT_APPLE_CLANG_MAJOR_VERSION, 5):greaterThan(QT_APPLE_CLANG_MINOR_VERSION, 0)): \
- WERROR += -Wno-error=unused-const-variable
-
-HEADERS += qtqmlglobal.h \
- qtqmlglobal_p.h \
- qtqmlcompilerglobal.h \
- qtqmlcompilerglobal_p.h
-
-#modules
-include(common/common.pri)
-include(util/util.pri)
-include(memory/memory.pri)
-include(parser/parser.pri)
-include(compiler/compiler.pri)
-include(jsapi/jsapi.pri)
-include(jsruntime/jsruntime.pri)
-qtConfig(qml-jit) {
- include(jit/jit.pri)
-}
-include(qml/qml.pri)
-include(debugger/debugger.pri)
-include(qmldirparser/qmldirparser.pri)
-qtConfig(qml-animation) {
- include(animations/animations.pri)
-}
-include(types/types.pri)
-include(../3rdparty/masm/masm-defs.pri)
-include(../3rdparty/masm/masm.pri)
-include(../3rdparty/llvm/llvm.pri)
-
-MODULE_PLUGIN_TYPES = \
- qmltooling
-load(qt_module)
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri
deleted file mode 100644
index eadba394b4..0000000000
--- a/src/qml/qml/ftw/ftw.pri
+++ /dev/null
@@ -1,26 +0,0 @@
-HEADERS += \
- $$PWD/qbitfield_p.h \
- $$PWD/qintrusivelist_p.h \
- $$PWD/qpodvector_p.h \
- $$PWD/qhashedstring_p.h \
- $$PWD/qprimefornumbits_p.h \
- $$PWD/qqmlrefcount_p.h \
- $$PWD/qfieldlist_p.h \
- $$PWD/qqmlthread_p.h \
- $$PWD/qfinitestack_p.h \
- $$PWD/qrecursionwatcher_p.h \
- $$PWD/qrecyclepool_p.h \
- $$PWD/qflagpointer_p.h \
- $$PWD/qlazilyallocated_p.h \
- $$PWD/qqmlnullablevalue_p.h \
- $$PWD/qstringhash_p.h \
- $$PWD/qlinkedstringhash_p.h
-
-SOURCES += \
- $$PWD/qintrusivelist.cpp \
- $$PWD/qhashedstring.cpp \
- $$PWD/qqmlthread.cpp
-
-# mirrors logic in $$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri
-# clock_gettime() is implemented in librt on these systems
-qtConfig(clock-gettime):linux-*|hpux-*|solaris-*:LIBS_PRIVATE *= -lrt
diff --git a/src/qml/qml/ftw/qbipointer_p.h b/src/qml/qml/ftw/qbipointer_p.h
new file mode 100644
index 0000000000..1597b9e4fc
--- /dev/null
+++ b/src/qml/qml/ftw/qbipointer_p.h
@@ -0,0 +1,203 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QBIPOINTER_P_H
+#define QBIPOINTER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qglobal_p.h>
+
+#include <QtCore/qhashfunctions.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+template <typename T> struct QFlagPointerAlignment
+{
+ enum : size_t { Value = Q_ALIGNOF(T) };
+};
+template <> struct QFlagPointerAlignment<void>
+{
+ enum : size_t { Value = ~size_t(0) };
+};
+}
+
+/*!
+ \internal
+ \class template<typename T1, typename T2> QBiPointer<T1, T2>
+
+ \short QBiPointer can be thought of as a space-optimized std::variant<T1*, T2*>
+ with a nicer API to check the active pointer. Its other main feature is that
+ it only requires sizeof(void *) space.
+
+ \note It can also store one additional flag for a user defined purpose.
+ */
+template<typename T, typename T2>
+class QBiPointer {
+public:
+ Q_NODISCARD_CTOR constexpr QBiPointer() noexcept = default;
+ ~QBiPointer() noexcept = default;
+ Q_NODISCARD_CTOR QBiPointer(const QBiPointer &o) noexcept = default;
+ Q_NODISCARD_CTOR QBiPointer(QBiPointer &&o) noexcept = default;
+ QBiPointer<T, T2> &operator=(const QBiPointer<T, T2> &o) noexcept = default;
+ QBiPointer<T, T2> &operator=(QBiPointer<T, T2> &&o) noexcept = default;
+
+ void swap(QBiPointer &other) noexcept { std::swap(ptr_value, other.ptr_value); }
+
+ Q_NODISCARD_CTOR inline QBiPointer(T *);
+ Q_NODISCARD_CTOR inline QBiPointer(T2 *);
+
+ inline bool isNull() const;
+ inline bool isT1() const;
+ inline bool isT2() const;
+
+ inline bool flag() const;
+ inline void setFlag();
+ inline void clearFlag();
+ inline void setFlagValue(bool);
+
+ inline QBiPointer<T, T2> &operator=(T *);
+ inline QBiPointer<T, T2> &operator=(T2 *);
+
+ friend inline bool operator==(QBiPointer<T, T2> ptr1, QBiPointer<T, T2> ptr2)
+ {
+ if (ptr1.isNull() && ptr2.isNull())
+ return true;
+ if (ptr1.isT1() && ptr2.isT1())
+ return ptr1.asT1() == ptr2.asT1();
+ if (ptr1.isT2() && ptr2.isT2())
+ return ptr1.asT2() == ptr2.asT2();
+ return false;
+ }
+ friend inline bool operator!=(QBiPointer<T, T2> ptr1, QBiPointer<T, T2> ptr2)
+ {
+ return !(ptr1 == ptr2);
+ }
+
+ friend void swap(QBiPointer &lhs, QBiPointer &rhs) noexcept { lhs.swap(rhs); }
+
+ inline T *asT1() const;
+ inline T2 *asT2() const;
+
+ friend size_t qHash(const QBiPointer<T, T2> &ptr, size_t seed = 0)
+ {
+ return qHash(ptr.isNull() ? quintptr(0) : ptr.ptr_value, seed);
+ }
+
+private:
+ quintptr ptr_value = 0;
+
+ static const quintptr FlagBit = 0x1;
+ static const quintptr Flag2Bit = 0x2;
+ static const quintptr FlagsMask = FlagBit | Flag2Bit;
+};
+
+template <typename...Ts> // can't use commas in macros
+Q_DECLARE_TYPEINFO_BODY(QBiPointer<Ts...>, Q_PRIMITIVE_TYPE);
+
+template<typename T, typename T2>
+QBiPointer<T, T2>::QBiPointer(T *v)
+: ptr_value(quintptr(v))
+{
+ Q_STATIC_ASSERT_X(QtPrivate::QFlagPointerAlignment<T>::Value >= 4,
+ "Type T does not have sufficient alignment");
+ Q_ASSERT((quintptr(v) & FlagsMask) == 0);
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2>::QBiPointer(T2 *v)
+: ptr_value(quintptr(v) | Flag2Bit)
+{
+ Q_STATIC_ASSERT_X(QtPrivate::QFlagPointerAlignment<T2>::Value >= 4,
+ "Type T2 does not have sufficient alignment");
+ Q_ASSERT((quintptr(v) & FlagsMask) == 0);
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::isNull() const
+{
+ return 0 == (ptr_value & (~FlagsMask));
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::isT1() const
+{
+ return !(ptr_value & Flag2Bit);
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::isT2() const
+{
+ return ptr_value & Flag2Bit;
+}
+
+template<typename T, typename T2>
+bool QBiPointer<T, T2>::flag() const
+{
+ return ptr_value & FlagBit;
+}
+
+template<typename T, typename T2>
+void QBiPointer<T, T2>::setFlag()
+{
+ ptr_value |= FlagBit;
+}
+
+template<typename T, typename T2>
+void QBiPointer<T, T2>::clearFlag()
+{
+ ptr_value &= ~FlagBit;
+}
+
+template<typename T, typename T2>
+void QBiPointer<T, T2>::setFlagValue(bool v)
+{
+ if (v) setFlag();
+ else clearFlag();
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T *o)
+{
+ Q_ASSERT((quintptr(o) & FlagsMask) == 0);
+
+ ptr_value = quintptr(o) | (ptr_value & FlagBit);
+ return *this;
+}
+
+template<typename T, typename T2>
+QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T2 *o)
+{
+ Q_ASSERT((quintptr(o) & FlagsMask) == 0);
+
+ ptr_value = quintptr(o) | (ptr_value & FlagBit) | Flag2Bit;
+ return *this;
+}
+
+template<typename T, typename T2>
+T *QBiPointer<T, T2>::asT1() const
+{
+ Q_ASSERT(isT1());
+ return (T *)(ptr_value & ~FlagsMask);
+}
+
+template<typename T, typename T2>
+T2 *QBiPointer<T, T2>::asT2() const
+{
+ Q_ASSERT(isT2());
+ return (T2 *)(ptr_value & ~FlagsMask);
+}
+
+QT_END_NAMESPACE
+
+#endif // QBIPOINTER_P_H
diff --git a/src/qml/qml/ftw/qbitfield_p.h b/src/qml/qml/ftw/qbitfield_p.h
deleted file mode 100644
index 92017580d6..0000000000
--- a/src/qml/qml/ftw/qbitfield_p.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QBITFIELD_P_H
-#define QBITFIELD_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qglobal.h>
-#include <QtCore/qtypeinfo.h>
-
-QT_BEGIN_NAMESPACE
-
-class QBitField
-{
-public:
- inline QBitField();
- inline QBitField(const quint32 *, int bits);
- inline QBitField(const QBitField &);
- inline ~QBitField();
-
- inline QBitField &operator=(const QBitField &);
-
- inline quint32 size() const;
- inline QBitField united(const QBitField &);
- inline bool testBit(int) const;
-
-private:
- quint32 bits:31;
- quint32 *ownData;
- const quint32 *data;
-};
-
-QBitField::QBitField()
-: bits(0), ownData(nullptr), data(nullptr)
-{
-}
-
-QBitField::QBitField(const quint32 *bitData, int bitCount)
-: bits((quint32)bitCount), ownData(nullptr), data(bitData)
-{
-}
-
-QBitField::QBitField(const QBitField &other)
-: bits(other.bits), ownData(other.ownData), data(other.data)
-{
- if (ownData)
- ++(*ownData);
-}
-
-QBitField::~QBitField()
-{
- if (ownData)
- if(0 == --(*ownData)) delete [] ownData;
-}
-
-QBitField &QBitField::operator=(const QBitField &other)
-{
- if (other.data == data)
- return *this;
-
- if (ownData)
- if(0 == --(*ownData)) delete [] ownData;
-
- bits = other.bits;
- ownData = other.ownData;
- data = other.data;
-
- if (ownData)
- ++(*ownData);
-
- return *this;
-}
-
-inline quint32 QBitField::size() const
-{
- return bits;
-}
-
-QBitField QBitField::united(const QBitField &o)
-{
- if (o.bits == 0) {
- return *this;
- } else if (bits == 0) {
- return o;
- } else {
- int max = (bits > o.bits)?bits:o.bits;
- int length = (max + 31) / 32;
- QBitField rv;
- rv.bits = max;
- rv.ownData = new quint32[length + 1];
- *(rv.ownData) = 1;
- quint32 *rvdata;
- rv.data = rvdata = rv.ownData + 1;
- if (bits > o.bits) {
- ::memcpy(rvdata, data, length * sizeof(quint32));
- for (quint32 ii = 0; ii < (o.bits + quint32(31)) / 32; ++ii)
- (rvdata)[ii] |= o.data[ii];
- } else {
- ::memcpy(rvdata, o.data, length * sizeof(quint32));
- for (quint32 ii = 0; ii < (bits + quint32(31)) / 32; ++ii)
- (rvdata)[ii] |= data[ii];
- }
- return rv;
- }
-}
-
-bool QBitField::testBit(int b) const
-{
- Q_ASSERT(b >= 0);
- if ((quint32)b < bits) {
- return data[b / 32] & (1 << (b % 32));
- } else {
- return false;
- }
-}
-
-Q_DECLARE_TYPEINFO(QBitField, Q_MOVABLE_TYPE);
-
-QT_END_NAMESPACE
-
-#endif // QBITFIELD_P_H
diff --git a/src/qml/qml/ftw/qdoubleendedlist_p.h b/src/qml/qml/ftw/qdoubleendedlist_p.h
new file mode 100644
index 0000000000..0a4d9f75d3
--- /dev/null
+++ b/src/qml/qml/ftw/qdoubleendedlist_p.h
@@ -0,0 +1,256 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QDOUBLEENDEDLIST_P_H
+#define QDOUBLEENDEDLIST_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QInheritedListNode
+{
+public:
+ ~QInheritedListNode() { remove(); }
+ bool isInList() const
+ {
+ Q_ASSERT((m_prev && m_next) || (!m_prev && !m_next));
+ return m_prev != nullptr;
+ }
+
+private:
+ template<class N>
+ friend class QDoubleEndedList;
+
+ void remove()
+ {
+ Q_ASSERT((m_prev && m_next) || (!m_prev && !m_next));
+ if (!m_prev)
+ return;
+
+ m_prev->m_next = m_next;
+ m_next->m_prev = m_prev;
+ m_prev = nullptr;
+ m_next = nullptr;
+ }
+
+ QInheritedListNode *m_next = nullptr;
+ QInheritedListNode *m_prev = nullptr;
+};
+
+template<class N>
+class QDoubleEndedList
+{
+public:
+ QDoubleEndedList()
+ {
+ m_head.m_next = &m_head;
+ m_head.m_prev = &m_head;
+ assertHeadConsistent();
+ }
+
+ ~QDoubleEndedList()
+ {
+ assertHeadConsistent();
+ while (!isEmpty())
+ m_head.m_next->remove();
+ assertHeadConsistent();
+ }
+
+ bool isEmpty() const
+ {
+ assertHeadConsistent();
+ return m_head.m_next == &m_head;
+ }
+
+ void prepend(N *n)
+ {
+ assertHeadConsistent();
+ QInheritedListNode *nnode = n;
+ nnode->remove();
+
+ nnode->m_next = m_head.m_next ? m_head.m_next : &m_head;
+ nnode->m_next->m_prev = nnode;
+
+ m_head.m_next = nnode;
+ nnode->m_prev = &m_head;
+ assertHeadConsistent();
+ }
+
+ void append(N *n)
+ {
+ assertHeadConsistent();
+ QInheritedListNode *nnode = n;
+ nnode->remove();
+
+ nnode->m_prev = m_head.m_prev ? m_head.m_prev : &m_head;
+ nnode->m_prev->m_next = nnode;
+
+ m_head.m_prev = nnode;
+ nnode->m_next = &m_head;
+ assertHeadConsistent();
+ }
+
+ void remove(N *n) {
+ Q_ASSERT(contains(n));
+ QInheritedListNode *nnode = n;
+ nnode->remove();
+ assertHeadConsistent();
+ }
+
+ bool contains(const N *n) const
+ {
+ assertHeadConsistent();
+ for (const QInheritedListNode *nnode = m_head.m_next;
+ nnode != &m_head; nnode = nnode->m_next) {
+ if (nnode == n)
+ return true;
+ }
+
+ return false;
+ }
+
+ template<typename T, typename Node>
+ class base_iterator {
+ public:
+ T *operator*() const { return QDoubleEndedList<N>::nodeToN(m_node); }
+ T *operator->() const { return QDoubleEndedList<N>::nodeToN(m_node); }
+
+ bool operator==(const base_iterator &other) const { return other.m_node == m_node; }
+ bool operator!=(const base_iterator &other) const { return other.m_node != m_node; }
+
+ base_iterator &operator++()
+ {
+ m_node = m_node->m_next;
+ return *this;
+ }
+
+ base_iterator operator++(int)
+ {
+ const base_iterator self(m_node);
+ m_node = m_node->m_next;
+ return self;
+ }
+
+ private:
+ friend class QDoubleEndedList<N>;
+
+ base_iterator(Node *node) : m_node(node)
+ {
+ Q_ASSERT(m_node != nullptr);
+ }
+
+ Node *m_node = nullptr;
+ };
+
+ using iterator = base_iterator<N, QInheritedListNode>;
+ using const_iterator = base_iterator<const N, const QInheritedListNode>;
+
+ const N *first() const { return checkedNodeToN(m_head.m_next); }
+ N *first() { return checkedNodeToN(m_head.m_next); }
+
+ const N *last() const { return checkedNodeToN(m_head.m_prev); }
+ N *last() { return checkedNodeToN(m_head.m_prev); }
+
+ const N *next(const N *current) const
+ {
+ Q_ASSERT(contains(current));
+ const QInheritedListNode *nnode = current;
+ return checkedNodeToN(nnode->m_next);
+ }
+
+ N *next(N *current)
+ {
+ Q_ASSERT(contains(current));
+ const QInheritedListNode *nnode = current;
+ return checkedNodeToN(nnode->m_next);
+ }
+
+ const N *prev(const N *current) const
+ {
+ Q_ASSERT(contains(current));
+ const QInheritedListNode *nnode = current;
+ return checkedNodeToN(nnode->m_prev);
+ }
+
+ N *prev(N *current)
+ {
+ Q_ASSERT(contains(current));
+ const QInheritedListNode *nnode = current;
+ return checkedNodeToN(nnode->m_prev);
+ }
+
+ iterator begin()
+ {
+ assertHeadConsistent();
+ return iterator(m_head.m_next);
+ }
+
+ iterator end()
+ {
+ assertHeadConsistent();
+ return iterator(&m_head);
+ }
+
+ const_iterator begin() const
+ {
+ assertHeadConsistent();
+ return const_iterator(m_head.m_next);
+ }
+
+ const_iterator end() const
+ {
+ assertHeadConsistent();
+ return const_iterator(&m_head);
+ }
+
+ qsizetype count() const
+ {
+ assertHeadConsistent();
+ qsizetype result = 0;
+ for (const auto *node = m_head.m_next; node != &m_head; node = node->m_next)
+ ++result;
+ return result;
+ }
+
+private:
+ static N *nodeToN(QInheritedListNode *node)
+ {
+ return static_cast<N *>(node);
+ }
+
+ static const N *nodeToN(const QInheritedListNode *node)
+ {
+ return static_cast<const N *>(node);
+ }
+
+ N *checkedNodeToN(QInheritedListNode *node) const
+ {
+ assertHeadConsistent();
+ return (!node || node == &m_head) ? nullptr : nodeToN(node);
+ }
+
+ void assertHeadConsistent() const
+ {
+ Q_ASSERT(m_head.m_next != nullptr);
+ Q_ASSERT(m_head.m_prev != nullptr);
+ Q_ASSERT(m_head.m_next != &m_head || m_head.m_prev == &m_head);
+ }
+
+ QInheritedListNode m_head;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDOUBLEENDEDLIST_P_H
diff --git a/src/qml/qml/ftw/qfieldlist_p.h b/src/qml/qml/ftw/qfieldlist_p.h
index 2bf07fb20d..b4c6a55f1a 100644
--- a/src/qml/qml/ftw/qfieldlist_p.h
+++ b/src/qml/qml/ftw/qfieldlist_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFIELDLIST_P_H
#define QFIELDLIST_P_H
@@ -51,12 +15,12 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qtaggedpointer.h>
-#include <private/qflagpointer_p.h>
// QForwardFieldList is a super simple linked list that can only prepend
-template<class N, N *N::*nextMember>
+template<class N, N *N::*nextMember, typename Tag = QtPrivate::TagInfo<N>>
class QForwardFieldList
{
public:
@@ -65,6 +29,8 @@ public:
inline N *takeFirst();
inline void prepend(N *);
+ template <typename OtherTag>
+ inline void copyAndClearPrepend(QForwardFieldList<N, nextMember, OtherTag> &);
inline bool isEmpty() const;
inline bool isOne() const;
@@ -72,17 +38,10 @@ public:
static inline N *next(N *v);
- inline bool flag() const;
- inline void setFlag();
- inline void clearFlag();
- inline void setFlagValue(bool);
-
- inline bool flag2() const;
- inline void setFlag2();
- inline void clearFlag2();
- inline void setFlag2Value(bool);
+ inline Tag tag() const;
+ inline void setTag(Tag t);
private:
- QFlagPointer<N> _first;
+ QTaggedPointer<N, Tag> _first;
};
// QFieldList is a simple linked list, that can append and prepend and also
@@ -108,8 +67,10 @@ public:
inline void insertAfter(N *, QFieldList<N, nextMember> &);
inline void copyAndClear(QFieldList<N, nextMember> &);
- inline void copyAndClearAppend(QForwardFieldList<N, nextMember> &);
- inline void copyAndClearPrepend(QForwardFieldList<N, nextMember> &);
+ template <typename Tag>
+ inline void copyAndClearAppend(QForwardFieldList<N, nextMember, Tag> &);
+ template <typename Tag>
+ inline void copyAndClearPrepend(QForwardFieldList<N, nextMember, Tag> &);
static inline N *next(N *v);
@@ -124,21 +85,21 @@ private:
quint32 _count:31;
};
-template<class N, N *N::*nextMember>
-QForwardFieldList<N, nextMember>::QForwardFieldList()
+template<class N, N *N::*nextMember, typename Tag>
+QForwardFieldList<N, nextMember, Tag>::QForwardFieldList()
{
}
-template<class N, N *N::*nextMember>
-N *QForwardFieldList<N, nextMember>::first() const
+template<class N, N *N::*nextMember, typename Tag>
+N *QForwardFieldList<N, nextMember, Tag>::first() const
{
- return *_first;
+ return _first.data();
}
-template<class N, N *N::*nextMember>
-N *QForwardFieldList<N, nextMember>::takeFirst()
+template<class N, N *N::*nextMember, typename Tag>
+N *QForwardFieldList<N, nextMember, Tag>::takeFirst()
{
- N *value = *_first;
+ N *value = _first.data();
if (value) {
_first = next(value);
value->*nextMember = nullptr;
@@ -146,85 +107,57 @@ N *QForwardFieldList<N, nextMember>::takeFirst()
return value;
}
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::prepend(N *v)
+template<class N, N *N::*nextMember, typename Tag>
+void QForwardFieldList<N, nextMember, Tag>::prepend(N *v)
{
Q_ASSERT(v->*nextMember == nullptr);
- v->*nextMember = *_first;
+ v->*nextMember = _first.data();
_first = v;
}
-template<class N, N *N::*nextMember>
-bool QForwardFieldList<N, nextMember>::isEmpty() const
+template<class N, N *N::*nextMember, typename Tag>
+template <typename OtherTag>
+void QForwardFieldList<N, nextMember, Tag>::copyAndClearPrepend(QForwardFieldList<N, nextMember, OtherTag> &o)
{
- return _first.isNull();
-}
-
-template<class N, N *N::*nextMember>
-bool QForwardFieldList<N, nextMember>::isOne() const
-{
- return *_first && _first->*nextMember == 0;
-}
-
-template<class N, N *N::*nextMember>
-bool QForwardFieldList<N, nextMember>::isMany() const
-{
- return *_first && _first->*nextMember != 0;
-}
-
-template<class N, N *N::*nextMember>
-N *QForwardFieldList<N, nextMember>::next(N *v)
-{
- Q_ASSERT(v);
- return v->*nextMember;
-}
-
-template<class N, N *N::*nextMember>
-bool QForwardFieldList<N, nextMember>::flag() const
-{
- return _first.flag();
-}
-
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::setFlag()
-{
- _first.setFlag();
+ _first = nullptr;
+ while (N *n = o.takeFirst()) prepend(n);
}
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::clearFlag()
+template<class N, N *N::*nextMember, typename Tag>
+bool QForwardFieldList<N, nextMember, Tag>::isEmpty() const
{
- _first.clearFlag();
+ return _first.isNull();
}
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::setFlagValue(bool v)
+template<class N, N *N::*nextMember, typename Tag>
+bool QForwardFieldList<N, nextMember, Tag>::isOne() const
{
- _first.setFlagValue(v);
+ return _first.data() && _first->*nextMember == 0;
}
-template<class N, N *N::*nextMember>
-bool QForwardFieldList<N, nextMember>::flag2() const
+template<class N, N *N::*nextMember, typename Tag>
+bool QForwardFieldList<N, nextMember, Tag>::isMany() const
{
- return _first.flag2();
+ return _first.data() && _first->*nextMember != 0;
}
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::setFlag2()
+template<class N, N *N::*nextMember, typename Tag>
+N *QForwardFieldList<N, nextMember, Tag>::next(N *v)
{
- _first.setFlag2();
+ Q_ASSERT(v);
+ return v->*nextMember;
}
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::clearFlag2()
+template<class N, N *N::*nextMember, typename Tag>
+Tag QForwardFieldList<N, nextMember, Tag>::tag() const
{
- _first.clearFlag2();
+ return _first.tag();
}
-template<class N, N *N::*nextMember>
-void QForwardFieldList<N, nextMember>::setFlag2Value(bool v)
+template<class N, N *N::*nextMember, typename Tag>
+void QForwardFieldList<N, nextMember, Tag>::setTag(Tag t)
{
- _first.setFlag2Value(v);
+ _first.setTag(t);
}
template<class N, N *N::*nextMember>
@@ -380,7 +313,8 @@ void QFieldList<N, nextMember>::copyAndClear(QFieldList<N, nextMember> &o)
}
template<class N, N *N::*nextMember>
-void QFieldList<N, nextMember>::copyAndClearAppend(QForwardFieldList<N, nextMember> &o)
+template <typename Tag>
+void QFieldList<N, nextMember>::copyAndClearAppend(QForwardFieldList<N, nextMember, Tag> &o)
{
_first = 0;
_last = 0;
@@ -389,7 +323,8 @@ void QFieldList<N, nextMember>::copyAndClearAppend(QForwardFieldList<N, nextMemb
}
template<class N, N *N::*nextMember>
-void QFieldList<N, nextMember>::copyAndClearPrepend(QForwardFieldList<N, nextMember> &o)
+template <typename Tag>
+void QFieldList<N, nextMember>::copyAndClearPrepend(QForwardFieldList<N, nextMember, Tag> &o)
{
_first = nullptr;
_last = nullptr;
diff --git a/src/qml/qml/ftw/qfinitestack_p.h b/src/qml/qml/ftw/qfinitestack_p.h
index 9a74199137..3e206e205f 100644
--- a/src/qml/qml/ftw/qfinitestack_p.h
+++ b/src/qml/qml/ftw/qfinitestack_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFINITESTACK_P_H
#define QFINITESTACK_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/ftw/qflagpointer_p.h b/src/qml/qml/ftw/qflagpointer_p.h
deleted file mode 100644
index 71b41cd30b..0000000000
--- a/src/qml/qml/ftw/qflagpointer_p.h
+++ /dev/null
@@ -1,350 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QFLAGPOINTER_P_H
-#define QFLAGPOINTER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-template<typename T>
-class QFlagPointer {
-public:
- inline QFlagPointer();
- inline QFlagPointer(T *);
- inline QFlagPointer(const QFlagPointer<T> &o);
-
- inline bool isNull() const;
-
- inline bool flag() const;
- inline void setFlag();
- inline void clearFlag();
- inline void setFlagValue(bool);
-
- inline bool flag2() const;
- inline void setFlag2();
- inline void clearFlag2();
- inline void setFlag2Value(bool);
-
- inline QFlagPointer<T> &operator=(const QFlagPointer &o);
- inline QFlagPointer<T> &operator=(T *);
-
- inline T *operator->() const;
- inline T *operator*() const;
-
- inline T *data() const;
-
- inline explicit operator bool() const;
-
-private:
- quintptr ptr_value = 0;
-
- static const quintptr FlagBit = 0x1;
- static const quintptr Flag2Bit = 0x2;
- static const quintptr FlagsMask = FlagBit | Flag2Bit;
-};
-
-template<typename T, typename T2>
-class QBiPointer {
-public:
- inline QBiPointer();
- inline QBiPointer(T *);
- inline QBiPointer(T2 *);
- inline QBiPointer(const QBiPointer<T, T2> &o);
-
- inline bool isNull() const;
- inline bool isT1() const;
- inline bool isT2() const;
-
- inline bool flag() const;
- inline void setFlag();
- inline void clearFlag();
- inline void setFlagValue(bool);
-
- inline QBiPointer<T, T2> &operator=(const QBiPointer<T, T2> &o);
- inline QBiPointer<T, T2> &operator=(T *);
- inline QBiPointer<T, T2> &operator=(T2 *);
-
- inline T *asT1() const;
- inline T2 *asT2() const;
-
-private:
- quintptr ptr_value = 0;
-
- static const quintptr FlagBit = 0x1;
- static const quintptr Flag2Bit = 0x2;
- static const quintptr FlagsMask = FlagBit | Flag2Bit;
-};
-
-template<typename T>
-QFlagPointer<T>::QFlagPointer()
-{
-}
-
-template<typename T>
-QFlagPointer<T>::QFlagPointer(T *v)
-: ptr_value(quintptr(v))
-{
- Q_ASSERT((ptr_value & FlagsMask) == 0);
-}
-
-template<typename T>
-QFlagPointer<T>::QFlagPointer(const QFlagPointer<T> &o)
-: ptr_value(o.ptr_value)
-{
-}
-
-template<typename T>
-bool QFlagPointer<T>::isNull() const
-{
- return 0 == (ptr_value & (~FlagsMask));
-}
-
-template<typename T>
-bool QFlagPointer<T>::flag() const
-{
- return ptr_value & FlagBit;
-}
-
-template<typename T>
-void QFlagPointer<T>::setFlag()
-{
- ptr_value |= FlagBit;
-}
-
-template<typename T>
-void QFlagPointer<T>::clearFlag()
-{
- ptr_value &= ~FlagBit;
-}
-
-template<typename T>
-void QFlagPointer<T>::setFlagValue(bool v)
-{
- if (v) setFlag();
- else clearFlag();
-}
-
-template<typename T>
-bool QFlagPointer<T>::flag2() const
-{
- return ptr_value & Flag2Bit;
-}
-
-template<typename T>
-void QFlagPointer<T>::setFlag2()
-{
- ptr_value|= Flag2Bit;
-}
-
-template<typename T>
-void QFlagPointer<T>::clearFlag2()
-{
- ptr_value &= ~Flag2Bit;
-}
-
-template<typename T>
-void QFlagPointer<T>::setFlag2Value(bool v)
-{
- if (v) setFlag2();
- else clearFlag2();
-}
-
-template<typename T>
-QFlagPointer<T> &QFlagPointer<T>::operator=(const QFlagPointer &o)
-{
- ptr_value = o.ptr_value;
- return *this;
-}
-
-template<typename T>
-QFlagPointer<T> &QFlagPointer<T>::operator=(T *o)
-{
- Q_ASSERT((quintptr(o) & FlagsMask) == 0);
-
- ptr_value = quintptr(o) | (ptr_value & FlagsMask);
- return *this;
-}
-
-template<typename T>
-T *QFlagPointer<T>::operator->() const
-{
- return (T *)(ptr_value & ~FlagsMask);
-}
-
-template<typename T>
-T *QFlagPointer<T>::operator*() const
-{
- return (T *)(ptr_value & ~FlagsMask);
-}
-
-template<typename T>
-T *QFlagPointer<T>::data() const
-{
- return (T *)(ptr_value & ~FlagsMask);
-}
-
-template<typename T>
-QFlagPointer<T>::operator bool() const
-{
- return data() != nullptr;
-}
-
-template<typename T, typename T2>
-QBiPointer<T, T2>::QBiPointer()
-{
-}
-
-template<typename T, typename T2>
-QBiPointer<T, T2>::QBiPointer(T *v)
-: ptr_value(quintptr(v))
-{
- Q_ASSERT((quintptr(v) & FlagsMask) == 0);
-}
-
-template<typename T, typename T2>
-QBiPointer<T, T2>::QBiPointer(T2 *v)
-: ptr_value(quintptr(v) | Flag2Bit)
-{
- Q_ASSERT((quintptr(v) & FlagsMask) == 0);
-}
-
-template<typename T, typename T2>
-QBiPointer<T, T2>::QBiPointer(const QBiPointer<T, T2> &o)
-: ptr_value(o.ptr_value)
-{
-}
-
-template<typename T, typename T2>
-bool QBiPointer<T, T2>::isNull() const
-{
- return 0 == (ptr_value & (~FlagsMask));
-}
-
-template<typename T, typename T2>
-bool QBiPointer<T, T2>::isT1() const
-{
- return !(ptr_value & Flag2Bit);
-}
-
-template<typename T, typename T2>
-bool QBiPointer<T, T2>::isT2() const
-{
- return ptr_value & Flag2Bit;
-}
-
-template<typename T, typename T2>
-bool QBiPointer<T, T2>::flag() const
-{
- return ptr_value & FlagBit;
-}
-
-template<typename T, typename T2>
-void QBiPointer<T, T2>::setFlag()
-{
- ptr_value |= FlagBit;
-}
-
-template<typename T, typename T2>
-void QBiPointer<T, T2>::clearFlag()
-{
- ptr_value &= ~FlagBit;
-}
-
-template<typename T, typename T2>
-void QBiPointer<T, T2>::setFlagValue(bool v)
-{
- if (v) setFlag();
- else clearFlag();
-}
-
-template<typename T, typename T2>
-QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(const QBiPointer<T, T2> &o)
-{
- ptr_value = o.ptr_value;
- return *this;
-}
-
-template<typename T, typename T2>
-QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T *o)
-{
- Q_ASSERT((quintptr(o) & FlagsMask) == 0);
-
- ptr_value = quintptr(o) | (ptr_value & FlagBit);
- return *this;
-}
-
-template<typename T, typename T2>
-QBiPointer<T, T2> &QBiPointer<T, T2>::operator=(T2 *o)
-{
- Q_ASSERT((quintptr(o) & FlagsMask) == 0);
-
- ptr_value = quintptr(o) | (ptr_value & FlagBit) | Flag2Bit;
- return *this;
-}
-
-template<typename T, typename T2>
-T *QBiPointer<T, T2>::asT1() const
-{
- Q_ASSERT(isT1());
- return (T *)(ptr_value & ~FlagsMask);
-}
-
-template<typename T, typename T2>
-T2 *QBiPointer<T, T2>::asT2() const
-{
- Q_ASSERT(isT2());
- return (T2 *)(ptr_value & ~FlagsMask);
-}
-
-QT_END_NAMESPACE
-
-#endif // QFLAGPOINTER_P_H
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index 7a8fdd0a14..b963bc7984 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -1,100 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhashedstring_p.h"
QT_BEGIN_NAMESPACE
-// Copy of QString's qMemCompare
-bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
-{
- Q_ASSERT(lhs && rhs);
- const quint16 *a = (const quint16 *)lhs;
- const quint16 *b = (const quint16 *)rhs;
-
- if (a == b || !length)
- return true;
-
- union {
- const quint16 *w;
- const quint32 *d;
- quintptr value;
- } sa, sb;
- sa.w = a;
- sb.w = b;
-
- // check alignment
- if ((sa.value & 2) == (sb.value & 2)) {
- // both addresses have the same alignment
- if (sa.value & 2) {
- // both addresses are not aligned to 4-bytes boundaries
- // compare the first character
- if (*sa.w != *sb.w)
- return false;
- --length;
- ++sa.w;
- ++sb.w;
-
- // now both addresses are 4-bytes aligned
- }
-
- // both addresses are 4-bytes aligned
- // do a fast 32-bit comparison
- const quint32 *e = sa.d + (length >> 1);
- for ( ; sa.d != e; ++sa.d, ++sb.d) {
- if (*sa.d != *sb.d)
- return false;
- }
-
- // do we have a tail?
- return (length & 1) ? *sa.w == *sb.w : true;
- } else {
- // one of the addresses isn't 4-byte aligned but the other is
- const quint16 *e = sa.w + length;
- for ( ; sa.w != e; ++sa.w, ++sb.w) {
- if (*sa.w != *sb.w)
- return false;
- }
- }
- return true;
-}
-
QHashedStringRef QHashedStringRef::mid(int offset, int length) const
{
Q_ASSERT(offset < m_length);
@@ -102,37 +12,41 @@ QHashedStringRef QHashedStringRef::mid(int offset, int length) const
(length == -1 || (offset + length) > m_length)?(m_length - offset):length);
}
-bool QHashedStringRef::endsWith(const QString &s) const
+QVector<QHashedStringRef> QHashedStringRef::split(const QChar sep) const
{
- return s.length() < m_length &&
- QHashedString::compare(s.constData(), m_data + m_length - s.length(), s.length());
+ QVector<QHashedStringRef> ret;
+ auto curLength = 0;
+ auto curOffset = m_data;
+ for (int offset = 0; offset < m_length; ++offset) {
+ if (*(m_data + offset) == sep) {
+ ret.push_back({curOffset, curLength});
+ curOffset = m_data + offset + 1;
+ curLength = 0;
+ } else {
+ ++curLength;
+ }
+ }
+ if (curLength > 0)
+ ret.push_back({curOffset, curLength});
+ return ret;
}
-bool QHashedStringRef::startsWith(const QString &s) const
+bool QHashedStringRef::endsWith(const QString &s) const
{
- return s.length() < m_length &&
- QHashedString::compare(s.constData(), m_data, s.length());
+ QStringView view {m_data, m_length};
+ return view.endsWith(s);
}
-static int findChar(const QChar *str, int len, QChar ch, int from)
+bool QHashedStringRef::startsWith(const QString &s) const
{
- const ushort *s = (const ushort *)str;
- ushort c = ch.unicode();
- if (from < 0)
- from = qMax(from + len, 0);
- if (from < len) {
- const ushort *n = s + from - 1;
- const ushort *e = s + len;
- while (++n != e)
- if (*n == c)
- return n - s;
- }
- return -1;
+ QStringView view {m_data, m_length};
+ return view.startsWith(s);
}
int QHashedStringRef::indexOf(const QChar &c, int from) const
{
- return findChar(m_data, m_length, c, from);
+ QStringView view {m_data, m_length};
+ return view.indexOf(c, from);
}
QString QHashedStringRef::toString() const
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
index b9f3f81219..78ce738f3b 100644
--- a/src/qml/qml/ftw/qhashedstring_p.h
+++ b/src/qml/qml/ftw/qhashedstring_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHASHEDSTRING_P_H
#define QHASHEDSTRING_P_H
@@ -55,8 +19,6 @@
#include <QtCore/qstring.h>
#include <private/qv4string_p.h>
-#include <private/qflagpointer_p.h>
-
#if defined(Q_OS_QNX)
#include <stdlib.h>
#endif
@@ -64,7 +26,7 @@
QT_BEGIN_NAMESPACE
class QHashedStringRef;
-class Q_QML_PRIVATE_EXPORT QHashedString : public QString
+class Q_QML_EXPORT QHashedString : public QString
{
public:
inline QHashedString();
@@ -79,7 +41,6 @@ public:
inline quint32 hash() const;
inline quint32 existingHash() const;
- static bool compare(const QChar *lhs, const QChar *rhs, int length);
static inline bool compare(const QChar *lhs, const char *rhs, int length);
static inline bool compare(const char *lhs, const char *rhs, int length);
@@ -95,12 +56,12 @@ private:
};
class QHashedCStringRef;
-class Q_QML_PRIVATE_EXPORT QHashedStringRef
+class Q_QML_EXPORT QHashedStringRef
{
public:
inline QHashedStringRef();
inline QHashedStringRef(const QString &);
- inline QHashedStringRef(const QStringRef &);
+ inline QHashedStringRef(QStringView);
inline QHashedStringRef(const QChar *, int);
inline QHashedStringRef(const QChar *, int, quint32);
inline QHashedStringRef(const QHashedString &);
@@ -125,6 +86,7 @@ public:
bool endsWith(const QString &) const;
int indexOf(const QChar &, int from=0) const;
QHashedStringRef mid(int, int) const;
+ QVector<QHashedStringRef> split(const QChar sep) const;
inline bool isEmpty() const;
inline int length() const;
@@ -144,7 +106,7 @@ private:
mutable quint32 m_hash = 0;
};
-class Q_AUTOTEST_EXPORT QHashedCStringRef
+class QHashedCStringRef
{
public:
inline QHashedCStringRef();
@@ -157,7 +119,7 @@ public:
inline const char *constData() const;
inline int length() const;
- QString toUtf16() const;
+ Q_AUTOTEST_EXPORT QString toUtf16() const;
inline int utf16length() const;
inline void writeUtf16(QChar *) const;
inline void writeUtf16(quint16 *) const;
@@ -171,12 +133,12 @@ private:
mutable quint32 m_hash = 0;
};
-inline uint qHash(const QHashedString &string)
+inline size_t qHash(const QHashedString &string)
{
return uint(string.hash());
}
-inline uint qHash(const QHashedStringRef &string)
+inline size_t qHash(const QHashedStringRef &string)
{
return uint(string.hash());
}
@@ -216,9 +178,10 @@ bool QHashedString::operator==(const QHashedString &string) const
bool QHashedString::operator==(const QHashedStringRef &string) const
{
- return length() == string.m_length &&
- (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
- QHashedString::compare(constData(), string.m_data, string.m_length);
+ if (m_hash && string.m_hash && m_hash != string.m_hash)
+ return false;
+ QStringView otherView {string.m_data, string.m_length};
+ return static_cast<const QString &>(*this) == otherView;
}
quint32 QHashedString::hash() const
@@ -236,14 +199,18 @@ QHashedStringRef::QHashedStringRef()
{
}
+// QHashedStringRef is meant for identifiers, property names, etc.
+// Those should alsways be smaller than std::numeric_limits<int>::max())
QHashedStringRef::QHashedStringRef(const QString &str)
-: m_data(str.constData()), m_length(str.length()), m_hash(0)
+: m_data(str.constData()), m_length(int(str.size())), m_hash(0)
{
+ Q_ASSERT(str.size() <= std::numeric_limits<int>::max());
}
-QHashedStringRef::QHashedStringRef(const QStringRef &str)
-: m_data(str.constData()), m_length(str.length()), m_hash(0)
+QHashedStringRef::QHashedStringRef(QStringView str)
+: m_data(str.constData()), m_length(int(str.size())), m_hash(0)
{
+ Q_ASSERT(str.size() <= std::numeric_limits<int>::max());
}
QHashedStringRef::QHashedStringRef(const QChar *data, int length)
@@ -257,8 +224,9 @@ QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash)
}
QHashedStringRef::QHashedStringRef(const QHashedString &string)
-: m_data(string.constData()), m_length(string.length()), m_hash(string.m_hash)
+: m_data(string.constData()), m_length(int(string.size())), m_hash(string.m_hash)
{
+ Q_ASSERT(string.size() <= std::numeric_limits<int>::max());
}
QHashedStringRef::QHashedStringRef(const QHashedStringRef &string)
@@ -276,22 +244,26 @@ QHashedStringRef &QHashedStringRef::operator=(const QHashedStringRef &o)
bool QHashedStringRef::operator==(const QString &string) const
{
- return m_length == string.length() &&
- QHashedString::compare(string.constData(), m_data, m_length);
+ QStringView view {m_data, m_length};
+ return view == string;
}
bool QHashedStringRef::operator==(const QHashedString &string) const
{
- return m_length == string.length() &&
- (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
- QHashedString::compare(string.constData(), m_data, m_length);
+ if (m_hash && string.m_hash && m_hash != string.m_hash)
+ return false;
+ QStringView view {m_data, m_length};
+ QStringView otherView {string.constData(), string.size()};
+ return view == otherView;
}
bool QHashedStringRef::operator==(const QHashedStringRef &string) const
{
- return m_length == string.m_length &&
- (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
- QHashedString::compare(string.m_data, m_data, m_length);
+ if (m_hash && string.m_hash && m_hash != string.m_hash)
+ return false;
+ QStringView view {m_data, m_length};
+ QStringView otherView {string.m_data, string.m_length};
+ return view == otherView;
}
bool QHashedStringRef::operator==(const QHashedCStringRef &string) const
@@ -303,29 +275,22 @@ bool QHashedStringRef::operator==(const QHashedCStringRef &string) const
bool QHashedStringRef::operator!=(const QString &string) const
{
- return m_length != string.length() ||
- !QHashedString::compare(string.constData(), m_data, m_length);
+ return !(*this == string);
}
bool QHashedStringRef::operator!=(const QHashedString &string) const
{
- return m_length != string.length() ||
- (m_hash != string.m_hash && m_hash && string.m_hash) ||
- !QHashedString::compare(string.constData(), m_data, m_length);
+ return !(*this == string);
}
bool QHashedStringRef::operator!=(const QHashedStringRef &string) const
{
- return m_length != string.m_length ||
- (m_hash != string.m_hash && m_hash && string.m_hash) ||
- QHashedString::compare(string.m_data, m_data, m_length);
+ return !(*this == string);
}
bool QHashedStringRef::operator!=(const QHashedCStringRef &string) const
{
- return m_length != string.m_length ||
- (m_hash != string.m_hash && m_hash && string.m_hash) ||
- QHashedString::compare(m_data, string.m_data, m_length);
+ return !(*this == string);
}
QChar *QHashedStringRef::data()
@@ -451,6 +416,7 @@ bool QHashedString::compare(const char *lhs, const char *rhs, int length)
return 0 == ::memcmp(lhs, rhs, length);
}
+
quint32 QHashedString::stringHash(const QChar *data, int length)
{
return QV4::String::createHashValue(data, length, nullptr);
@@ -463,7 +429,12 @@ quint32 QHashedString::stringHash(const char *data, int length)
void QHashedString::computeHash() const
{
- m_hash = stringHash(constData(), length());
+ m_hash = stringHash(constData(), int(size()));
+}
+
+namespace QtPrivate {
+inline QString asString(const QHashedCStringRef &ref) { return ref.toUtf16(); }
+inline QString asString(const QHashedStringRef &ref) { return ref.toString(); }
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qintrusivelist.cpp b/src/qml/qml/ftw/qintrusivelist.cpp
index 2ebaffb375..a0a1ddb470 100644
--- a/src/qml/qml/ftw/qintrusivelist.cpp
+++ b/src/qml/qml/ftw/qintrusivelist.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qintrusivelist_p.h"
diff --git a/src/qml/qml/ftw/qintrusivelist_p.h b/src/qml/qml/ftw/qintrusivelist_p.h
index 8992be9f93..1170370fae 100644
--- a/src/qml/qml/ftw/qintrusivelist_p.h
+++ b/src/qml/qml/ftw/qintrusivelist_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QINTRUSIVELIST_P_H
#define QINTRUSIVELIST_P_H
@@ -51,220 +15,144 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
-class QIntrusiveListNode;
-template<class N, QIntrusiveListNode N::*member>
-class QIntrusiveList
+class QIntrusiveListNode
{
public:
- inline QIntrusiveList();
- inline ~QIntrusiveList();
-
- inline bool isEmpty() const;
- inline void insert(N *n);
- inline void remove(N *n);
- inline bool contains(N *) const;
-
- class iterator {
- public:
- inline iterator();
- inline iterator(N *value);
-
- inline N *operator*() const;
- inline N *operator->() const;
- inline bool operator==(const iterator &other) const;
- inline bool operator!=(const iterator &other) const;
- inline iterator &operator++();
-
- inline iterator &erase();
-
- private:
- N *_value;
- };
- typedef iterator Iterator;
-
- inline N *first() const;
- static inline N *next(N *current);
+ ~QIntrusiveListNode() { remove(); }
+
+ void remove()
+ {
+ if (_prev) *_prev = _next;
+ if (_next) _next->_prev = _prev;
+ _prev = nullptr;
+ _next = nullptr;
+ }
- inline iterator begin();
- inline iterator end();
+ bool isInList() const { return _prev != nullptr; }
private:
- static inline N *nodeToN(QIntrusiveListNode *node);
-
- QIntrusiveListNode *__first = nullptr;
-};
-
-class QIntrusiveListNode
-{
-public:
- inline QIntrusiveListNode();
- inline ~QIntrusiveListNode();
-
- inline void remove();
- inline bool isInList() const;
+ template<class N, QIntrusiveListNode N::*member>
+ friend class QIntrusiveList;
QIntrusiveListNode *_next = nullptr;
QIntrusiveListNode**_prev = nullptr;
};
template<class N, QIntrusiveListNode N::*member>
-QIntrusiveList<N, member>::iterator::iterator()
-: _value(nullptr)
-{
-}
-
-template<class N, QIntrusiveListNode N::*member>
-QIntrusiveList<N, member>::iterator::iterator(N *value)
-: _value(value)
-{
-}
-
-template<class N, QIntrusiveListNode N::*member>
-N *QIntrusiveList<N, member>::iterator::operator*() const
-{
- return _value;
-}
-
-template<class N, QIntrusiveListNode N::*member>
-N *QIntrusiveList<N, member>::iterator::operator->() const
-{
- return _value;
-}
-
-template<class N, QIntrusiveListNode N::*member>
-bool QIntrusiveList<N, member>::iterator::operator==(const iterator &other) const
-{
- return other._value == _value;
-}
-
-template<class N, QIntrusiveListNode N::*member>
-bool QIntrusiveList<N, member>::iterator::operator!=(const iterator &other) const
-{
- return other._value != _value;
-}
-
-template<class N, QIntrusiveListNode N::*member>
-typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::operator++()
-{
- _value = QIntrusiveList<N, member>::next(_value);
- return *this;
-}
-
-template<class N, QIntrusiveListNode N::*member>
-typename QIntrusiveList<N, member>::iterator &QIntrusiveList<N, member>::iterator::erase()
+class QIntrusiveList
{
- N *old = _value;
- _value = QIntrusiveList<N, member>::next(_value);
- (old->*member).remove();
- return *this;
-}
+private:
+ template<typename O>
+ class iterator_impl {
+ public:
+ iterator_impl() = default;
+ iterator_impl(O value) : _value(value) {}
+
+ O operator*() const { return _value; }
+ O operator->() const { return _value; }
+ bool operator==(const iterator_impl &other) const { return other._value == _value; }
+ bool operator!=(const iterator_impl &other) const { return other._value != _value; }
+ iterator_impl &operator++()
+ {
+ _value = QIntrusiveList<N, member>::next(_value);
+ return *this;
+ }
+
+ protected:
+ O _value = nullptr;
+ };
-template<class N, QIntrusiveListNode N::*member>
-QIntrusiveList<N, member>::QIntrusiveList()
+public:
+ class iterator : public iterator_impl<N *>
+ {
+ public:
+ iterator() = default;
+ iterator(N *value) : iterator_impl<N *>(value) {}
+
+ iterator &erase()
+ {
+ N *old = this->_value;
+ this->_value = QIntrusiveList<N, member>::next(this->_value);
+ (old->*member).remove();
+ return *this;
+ }
+ };
-{
-}
+ using const_iterator = iterator_impl<const N *>;
-template<class N, QIntrusiveListNode N::*member>
-QIntrusiveList<N, member>::~QIntrusiveList()
-{
- while (__first) __first->remove();
-}
+ using Iterator = iterator;
+ using ConstIterator = const_iterator;
-template<class N, QIntrusiveListNode N::*member>
-bool QIntrusiveList<N, member>::isEmpty() const
-{
- return __first == nullptr;
-}
+ ~QIntrusiveList() { while (__first) __first->remove(); }
-template<class N, QIntrusiveListNode N::*member>
-void QIntrusiveList<N, member>::insert(N *n)
-{
- QIntrusiveListNode *nnode = &(n->*member);
- nnode->remove();
+ bool isEmpty() const { return __first == nullptr; }
- nnode->_next = __first;
- if (nnode->_next) nnode->_next->_prev = &nnode->_next;
- __first = nnode;
- nnode->_prev = &__first;
-}
+ void insert(N *n)
+ {
+ QIntrusiveListNode *nnode = &(n->*member);
+ nnode->remove();
-template<class N, QIntrusiveListNode N::*member>
-void QIntrusiveList<N, member>::remove(N *n)
-{
- QIntrusiveListNode *nnode = &(n->*member);
- nnode->remove();
-}
+ nnode->_next = __first;
+ if (nnode->_next) nnode->_next->_prev = &nnode->_next;
+ __first = nnode;
+ nnode->_prev = &__first;
+ }
-template<class N, QIntrusiveListNode N::*member>
-bool QIntrusiveList<N, member>::contains(N *n) const
-{
- QIntrusiveListNode *nnode = __first;
- while (nnode) {
- if (nodeToN(nnode) == n)
- return true;
- nnode = nnode->_next;
+ void remove(N *n)
+ {
+ QIntrusiveListNode *nnode = &(n->*member);
+ nnode->remove();
}
- return false;
-}
-template<class N, QIntrusiveListNode N::*member>
-N *QIntrusiveList<N, member>::first() const
-{
- return __first?nodeToN(__first):nullptr;
-}
+ bool contains(const N *n) const
+ {
+ QIntrusiveListNode *nnode = __first;
+ while (nnode) {
+ if (nodeToN(nnode) == n)
+ return true;
+ nnode = nnode->_next;
+ }
+ return false;
+ }
-template<class N, QIntrusiveListNode N::*member>
-N *QIntrusiveList<N, member>::next(N *current)
-{
- QIntrusiveListNode *nextnode = (current->*member)._next;
- N *nextstruct = nextnode?nodeToN(nextnode):nullptr;
- return nextstruct;
-}
+ const N *first() const { return __first ? nodeToN(__first) : nullptr; }
+ N *first() { return __first ? nodeToN(__first) : nullptr; }
-template<class N, QIntrusiveListNode N::*member>
-typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::begin()
-{
- return __first?iterator(nodeToN(__first)):iterator();
-}
+ template<typename O>
+ static O next(O current)
+ {
+ QIntrusiveListNode *nextnode = (current->*member)._next;
+ return nextnode ? nodeToN(nextnode) : nullptr;
+ }
-template<class N, QIntrusiveListNode N::*member>
-typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::end()
-{
- return iterator();
-}
+ iterator begin() { return __first ? iterator(nodeToN(__first)) : iterator(); }
+ iterator end() { return iterator(); }
-template<class N, QIntrusiveListNode N::*member>
-N *QIntrusiveList<N, member>::nodeToN(QIntrusiveListNode *node)
-{
- return (N *)((char *)node - ((char *)&(((N *)nullptr)->*member) - (char *)nullptr));
-}
+ const_iterator begin() const
+ {
+ return __first ? const_iterator(nodeToN(__first)) : const_iterator();
+ }
-QIntrusiveListNode::QIntrusiveListNode()
-{
-}
+ const_iterator end() const { return const_iterator(); }
-QIntrusiveListNode::~QIntrusiveListNode()
-{
- remove();
-}
+private:
-void QIntrusiveListNode::remove()
-{
- if (_prev) *_prev = _next;
- if (_next) _next->_prev = _prev;
- _prev = nullptr;
- _next = nullptr;
-}
+ static N *nodeToN(QIntrusiveListNode *node)
+ {
+ QT_WARNING_PUSH
+#if defined(Q_CC_CLANG) && Q_CC_CLANG >= 1300
+ QT_WARNING_DISABLE_CLANG("-Wnull-pointer-subtraction")
+#endif
+ return (N *)((char *)node - ((char *)&(((N *)nullptr)->*member) - (char *)nullptr));
+ QT_WARNING_POP
+ }
-bool QIntrusiveListNode::isInList() const
-{
- return _prev != nullptr;
-}
+ QIntrusiveListNode *__first = nullptr;
+};
QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qlazilyallocated_p.h b/src/qml/qml/ftw/qlazilyallocated_p.h
index 9073e41558..81f6ab7e89 100644
--- a/src/qml/qml/ftw/qlazilyallocated_p.h
+++ b/src/qml/qml/ftw/qlazilyallocated_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLAZILYALLOCATED_P_H
#define QLAZILYALLOCATED_P_H
@@ -51,13 +15,12 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
-
-#include <private/qflagpointer_p.h>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qtaggedpointer.h>
QT_BEGIN_NAMESPACE
-template<typename T>
+template<typename T, typename Tag = typename QtPrivate::TagInfo<T>::TagType>
class QLazilyAllocated {
public:
inline QLazilyAllocated();
@@ -70,73 +33,59 @@ public:
inline T &value();
inline const T &value() const;
- inline bool flag() const;
- inline void setFlag();
- inline void clearFlag();
- inline void setFlagValue(bool);
+ inline Tag tag() const;
+ inline void setTag(Tag t);
private:
- mutable QFlagPointer<T> d;
+ mutable QTaggedPointer<T, Tag> d;
};
-template<typename T>
-QLazilyAllocated<T>::QLazilyAllocated()
+template<typename T, typename Tag>
+QLazilyAllocated<T, Tag>::QLazilyAllocated()
{
}
-template<typename T>
-QLazilyAllocated<T>::~QLazilyAllocated()
+template<typename T, typename Tag>
+QLazilyAllocated<T, Tag>::~QLazilyAllocated()
{
- delete *d;
+ delete d.data();
}
-template<typename T>
-bool QLazilyAllocated<T>::isAllocated() const
+template<typename T, typename Tag>
+bool QLazilyAllocated<T, Tag>::isAllocated() const
{
return !d.isNull();
}
-template<typename T>
-T &QLazilyAllocated<T>::value()
+template<typename T, typename Tag>
+T &QLazilyAllocated<T, Tag>::value()
{
if (d.isNull()) d = new T;
- return *(*d);
+ return *d;
}
-template<typename T>
-const T &QLazilyAllocated<T>::value() const
+template<typename T, typename Tag>
+const T &QLazilyAllocated<T, Tag>::value() const
{
if (d.isNull()) d = new T;
- return *(*d);
-}
-
-template<typename T>
-T *QLazilyAllocated<T>::operator->() const
-{
return *d;
}
-template<typename T>
-bool QLazilyAllocated<T>::flag() const
-{
- return d.flag();
-}
-
-template<typename T>
-void QLazilyAllocated<T>::setFlag()
+template<typename T, typename Tag>
+T *QLazilyAllocated<T, Tag>::operator->() const
{
- d.setFlag();
+ return d.data();
}
-template<typename T>
-void QLazilyAllocated<T>::clearFlag()
+template<typename T, typename Tag>
+Tag QLazilyAllocated<T, Tag>::tag() const
{
- d.clearFlag();
+ return d.tag();
}
-template<typename T>
-void QLazilyAllocated<T>::setFlagValue(bool v)
+template<typename T, typename Tag>
+void QLazilyAllocated<T, Tag>::setTag(Tag t)
{
- d.setFlagValue(v);
+ d.setTag(t);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qlinkedstringhash_p.h b/src/qml/qml/ftw/qlinkedstringhash_p.h
index 67ced7fbbf..a2309db717 100644
--- a/src/qml/qml/ftw/qlinkedstringhash_p.h
+++ b/src/qml/qml/ftw/qlinkedstringhash_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QLINKEDSTRINGHASH_P_H
#define QLINKEDSTRINGHASH_P_H
@@ -223,7 +187,7 @@ public:
{
if (auto *node = iter.node()) {
QHashedString key(node->key());
- while ((node = static_cast<typename QLinkedStringHash<T>::Node *>(*node->next))) {
+ while ((node = static_cast<typename QLinkedStringHash<T>::Node *>(node->next.data()))) {
if (node->equals(key))
return QLinkedStringHash<T>::iterator(node);
}
diff --git a/src/qml/qml/ftw/qpodvector_p.h b/src/qml/qml/ftw/qpodvector_p.h
index b2fb481793..6508071105 100644
--- a/src/qml/qml/ftw/qpodvector_p.h
+++ b/src/qml/qml/ftw/qpodvector_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPODVECTOR_P_H
#define QPODVECTOR_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/ftw/qprimefornumbits_p.h b/src/qml/qml/ftw/qprimefornumbits_p.h
index 6e9acbf7fd..82c9ea023e 100644
--- a/src/qml/qml/ftw/qprimefornumbits_p.h
+++ b/src/qml/qml/ftw/qprimefornumbits_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPRIMEFORNUMBITS_P_H
#define QPRIMEFORNUMBITS_P_H
diff --git a/src/qml/qml/ftw/qqmlnullablevalue_p.h b/src/qml/qml/ftw/qqmlnullablevalue_p.h
index 5b3d2fc456..9a3f032b68 100644
--- a/src/qml/qml/ftw/qqmlnullablevalue_p.h
+++ b/src/qml/qml/ftw/qqmlnullablevalue_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLNULLABLEVALUE_P_H
#define QQMLNULLABLEVALUE_P_H
@@ -51,27 +15,76 @@
// We mean it.
//
+#include <QtCore/private/qglobal_p.h>
+
QT_BEGIN_NAMESPACE
template<typename T>
struct QQmlNullableValue
{
- QQmlNullableValue()
- : value(T()) {}
+ QQmlNullableValue() = default;
+
QQmlNullableValue(const QQmlNullableValue<T> &o)
- : isNull(o.isNull), value(o.value) {}
+ : m_value(o.m_value)
+ , m_isNull(o.m_isNull)
+ {}
+
+ QQmlNullableValue(QQmlNullableValue<T> &&o) noexcept
+ : m_value(std::move(o.value))
+ , m_isNull(std::exchange(o.m_isNull, true))
+ {}
+
QQmlNullableValue(const T &t)
- : isNull(false), value(t) {}
- QQmlNullableValue<T> &operator=(const T &t)
- { isNull = false; value = t; return *this; }
+ : m_value(t)
+ , m_isNull(false)
+ {}
+
+ QQmlNullableValue(T &&t) noexcept
+ : m_value(std::move(t))
+ , m_isNull(false)
+ {}
+
QQmlNullableValue<T> &operator=(const QQmlNullableValue<T> &o)
- { isNull = o.isNull; value = o.value; return *this; }
- operator T() const { return value; }
+ {
+ if (&o != this) {
+ m_value = o.m_value;
+ m_isNull = o.m_isNull;
+ }
+ return *this;
+ }
+
+ QQmlNullableValue<T> &operator=(QQmlNullableValue<T> &&o) noexcept
+ {
+ if (&o != this) {
+ m_value = std::move(o.m_value);
+ m_isNull = std::exchange(o.m_isNull, true);
+ }
+ return *this;
+ }
+
+ QQmlNullableValue<T> &operator=(const T &t)
+ {
+ m_value = t;
+ m_isNull = false;
+ return *this;
+ }
+
+ QQmlNullableValue<T> &operator=(T &&t) noexcept
+ {
+ m_value = std::move(t);
+ m_isNull = false;
+ return *this;
+ }
+
+ const T &value() const { return m_value; }
+ operator T() const { return m_value; }
+
+ void invalidate() { m_isNull = true; }
+ bool isValid() const { return !m_isNull; }
- void invalidate() { isNull = true; }
- bool isValid() const { return !isNull; }
- bool isNull = true;
- T value;
+private:
+ T m_value = T();
+ bool m_isNull = true;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qqmlrefcount_p.h b/src/qml/qml/ftw/qqmlrefcount_p.h
index b4f8acad49..e7616915eb 100644
--- a/src/qml/qml/ftw/qqmlrefcount_p.h
+++ b/src/qml/qml/ftw/qqmlrefcount_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLREFCOUNT_P_H
#define QQMLREFCOUNT_P_H
@@ -57,23 +21,34 @@
QT_BEGIN_NAMESPACE
+template <typename T>
+class QQmlRefCounted;
-class Q_QML_PRIVATE_EXPORT QQmlRefCount
+class QQmlRefCount
{
Q_DISABLE_COPY_MOVE(QQmlRefCount)
public:
inline QQmlRefCount();
inline void addref() const;
- inline void release() const;
inline int count() const;
-protected:
- inline virtual ~QQmlRefCount();
+private:
+ inline ~QQmlRefCount();
+ template <typename T> friend class QQmlRefCounted;
private:
mutable QAtomicInt refCount;
};
+template <typename T>
+class QQmlRefCounted : public QQmlRefCount
+{
+public:
+ inline void release() const;
+protected:
+ inline ~QQmlRefCounted();
+};
+
template<class T>
class QQmlRefPointer
{
@@ -82,14 +57,16 @@ public:
AddRef,
Adopt
};
- inline QQmlRefPointer();
- inline QQmlRefPointer(T *, Mode m = AddRef);
- inline QQmlRefPointer(const QQmlRefPointer<T> &);
- inline QQmlRefPointer(QQmlRefPointer<T> &&);
+ Q_NODISCARD_CTOR inline QQmlRefPointer() noexcept;
+ Q_NODISCARD_CTOR inline QQmlRefPointer(T *, Mode m = AddRef);
+ Q_NODISCARD_CTOR inline QQmlRefPointer(const QQmlRefPointer &);
+ Q_NODISCARD_CTOR inline QQmlRefPointer(QQmlRefPointer &&) noexcept;
inline ~QQmlRefPointer();
+ void swap(QQmlRefPointer &other) noexcept { qt_ptr_swap(o, other.o); }
+
inline QQmlRefPointer<T> &operator=(const QQmlRefPointer<T> &o);
- inline QQmlRefPointer<T> &operator=(QQmlRefPointer<T> &&o);
+ inline QQmlRefPointer<T> &operator=(QQmlRefPointer<T> &&o) noexcept;
inline bool isNull() const { return !o; }
@@ -102,10 +79,54 @@ public:
inline T* take() { T *res = o; o = nullptr; return res; }
+ friend bool operator==(const QQmlRefPointer &a, const QQmlRefPointer &b) noexcept
+ {
+ return a.o == b.o;
+ }
+
+ friend bool operator!=(const QQmlRefPointer &a, const QQmlRefPointer &b) noexcept
+ {
+ return !(a == b);
+ }
+
+ friend size_t qHash(const QQmlRefPointer &v, size_t seed = 0) noexcept
+ {
+ return qHash(v.o, seed);
+ }
+
+ void reset(T *t = nullptr)
+ {
+ if (t == o)
+ return;
+ if (o)
+ o->release();
+ if (t)
+ t->addref();
+ o = t;
+ }
+
private:
T *o;
};
+namespace QQml {
+/*!
+ \internal
+ Creates a QQmlRefPointer which takes ownership of a newly constructed T.
+ T must derive from QQmlRefCounted<T> (as we rely on an initial refcount of _1_).
+ T will be constructed by forwarding \a args to its constructor.
+ */
+template <typename T, typename ...Args>
+QQmlRefPointer<T> makeRefPointer(Args&&... args)
+{
+ static_assert(std::is_base_of_v<QQmlRefCount, T>);
+ return QQmlRefPointer<T>(new T(std::forward<Args>(args)...), QQmlRefPointer<T>::Adopt);
+}
+}
+
+template <typename T>
+Q_DECLARE_TYPEINFO_BODY(QQmlRefPointer<T>, Q_RELOCATABLE_TYPE);
+
QQmlRefCount::QQmlRefCount()
: refCount(1)
{
@@ -122,11 +143,22 @@ void QQmlRefCount::addref() const
refCount.ref();
}
-void QQmlRefCount::release() const
+template <typename T>
+void QQmlRefCounted<T>::release() const
{
+ static_assert(std::is_base_of_v<QQmlRefCounted, T>,
+ "QQmlRefCounted<T> must be a base of T (CRTP)");
Q_ASSERT(refCount.loadRelaxed() > 0);
if (!refCount.deref())
- delete this;
+ delete static_cast<const T *>(this);
+}
+
+template <typename T>
+QQmlRefCounted<T>::~QQmlRefCounted()
+{
+ static_assert(std::is_final_v<T> || std::has_virtual_destructor_v<T>,
+ "T must either be marked final or have a virtual dtor, "
+ "lest release() runs into UB.");
}
int QQmlRefCount::count() const
@@ -135,7 +167,7 @@ int QQmlRefCount::count() const
}
template<class T>
-QQmlRefPointer<T>::QQmlRefPointer()
+QQmlRefPointer<T>::QQmlRefPointer() noexcept
: o(nullptr)
{
}
@@ -156,7 +188,7 @@ QQmlRefPointer<T>::QQmlRefPointer(const QQmlRefPointer<T> &other)
}
template <class T>
-QQmlRefPointer<T>::QQmlRefPointer(QQmlRefPointer<T> &&other)
+QQmlRefPointer<T>::QQmlRefPointer(QQmlRefPointer<T> &&other) noexcept
: o(other.take())
{
}
@@ -170,17 +202,21 @@ QQmlRefPointer<T>::~QQmlRefPointer()
template<class T>
QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(const QQmlRefPointer<T> &other)
{
- if (other.o) other.o->addref();
- if (o) o->release();
+ if (o == other.o)
+ return *this;
+ if (other.o)
+ other.o->addref();
+ if (o)
+ o->release();
o = other.o;
return *this;
}
template <class T>
-QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(QQmlRefPointer<T> &&other)
+QQmlRefPointer<T> &QQmlRefPointer<T>::operator=(QQmlRefPointer<T> &&other) noexcept
{
QQmlRefPointer<T> m(std::move(other));
- qSwap(o, m.o);
+ swap(m);
return *this;
}
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp
index e961ed3d0d..57f91b6b4d 100644
--- a/src/qml/qml/ftw/qqmlthread.cpp
+++ b/src/qml/qml/ftw/qqmlthread.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlthread_p.h"
@@ -47,6 +11,8 @@
#include <QtCore/qwaitcondition.h>
#include <QtCore/qcoreapplication.h>
+#include <QtCore/private/qthread_p.h>
+
QT_BEGIN_NAMESPACE
class QQmlThreadPrivate : public QThread
@@ -55,19 +21,16 @@ public:
QQmlThreadPrivate(QQmlThread *);
QQmlThread *q;
- void run() override;
-
inline QMutex &mutex() { return _mutex; }
inline void lock() { _mutex.lock(); }
inline void unlock() { _mutex.unlock(); }
inline void wait() { _wait.wait(&_mutex); }
inline void wakeOne() { _wait.wakeOne(); }
- inline void wakeAll() { _wait.wakeAll(); }
- quint32 m_threadProcessing:1; // Set when the thread is processing messages
- quint32 m_mainProcessing:1; // Set when the main thread is processing messages
- quint32 m_shutdown:1; // Set by main thread to request a shutdown
- quint32 m_mainThreadWaiting:1; // Set by main thread if it is waiting for the message queue to empty
+ bool m_threadProcessing; // Set when the thread is processing messages
+ bool m_mainProcessing; // Set when the main thread is processing messages
+ bool m_shutdown; // Set by main thread to request a shutdown
+ bool m_mainThreadWaiting; // Set by main thread if it is waiting for the message queue to empty
typedef QFieldList<QQmlThread::Message, &QQmlThread::Message::next> MessageList;
MessageList threadList;
@@ -131,6 +94,9 @@ QQmlThreadPrivate::QQmlThreadPrivate(QQmlThread *q)
m_mainThreadWaiting(false), mainSync(nullptr), m_mainObject(this)
{
setObjectName(QStringLiteral("QQmlThread"));
+ // This size is aligned with the recursion depth limits in the parser/codegen. In case of
+ // absurd content we want to hit the recursion checks instead of running out of stack.
+ setStackSize(8 * 1024 * 1024);
}
bool QQmlThreadPrivate::event(QEvent *e)
@@ -140,19 +106,6 @@ bool QQmlThreadPrivate::event(QEvent *e)
return QThread::event(e);
}
-void QQmlThreadPrivate::run()
-{
- lock();
-
- wakeOne();
-
- unlock();
-
- q->startupThread();
- exec();
- q->shutdownThread();
-}
-
void QQmlThreadPrivate::mainEvent()
{
lock();
@@ -185,13 +138,7 @@ void QQmlThreadPrivate::threadEvent()
lock();
for (;;) {
- if (m_shutdown) {
- quit();
- wakeOne();
- unlock();
-
- return;
- } else if (!threadList.isEmpty()) {
+ if (!threadList.isEmpty()) {
m_threadProcessing = true;
QQmlThread::Message *message = threadList.first();
@@ -203,6 +150,12 @@ void QQmlThreadPrivate::threadEvent()
lock();
delete threadList.takeFirst();
+ } else if (m_shutdown) {
+ quit();
+ wakeOne();
+ unlock();
+
+ return;
} else {
wakeOne();
@@ -225,12 +178,13 @@ QQmlThread::~QQmlThread()
delete d;
}
+/*!
+ \internal
+ Starts the actual worker thread.
+ */
void QQmlThread::startup()
{
- d->lock();
d->start();
- d->wait();
- d->unlock();
d->moveToThread(d);
}
@@ -239,28 +193,19 @@ void QQmlThread::shutdown()
d->lock();
Q_ASSERT(!d->m_shutdown);
- for (;;) {
- if (d->mainSync || !d->mainList.isEmpty()) {
- d->unlock();
- d->mainEvent();
- d->lock();
- } else if (!d->threadList.isEmpty()) {
- d->wait();
- } else {
- break;
- }
- }
-
d->m_shutdown = true;
- if (QCoreApplication::closingDown()) {
+
+ if (QCoreApplication::closingDown())
d->quit();
- } else {
+ else
d->triggerThreadEvent();
- d->wait();
- }
d->unlock();
d->QThread::wait();
+
+ // Discard all remaining messages.
+ // We don't need the lock anymore because the thread is dead.
+ discardMessages();
}
bool QQmlThread::isShutdown() const
@@ -288,11 +233,6 @@ void QQmlThread::wakeOne()
d->wakeOne();
}
-void QQmlThread::wakeAll()
-{
- d->wakeAll();
-}
-
void QQmlThread::wait()
{
d->wait();
@@ -300,7 +240,7 @@ void QQmlThread::wait()
bool QQmlThread::isThisThread() const
{
- return QThread::currentThread() == d;
+ return QThread::currentThreadId() == static_cast<QThreadPrivate *>(QObjectPrivate::get(d))->threadData.loadRelaxed()->threadId.loadRelaxed();
}
QThread *QQmlThread::thread() const
@@ -308,16 +248,6 @@ QThread *QQmlThread::thread() const
return const_cast<QThread *>(static_cast<const QThread *>(d));
}
-// Called when the thread starts. Do startup stuff in here.
-void QQmlThread::startupThread()
-{
-}
-
-// Called when the thread shuts down. Do cleanup in here.
-void QQmlThread::shutdownThread()
-{
-}
-
void QQmlThread::internalCallMethodInThread(Message *message)
{
#if !QT_CONFIG(thread)
@@ -355,6 +285,13 @@ void QQmlThread::internalCallMethodInThread(Message *message)
d->unlock();
}
+/*!
+ \internal
+ \note This method needs to run in the worker/QQmlThread
+
+ This runs \a message in the main thread, and blocks the
+ worker thread until the call has completed
+ */
void QQmlThread::internalCallMethodInMain(Message *message)
{
#if !QT_CONFIG(thread)
@@ -418,12 +355,22 @@ void QQmlThread::internalPostMethodToMain(Message *message)
d->unlock();
}
+/*!
+ \internal
+ \note This method must be called in the main thread
+ \warning This method requires that the lock is held!
+
+ A call to this method will either:
+ - run a message requested to run synchronously on the main thread if there is one
+ (and return afterrwards),
+ - wait for the worker thread to notify it if the worker thread has pending work,
+ - or simply return if neither of the conditions above hold
+ */
void QQmlThread::waitForNextMessage()
{
#if QT_CONFIG(thread)
Q_ASSERT(!isThisThread());
#endif
- d->lock();
Q_ASSERT(d->m_mainThreadWaiting == false);
d->m_mainThreadWaiting = true;
@@ -443,8 +390,24 @@ void QQmlThread::waitForNextMessage()
}
d->m_mainThreadWaiting = false;
- d->unlock();
}
+/*!
+ \internal
+ \note This method must be called in the main thread
+ \warning This method requires that the lock is held!
+
+ Clear all pending events, for either thread.
+*/
+void QQmlThread::discardMessages()
+{
+ Q_ASSERT(!isThisThread());
+ if (Message *mainSync = std::exchange(d->mainSync, nullptr))
+ delete mainSync;
+ while (!d->mainList.isEmpty())
+ delete d->mainList.takeFirst();
+ while (!d->threadList.isEmpty())
+ delete d->threadList.takeFirst();
+}
QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h
index b5c580fe8b..35f586f7e7 100644
--- a/src/qml/qml/ftw/qqmlthread_p.h
+++ b/src/qml/qml/ftw/qqmlthread_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTHREAD_P_H
#define QQMLTHREAD_P_H
@@ -76,51 +40,31 @@ public:
void lock();
void unlock();
void wakeOne();
- void wakeAll();
void wait();
QThread *thread() const;
bool isThisThread() const;
// Synchronously invoke a method in the thread
- template<class O>
- inline void callMethodInThread(void (O::*Member)());
- template<typename T, class V, class O>
- inline void callMethodInThread(void (O::*Member)(V), const T &);
- template<typename T, typename T2, class V, class V2, class O>
- inline void callMethodInThread(void (O::*Member)(V, V2), const T &, const T2 &);
+ template<typename Method, typename ...Args>
+ void callMethodInThread(Method &&method, Args &&...args);
// Synchronously invoke a method in the main thread. If the main thread is
// blocked in a callMethodInThread() call, the call is made from within that
// call.
- template<class O>
- inline void callMethodInMain(void (O::*Member)());
- template<typename T, class V, class O>
- inline void callMethodInMain(void (O::*Member)(V), const T &);
- template<typename T, typename T2, class V, class V2, class O>
- inline void callMethodInMain(void (O::*Member)(V, V2), const T &, const T2 &);
+ template<typename Method, typename ...Args>
+ void callMethodInMain(Method &&method, Args &&...args);
// Asynchronously invoke a method in the thread.
- template<class O>
- inline void postMethodToThread(void (O::*Member)());
- template<typename T, class V, class O>
- inline void postMethodToThread(void (O::*Member)(V), const T &);
- template<typename T, typename T2, class V, class V2, class O>
- inline void postMethodToThread(void (O::*Member)(V, V2), const T &, const T2 &);
+ template<typename Method, typename ...Args>
+ void postMethodToThread(Method &&method, Args &&...args);
// Asynchronously invoke a method in the main thread.
- template<class O>
- inline void postMethodToMain(void (O::*Member)());
- template<typename T, class V, class O>
- inline void postMethodToMain(void (O::*Member)(V), const T &);
- template<typename T, typename T2, class V, class V2, class O>
- inline void postMethodToMain(void (O::*Member)(V, V2), const T &, const T2 &);
+ template<typename Method, typename ...Args>
+ void postMethodToMain(Method &&method, Args &&...args);
void waitForNextMessage();
-
-protected:
- virtual void startupThread();
- virtual void shutdownThread();
+ void discardMessages();
private:
friend class QQmlThreadPrivate;
@@ -131,6 +75,8 @@ private:
Message *next;
virtual void call(QQmlThread *) = 0;
};
+ template<typename Method, typename ...Args>
+ Message *createMessageFromMethod(Method &&method, Args &&...args);
void internalCallMethodInThread(Message *);
void internalCallMethodInMain(Message *);
void internalPostMethodToThread(Message *);
@@ -138,184 +84,58 @@ private:
QQmlThreadPrivate *d;
};
-template<class O>
-void QQmlThread::callMethodInThread(void (O::*Member)())
-{
- struct I : public Message {
- void (O::*Member)();
- I(void (O::*Member)()) : Member(Member) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)();
- }
- };
- internalCallMethodInThread(new I(Member));
-}
-
-template<typename T, class V, class O>
-void QQmlThread::callMethodInThread(void (O::*Member)(V), const T &arg)
-{
- struct I : public Message {
- void (O::*Member)(V);
- T arg;
- I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg);
- }
- };
- internalCallMethodInThread(new I(Member, arg));
-}
-
-template<typename T, typename T2, class V, class V2, class O>
-void QQmlThread::callMethodInThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
-{
- struct I : public Message {
- void (O::*Member)(V, V2);
- T arg;
- T2 arg2;
- I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg, arg2);
- }
- };
- internalCallMethodInThread(new I(Member, arg, arg2));
-}
-
-template<class O>
-void QQmlThread::callMethodInMain(void (O::*Member)())
-{
- struct I : public Message {
- void (O::*Member)();
- I(void (O::*Member)()) : Member(Member) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)();
- }
- };
- internalCallMethodInMain(new I(Member));
-}
+namespace QtPrivate {
+template <typename> struct member_function_traits;
-template<typename T, class V, class O>
-void QQmlThread::callMethodInMain(void (O::*Member)(V), const T &arg)
+template <typename Return, typename Object, typename... Args>
+struct member_function_traits<Return (Object::*)(Args...)>
{
- struct I : public Message {
- void (O::*Member)(V);
- T arg;
- I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg);
- }
- };
- internalCallMethodInMain(new I(Member, arg));
+ using class_type = Object;
+};
}
-template<typename T, typename T2, class V, class V2, class O>
-void QQmlThread::callMethodInMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+template<typename Method, typename ...Args>
+QQmlThread::Message *QQmlThread::createMessageFromMethod(Method &&method, Args &&...args)
{
struct I : public Message {
- void (O::*Member)(V, V2);
- T arg;
- T2 arg2;
- I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
+ Method m;
+ std::tuple<std::decay_t<Args>...> arguments;
+ I(Method &&method, Args&& ...args) : m(std::forward<Method>(method)), arguments(std::forward<Args>(args)...) {}
void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg, arg2);
+ using class_type = typename QtPrivate::member_function_traits<Method>::class_type;
+ class_type *me = static_cast<class_type *>(thread);
+ std::apply(m, std::tuple_cat(std::make_tuple(me), arguments));
}
};
- internalCallMethodInMain(new I(Member, arg, arg2));
+ return new I(std::forward<Method>(method), std::forward<Args>(args)...);
}
-template<class O>
-void QQmlThread::postMethodToThread(void (O::*Member)())
+template<typename Method, typename ...Args>
+void QQmlThread::callMethodInMain(Method &&method, Args&& ...args)
{
- struct I : public Message {
- void (O::*Member)();
- I(void (O::*Member)()) : Member(Member) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)();
- }
- };
- internalPostMethodToThread(new I(Member));
+ Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...);
+ internalCallMethodInMain(m);
}
-template<typename T, class V, class O>
-void QQmlThread::postMethodToThread(void (O::*Member)(V), const T &arg)
+template<typename Method, typename ...Args>
+void QQmlThread::callMethodInThread(Method &&method, Args&& ...args)
{
- struct I : public Message {
- void (O::*Member)(V);
- T arg;
- I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg);
- }
- };
- internalPostMethodToThread(new I(Member, arg));
+ Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...);
+ internalCallMethodInThread(m);
}
-template<typename T, typename T2, class V, class V2, class O>
-void QQmlThread::postMethodToThread(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
+template<typename Method, typename ...Args>
+void QQmlThread::postMethodToThread(Method &&method, Args&& ...args)
{
- struct I : public Message {
- void (O::*Member)(V, V2);
- T arg;
- T2 arg2;
- I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg, arg2);
- }
- };
- internalPostMethodToThread(new I(Member, arg, arg2));
+ Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...);
+ internalPostMethodToThread(m);
}
-template<class O>
-void QQmlThread::postMethodToMain(void (O::*Member)())
+template<typename Method, typename ...Args>
+void QQmlThread::postMethodToMain(Method &&method, Args&& ...args)
{
- struct I : public Message {
- void (O::*Member)();
- I(void (O::*Member)()) : Member(Member) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)();
- }
- };
- internalPostMethodToMain(new I(Member));
-}
-
-template<typename T, class V, class O>
-void QQmlThread::postMethodToMain(void (O::*Member)(V), const T &arg)
-{
- struct I : public Message {
- void (O::*Member)(V);
- T arg;
- I(void (O::*Member)(V), const T &arg) : Member(Member), arg(arg) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg);
- }
- };
- internalPostMethodToMain(new I(Member, arg));
-}
-
-template<typename T, typename T2, class V, class V2, class O>
-void QQmlThread::postMethodToMain(void (O::*Member)(V, V2), const T &arg, const T2 &arg2)
-{
- struct I : public Message {
- void (O::*Member)(V, V2);
- T arg;
- T2 arg2;
- I(void (O::*Member)(V, V2), const T &arg, const T2 &arg2) : Member(Member), arg(arg), arg2(arg2) {}
- void call(QQmlThread *thread) override {
- O *me = static_cast<O *>(thread);
- (me->*Member)(arg, arg2);
- }
- };
- internalPostMethodToMain(new I(Member, arg, arg2));
+ Message *m = createMessageFromMethod(std::forward<Method>(method), std::forward<Args>(args)...);
+ internalPostMethodToMain(m);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/ftw/qrecursionwatcher_p.h b/src/qml/qml/ftw/qrecursionwatcher_p.h
index 56b714f922..668695877e 100644
--- a/src/qml/qml/ftw/qrecursionwatcher_p.h
+++ b/src/qml/qml/ftw/qrecursionwatcher_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRECURSIONWATCHER_P_H
#define QRECURSIONWATCHER_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/ftw/qrecyclepool_p.h b/src/qml/qml/ftw/qrecyclepool_p.h
index 39f4f88512..6661c88631 100644
--- a/src/qml/qml/ftw/qrecyclepool_p.h
+++ b/src/qml/qml/ftw/qrecyclepool_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRECYCLEPOOL_P_H
#define QRECYCLEPOOL_P_H
@@ -51,6 +15,10 @@
// We mean it.
//
+#include <QtCore/private/qglobal_p.h>
+
+#include <QtCore/q20memory.h>
+
QT_BEGIN_NAMESPACE
#define QRECYCLEPOOLCOOKIE 0x33218ADF
@@ -101,11 +69,8 @@ public:
inline QRecyclePool();
inline ~QRecyclePool();
- inline T *New();
- template<typename T1>
- inline T *New(const T1 &);
- template<typename T1>
- inline T *New(T1 &);
+ template<typename...Args>
+ [[nodiscard]] inline T *New(Args&&...args);
static inline void Delete(T *);
@@ -127,29 +92,10 @@ QRecyclePool<T, Step>::~QRecyclePool()
}
template<typename T, int Step>
-T *QRecyclePool<T, Step>::New()
-{
- T *rv = d->allocate();
- new (rv) T;
- return rv;
-}
-
-template<typename T, int Step>
-template<typename T1>
-T *QRecyclePool<T, Step>::New(const T1 &a)
+template<typename...Args>
+T *QRecyclePool<T, Step>::New(Args&&...args)
{
- T *rv = d->allocate();
- new (rv) T(a);
- return rv;
-}
-
-template<typename T, int Step>
-template<typename T1>
-T *QRecyclePool<T, Step>::New(T1 &a)
-{
- T *rv = d->allocate();
- new (rv) T(a);
- return rv;
+ return q20::construct_at(d->allocate(), std::forward<Args>(args)...);
}
template<typename T, int Step>
diff --git a/src/qml/qml/ftw/qstringhash_p.h b/src/qml/qml/ftw/qstringhash_p.h
index f9435b4919..c431a4d6b3 100644
--- a/src/qml/qml/ftw/qstringhash_p.h
+++ b/src/qml/qml/ftw/qstringhash_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSTRINGHASH_P_H
#define QSTRINGHASH_P_H
@@ -54,25 +18,34 @@
#include <private/qhashedstring_p.h>
#include <private/qprimefornumbits_p.h>
-#include <QtCore/qglobal.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qtaggedpointer.h>
QT_BEGIN_NAMESPACE
+static inline QString::DataPointer &mutableStringData(const QHashedString &key)
+{
+ return const_cast<QHashedString &>(key).data_ptr();
+}
+
class QStringHashData;
class QStringHashNode
{
public:
QStringHashNode()
- : ckey(nullptr)
{
}
QStringHashNode(const QHashedString &key)
- : length(key.length()), hash(key.hash()), symbolId(0)
+ : length(int(key.size())), hash(key.hash()), symbolId(0)
+ , arrayData(mutableStringData(key).d_ptr())
+ , strData(mutableStringData(key).data())
{
- strData = const_cast<QHashedString &>(key).data_ptr();
+ Q_ASSERT(key.size() <= std::numeric_limits<int>::max());
+ if (arrayData)
+ arrayData->ref();
setQString(true);
- strData->ref.ref();
}
QStringHashNode(const QHashedCStringRef &key)
@@ -81,49 +54,63 @@ public:
}
QStringHashNode(const QStringHashNode &o)
- : length(o.length), hash(o.hash), symbolId(o.symbolId), ckey(o.ckey)
+ : length(o.length), hash(o.hash), symbolId(o.symbolId), arrayData(o.arrayData)
{
setQString(o.isQString());
- if (isQString()) { strData->ref.ref(); }
+ if (isQString()) {
+ strData = o.strData;
+ if (arrayData)
+ arrayData->ref();
+ } else {
+ ckey = o.ckey;
+ }
}
~QStringHashNode()
{
- if (isQString()) { if (!strData->ref.deref()) free(strData); }
+ if (isQString() && arrayData && !arrayData->deref())
+ QTypedArrayData<char16_t>::deallocate(arrayData);
}
- QFlagPointer<QStringHashNode> next;
+ enum Tag {
+ NodeIsCString,
+ NodeIsQString
+ };
+
+ QTaggedPointer<QStringHashNode, Tag> next;
qint32 length = 0;
quint32 hash = 0;
quint32 symbolId = 0;
+ QTypedArrayData<char16_t> *arrayData = nullptr;
union {
- const char *ckey;
- QStringData *strData;
+ const char *ckey = nullptr;
+ char16_t *strData;
};
inline QHashedString key() const
{
- if (isQString())
- return QHashedString(QString((QChar *)strData->data(), length), hash);
+ if (isQString()) {
+ if (arrayData)
+ arrayData->ref();
+ return QHashedString(QString(QStringPrivate(arrayData, strData, length)), hash);
+ }
return QHashedString(QString::fromLatin1(ckey, length), hash);
}
- bool isQString() const { return next.flag(); }
- void setQString(bool v) { if (v) next.setFlag(); else next.clearFlag(); }
+ bool isQString() const { return next.tag() == NodeIsQString; }
+ void setQString(bool v) { if (v) next.setTag(NodeIsQString); else next.setTag(NodeIsCString); }
- inline char *cStrData() const { return (char *)ckey; }
- inline quint16 *utf16Data() const { return (quint16 *)strData->data(); }
+ inline qsizetype size() const { return length; }
+ inline const char *cStrData() const { return ckey; }
+ inline const char16_t *utf16Data() const { return strData; }
inline bool equals(const QV4::Value &string) const {
QString s = string.toQStringNoThrow();
if (isQString()) {
- QStringDataPtr dd;
- dd.ptr = strData;
- strData->ref.ref();
- return QString(dd) == s;
+ return QStringView(utf16Data(), length) == s;
} else {
return QLatin1String(cStrData(), length) == s;
}
@@ -133,10 +120,7 @@ public:
if (length != string->d()->length() || hash != string->hashValue())
return false;
if (isQString()) {
- QStringDataPtr dd;
- dd.ptr = strData;
- strData->ref.ref();
- return QString(dd) == string->toQString();
+ return QStringView(utf16Data(), length) == string->toQString();
} else {
return QLatin1String(cStrData(), length) == string->toQString();
}
@@ -145,7 +129,7 @@ public:
inline bool equals(const QHashedStringRef &string) const {
return length == string.length() &&
hash == string.hash() &&
- (isQString()?QHashedString::compare(string.constData(), (const QChar *)utf16Data(), length):
+ (isQString()? string == QStringView {utf16Data(), length}:
QHashedString::compare(string.constData(), cStrData(), length));
}
@@ -237,7 +221,7 @@ template<typename T>
struct HashedForm {};
template<> struct HashedForm<QString> { typedef QHashedString Type; };
-template<> struct HashedForm<QStringRef> { typedef QHashedStringRef Type; };
+template<> struct HashedForm<QStringView> { typedef QHashedStringRef Type; };
template<> struct HashedForm<QHashedString> { typedef const QHashedString &Type; };
template<> struct HashedForm<QV4::String *> { typedef const QV4::String *Type; };
template<> struct HashedForm<const QV4::String *> { typedef const QV4::String *Type; };
@@ -249,13 +233,21 @@ class QStringHashBase
{
public:
static HashedForm<QString>::Type hashedString(const QString &s) { return QHashedString(s);}
- static HashedForm<QStringRef>::Type hashedString(const QStringRef &s) { return QHashedStringRef(s.constData(), s.size());}
+ static HashedForm<QStringView>::Type hashedString(QStringView s)
+ {
+ Q_ASSERT(s.size() <= std::numeric_limits<int>::max());
+ return QHashedStringRef(s.constData(), int(s.size()));
+ }
static HashedForm<QHashedString>::Type hashedString(const QHashedString &s) { return s; }
static HashedForm<QV4::String *>::Type hashedString(QV4::String *s) { return s; }
static HashedForm<const QV4::String *>::Type hashedString(const QV4::String *s) { return s; }
static HashedForm<QHashedStringRef>::Type hashedString(const QHashedStringRef &s) { return s; }
- static HashedForm<QLatin1String>::Type hashedString(const QLatin1String &s) { return QHashedCStringRef(s.data(), s.size()); }
+ static HashedForm<QLatin1StringView>::Type hashedString(QLatin1StringView s)
+ {
+ Q_ASSERT(s.size() <= std::numeric_limits<int>::max());
+ return QHashedCStringRef(s.data(), int(s.size()));
+ }
static HashedForm<QHashedCStringRef>::Type hashedString(const QHashedCStringRef &s) { return s; }
static const QString &toQString(const QString &s) { return s; }
@@ -508,10 +500,12 @@ int QStringHash<T>::numBuckets() const
template<class T>
void QStringHash<T>::initializeNode(Node *node, const QHashedString &key)
{
- node->length = key.length();
+ node->length = key.size();
node->hash = key.hash();
- node->strData = const_cast<QHashedString &>(key).data_ptr();
- node->strData->ref.ref();
+ node->arrayData = mutableStringData(key).d_ptr();
+ node->strData = mutableStringData(key).data();
+ if (node->arrayData)
+ node->arrayData->ref();
node->setQString(true);
}
@@ -547,10 +541,12 @@ typename QStringHash<T>::Node *QStringHash<T>::takeNode(const Node &o)
Node *rv = nodePool->nodes + nodePool->used++;
rv->length = o.length;
rv->hash = o.hash;
+ rv->arrayData = o.arrayData;
if (o.isQString()) {
rv->strData = o.strData;
- rv->strData->ref.ref();
rv->setQString(true);
+ if (rv->arrayData)
+ rv->arrayData->ref();
} else {
rv->ckey = o.ckey;
}
@@ -700,7 +696,7 @@ typename QStringHash<T>::Node *QStringHash<T>::findNode(const K &key) const
typename HashedForm<K>::Type hashedKey(hashedString(key));
while (node && !node->equals(hashedKey))
- node = (*node->next);
+ node = node->next.data();
return (Node *)node;
}
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
deleted file mode 100644
index a16f3d4167..0000000000
--- a/src/qml/qml/qml.pri
+++ /dev/null
@@ -1,194 +0,0 @@
-SOURCES += \
- $$PWD/qqml.cpp \
- $$PWD/qqmldatablob.cpp \
- $$PWD/qqmldirdata.cpp \
- $$PWD/qqmlerror.cpp \
- $$PWD/qqmlmoduleregistration.cpp \
- $$PWD/qqmlopenmetaobject.cpp \
- $$PWD/qqmlscriptblob.cpp \
- $$PWD/qqmlscriptdata.cpp \
- $$PWD/qqmltypedata.cpp \
- $$PWD/qqmltypeloaderqmldircontent.cpp \
- $$PWD/qqmltypeloaderthread.cpp \
- $$PWD/qqmlvmemetaobject.cpp \
- $$PWD/qqmlengine.cpp \
- $$PWD/qqmlexpression.cpp \
- $$PWD/qqmlproperty.cpp \
- $$PWD/qqmlcomponent.cpp \
- $$PWD/qqmlincubator.cpp \
- $$PWD/qqmlcontext.cpp \
- $$PWD/qqmlcustomparser.cpp \
- $$PWD/qqmlpropertyvaluesource.cpp \
- $$PWD/qqmlpropertyvalueinterceptor.cpp \
- $$PWD/qqmlproxymetaobject.cpp \
- $$PWD/qqmlvme.cpp \
- $$PWD/qqmlboundsignal.cpp \
- $$PWD/qqmlmetatype.cpp \
- $$PWD/qqmlmetatypedata.cpp \
- $$PWD/qqmlstringconverters.cpp \
- $$PWD/qqmltype.cpp \
- $$PWD/qqmltypemodule.cpp \
- $$PWD/qqmltypemoduleversion.cpp \
- $$PWD/qqmlparserstatus.cpp \
- $$PWD/qqmltypeloader.cpp \
- $$PWD/qqmlinfo.cpp \
- $$PWD/qqmlvaluetype.cpp \
- $$PWD/qqmlcleanup.cpp \
- $$PWD/qqmlpropertycache.cpp \
- $$PWD/qqmlmetaobject.cpp \
- $$PWD/qqmlnotifier.cpp \
- $$PWD/qqmlobjectorgadget.cpp \
- $$PWD/qqmlstaticmetaobject.cpp \
- $$PWD/qqmltypenotavailable.cpp \
- $$PWD/qqmltypenamecache.cpp \
- $$PWD/qqmlscriptstring.cpp \
- $$PWD/qqmlnetworkaccessmanagerfactory.cpp \
- $$PWD/qqmlextensionplugin.cpp \
- $$PWD/qqmlimport.cpp \
- $$PWD/qqmllist.cpp \
- $$PWD/qqmljavascriptexpression.cpp \
- $$PWD/qqmlabstractbinding.cpp \
- $$PWD/qqmlvaluetypeproxybinding.cpp \
- $$PWD/qqmlglobal.cpp \
- $$PWD/qqmlfile.cpp \
- $$PWD/qqmlplatform.cpp \
- $$PWD/qqmlbinding.cpp \
- $$PWD/qqmlabstracturlinterceptor.cpp \
- $$PWD/qqmlapplicationengine.cpp \
- $$PWD/qqmllistwrapper.cpp \
- $$PWD/qqmlvaluetypewrapper.cpp \
- $$PWD/qqmltypewrapper.cpp \
- $$PWD/qqmlfileselector.cpp \
- $$PWD/qqmlobjectcreator.cpp \
- $$PWD/qqmldelayedcallqueue.cpp \
- $$PWD/qqmlloggingcategory.cpp \
- $$PWD/qqmlirloader.cpp \
- $$PWD/qqmlpropertyresolver.cpp \
- $$PWD/qqmltypecompiler.cpp \
- $$PWD/qqmlpropertycachecreator.cpp \
- $$PWD/qqmlpropertyvalidator.cpp
-
-HEADERS += \
- $$PWD/qqmldatablob_p.h \
- $$PWD/qqmldirdata_p.h \
- $$PWD/qqmlglobal_p.h \
- $$PWD/qqmlmoduleregistration.h \
- $$PWD/qqmlopenmetaobject_p.h \
- $$PWD/qqmlscriptblob_p.h \
- $$PWD/qqmlscriptdata_p.h \
- $$PWD/qqmltypedata_p.h \
- $$PWD/qqmltypeloaderqmldircontent_p.h \
- $$PWD/qqmltypeloaderthread_p.h \
- $$PWD/qqmlvmemetaobject_p.h \
- $$PWD/qqml.h \
- $$PWD/qqmlerror.h \
- $$PWD/qqmlproperty.h \
- $$PWD/qqmlcomponent.h \
- $$PWD/qqmlcomponent_p.h \
- $$PWD/qqmlincubator.h \
- $$PWD/qqmlincubator_p.h \
- $$PWD/qqmlcustomparser_p.h \
- $$PWD/qqmlpropertyvaluesource.h \
- $$PWD/qqmlpropertyvalueinterceptor_p.h \
- $$PWD/qqmlboundsignal_p.h \
- $$PWD/qqmlboundsignalexpressionpointer_p.h \
- $$PWD/qqmlparserstatus.h \
- $$PWD/qqmlproxymetaobject_p.h \
- $$PWD/qqmlvme_p.h \
- $$PWD/qqmlengine_p.h \
- $$PWD/qqmlexpression_p.h \
- $$PWD/qqmlprivate.h \
- $$PWD/qqmlmetatype_p.h \
- $$PWD/qqmlmetatypedata_p.h \
- $$PWD/qqmltype_p.h \
- $$PWD/qqmltype_p_p.h \
- $$PWD/qqmltypemodule_p.h \
- $$PWD/qqmltypemodule_p_p.h \
- $$PWD/qqmltypemoduleversion_p.h \
- $$PWD/qqmlengine.h \
- $$PWD/qqmlcontext.h \
- $$PWD/qqmlexpression.h \
- $$PWD/qqmlstringconverters_p.h \
- $$PWD/qqmlinfo.h \
- $$PWD/qqmlproperty_p.h \
- $$PWD/qqmlcontext_p.h \
- $$PWD/qqmltypeloader_p.h \
- $$PWD/qqmllist.h \
- $$PWD/qqmllist_p.h \
- $$PWD/qqmldata_p.h \
- $$PWD/qqmlvaluetype_p.h \
- $$PWD/qqmlcleanup_p.h \
- $$PWD/qqmlenumdata_p.h \
- $$PWD/qqmlenumvalue_p.h \
- $$PWD/qqmlpropertycache_p.h \
- $$PWD/qqmlpropertycachemethodarguments_p.h \
- $$PWD/qqmlpropertycachevector_p.h \
- $$PWD/qqmlpropertydata_p.h \
- $$PWD/qqmlpropertyindex_p.h \
- $$PWD/qqmlmetaobject_p.h \
- $$PWD/qqmlnotifier_p.h \
- $$PWD/qqmlobjectorgadget_p.h \
- $$PWD/qqmlstaticmetaobject_p.h \
- $$PWD/qqmltypenotavailable_p.h \
- $$PWD/qqmltypenamecache_p.h \
- $$PWD/qqmlscriptstring.h \
- $$PWD/qqmlguard_p.h \
- $$PWD/qqmlnetworkaccessmanagerfactory.h \
- $$PWD/qqmlextensioninterface.h \
- $$PWD/qqmlimport_p.h \
- $$PWD/qqmlextensionplugin.h \
- $$PWD/qqmlscriptstring_p.h \
- $$PWD/qqmlcomponentattached_p.h \
- $$PWD/qqmljavascriptexpression_p.h \
- $$PWD/qqmlabstractbinding_p.h \
- $$PWD/qqmlvaluetypeproxybinding_p.h \
- $$PWD/qqmlfile.h \
- $$PWD/qqmlplatform_p.h \
- $$PWD/qqmlbinding_p.h \
- $$PWD/qqmlextensionplugin_p.h \
- $$PWD/qqmlabstracturlinterceptor.h \
- $$PWD/qqmlapplicationengine_p.h \
- $$PWD/qqmlapplicationengine.h \
- $$PWD/qqmllistwrapper_p.h \
- $$PWD/qqmltypewrapper_p.h \
- $$PWD/qqmlfileselector_p.h \
- $$PWD/qqmlfileselector.h \
- $$PWD/qqmlobjectcreator_p.h \
- $$PWD/qqmldelayedcallqueue_p.h \
- $$PWD/qqmlloggingcategory_p.h \
- $$PWD/qqmlirloader_p.h \
- $$PWD/qqmlpropertyresolver_p.h \
- $$PWD/qqmltypecompiler_p.h \
- $$PWD/qqmlpropertycachecreator_p.h \
- $$PWD/qqmlpropertyvalidator_p.h \
- $$PWD/qqmlsourcecoordinate_p.h
-
-qtConfig(qml-xml-http-request) {
- HEADERS += \
- $$PWD/qqmlxmlhttprequest_p.h
-
- SOURCES += \
- $$PWD/qqmlxmlhttprequest.cpp
-
-}
-
-qtConfig(qml-locale) {
- HEADERS += \
- $$PWD/qqmllocale_p.h
-
- SOURCES += \
- $$PWD/qqmllocale.cpp
-}
-
-qtConfig(qml-network) {
- HEADERS += \
- $$PWD/qqmltypeloadernetworkreplyproxy_p.h
-
- SOURCES += \
- $$PWD/qqmltypeloadernetworkreplyproxy.cpp
-}
-
-android: DEFINES += LIBS_SUFFIX='\\"_$${QT_ARCH}.so\\"'
-
-include(ftw/ftw.pri)
-include(v8/v8.pri)
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index a33936647f..eb716671b1 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -1,56 +1,232 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqml.h"
#include <QtQml/qqmlprivate.h>
+#include <private/qjsvalue_p.h>
+#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmlcomponent_p.h>
#include <private/qqmlengine_p.h>
+#include <private/qqmlfinalizer_p.h>
+#include <private/qqmlloggingcategory_p.h>
#include <private/qqmlmetatype_p.h>
#include <private/qqmlmetatypedata_p.h>
#include <private/qqmltype_p_p.h>
-#include <private/qqmltypemodule_p_p.h>
+#include <private/qqmltypemodule_p.h>
+#include <private/qqmltypewrapper_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qv4dateobject_p.h>
+#include <private/qv4errorobject_p.h>
+#include <private/qv4identifiertable_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4qobjectwrapper_p.h>
#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQml);
+Q_DECLARE_LOGGING_CATEGORY(lcJs);
+
+/*!
+ \internal
+
+ This method completes the setup of all deferred properties of \a object.
+ Deferred properties are declared with
+ Q_CLASSINFO("DeferredPropertyNames", "comma,separated,property,list");
+
+ Any binding to a deferred property is not executed when the object is instantiated,
+ but only when completion is requested with qmlExecuteDeferred, or by manually
+ calling QQmlComponentPrivate::beginDeferred and completeDeferred.
+
+ \sa QV4::CompiledData::Binding::IsDeferredBinding,
+ QV4::CompiledData::Object::HasDeferredBindings,
+ QQmlData::deferData,
+ QQmlObjectCreator::setupBindings
+*/
+void qmlExecuteDeferred(QObject *object)
+{
+ QQmlData *data = QQmlData::get(object);
+
+ if (!data
+ || !data->context
+ || !data->context->engine()
+ || data->deferredData.isEmpty()
+ || data->wasDeleted(object)) {
+ return;
+ }
+
+ if (!data->propertyCache)
+ data->propertyCache = QQmlMetaType::propertyCache(object->metaObject());
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
+
+ QQmlComponentPrivate::DeferredState state;
+ QQmlComponentPrivate::beginDeferred(ep, object, &state);
+
+ // Release the reference for the deferral action (we still have one from construction)
+ data->releaseDeferredData();
+
+ QQmlComponentPrivate::completeDeferred(ep, &state);
+}
+
+QQmlContext *qmlContext(const QObject *obj)
+{
+ return QQmlEngine::contextForObject(obj);
+}
+
+QQmlEngine *qmlEngine(const QObject *obj)
+{
+ QQmlData *data = QQmlData::get(obj);
+ if (!data || !data->context)
+ return nullptr;
+ return data->context->engine();
+}
+
+static QObject *resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlData *data,
+ QObject *object, bool create)
+{
+ if (!pf)
+ return nullptr;
+
+ QObject *rv = data->hasExtendedData() ? data->attachedProperties()->value(pf) : 0;
+ if (rv || !create)
+ return rv;
+
+ rv = pf(object);
+
+ if (rv)
+ data->attachedProperties()->insert(pf, rv);
+
+ return rv;
+}
+
+QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object,
+ const QMetaObject *attachedMetaObject)
+{
+ QQmlEngine *engine = object ? qmlEngine(object) : nullptr;
+ return QQmlMetaType::attachedPropertiesFunc(engine ? QQmlEnginePrivate::get(engine) : nullptr,
+ attachedMetaObject);
+}
+
+QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool create)
+{
+ if (!object)
+ return nullptr;
+
+ QQmlData *data = QQmlData::get(object, create);
+
+ // Attached properties are only on objects created by QML,
+ // unless explicitly requested (create==true)
+ if (!data)
+ return nullptr;
+
+ return resolveAttachedProperties(func, data, object, create);
+}
+
+QObject *qmlExtendedObject(QObject *object)
+{
+ return QQmlPrivate::qmlExtendedObject(object, 0);
+}
+
+QObject *QQmlPrivate::qmlExtendedObject(QObject *object, int index)
+{
+ if (!object)
+ return nullptr;
+
+ void *result = nullptr;
+ QObjectPrivate *d = QObjectPrivate::get(object);
+ if (!d->metaObject)
+ return nullptr;
+
+ const int id = d->metaObject->metaCall(
+ object, QMetaObject::CustomCall,
+ QQmlProxyMetaObject::extensionObjectId(index), &result);
+ if (id != QQmlProxyMetaObject::extensionObjectId(index))
+ return nullptr;
+
+ return static_cast<QObject *>(result);
+}
+
+void QQmlPrivate::qmlRegistrationWarning(
+ QQmlPrivate::QmlRegistrationWarning warning, QMetaType metaType)
+{
+ switch (warning) {
+ case UnconstructibleType:
+ qWarning().nospace()
+ << metaType.name()
+ << " is neither a default constructible QObject, nor a default- "
+ << "and copy-constructible Q_GADGET, nor marked as uncreatable.\n"
+ << "You should not use it as a QML type.";
+ break;
+ case UnconstructibleSingleton:
+ qWarning()
+ << "Singleton" << metaType.name()
+ << "needs to be a concrete class with either a default constructor"
+ << "or, when adding a default constructor is infeasible, a public static"
+ << "create(QQmlEngine *, QJSEngine *) method.";
+ break;
+ case NonQObjectWithAtached:
+ qWarning()
+ << metaType.name()
+ << "is not a QObject, but has attached properties. This won't work.";
+ break;
+ }
+}
+
+QMetaType QQmlPrivate::compositeMetaType(
+ QV4::ExecutableCompilationUnit *unit, const QString &elementName)
+{
+ return QQmlTypePrivate::compositeQmlType(
+ unit->baseCompilationUnit(), unit->engine->typeLoader(), elementName)
+ .typeId();
+}
+
+QMetaType QQmlPrivate::compositeListMetaType(
+ QV4::ExecutableCompilationUnit *unit, const QString &elementName)
+{
+ return QQmlTypePrivate::compositeQmlType(
+ unit->baseCompilationUnit(), unit->engine->typeLoader(), elementName)
+ .qListTypeId();
+}
+
+int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
+ const char *uri, int versionMajor,
+ int versionMinor, const char *qmlName,
+ const QString& reason)
+{
+ QQmlPrivate::RegisterType type = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QMetaType(),
+ QMetaType(),
+ 0,
+ nullptr,
+ nullptr,
+ reason,
+ nullptr,
+
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &staticMetaObject,
+
+ QQmlAttachedPropertiesFunc(),
+ nullptr,
+
+ -1,
+ -1,
+ -1,
+
+ nullptr, nullptr,
+
+ nullptr,
+ QTypeRevision::zero(),
+ -1,
+ QQmlPrivate::ValueTypeCreationMethod::None
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
void qmlClearTypeRegistrations() // Declared in qqml.h
{
QQmlMetaType::clearTypeRegistrations();
@@ -61,60 +237,200 @@ void qmlClearTypeRegistrations() // Declared in qqml.h
//From qqml.h
bool qmlProtectModule(const char *uri, int majVersion)
{
- return QQmlMetaType::protectModule(QString::fromUtf8(uri), majVersion);
+ return QQmlMetaType::protectModule(QString::fromUtf8(uri),
+ QTypeRevision::fromMajorVersion(majVersion));
}
//From qqml.h
void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor)
{
- QQmlMetaType::registerModule(uri, versionMajor, versionMinor);
+ QQmlMetaType::registerModule(uri, QTypeRevision::fromVersion(versionMajor, versionMinor));
+}
+
+static QQmlDirParser::Import resolveImport(const QString &uri, int importMajor, int importMinor)
+{
+ if (importMajor == QQmlModuleImportAuto)
+ return QQmlDirParser::Import(uri, QTypeRevision(), QQmlDirParser::Import::Auto);
+ else if (importMajor == QQmlModuleImportLatest)
+ return QQmlDirParser::Import(uri, QTypeRevision(), QQmlDirParser::Import::Default);
+ else if (importMinor == QQmlModuleImportLatest)
+ return QQmlDirParser::Import(uri, QTypeRevision::fromMajorVersion(importMajor), QQmlDirParser::Import::Default);
+ return QQmlDirParser::Import(uri, QTypeRevision::fromVersion(importMajor, importMinor), QQmlDirParser::Import::Default);
+}
+
+static QTypeRevision resolveModuleVersion(int moduleMajor)
+{
+ return moduleMajor == QQmlModuleImportModuleAny
+ ? QTypeRevision()
+ : QTypeRevision::fromMajorVersion(moduleMajor);
+}
+
+/*!
+ * \enum QQmlModuleImportSpecialVersions
+ * \relates QQmlEngine
+ *
+ * Defines some special values that can be passed to the version arguments of
+ * qmlRegisterModuleImport() and qmlUnregisterModuleImport().
+ *
+ * \value QQmlModuleImportModuleAny When passed as majorVersion of the base
+ * module, signifies that the import is to be
+ * applied to any version of the module.
+ * \value QQmlModuleImportLatest When passed as major or minor version of
+ * the imported module, signifies that the
+ * latest overall, or latest minor version
+ * of a specified major version shall be
+ * imported.
+ * \value QQmlModuleImportAuto When passed as major version of the imported
+ * module, signifies that the version of the
+ * base module shall be forwarded.
+ */
+
+/*!
+ * \relates QQmlEngine
+ * Registers a qmldir-import for module \a uri of major version \a moduleMajor.
+ *
+ * This has the same effect as an \c import statement in a qmldir file: Whenever
+ * \a uri of version \a moduleMajor is imported, \a import of version
+ * \a importMajor. \a importMinor is automatically imported, too. If
+ * \a importMajor is \l QQmlModuleImportLatest the latest version
+ * available of that module is imported, and \a importMinor does not matter. If
+ * \a importMinor is \l QQmlModuleImportLatest the latest minor version of a
+ * \a importMajor is chosen. If \a importMajor is \l QQmlModuleImportAuto the
+ * version of \a import is version of \a uri being imported, and \a importMinor
+ * does not matter. If \a moduleMajor is \l QQmlModuleImportModuleAny the module
+ * import is applied for any major version of \a uri. For example, you may
+ * specify that whenever any version of MyModule is imported, the latest version
+ * of MyOtherModule should be imported. Then, the following call would be
+ * appropriate:
+ *
+ * \code
+ * qmlRegisterModuleImport("MyModule", QQmlModuleImportModuleAny,
+ * "MyOtherModule", QQmlModuleImportLatest);
+ * \endcode
+ *
+ * Or, you may specify that whenever major version 5 of "MyModule" is imported,
+ * then version 3.14 of "MyOtherModule" should be imported:
+ *
+ * \code
+ * qmlRegisterModuleImport("MyModule", 5, "MyOtherModule", 3, 14);
+ * \endcode
+ *
+ * Finally, if you always want the same version of "MyOtherModule" to be
+ * imported whenever "MyModule" is imported, specify the following:
+ *
+ * \code
+ * qmlRegisterModuleImport("MyModule", QQmlModuleImportModuleAny,
+ * "MyOtherModule", QQmlModuleImportAuto);
+ * \endcode
+ *
+ * \sa qmlUnregisterModuleImport()
+ */
+void qmlRegisterModuleImport(const char *uri, int moduleMajor,
+ const char *import, int importMajor, int importMinor)
+{
+ QQmlMetaType::registerModuleImport(
+ QString::fromUtf8(uri), resolveModuleVersion(moduleMajor),
+ resolveImport(QString::fromUtf8(import), importMajor, importMinor));
+}
+
+
+/*!
+ * \relates QQmlEngine
+ * Removes a module import previously registered with qmlRegisterModuleImport()
+ *
+ * Calling this function makes sure that \a import of version
+ * \a{importMajor}.\a{importMinor} is not automatically imported anymore when
+ * \a uri of version \a moduleMajor is. The version resolution works the same
+ * way as with \l qmlRegisterModuleImport().
+ *
+ * \sa qmlRegisterModuleImport()
+ */
+void qmlUnregisterModuleImport(const char *uri, int moduleMajor,
+ const char *import, int importMajor, int importMinor)
+{
+ QQmlMetaType::unregisterModuleImport(
+ QString::fromUtf8(uri), resolveModuleVersion(moduleMajor),
+ resolveImport(QString::fromUtf8(import), importMajor, importMinor));
}
//From qqml.h
int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
- return QQmlMetaType::typeId(uri, versionMajor, versionMinor, qmlName);
+ return QQmlMetaType::typeId(uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName);
}
-// From qqmlprivate.h
-QObject *QQmlPrivate::RegisterSingletonFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
+static bool checkSingletonInstance(QQmlEngine *engine, QObject *instance)
{
- if (!m_object) {
+ if (!instance) {
QQmlError error;
- error.setDescription(QLatin1String("The registered singleton has already been deleted. Ensure that it outlives the engine."));
- QQmlEnginePrivate::get(qeng)->warning(qeng, error);
- return nullptr;
+ error.setDescription(QStringLiteral("The registered singleton has already been deleted. "
+ "Ensure that it outlives the engine."));
+ QQmlEnginePrivate::get(engine)->warning(engine, error);
+ return false;
}
- if (qeng->thread() != m_object->thread()) {
+ if (engine->thread() != instance->thread()) {
+ QQmlError error;
+ error.setDescription(QStringLiteral("Registered object must live in the same thread "
+ "as the engine it was registered with"));
+ QQmlEnginePrivate::get(engine)->warning(engine, error);
+ return false;
+ }
+
+ return true;
+}
+
+// From qqmlprivate.h
+#if QT_DEPRECATED_SINCE(6, 3)
+QObject *QQmlPrivate::SingletonFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
+{
+ if (!checkSingletonInstance(qeng, m_object))
+ return nullptr;
+
+ if (alreadyCalled) {
QQmlError error;
- error.setDescription(QLatin1String("Registered object must live in the same thread as the engine it was registered with"));
+ error.setDescription(QStringLiteral("Singleton registered by registerSingletonInstance "
+ "must only be accessed from one engine"));
QQmlEnginePrivate::get(qeng)->warning(qeng, error);
return nullptr;
}
- if (alreadyCalled) {
+
+ alreadyCalled = true;
+ QJSEngine::setObjectOwnership(m_object, QQmlEngine::CppOwnership);
+ return m_object;
+};
+#endif
+
+QObject *QQmlPrivate::SingletonInstanceFunctor::operator()(QQmlEngine *qeng, QJSEngine *)
+{
+ if (!checkSingletonInstance(qeng, m_object))
+ return nullptr;
+
+ if (!m_engine) {
+ m_engine = qeng;
+ QJSEngine::setObjectOwnership(m_object, QQmlEngine::CppOwnership);
+ } else if (m_engine != qeng) {
QQmlError error;
error.setDescription(QLatin1String("Singleton registered by registerSingletonInstance must only be accessed from one engine"));
QQmlEnginePrivate::get(qeng)->warning(qeng, error);
return nullptr;
}
- alreadyCalled = true;
- qeng->setObjectOwnership(m_object, QQmlEngine::CppOwnership);
+
return m_object;
};
-static QVector<int> availableRevisions(const QMetaObject *metaObject)
+static QVector<QTypeRevision> availableRevisions(const QMetaObject *metaObject)
{
- QVector<int> revisions;
+ QVector<QTypeRevision> revisions;
if (!metaObject)
return revisions;
const int propertyOffset = metaObject->propertyOffset();
const int propertyCount = metaObject->propertyCount();
- for (int propertyIndex = propertyOffset, propertyEnd = propertyOffset + propertyCount;
- propertyIndex < propertyEnd; ++propertyIndex) {
- const QMetaProperty property = metaObject->property(propertyIndex);
+ for (int coreIndex = propertyOffset, propertyEnd = propertyOffset + propertyCount;
+ coreIndex < propertyEnd; ++coreIndex) {
+ const QMetaProperty property = metaObject->property(coreIndex);
if (int revision = property.revision())
- revisions.append(revision);
+ revisions.append(QTypeRevision::fromEncodedVersion(revision));
}
const int methodOffset = metaObject->methodOffset();
const int methodCount = metaObject->methodCount();
@@ -122,7 +438,7 @@ static QVector<int> availableRevisions(const QMetaObject *metaObject)
methodIndex < methodEnd; ++methodIndex) {
const QMetaMethod method = metaObject->method(methodIndex);
if (int revision = method.revision())
- revisions.append(revision);
+ revisions.append(QTypeRevision::fromEncodedVersion(revision));
}
// Need to also check parent meta objects, as their revisions are inherited.
@@ -132,13 +448,328 @@ static QVector<int> availableRevisions(const QMetaObject *metaObject)
return revisions;
}
+template<typename Registration>
+void assignVersions(Registration *registration, QTypeRevision revision,
+ QTypeRevision defaultVersion)
+{
+ const quint8 majorVersion = revision.hasMajorVersion() ? revision.majorVersion()
+ : defaultVersion.majorVersion();
+ registration->version = revision.hasMinorVersion()
+ ? QTypeRevision::fromVersion(majorVersion, revision.minorVersion())
+ : QTypeRevision::fromMajorVersion(majorVersion);
+ registration->revision = revision;
+}
+
+static QVector<QTypeRevision> prepareRevisions(const QMetaObject *metaObject, QTypeRevision added)
+{
+ auto revisions = availableRevisions(metaObject);
+ revisions.append(added);
+ return revisions;
+}
+
+static void uniqueRevisions(QVector<QTypeRevision> *revisions, QTypeRevision defaultVersion,
+ QTypeRevision added)
+{
+ bool revisionsHaveMajorVersions = false;
+ for (QTypeRevision revision : QVector<QTypeRevision>(*revisions)) { // yes, copy
+ // allow any minor version for each explicitly specified past major one
+ if (revision.hasMajorVersion()) {
+ revisionsHaveMajorVersions = true;
+ if (revision.majorVersion() < defaultVersion.majorVersion())
+ revisions->append(QTypeRevision::fromVersion(revision.majorVersion(), 254));
+ }
+ }
+
+ if (revisionsHaveMajorVersions) {
+ if (!added.hasMajorVersion()) {
+ // If added in unspecified major version, assume default one.
+ revisions->append(QTypeRevision::fromVersion(defaultVersion.majorVersion(),
+ added.minorVersion()));
+ } else if (added.majorVersion() < defaultVersion.majorVersion()) {
+ // If added in past major version, add .0 of default version.
+ revisions->append(QTypeRevision::fromVersion(defaultVersion.majorVersion(), 0));
+ }
+ }
+
+ std::sort(revisions->begin(), revisions->end());
+ const auto it = std::unique(revisions->begin(), revisions->end());
+ revisions->erase(it, revisions->end());
+}
+
+static QQmlType::SingletonInstanceInfo::ConstPtr singletonInstanceInfo(
+ const QQmlPrivate::RegisterSingletonType &type)
+{
+ QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
+ siinfo->scriptCallback = type.scriptApi;
+ siinfo->qobjectCallback = type.qObjectApi;
+ siinfo->typeName = type.typeName;
+ return QQmlType::SingletonInstanceInfo::ConstPtr(
+ siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
+}
+
+static QQmlType::SingletonInstanceInfo::ConstPtr singletonInstanceInfo(
+ const QQmlPrivate::RegisterCompositeSingletonType &type)
+{
+ QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
+ siinfo->url = QQmlTypeLoader::normalize(type.url);
+ siinfo->typeName = type.typeName;
+ return QQmlType::SingletonInstanceInfo::ConstPtr(
+ siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
+}
+
+static int finalizeType(const QQmlType &dtype)
+{
+ if (!dtype.isValid())
+ return -1;
+
+ QQmlMetaType::registerUndeletableType(dtype);
+ return dtype.index();
+}
+
+using ElementNames = QVarLengthArray<const char *, 8>;
+static ElementNames classElementNames(const QMetaObject *metaObject)
+{
+ Q_ASSERT(metaObject);
+ const char *key = "QML.Element";
+
+ const int offset = metaObject->classInfoOffset();
+ const int start = metaObject->classInfoCount() + offset - 1;
+
+ ElementNames elementNames;
+
+ for (int i = start; i >= offset; --i) {
+ const QMetaClassInfo classInfo = metaObject->classInfo(i);
+ if (qstrcmp(key, classInfo.name()) == 0) {
+ const char *elementName = classInfo.value();
+
+ if (qstrcmp(elementName, "auto") == 0) {
+ const char *strippedClassName = metaObject->className();
+ for (const char *c = strippedClassName; *c != '\0'; c++) {
+ if (*c == ':')
+ strippedClassName = c + 1;
+ }
+ elementName = strippedClassName;
+ } else if (qstrcmp(elementName, "anonymous") == 0) {
+ if (elementNames.isEmpty())
+ elementNames.push_back(nullptr);
+ else if (elementNames[0] != nullptr)
+ qWarning() << metaObject->className() << "is both anonymous and named";
+ continue;
+ }
+
+ if (!elementNames.isEmpty() && elementNames[0] == nullptr) {
+ qWarning() << metaObject->className() << "is both anonymous and named";
+ elementNames[0] = elementName;
+ } else {
+ elementNames.push_back(elementName);
+ }
+ }
+ }
+
+ return elementNames;
+}
+
+struct AliasRegistrar
+{
+ AliasRegistrar(const ElementNames *elementNames) : elementNames(elementNames) {}
+
+ void registerAliases(int typeId)
+ {
+ if (elementNames) {
+ for (int i = 1, end = elementNames->length(); i < end; ++i)
+ otherNames.append(QString::fromUtf8(elementNames->at(i)));
+ elementNames = nullptr;
+ }
+
+ for (const QString &otherName : std::as_const(otherNames))
+ QQmlMetaType::registerTypeAlias(typeId, otherName);
+ }
+
+private:
+ const ElementNames *elementNames;
+ QVarLengthArray<QString, 8> otherNames;
+};
+
+
+static void doRegisterTypeAndRevisions(
+ const QQmlPrivate::RegisterTypeAndRevisions &type,
+ const ElementNames &elementNames)
+{
+ using namespace QQmlPrivate;
+
+ const bool isValueType = !(type.typeId.flags() & QMetaType::PointerToQObject);
+ const bool creatable = (elementNames[0] != nullptr || isValueType)
+ && boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true);
+
+ QString noCreateReason;
+ ValueTypeCreationMethod creationMethod = ValueTypeCreationMethod::None;
+
+ if (!creatable) {
+ noCreateReason = QString::fromUtf8(
+ classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
+ if (noCreateReason.isEmpty())
+ noCreateReason = QLatin1String("Type cannot be created in QML.");
+ } else if (isValueType) {
+ const char *method = classInfo(type.classInfoMetaObject, "QML.CreationMethod");
+ if (qstrcmp(method, "structured") == 0)
+ creationMethod = ValueTypeCreationMethod::Structured;
+ else if (qstrcmp(method, "construct") == 0)
+ creationMethod = ValueTypeCreationMethod::Construct;
+ }
+
+ RegisterType typeRevision = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ type.typeId,
+ type.listId,
+ creatable ? type.objectSize : 0,
+ nullptr,
+ nullptr,
+ noCreateReason,
+ type.createValueType,
+ type.uri,
+ type.version,
+ nullptr,
+ type.metaObject,
+ type.attachedPropertiesFunction,
+ type.attachedPropertiesMetaObject,
+ type.parserStatusCast,
+ type.valueSourceCast,
+ type.valueInterceptorCast,
+ type.extensionObjectCreate,
+ type.extensionMetaObject,
+ nullptr,
+ QTypeRevision(),
+ type.structVersion > 0 ? type.finalizerCast : -1,
+ creationMethod
+ };
+
+ QQmlPrivate::RegisterSequentialContainer sequenceRevision = {
+ 0,
+ type.uri,
+ type.version,
+ nullptr,
+ type.listId,
+ type.structVersion > 1 ? type.listMetaSequence : QMetaSequence(),
+ QTypeRevision(),
+ };
+
+ const QTypeRevision added = revisionClassInfo(
+ type.classInfoMetaObject, "QML.AddedInVersion",
+ QTypeRevision::fromVersion(type.version.majorVersion(), 0));
+ const QTypeRevision removed = revisionClassInfo(
+ type.classInfoMetaObject, "QML.RemovedInVersion");
+ const QList<QTypeRevision> furtherRevisions = revisionClassInfos(type.classInfoMetaObject,
+ "QML.ExtraVersion");
+
+ auto revisions = prepareRevisions(type.metaObject, added) + furtherRevisions;
+ if (type.attachedPropertiesMetaObject)
+ revisions += availableRevisions(type.attachedPropertiesMetaObject);
+ uniqueRevisions(&revisions, type.version, added);
+
+ AliasRegistrar aliasRegistrar(&elementNames);
+ for (QTypeRevision revision : revisions) {
+ if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
+ break;
+
+ assignVersions(&typeRevision, revision, type.version);
+
+ // When removed or before added, we still add revisions, but anonymous ones
+ if (typeRevision.version < added
+ || (removed.isValid() && !(typeRevision.version < removed))) {
+ typeRevision.elementName = nullptr;
+ typeRevision.create = nullptr;
+ typeRevision.userdata = nullptr;
+ } else {
+ typeRevision.elementName = elementNames[0];
+ typeRevision.create = creatable ? type.create : nullptr;
+ typeRevision.userdata = type.userdata;
+ }
+
+ typeRevision.customParser = type.customParserFactory();
+ const int id = qmlregister(TypeRegistration, &typeRevision);
+ if (type.qmlTypeIds)
+ type.qmlTypeIds->append(id);
+
+ if (typeRevision.elementName)
+ aliasRegistrar.registerAliases(id);
+
+ if (sequenceRevision.metaSequence != QMetaSequence()) {
+ sequenceRevision.version = typeRevision.version;
+ sequenceRevision.revision = typeRevision.revision;
+ const int id = QQmlPrivate::qmlregister(
+ QQmlPrivate::SequentialContainerRegistration, &sequenceRevision);
+ if (type.qmlTypeIds)
+ type.qmlTypeIds->append(id);
+ }
+ }
+}
+
+static void doRegisterSingletonAndRevisions(
+ const QQmlPrivate::RegisterSingletonTypeAndRevisions &type,
+ const ElementNames &elementNames)
+{
+ using namespace QQmlPrivate;
+
+ RegisterSingletonType revisionRegistration = {
+ 0,
+ type.uri,
+ type.version,
+ elementNames[0],
+ nullptr,
+ type.qObjectApi,
+ type.instanceMetaObject,
+ type.typeId,
+ type.extensionObjectCreate,
+ type.extensionMetaObject,
+ QTypeRevision()
+ };
+ const QQmlType::SingletonInstanceInfo::ConstPtr siinfo
+ = singletonInstanceInfo(revisionRegistration);
+
+ const QTypeRevision added = revisionClassInfo(
+ type.classInfoMetaObject, "QML.AddedInVersion",
+ QTypeRevision::fromVersion(type.version.majorVersion(), 0));
+ const QTypeRevision removed = revisionClassInfo(
+ type.classInfoMetaObject, "QML.RemovedInVersion");
+ const QList<QTypeRevision> furtherRevisions = revisionClassInfos(type.classInfoMetaObject,
+ "QML.ExtraVersion");
+
+ auto revisions = prepareRevisions(type.instanceMetaObject, added) + furtherRevisions;
+ uniqueRevisions(&revisions, type.version, added);
+
+ AliasRegistrar aliasRegistrar(&elementNames);
+ for (QTypeRevision revision : std::as_const(revisions)) {
+ if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
+ break;
+
+ assignVersions(&revisionRegistration, revision, type.version);
+
+ // When removed or before added, we still add revisions, but anonymous ones
+ if (revisionRegistration.version < added
+ || (removed.isValid() && !(revisionRegistration.version < removed))) {
+ revisionRegistration.typeName = nullptr;
+ revisionRegistration.qObjectApi = nullptr;
+ } else {
+ revisionRegistration.typeName = elementNames[0];
+ revisionRegistration.qObjectApi = type.qObjectApi;
+ }
+
+ const int id = finalizeType(
+ QQmlMetaType::registerSingletonType(revisionRegistration, siinfo));
+ if (type.qmlTypeIds)
+ type.qmlTypeIds->append(id);
+
+ if (revisionRegistration.typeName)
+ aliasRegistrar.registerAliases(id);
+ }
+}
+
/*
This method is "over generalized" to allow us to (potentially) register more types of things in
the future without adding exported symbols.
*/
int QQmlPrivate::qmlregister(RegistrationType type, void *data)
{
- QQmlType dtype;
switch (type) {
case AutoParentRegistration:
return QQmlMetaType::registerAutoParentFunction(
@@ -148,149 +779,91 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
*reinterpret_cast<RegisterQmlUnitCacheHook *>(data));
case TypeAndRevisionsRegistration: {
const RegisterTypeAndRevisions &type = *reinterpret_cast<RegisterTypeAndRevisions *>(data);
- const char *elementName = classElementName(type.classInfoMetaObject);
- const bool creatable = (elementName != nullptr)
- && boolClassInfo(type.classInfoMetaObject, "QML.Creatable", true);
-
- const QString noCreateReason = creatable
- ? QString()
- : QString::fromUtf8(classInfo(type.classInfoMetaObject, "QML.UncreatableReason"));
- RegisterType revisionRegistration = {
- 1,
- type.typeId,
- type.listId,
- creatable ? type.objectSize : 0,
- nullptr,
- noCreateReason,
- type.uri,
- type.versionMajor,
- -1,
- nullptr,
- type.metaObject,
- type.attachedPropertiesFunction,
- type.attachedPropertiesMetaObject,
- type.parserStatusCast,
- type.valueSourceCast,
- type.valueInterceptorCast,
- type.extensionObjectCreate,
- type.extensionMetaObject,
- nullptr,
- -1
- };
-
- const int added = intClassInfo(type.classInfoMetaObject, "QML.AddedInMinorVersion", 0);
- const int removed = intClassInfo(type.classInfoMetaObject, "QML.RemovedInMinorVersion", -1);
-
- auto revisions = availableRevisions(type.metaObject);
- revisions.append(qMax(added, 0));
- if (type.attachedPropertiesMetaObject)
- revisions += availableRevisions(type.attachedPropertiesMetaObject);
-
- std::sort(revisions.begin(), revisions.end());
- const auto it = std::unique(revisions.begin(), revisions.end());
- revisions.erase(it, revisions.end());
-
- const bool typeWasRemoved = removed >= added;
- for (int revision : revisions) {
- if (revision < added)
- continue;
-
- // When removed, we still add revisions, but anonymous ones
- if (typeWasRemoved && revision >= removed) {
- revisionRegistration.elementName = nullptr;
- revisionRegistration.create = nullptr;
+ if (type.structVersion > 1 && type.forceAnonymous) {
+ doRegisterTypeAndRevisions(type, {nullptr});
+ } else {
+ const ElementNames names = classElementNames(type.classInfoMetaObject);
+ if (names.isEmpty()) {
+ qWarning().nospace() << "Missing QML.Element class info for "
+ << type.classInfoMetaObject->className();
} else {
- revisionRegistration.elementName = elementName;
- revisionRegistration.create = creatable ? type.create : nullptr;
+ doRegisterTypeAndRevisions(type, names);
}
- // Equivalent of qmlRegisterRevision<T, revision>(...)
- revisionRegistration.versionMinor = revision;
- revisionRegistration.revision = revision;
- revisionRegistration.customParser = type.customParserFactory();
-
- qmlregister(TypeRegistration, &revisionRegistration);
}
break;
}
case SingletonAndRevisionsRegistration: {
const RegisterSingletonTypeAndRevisions &type
= *reinterpret_cast<RegisterSingletonTypeAndRevisions *>(data);
- const char *elementName = classElementName(type.classInfoMetaObject);
- RegisterSingletonType revisionRegistration = {
- QmlCurrentSingletonTypeRegistrationVersion,
+ const ElementNames names = classElementNames(type.classInfoMetaObject);
+ if (names.isEmpty()) {
+ qWarning().nospace() << "Missing QML.Element class info for "
+ << type.classInfoMetaObject->className();
+ } else {
+ doRegisterSingletonAndRevisions(type, names);
+ }
+ break;
+ }
+ case SequentialContainerAndRevisionsRegistration: {
+ const RegisterSequentialContainerAndRevisions &type
+ = *reinterpret_cast<RegisterSequentialContainerAndRevisions *>(data);
+ RegisterSequentialContainer revisionRegistration = {
+ 0,
type.uri,
- type.versionMajor,
- -1,
- elementName,
-
- type.scriptApi,
+ type.version,
nullptr,
- type.instanceMetaObject,
type.typeId,
- -1,
-
- type.generalizedQobjectApi
+ type.metaSequence,
+ QTypeRevision()
};
- const int added = intClassInfo(type.classInfoMetaObject, "QML.AddedInMinorVersion", 0);
- const int removed = intClassInfo(type.classInfoMetaObject, "QML.RemovedInMinorVersion", -1);
-
- auto revisions = availableRevisions(type.instanceMetaObject);
- revisions.append(qMax(added, 0));
+ const QTypeRevision added = revisionClassInfo(
+ type.classInfoMetaObject, "QML.AddedInVersion",
+ QTypeRevision::fromMinorVersion(0));
+ QList<QTypeRevision> revisions = revisionClassInfos(
+ type.classInfoMetaObject, "QML.ExtraVersion");
+ revisions.append(added);
+ uniqueRevisions(&revisions, type.version, added);
- std::sort(revisions.begin(), revisions.end());
- const auto it = std::unique(revisions.begin(), revisions.end());
- revisions.erase(it, revisions.end());
-
- const bool typeWasRemoved = removed >= added;
- for (int revision : qAsConst(revisions)) {
+ for (QTypeRevision revision : std::as_const(revisions)) {
if (revision < added)
continue;
+ if (revision.hasMajorVersion() && revision.majorVersion() > type.version.majorVersion())
+ break;
- // When removed, we still add revisions, but anonymous ones
- if (typeWasRemoved && revision >= removed) {
- revisionRegistration.typeName = nullptr;
- revisionRegistration.scriptApi = nullptr;
- revisionRegistration.generalizedQobjectApi = nullptr;
- } else {
- revisionRegistration.typeName = elementName;
- revisionRegistration.scriptApi = type.scriptApi;
- revisionRegistration.generalizedQobjectApi = type.generalizedQobjectApi;
- }
-
- // Equivalent of qmlRegisterRevision<T, revision>(...)
- revisionRegistration.versionMinor = revision;
- revisionRegistration.revision = revision;
-
- qmlregister(SingletonRegistration, &revisionRegistration);
+ assignVersions(&revisionRegistration, revision, type.version);
+ const int id = qmlregister(SequentialContainerRegistration, &revisionRegistration);
+ if (type.qmlTypeIds)
+ type.qmlTypeIds->append(id);
}
break;
}
case TypeRegistration:
- dtype = QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data));
- break;
+ return finalizeType(
+ QQmlMetaType::registerType(*reinterpret_cast<RegisterType *>(data)));
case InterfaceRegistration:
- dtype = QQmlMetaType::registerInterface(*reinterpret_cast<RegisterInterface *>(data));
- break;
+ return finalizeType(
+ QQmlMetaType::registerInterface(*reinterpret_cast<RegisterInterface *>(data)));
case SingletonRegistration:
- dtype = QQmlMetaType::registerSingletonType(*reinterpret_cast<RegisterSingletonType *>(data));
- break;
+ return finalizeType(QQmlMetaType::registerSingletonType(
+ *reinterpret_cast<RegisterSingletonType *>(data),
+ singletonInstanceInfo(*reinterpret_cast<RegisterSingletonType *>(data))));
case CompositeRegistration:
- dtype = QQmlMetaType::registerCompositeType(*reinterpret_cast<RegisterCompositeType *>(data));
- break;
+ return finalizeType(QQmlMetaType::registerCompositeType(
+ *reinterpret_cast<RegisterCompositeType *>(data)));
case CompositeSingletonRegistration:
- dtype = QQmlMetaType::registerCompositeSingletonType(*reinterpret_cast<RegisterCompositeSingletonType *>(data));
- break;
+ return finalizeType(QQmlMetaType::registerCompositeSingletonType(
+ *reinterpret_cast<RegisterCompositeSingletonType *>(data),
+ singletonInstanceInfo(*reinterpret_cast<RegisterCompositeSingletonType *>(data))));
+ case SequentialContainerRegistration:
+ return finalizeType(QQmlMetaType::registerSequentialContainer(
+ *reinterpret_cast<RegisterSequentialContainer *>(data)));
default:
return -1;
}
- if (!dtype.isValid())
- return -1;
-
- QQmlMetaType::registerUndeletableType(dtype);
- return dtype.index();
+ return -1;
}
void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
@@ -303,6 +876,9 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
QQmlMetaType::removeCachedUnitLookupFunction(
reinterpret_cast<QmlUnitCacheLookupFunction>(data));
break;
+ case SequentialContainerRegistration:
+ QQmlMetaType::unregisterSequentialContainer(data);
+ break;
case TypeRegistration:
case InterfaceRegistration:
case SingletonRegistration:
@@ -312,6 +888,7 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
break;
case TypeAndRevisionsRegistration:
case SingletonAndRevisionsRegistration:
+ case SequentialContainerAndRevisionsRegistration:
// Currently unnecessary. We'd need a special data structure to hold
// URI + majorVersion and then we'd iterate the minor versions, look up the
// associated QQmlType objects by uri/elementName/major/minor and qmlunregister
@@ -321,4 +898,1520 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data)
}
}
+QList<QTypeRevision> QQmlPrivate::revisionClassInfos(const QMetaObject *metaObject,
+ const char *key)
+{
+ QList<QTypeRevision> revisions;
+ for (int index = indexOfOwnClassInfo(metaObject, key); index != -1;
+ index = indexOfOwnClassInfo(metaObject, key, index - 1)) {
+ revisions.push_back(QTypeRevision::fromEncodedVersion(
+ QLatin1StringView(metaObject->classInfo(index).value()).toInt()));
+ }
+ return revisions;
+}
+
+int qmlRegisterTypeNotAvailable(
+ const char *uri, int versionMajor, int versionMinor,
+ const char *qmlName, const QString &message)
+{
+ return qmlRegisterUncreatableType<QQmlTypeNotAvailable>(
+ uri, versionMajor, versionMinor, qmlName, message);
+}
+
+namespace QQmlPrivate {
+template<>
+void qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
+ const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,
+ QVector<int> *qmlTypeIds, const QMetaObject *extension, bool)
+{
+ using T = QQmlTypeNotAvailable;
+
+ RegisterTypeAndRevisions type = {
+ 3,
+ QmlMetaType<T>::self(),
+ QmlMetaType<T>::list(),
+ 0,
+ nullptr,
+ nullptr,
+ nullptr,
+
+ uri,
+ QTypeRevision::fromMajorVersion(versionMajor),
+
+ &QQmlTypeNotAvailable::staticMetaObject,
+ classInfoMetaObject,
+
+ attachedPropertiesFunc<T>(),
+ attachedPropertiesMetaObject<T>(),
+
+ StaticCastSelector<T, QQmlParserStatus>::cast(),
+ StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
+ StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
+
+ nullptr,
+ extension,
+ qmlCreateCustomParser<T>,
+ qmlTypeIds,
+ QQmlPrivate::StaticCastSelector<T, QQmlFinalizerHook>::cast(),
+ false,
+ QmlMetaType<T>::sequence(),
+ };
+
+ qmlregister(TypeAndRevisionsRegistration, &type);
+}
+
+QObject *AOTCompiledContext::thisObject() const
+{
+ return static_cast<QV4::MetaTypesStackFrame *>(engine->handle()->currentStackFrame)
+ ->thisObject();
+}
+
+QQmlEngine *AOTCompiledContext::qmlEngine() const
+{
+ return engine->handle()->qmlEngine();
+}
+
+static QQmlPropertyCapture *propertyCapture(const AOTCompiledContext *aotContext)
+{
+ QQmlEngine *engine = aotContext->qmlEngine();
+ return engine ? QQmlEnginePrivate::get(aotContext->qmlEngine())->propertyCapture : nullptr;
+}
+
+QJSValue AOTCompiledContext::jsMetaType(int index) const
+{
+ return QJSValuePrivate::fromReturnedValue(
+ compilationUnit->runtimeClasses[index]->asReturnedValue());
+}
+
+void AOTCompiledContext::setInstructionPointer(int offset) const
+{
+ if (auto *frame = engine->handle()->currentStackFrame)
+ frame->instructionPointer = offset;
+}
+
+void AOTCompiledContext::setReturnValueUndefined() const
+{
+ if (auto *frame = engine->handle()->currentStackFrame) {
+ Q_ASSERT(frame->isMetaTypesFrame());
+ static_cast<QV4::MetaTypesStackFrame *>(frame)->setReturnValueUndefined();
+ }
+}
+
+static void captureFallbackProperty(
+ QObject *object, int coreIndex, int notifyIndex, bool isConstant,
+ const AOTCompiledContext *aotContext)
+{
+ if (isConstant)
+ return;
+
+ if (QQmlPropertyCapture *capture = propertyCapture(aotContext))
+ capture->captureProperty(object, coreIndex, notifyIndex);
+}
+
+static void captureObjectProperty(
+ QObject *object, const QQmlPropertyCache *propertyCache,
+ const QQmlPropertyData *property, const AOTCompiledContext *aotContext)
+{
+ if (property->isConstant())
+ return;
+
+ if (QQmlPropertyCapture *capture = propertyCapture(aotContext))
+ capture->captureProperty(object, propertyCache, property);
+}
+
+static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCache *ancestor)
+{
+ for (const QQmlPropertyCache *cache = descendent; cache; cache = cache->parent().data()) {
+ if (cache == ancestor)
+ return true;
+ }
+ return false;
+}
+
+enum class ObjectPropertyResult { OK, NeedsInit, Deleted };
+
+struct ObjectPropertyQmlData
+{
+ QQmlData *qmlData;
+ ObjectPropertyResult result;
+};
+
+template<bool StrictType>
+ObjectPropertyQmlData findObjectPropertyQmlData(QV4::Lookup *l, QObject *object)
+{
+ QQmlData *qmlData = QQmlData::get(object);
+ if (!qmlData)
+ return {qmlData, ObjectPropertyResult::NeedsInit};
+ if (qmlData->isQueuedForDeletion)
+ return {qmlData, ObjectPropertyResult::Deleted};
+ Q_ASSERT(!QQmlData::wasDeleted(object));
+ const QQmlPropertyCache *propertyCache = l->qobjectLookup.propertyCache;
+ if (StrictType) {
+ if (qmlData->propertyCache.data() != propertyCache)
+ return {qmlData, ObjectPropertyResult::NeedsInit};
+ } else if (!inherits(qmlData->propertyCache.data(), propertyCache)) {
+ return {qmlData, ObjectPropertyResult::NeedsInit};
+ }
+ return {qmlData, ObjectPropertyResult::OK};
+}
+
+template<bool StrictType = false>
+ObjectPropertyResult loadObjectProperty(
+ QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
+{
+ const ObjectPropertyQmlData data = findObjectPropertyQmlData<StrictType>(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ const QQmlPropertyData *propertyData = l->qobjectLookup.propertyData;
+ const int coreIndex = propertyData->coreIndex();
+ if (data.qmlData->hasPendingBindingBit(coreIndex))
+ data.qmlData->flushPendingBinding(coreIndex);
+
+ captureObjectProperty(object, l->qobjectLookup.propertyCache, propertyData, aotContext);
+ propertyData->readProperty(object, target);
+ return ObjectPropertyResult::OK;
+}
+
+template<bool StrictType = false>
+ObjectPropertyResult writeBackObjectProperty(QV4::Lookup *l, QObject *object, void *source)
+{
+ const ObjectPropertyQmlData data = findObjectPropertyQmlData<StrictType>(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ l->qobjectLookup.propertyData->writeProperty(object, source, {});
+ return ObjectPropertyResult::OK;
+}
+
+struct FallbackPropertyQmlData
+{
+ QQmlData *qmlData;
+ const QMetaObject *metaObject;
+ ObjectPropertyResult result;
+};
+
+static FallbackPropertyQmlData findFallbackPropertyQmlData(QV4::Lookup *l, QObject *object)
+{
+ QQmlData *qmlData = QQmlData::get(object);
+ if (qmlData && qmlData->isQueuedForDeletion)
+ return {qmlData, nullptr, ObjectPropertyResult::Deleted};
+
+ Q_ASSERT(!QQmlData::wasDeleted(object));
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ if (!metaObject || metaObject != object->metaObject())
+ return {qmlData, nullptr, ObjectPropertyResult::NeedsInit};
+
+ return {qmlData, metaObject, ObjectPropertyResult::OK};
+}
+
+static ObjectPropertyResult loadFallbackProperty(
+ QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
+{
+ const FallbackPropertyQmlData data = findFallbackPropertyQmlData(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ if (data.qmlData && data.qmlData->hasPendingBindingBit(coreIndex))
+ data.qmlData->flushPendingBinding(coreIndex);
+
+ captureFallbackProperty(object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
+ l->qobjectFallbackLookup.isConstant, aotContext);
+
+ void *a[] = { target, nullptr };
+ data.metaObject->metacall(object, QMetaObject::ReadProperty, coreIndex, a);
+
+ return ObjectPropertyResult::OK;
+}
+
+static ObjectPropertyResult writeBackFallbackProperty(QV4::Lookup *l, QObject *object, void *source)
+{
+ const FallbackPropertyQmlData data = findFallbackPropertyQmlData(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ void *a[] = { source, nullptr };
+ data.metaObject->metacall(
+ object, QMetaObject::WriteProperty, l->qobjectFallbackLookup.coreIndex, a);
+
+ return ObjectPropertyResult::OK;
+}
+
+ObjectPropertyResult loadObjectAsVariant(
+ QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
+{
+ QVariant *variant = static_cast<QVariant *>(target);
+ const QMetaType propType = l->qobjectLookup.propertyData->propType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return loadObjectProperty<true>(l, object, variant, aotContext);
+
+ *variant = QVariant(propType);
+ return loadObjectProperty<true>(l, object, variant->data(), aotContext);
+}
+
+ObjectPropertyResult writeBackObjectAsVariant(QV4::Lookup *l, QObject *object, void *source)
+{
+ QVariant *variant = static_cast<QVariant *>(source);
+ const QMetaType propType = l->qobjectLookup.propertyData->propType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return writeBackObjectProperty<true>(l, object, variant);
+
+ Q_ASSERT(variant->metaType() == propType);
+ return writeBackObjectProperty<true>(l, object, variant->data());
+}
+
+ObjectPropertyResult loadFallbackAsVariant(
+ QV4::Lookup *l, QObject *object, void *target, const AOTCompiledContext *aotContext)
+{
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ QVariant *variant = static_cast<QVariant *>(target);
+ const QMetaType propType = metaObject->property(l->qobjectFallbackLookup.coreIndex).metaType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return loadFallbackProperty(l, object, variant, aotContext);
+
+ *variant = QVariant(propType);
+ return loadFallbackProperty(l, object, variant->data(), aotContext);
+}
+
+ObjectPropertyResult writeBackFallbackAsVariant(QV4::Lookup *l, QObject *object, void *source)
+{
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ QVariant *variant = static_cast<QVariant *>(source);
+ const QMetaType propType = metaObject->property(l->qobjectFallbackLookup.coreIndex).metaType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return writeBackFallbackProperty(l, object, variant);
+
+ Q_ASSERT(variant->metaType() == propType);
+ return writeBackFallbackProperty(l, object, variant->data());
+}
+
+template<bool StrictType, typename Op>
+static ObjectPropertyResult changeObjectProperty(QV4::Lookup *l, QObject *object, Op op)
+{
+ const ObjectPropertyQmlData data = findObjectPropertyQmlData<StrictType>(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
+ op(property);
+ return ObjectPropertyResult::OK;
+}
+
+template<bool StrictType = false>
+static ObjectPropertyResult resetObjectProperty(
+ QV4::Lookup *l, QObject *object, QV4::ExecutionEngine *v4)
+{
+ return changeObjectProperty<StrictType>(l, object, [&](const QQmlPropertyData *property) {
+ if (property->isResettable()) {
+ property->resetProperty(object, {});
+ } else {
+ v4->throwError(
+ QLatin1String("Cannot assign [undefined] to ") +
+ QLatin1String(property->propType().name()));
+ }
+ });
+}
+
+template<bool StrictType = false>
+static ObjectPropertyResult storeObjectProperty(QV4::Lookup *l, QObject *object, void *value)
+{
+ return changeObjectProperty<StrictType>(l, object, [&](const QQmlPropertyData *property) {
+ property->writeProperty(object, value, {});
+ });
+}
+
+template<typename Op>
+static ObjectPropertyResult changeFallbackProperty(QV4::Lookup *l, QObject *object, Op op)
+{
+ const FallbackPropertyQmlData data = findFallbackPropertyQmlData(l, object);
+ if (data.result != ObjectPropertyResult::OK)
+ return data.result;
+
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(coreIndex));
+
+ op(data.metaObject, coreIndex);
+ return ObjectPropertyResult::OK;
+}
+
+static ObjectPropertyResult storeFallbackProperty(QV4::Lookup *l, QObject *object, void *value)
+{
+ return changeFallbackProperty(l, object, [&](const QMetaObject *metaObject, int coreIndex) {
+ void *args[] = { value, nullptr };
+ metaObject->metacall(object, QMetaObject::WriteProperty, coreIndex, args);
+ });
+}
+
+static ObjectPropertyResult resetFallbackProperty(
+ QV4::Lookup *l, QObject *object, const QMetaProperty *property, QV4::ExecutionEngine *v4)
+{
+ return changeFallbackProperty(l, object, [&](const QMetaObject *metaObject, int coreIndex) {
+ if (property->isResettable()) {
+ void *args[] = { nullptr };
+ metaObject->metacall(object, QMetaObject::ResetProperty, coreIndex, args);
+ } else {
+ v4->throwError(
+ QLatin1String("Cannot assign [undefined] to ") +
+ QLatin1String(property->typeName()));
+ }
+ });
+}
+
+static bool isTypeCompatible(QMetaType lookupType, QMetaType propertyType)
+{
+ if (!lookupType.isValid()) {
+ // If type is invalid, then the calling code depends on the lookup
+ // to be set up in order to query the type, via lookupResultMetaType.
+ // We cannot verify the type in this case.
+ } else if ((lookupType.flags() & QMetaType::IsQmlList)
+ && (propertyType.flags() & QMetaType::IsQmlList)) {
+ // We want to check the value types here, but we cannot easily do it.
+ // Internally those are all QObject* lists, though.
+ } else if (lookupType.flags() & QMetaType::PointerToQObject) {
+ // We accept any base class as type, too
+
+ const QMetaObject *typeMetaObject = lookupType.metaObject();
+ const QMetaObject *foundMetaObject = propertyType.metaObject();
+ if (!foundMetaObject)
+ foundMetaObject = QQmlMetaType::metaObjectForType(propertyType).metaObject();
+
+ while (foundMetaObject && foundMetaObject != typeMetaObject)
+ foundMetaObject = foundMetaObject->superClass();
+
+ if (!foundMetaObject)
+ return false;
+ } else if (propertyType.flags() & QMetaType::IsEnumeration) {
+ if (propertyType == lookupType)
+ return true;
+
+ // You can pass the underlying type of an enum.
+ // We don't want to check for the actual underlying type because
+ // moc and qmltyperegistrar are not very precise about it. Especially
+ // the long and longlong types can be ambiguous.
+
+ const bool isUnsigned = propertyType.flags() & QMetaType::IsUnsignedEnumeration;
+ switch (propertyType.sizeOf()) {
+ case 1:
+ return isUnsigned
+ ? lookupType == QMetaType::fromType<quint8>()
+ : lookupType == QMetaType::fromType<qint8>();
+ case 2:
+ return isUnsigned
+ ? lookupType == QMetaType::fromType<ushort>()
+ : lookupType == QMetaType::fromType<short>();
+ case 4:
+ // The default type, if moc doesn't know the actual enum type, is int.
+ // However, the compiler can still decide to encode the enum in uint.
+ // Therefore, we also accept int for uint enums.
+ // TODO: This is technically UB.
+ return isUnsigned
+ ? (lookupType == QMetaType::fromType<int>()
+ || lookupType == QMetaType::fromType<uint>())
+ : lookupType == QMetaType::fromType<int>();
+ case 8:
+ return isUnsigned
+ ? lookupType == QMetaType::fromType<qulonglong>()
+ : lookupType == QMetaType::fromType<qlonglong>();
+ }
+
+ return false;
+ } else if (propertyType != lookupType) {
+ return false;
+ }
+ return true;
+}
+
+static ObjectPropertyResult storeObjectAsVariant(
+ QV4::ExecutionEngine *v4, QV4::Lookup *l, QObject *object, void *value)
+{
+ QVariant *variant = static_cast<QVariant *>(value);
+ const QMetaType propType = l->qobjectLookup.propertyData->propType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return storeObjectProperty<true>(l, object, variant);
+
+ if (!variant->isValid())
+ return resetObjectProperty<true>(l, object, v4);
+
+ if (isTypeCompatible(variant->metaType(), propType))
+ return storeObjectProperty<true>(l, object, variant->data());
+
+ QVariant converted(propType);
+ v4->metaTypeFromJS(v4->fromVariant(*variant), propType, converted.data());
+ return storeObjectProperty<true>(l, object, converted.data());
+}
+
+static ObjectPropertyResult storeFallbackAsVariant(
+ QV4::ExecutionEngine *v4, QV4::Lookup *l, QObject *object, void *value)
+{
+ QVariant *variant = static_cast<QVariant *>(value);
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ const QMetaProperty property = metaObject->property(l->qobjectFallbackLookup.coreIndex);
+ const QMetaType propType = property.metaType();
+ if (propType == QMetaType::fromType<QVariant>())
+ return storeFallbackProperty(l, object, variant);
+
+ if (!variant->isValid())
+ return resetFallbackProperty(l, object, &property, v4);
+
+ if (isTypeCompatible(variant->metaType(), propType))
+ return storeFallbackProperty(l, object, variant->data());
+
+ QVariant converted(propType);
+ v4->metaTypeFromJS(v4->fromVariant(*variant), propType, converted.data());
+ return storeFallbackProperty(l, object, converted.data());
+}
+
+enum class ObjectLookupResult {
+ Failure,
+ Object,
+ Fallback,
+ ObjectAsVariant,
+ FallbackAsVariant,
+};
+
+static ObjectLookupResult initObjectLookup(
+ const AOTCompiledContext *aotContext, QV4::Lookup *l, QObject *object, QMetaType type)
+{
+ QV4::Scope scope(aotContext->engine->handle());
+ QV4::PropertyKey id = scope.engine->identifierTable->asPropertyKey(
+ aotContext->compilationUnit->runtimeStrings[l->nameIndex]);
+
+ Q_ASSERT(id.isString());
+
+ QV4::ScopedString name(scope, id.asStringOrSymbol());
+
+ Q_ASSERT(!name->equals(scope.engine->id_toString()));
+ Q_ASSERT(!name->equals(scope.engine->id_destroy()));
+
+ QQmlData *ddata = QQmlData::get(object, true);
+ Q_ASSERT(ddata);
+ if (ddata->isQueuedForDeletion)
+ return ObjectLookupResult::Failure;
+
+ const QQmlPropertyData *property;
+ if (!ddata->propertyCache) {
+ property = QQmlPropertyCache::property(object, name, aotContext->qmlContext, nullptr);
+ } else {
+ property = ddata->propertyCache->property(
+ name.getPointer(), object, aotContext->qmlContext);
+ }
+
+ const bool doVariantLookup = type == QMetaType::fromType<QVariant>();
+ if (!property) {
+ const QMetaObject *metaObject = object->metaObject();
+ if (!metaObject)
+ return ObjectLookupResult::Failure;
+
+ const int coreIndex = metaObject->indexOfProperty(
+ name->toQStringNoThrow().toUtf8().constData());
+ if (coreIndex < 0)
+ return ObjectLookupResult::Failure;
+
+ const QMetaProperty property = metaObject->property(coreIndex);
+ if (!doVariantLookup && !isTypeCompatible(type, property.metaType()))
+ return ObjectLookupResult::Failure;
+
+ l->releasePropertyCache();
+ // & 1 to tell the gc that this is not heap allocated; see markObjects in qv4lookup_p.h
+ l->qobjectFallbackLookup.metaObject = quintptr(metaObject) + 1;
+ l->qobjectFallbackLookup.coreIndex = coreIndex;
+ l->qobjectFallbackLookup.notifyIndex =
+ QMetaObjectPrivate::signalIndex(property.notifySignal());
+ l->qobjectFallbackLookup.isConstant = property.isConstant() ? 1 : 0;
+ return doVariantLookup
+ ? ObjectLookupResult::FallbackAsVariant
+ : ObjectLookupResult::Fallback;
+ }
+
+ if (!doVariantLookup && !isTypeCompatible(type, property->propType()))
+ return ObjectLookupResult::Failure;
+
+ Q_ASSERT(ddata->propertyCache);
+
+ QV4::setupQObjectLookup(l, ddata, property);
+
+ return doVariantLookup
+ ? ObjectLookupResult::ObjectAsVariant
+ : ObjectLookupResult::Object;
+}
+
+static bool initValueLookup(QV4::Lookup *l, QV4::ExecutableCompilationUnit *compilationUnit,
+ const QMetaObject *metaObject, QMetaType type)
+{
+ Q_ASSERT(metaObject);
+ const QByteArray name = compilationUnit->runtimeStrings[l->nameIndex]->toQString().toUtf8();
+ const int coreIndex = metaObject->indexOfProperty(name.constData());
+ QMetaType lookupType = metaObject->property(coreIndex).metaType();
+ if (!isTypeCompatible(type, lookupType))
+ return false;
+ l->qgadgetLookup.metaObject = quintptr(metaObject) + 1;
+ l->qgadgetLookup.coreIndex = coreIndex;
+ l->qgadgetLookup.metaType = lookupType.iface();
+ return true;
+}
+
+static void amendException(QV4::ExecutionEngine *engine)
+{
+ const int missingLineNumber = engine->currentStackFrame->missingLineNumber();
+ const int lineNumber = engine->currentStackFrame->lineNumber();
+ Q_ASSERT(missingLineNumber != lineNumber);
+
+ auto amendStackTrace = [&](QV4::StackTrace *stackTrace) {
+ for (auto it = stackTrace->begin(), end = stackTrace->end(); it != end; ++it) {
+ if (it->line == missingLineNumber) {
+ it->line = lineNumber;
+ break;
+ }
+ }
+ };
+
+ amendStackTrace(&engine->exceptionStackTrace);
+
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::ErrorObject> error(scope, *engine->exceptionValue);
+ if (error) // else some other value was thrown
+ amendStackTrace(error->d()->stackTrace);
+}
+
+
+bool AOTCompiledContext::captureLookup(uint index, QObject *object) const
+{
+ if (!object)
+ return false;
+
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter == QV4::QQmlTypeWrapper::lookupSingletonProperty
+ || l->getter == QV4::Lookup::getterQObject
+ || l->getter == QV4::Lookup::getterQObjectAsVariant) {
+ const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ QQmlData::flushPendingBinding(object, property->coreIndex());
+ captureObjectProperty(object, l->qobjectLookup.propertyCache, property, this);
+ return true;
+ }
+
+ if (l->getter == QV4::Lookup::getterFallback
+ || l->getter == QV4::Lookup::getterFallbackAsVariant) {
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ QQmlData::flushPendingBinding(object, coreIndex);
+ captureFallbackProperty(
+ object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
+ l->qobjectFallbackLookup.isConstant, this);
+ return true;
+ }
+
+ return false;
+}
+
+bool AOTCompiledContext::captureQmlContextPropertyLookup(uint index) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty
+ && l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupContextObjectProperty) {
+ const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ QQmlData::flushPendingBinding(qmlScopeObject, property->coreIndex());
+ captureObjectProperty(qmlScopeObject, l->qobjectLookup.propertyCache, property, this);
+ return true;
+ }
+
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty) {
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ QQmlData::flushPendingBinding(qmlScopeObject, coreIndex);
+ captureFallbackProperty(qmlScopeObject, coreIndex, l->qobjectFallbackLookup.notifyIndex,
+ l->qobjectFallbackLookup.isConstant, this);
+ return true;
+ }
+
+ return false;
+}
+
+void AOTCompiledContext::captureTranslation() const
+{
+ if (QQmlPropertyCapture *capture = propertyCapture(this))
+ capture->captureTranslation();
+}
+
+QString AOTCompiledContext::translationContext() const
+{
+#if QT_CONFIG(translation)
+ return QV4::GlobalExtensions::currentTranslationContext(engine->handle());
+#else
+ return QString();
+#endif
+}
+
+QMetaType AOTCompiledContext::lookupResultMetaType(uint index) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty
+ || l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupContextObjectProperty
+ || l->getter == QV4::QQmlTypeWrapper::lookupSingletonProperty
+ || l->getter == QV4::Lookup::getterQObject
+ || l->setter == QV4::Lookup::setterQObject
+ || l->getter == QV4::Lookup::getterQObjectAsVariant
+ || l->setter == QV4::Lookup::setterQObjectAsVariant) {
+ return l->qobjectLookup.propertyData->propType();
+ } else if (l->getter == QV4::QQmlValueTypeWrapper::lookupGetter) {
+ return QMetaType(l->qgadgetLookup.metaType);
+ } else if (l->getter == QV4::QQmlTypeWrapper::lookupEnumValue) {
+ return QMetaType::fromType<int>();
+ } else if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupIdObject
+ || l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupType
+ || l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupSingleton
+ || l->getter == QV4::QObjectWrapper::lookupAttached) {
+ return QMetaType::fromType<QObject *>();
+ } else if (l->getter == QV4::Lookup::getterFallback
+ || l->setter == QV4::Lookup::setterFallback
+ || l->getter == QV4::Lookup::getterFallbackAsVariant
+ || l->setter == QV4::Lookup::setterFallbackAsVariant
+ || l->qmlContextPropertyGetter
+ == QV4::QQmlContextWrapper::lookupScopeFallbackProperty) {
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ return metaObject->property(coreIndex).metaType();
+ }
+ return QMetaType();
+}
+
+static bool isUndefined(const void *value, QMetaType type)
+{
+ if (type == QMetaType::fromType<QVariant>())
+ return !static_cast<const QVariant *>(value)->isValid();
+ if (type == QMetaType::fromType<QJSValue>())
+ return static_cast<const QJSValue *>(value)->isUndefined();
+ if (type == QMetaType::fromType<QJSPrimitiveValue>()) {
+ return static_cast<const QJSPrimitiveValue *>(value)->type()
+ == QJSPrimitiveValue::Undefined;
+ }
+ return false;
+}
+
+void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType type) const
+{
+ // We don't really use any part of the lookup machinery here.
+ // The QV4::Lookup is created on the stack to conveniently get the property cache, and through
+ // the property cache we store a value into the property.
+
+ QV4::Lookup l;
+ memset(&l, 0, sizeof(QV4::Lookup));
+ l.nameIndex = nameIndex;
+ l.forCall = false;
+ ObjectPropertyResult storeResult = ObjectPropertyResult::NeedsInit;
+ switch (initObjectLookup(this, &l, qmlScopeObject, QMetaType())) {
+ case ObjectLookupResult::ObjectAsVariant:
+ case ObjectLookupResult::Object: {
+ const QMetaType propType = l.qobjectLookup.propertyData->propType();
+ if (isTypeCompatible(type, propType)) {
+ storeResult = storeObjectProperty(&l, qmlScopeObject, value);
+ } else if (isUndefined(value, type)) {
+ storeResult = resetObjectProperty(&l, qmlScopeObject, engine->handle());
+ } else {
+ QVariant var(propType);
+ QV4::ExecutionEngine *v4 = engine->handle();
+ v4->metaTypeFromJS(v4->metaTypeToJS(type, value), propType, var.data());
+ storeResult = storeObjectProperty(&l, qmlScopeObject, var.data());
+ }
+
+ l.qobjectLookup.propertyCache->release();
+ break;
+ }
+ case ObjectLookupResult::FallbackAsVariant:
+ case ObjectLookupResult::Fallback: {
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l.qobjectFallbackLookup.metaObject - 1);
+ const QMetaProperty property = metaObject->property(l.qobjectFallbackLookup.coreIndex);
+ const QMetaType propType = property.metaType();
+ if (isTypeCompatible(type, propType)) {
+ storeResult = storeFallbackProperty(&l, qmlScopeObject, value);
+ } else if (isUndefined(value, type)) {
+ storeResult = resetFallbackProperty(&l, qmlScopeObject, &property, engine->handle());
+ } else {
+ QVariant var(propType);
+ QV4::ExecutionEngine *v4 = engine->handle();
+ v4->metaTypeFromJS(v4->metaTypeToJS(type, value), propType, var.data());
+ storeResult = storeFallbackProperty(&l, qmlScopeObject, var.data());
+ }
+ break;
+ }
+ case ObjectLookupResult::Failure:
+ engine->handle()->throwTypeError();
+ return;
+ }
+
+ switch (storeResult) {
+ case ObjectPropertyResult::NeedsInit:
+ engine->handle()->throwTypeError();
+ break;
+ case ObjectPropertyResult::Deleted:
+ engine->handle()->throwTypeError(
+ QStringLiteral("Value is null and could not be converted to an object"));
+ break;
+ case ObjectPropertyResult::OK:
+ break;
+ }
+}
+
+QJSValue AOTCompiledContext::javaScriptGlobalProperty(uint nameIndex) const
+{
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedString name(scope, compilationUnit->runtimeStrings[nameIndex]);
+ QV4::ScopedObject global(scope, scope.engine->globalObject);
+ return QJSValuePrivate::fromReturnedValue(global->get(name->toPropertyKey()));
+}
+
+const QLoggingCategory *AOTCompiledContext::resolveLoggingCategory(QObject *wrapper, bool *ok) const
+{
+ if (wrapper) {
+ // We have to check this here because you may pass a plain QObject that only
+ // turns out to be a QQmlLoggingCategory at run time.
+ if (QQmlLoggingCategory *qQmlLoggingCategory
+ = qobject_cast<QQmlLoggingCategory *>(wrapper)) {
+ QLoggingCategory *loggingCategory = qQmlLoggingCategory->category();
+ *ok = true;
+ if (!loggingCategory) {
+ engine->handle()->throwError(
+ QStringLiteral("A QmlLoggingCatgory was provided without a valid name"));
+ }
+ return loggingCategory;
+ }
+ }
+
+ *ok = false;
+ return qmlEngine() ? &lcQml() : &lcJs();
+}
+
+void AOTCompiledContext::writeToConsole(
+ QtMsgType type, const QString &message, const QLoggingCategory *loggingCategory) const
+{
+ Q_ASSERT(loggingCategory->isEnabled(type));
+
+ const QV4::CppStackFrame *frame = engine->handle()->currentStackFrame;
+ Q_ASSERT(frame);
+
+ const QByteArray source(frame->source().toUtf8());
+ const QByteArray function(frame->function().toUtf8());
+ QMessageLogger logger(source.constData(), frame->lineNumber(),
+ function.constData(), loggingCategory->categoryName());
+
+ switch (type) {
+ case QtDebugMsg:
+ logger.debug("%s", qUtf8Printable(message));
+ break;
+ case QtInfoMsg:
+ logger.info("%s", qUtf8Printable(message));
+ break;
+ case QtWarningMsg:
+ logger.warning("%s", qUtf8Printable(message));
+ break;
+ case QtCriticalMsg:
+ logger.critical("%s", qUtf8Printable(message));
+ break;
+ default:
+ break;
+ }
+}
+
+QVariant AOTCompiledContext::constructValueType(
+ QMetaType resultMetaType, const QMetaObject *resultMetaObject,
+ int ctorIndex, void *ctorArg) const
+{
+ return QQmlValueTypeProvider::constructValueType(
+ resultMetaType, resultMetaObject, ctorIndex, ctorArg);
+}
+
+QDateTime AOTCompiledContext::constructDateTime(double timestamp) const
+{
+ return QV4::DateObject::timestampToDateTime(timestamp);
+}
+
+QDateTime AOTCompiledContext::constructDateTime(const QString &string) const
+{
+ return QV4::DateObject::stringToDateTime(string, engine->handle());
+}
+
+QDateTime AOTCompiledContext::constructDateTime(
+ double year, double month, double day, double hours,
+ double minutes, double seconds, double msecs) const
+{
+ return constructDateTime(QV4::DateObject::componentsToTimestamp(
+ year, month, day, hours, minutes, seconds, msecs, engine->handle()));
+}
+
+bool AOTCompiledContext::callQmlContextPropertyLookup(
+ uint index, void **args, const QMetaType *types, int argc) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedValue thisObject(scope);
+ QV4::ScopedFunctionObject function(
+ scope, l->qmlContextPropertyGetter(l, scope.engine, thisObject));
+ if (!function) {
+ scope.engine->throwTypeError(
+ QStringLiteral("Property '%1' of object [null] is not a function").arg(
+ compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ }
+
+ function->call(qmlScopeObject, args, types, argc);
+ return !scope.hasException();
+}
+
+void AOTCompiledContext::initCallQmlContextPropertyLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
+}
+
+bool AOTCompiledContext::loadContextIdLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ int objectId = -1;
+ QQmlContextData *context = nullptr;
+ Q_ASSERT(qmlContext);
+
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupIdObject) {
+ objectId = l->qmlContextIdObjectLookup.objectId;
+ context = qmlContext;
+ } else if (l->qmlContextPropertyGetter
+ == QV4::QQmlContextWrapper::lookupIdObjectInParentContext) {
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedString name(scope, compilationUnit->runtimeStrings[l->nameIndex]);
+ for (context = qmlContext; context; context = context->parent().data()) {
+ objectId = context->propertyIndex(name);
+ if (objectId != -1 && objectId < context->numIdValues())
+ break;
+ }
+ } else {
+ return false;
+ }
+
+ Q_ASSERT(objectId >= 0);
+ Q_ASSERT(context != nullptr);
+ QQmlEnginePrivate *engine = QQmlEnginePrivate::get(qmlEngine());
+ if (QQmlPropertyCapture *capture = engine->propertyCapture)
+ capture->captureProperty(context->idValueBindings(objectId));
+ *static_cast<QObject **>(target) = context->idValue(objectId);
+ return true;
+}
+
+void AOTCompiledContext::initLoadContextIdLookup(uint index) const
+{
+ Q_ASSERT(!engine->hasError());
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedString name(scope, compilationUnit->runtimeStrings[l->nameIndex]);
+ const QQmlRefPointer<QQmlContextData> ownContext = qmlContext;
+ for (auto context = ownContext; context; context = context->parent()) {
+ const int propertyIdx = context->propertyIndex(name);
+ if (propertyIdx == -1 || propertyIdx >= context->numIdValues())
+ continue;
+
+ if (context.data() == ownContext.data()) {
+ l->qmlContextIdObjectLookup.objectId = propertyIdx;
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupIdObject;
+ } else {
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupIdObjectInParentContext;
+ }
+
+ return;
+ }
+
+ Q_UNREACHABLE();
+}
+
+bool AOTCompiledContext::callObjectPropertyLookup(
+ uint index, QObject *object, void **args, const QMetaType *types, int argc) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedValue thisObject(scope, QV4::QObjectWrapper::wrap(scope.engine, object));
+ QV4::ScopedFunctionObject function(scope, l->getter(l, engine->handle(), thisObject));
+ if (!function) {
+ scope.engine->throwTypeError(
+ QStringLiteral("Property '%1' of object [object Object] is not a function")
+ .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ }
+
+ function->call(object, args, types, argc);
+ return !scope.hasException();
+}
+
+void AOTCompiledContext::initCallObjectPropertyLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
+}
+
+bool AOTCompiledContext::callGlobalLookup(
+ uint index, void **args, const QMetaType *types, int argc) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedFunctionObject function(scope, l->globalGetter(l, scope.engine));
+ if (!function) {
+ scope.engine->throwTypeError(
+ QStringLiteral("Property '%1' of object [null] is not a function")
+ .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ }
+
+ function->call(nullptr, args, types, argc);
+ return true;
+}
+
+void AOTCompiledContext::initCallGlobalLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
+}
+
+bool AOTCompiledContext::loadGlobalLookup(uint index, void *target, QMetaType type) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (!QV4::ExecutionEngine::metaTypeFromJS(l->globalGetter(l, engine->handle()), type, target)) {
+ engine->handle()->throwTypeError();
+ return false;
+ }
+ return true;
+}
+
+void AOTCompiledContext::initLoadGlobalLookup(uint index) const
+{
+ Q_UNUSED(index);
+ Q_ASSERT(engine->hasError());
+ amendException(engine->handle());
+}
+
+bool AOTCompiledContext::loadScopeObjectPropertyLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+
+ if (!qmlScopeObject) {
+ engine->handle()->throwReferenceError(
+ compilationUnit->runtimeStrings[l->nameIndex]->toQString());
+ return false;
+ }
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty)
+ result = loadObjectProperty(l, qmlScopeObject, target, this);
+ else if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty)
+ result = loadFallbackProperty(l, qmlScopeObject, target, this);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::Deleted:
+ engine->handle()->throwTypeError(
+ QStringLiteral("Cannot read property '%1' of null")
+ .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+bool AOTCompiledContext::writeBackScopeObjectPropertyLookup(uint index, void *source) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty)
+ result = writeBackObjectProperty(l, qmlScopeObject, source);
+ else if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty)
+ result = writeBackFallbackProperty(l, qmlScopeObject, source);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::Deleted: // Silently omit the write back. Same as interpreter
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+void AOTCompiledContext::initLoadScopeObjectPropertyLookup(uint index, QMetaType type) const
+{
+ QV4::ExecutionEngine *v4 = engine->handle();
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+
+ if (v4->hasException) {
+ amendException(v4);
+ return;
+ }
+
+ switch (initObjectLookup(this, l, qmlScopeObject, type)) {
+ case ObjectLookupResult::ObjectAsVariant:
+ case ObjectLookupResult::Object:
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupScopeObjectProperty;
+ break;
+ case ObjectLookupResult::FallbackAsVariant:
+ case ObjectLookupResult::Fallback:
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupScopeFallbackProperty;
+ break;
+ case ObjectLookupResult::Failure:
+ v4->throwTypeError();
+ break;
+ }
+}
+
+bool AOTCompiledContext::loadSingletonLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupSingleton) {
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
+ scope, l->qmlContextSingletonLookup.singletonObject);
+
+ // We don't handle non-QObject singletons (as those can't be declared in qmltypes anyway)
+ Q_ASSERT(wrapper);
+ *static_cast<QObject **>(target) = wrapper->object();
+ return true;
+ }
+
+ return false;
+}
+
+using QmlContextPropertyGetter
+ = QV4::ReturnedValue (*)(QV4::Lookup *l, QV4::ExecutionEngine *engine, QV4::Value *thisObject);
+
+template<QmlContextPropertyGetter qmlContextPropertyGetter>
+static void initTypeWrapperLookup(
+ const AOTCompiledContext *context, QV4::Lookup *l, uint importNamespace)
+{
+ Q_ASSERT(!context->engine->hasError());
+ if (importNamespace != AOTCompiledContext::InvalidStringId) {
+ QV4::Scope scope(context->engine->handle());
+ QV4::ScopedString import(scope, context->compilationUnit->runtimeStrings[importNamespace]);
+
+ QQmlTypeLoader *typeLoader = scope.engine->typeLoader();
+ Q_ASSERT(typeLoader);
+ if (const QQmlImportRef *importRef
+ = context->qmlContext->imports()->query(import, typeLoader).importNamespace) {
+
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
+ scope, QV4::QQmlTypeWrapper::create(
+ scope.engine, nullptr, context->qmlContext->imports(), importRef));
+ wrapper = l->qmlContextPropertyGetter(l, context->engine->handle(), wrapper);
+ l->qmlContextPropertyGetter = qmlContextPropertyGetter;
+ if (qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupSingleton)
+ l->qmlContextSingletonLookup.singletonObject.set(scope.engine, wrapper->heapObject());
+ else if (qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupType)
+ l->qmlTypeLookup.qmlTypeWrapper.set(scope.engine, wrapper->heapObject());
+ return;
+ }
+ scope.engine->throwTypeError();
+ } else {
+ QV4::ExecutionEngine *v4 = context->engine->handle();
+ l->qmlContextPropertyGetter(l, v4, nullptr);
+ if (l->qmlContextPropertyGetter != qmlContextPropertyGetter) {
+ const QString error
+ = QLatin1String(qmlContextPropertyGetter
+ == QV4::QQmlContextWrapper::lookupSingleton
+ ? "%1 was a singleton at compile time, "
+ "but is not a singleton anymore."
+ : "%1 was not a singleton at compile time, "
+ "but is a singleton now.")
+ .arg(context->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
+ v4->throwTypeError(error);
+ }
+ }
+}
+
+void AOTCompiledContext::initLoadSingletonLookup(uint index, uint importNamespace) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ initTypeWrapperLookup<QV4::QQmlContextWrapper::lookupSingleton>(this, l, importNamespace);
+}
+
+bool AOTCompiledContext::loadAttachedLookup(uint index, QObject *object, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QObjectWrapper::lookupAttached)
+ return false;
+
+ QV4::Scope scope(engine->handle());
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(scope, l->qmlTypeLookup.qmlTypeWrapper);
+ Q_ASSERT(wrapper);
+ *static_cast<QObject **>(target) = qmlAttachedPropertiesObject(
+ object, wrapper->d()->type().attachedPropertiesFunction(
+ QQmlEnginePrivate::get(qmlEngine())));
+ return true;
+}
+
+void AOTCompiledContext::initLoadAttachedLookup(
+ uint index, uint importNamespace, QObject *object) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedString name(scope, compilationUnit->runtimeStrings[l->nameIndex]);
+
+ QQmlType type;
+ QQmlTypeLoader *typeLoader = scope.engine->typeLoader();
+ Q_ASSERT(typeLoader);
+ if (importNamespace != InvalidStringId) {
+ QV4::ScopedString import(scope, compilationUnit->runtimeStrings[importNamespace]);
+ if (const QQmlImportRef *importRef
+ = qmlContext->imports()->query(import, typeLoader).importNamespace) {
+ type = qmlContext->imports()->query(name, importRef, typeLoader).type;
+ }
+ } else {
+ type = qmlContext->imports()->query<QQmlImport::AllowRecursion>(name, typeLoader).type;
+ }
+
+ if (!type.isValid()) {
+ scope.engine->throwTypeError();
+ return;
+ }
+
+ QV4::Scoped<QV4::QQmlTypeWrapper> wrapper(
+ scope, QV4::QQmlTypeWrapper::create(scope.engine, object, type,
+ QV4::Heap::QQmlTypeWrapper::ExcludeEnums));
+
+ l->qmlTypeLookup.qmlTypeWrapper.set(scope.engine, wrapper->d());
+ l->getter = QV4::QObjectWrapper::lookupAttached;
+}
+
+bool AOTCompiledContext::loadTypeLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->qmlContextPropertyGetter != QV4::QQmlContextWrapper::lookupType)
+ return false;
+
+ const QV4::Heap::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::Heap::QQmlTypeWrapper *>(
+ l->qmlTypeLookup.qmlTypeWrapper.get());
+
+ QMetaType metaType = typeWrapper->type().typeId();
+ *static_cast<const QMetaObject **>(target)
+ = QQmlMetaType::metaObjectForType(metaType).metaObject();
+ return true;
+}
+
+void AOTCompiledContext::initLoadTypeLookup(uint index, uint importNamespace) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ initTypeWrapperLookup<QV4::QQmlContextWrapper::lookupType>(this, l, importNamespace);
+}
+
+bool AOTCompiledContext::getObjectLookup(uint index, QObject *object, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ const auto doThrow = [&]() {
+ engine->handle()->throwTypeError(
+ QStringLiteral("Cannot read property '%1' of null")
+ .arg(compilationUnit->runtimeStrings[l->nameIndex]->toQString()));
+ return false;
+ };
+
+ if (!object)
+ return doThrow();
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->getter == QV4::Lookup::getterQObject)
+ result = loadObjectProperty(l, object, target, this);
+ else if (l->getter == QV4::Lookup::getterFallback)
+ result = loadFallbackProperty(l, object, target, this);
+ else if (l->getter == QV4::Lookup::getterQObjectAsVariant)
+ result = loadObjectAsVariant(l, object, target, this);
+ else if (l->getter == QV4::Lookup::getterFallbackAsVariant)
+ result = loadFallbackAsVariant(l, object, target, this);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::Deleted:
+ return doThrow();
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+bool AOTCompiledContext::writeBackObjectLookup(uint index, QObject *object, void *source) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (!object)
+ return true;
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->getter == QV4::Lookup::getterQObject)
+ result = writeBackObjectProperty(l, object, source);
+ else if (l->getter == QV4::Lookup::getterFallback)
+ result = writeBackFallbackProperty(l, object, source);
+ else if (l->getter == QV4::Lookup::getterQObjectAsVariant)
+ result = writeBackObjectAsVariant(l, object, source);
+ else if (l->getter == QV4::Lookup::getterFallbackAsVariant)
+ result = writeBackFallbackAsVariant(l, object, source);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::Deleted: // Silently omit the write back
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+void AOTCompiledContext::initGetObjectLookup(uint index, QObject *object, QMetaType type) const
+{
+ QV4::ExecutionEngine *v4 = engine->handle();
+ if (v4->hasException) {
+ amendException(v4);
+ } else {
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ switch (initObjectLookup(this, l, object, type)) {
+ case ObjectLookupResult::Object:
+ l->getter = QV4::Lookup::getterQObject;
+ break;
+ case ObjectLookupResult::ObjectAsVariant:
+ l->getter = QV4::Lookup::getterQObjectAsVariant;
+ break;
+ case ObjectLookupResult::Fallback:
+ l->getter = QV4::Lookup::getterFallback;
+ break;
+ case ObjectLookupResult::FallbackAsVariant:
+ l->getter = QV4::Lookup::getterFallbackAsVariant;
+ break;
+ case ObjectLookupResult::Failure:
+ engine->handle()->throwTypeError();
+ break;
+ }
+ }
+}
+
+bool AOTCompiledContext::getValueLookup(uint index, void *value, void *target) const
+{
+ Q_ASSERT(value);
+
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QQmlValueTypeWrapper::lookupGetter)
+ return false;
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qgadgetLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ void *args[] = { target, nullptr };
+ metaObject->d.static_metacall(
+ reinterpret_cast<QObject*>(value), QMetaObject::ReadProperty,
+ l->qgadgetLookup.coreIndex, args);
+ return true;
+}
+
+bool AOTCompiledContext::writeBackValueLookup(uint index, void *value, void *source) const
+{
+ Q_ASSERT(value);
+
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QQmlValueTypeWrapper::lookupGetter)
+ return false;
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qgadgetLookup.metaObject - 1);
+ Q_ASSERT(metaObject);
+
+ void *args[] = { source, nullptr };
+ metaObject->d.static_metacall(
+ reinterpret_cast<QObject*>(value), QMetaObject::WriteProperty,
+ l->qgadgetLookup.coreIndex, args);
+ return true;
+}
+
+void AOTCompiledContext::initGetValueLookup(
+ uint index, const QMetaObject *metaObject, QMetaType type) const
+{
+ Q_ASSERT(!engine->hasError());
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (initValueLookup(l, compilationUnit, metaObject, type))
+ l->getter = QV4::QQmlValueTypeWrapper::lookupGetter;
+ else
+ engine->handle()->throwTypeError();
+}
+
+bool AOTCompiledContext::getEnumLookup(uint index, void *target) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->getter != QV4::QQmlTypeWrapper::lookupEnumValue)
+ return false;
+ const bool isUnsigned
+ = l->qmlEnumValueLookup.metaType->flags & QMetaType::IsUnsignedEnumeration;
+ const QV4::ReturnedValue encoded = l->qmlEnumValueLookup.encodedEnumValue;
+ switch (l->qmlEnumValueLookup.metaType->size) {
+ case 1:
+ if (isUnsigned)
+ *static_cast<quint8 *>(target) = encoded;
+ else
+ *static_cast<qint8 *>(target) = encoded;
+ return true;
+ case 2:
+ if (isUnsigned)
+ *static_cast<quint16 *>(target) = encoded;
+ else
+ *static_cast<qint16 *>(target) = encoded;
+ return true;
+ case 4:
+ if (isUnsigned)
+ *static_cast<quint32 *>(target) = encoded;
+ else
+ *static_cast<qint32 *>(target) = encoded;
+ return true;
+ case 8:
+ if (isUnsigned)
+ *static_cast<quint64 *>(target) = encoded;
+ else
+ *static_cast<qint64 *>(target) = encoded;
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void AOTCompiledContext::initGetEnumLookup(
+ uint index, const QMetaObject *metaObject,
+ const char *enumerator, const char *enumValue) const
+{
+ Q_ASSERT(!engine->hasError());
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (!metaObject) {
+ engine->handle()->throwTypeError(
+ QStringLiteral("Cannot read property '%1' of undefined")
+ .arg(QString::fromUtf8(enumValue)));
+ return;
+ }
+ const int enumIndex = metaObject->indexOfEnumerator(enumerator);
+ const QMetaEnum metaEnum = metaObject->enumerator(enumIndex);
+ l->qmlEnumValueLookup.encodedEnumValue = metaEnum.keyToValue(enumValue);
+ l->qmlEnumValueLookup.metaType = metaEnum.metaType().iface();
+ l->getter = QV4::QQmlTypeWrapper::lookupEnumValue;
+}
+
+bool AOTCompiledContext::setObjectLookup(uint index, QObject *object, void *value) const
+{
+ const auto doThrow = [&]() {
+ engine->handle()->throwTypeError(
+ QStringLiteral("Value is null and could not be converted to an object"));
+ return false;
+ };
+
+ if (!object)
+ return doThrow();
+
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->setter == QV4::Lookup::setterQObject)
+ result = storeObjectProperty(l, object, value);
+ else if (l->setter == QV4::Lookup::setterFallback)
+ result = storeFallbackProperty(l, object, value);
+ else if (l->setter == QV4::Lookup::setterQObjectAsVariant)
+ result = storeObjectAsVariant(engine->handle(), l, object, value);
+ else if (l->setter == QV4::Lookup::setterFallbackAsVariant)
+ result = storeFallbackAsVariant(engine->handle(), l, object, value);
+ else
+ return false;
+
+ switch (result) {
+ case ObjectPropertyResult::Deleted:
+ return doThrow();
+ case ObjectPropertyResult::NeedsInit:
+ return false;
+ case ObjectPropertyResult::OK:
+ return true;
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
+void AOTCompiledContext::initSetObjectLookup(uint index, QObject *object, QMetaType type) const
+{
+ QV4::ExecutionEngine *v4 = engine->handle();
+ if (v4->hasException) {
+ amendException(v4);
+ } else {
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ switch (initObjectLookup(this, l, object, type)) {
+ case ObjectLookupResult::Object:
+ l->setter = QV4::Lookup::setterQObject;
+ break;
+ case ObjectLookupResult::ObjectAsVariant:
+ l->setter = QV4::Lookup::setterQObjectAsVariant;
+ break;
+ case ObjectLookupResult::Fallback:
+ l->setter = QV4::Lookup::setterFallback;
+ break;
+ case ObjectLookupResult::FallbackAsVariant:
+ l->setter = QV4::Lookup::setterFallbackAsVariant;
+ break;
+ case ObjectLookupResult::Failure:
+ engine->handle()->throwTypeError();
+ break;
+ }
+ }
+}
+
+bool AOTCompiledContext::setValueLookup(
+ uint index, void *target, void *value) const
+{
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (l->setter != QV4::QQmlValueTypeWrapper::lookupSetter)
+ return false;
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qgadgetLookup.metaObject - 1);
+
+ void *args[] = { value, nullptr };
+ metaObject->d.static_metacall(
+ reinterpret_cast<QObject*>(target), QMetaObject::WriteProperty,
+ l->qgadgetLookup.coreIndex, args);
+ return true;
+}
+
+void AOTCompiledContext::initSetValueLookup(uint index, const QMetaObject *metaObject,
+ QMetaType type) const
+{
+ Q_ASSERT(!engine->hasError());
+ QV4::Lookup *l = compilationUnit->runtimeLookups + index;
+ if (initValueLookup(l, compilationUnit, metaObject, type))
+ l->setter = QV4::QQmlValueTypeWrapper::lookupSetter;
+ else
+ engine->handle()->throwTypeError();
+}
+
+} // namespace QQmlPrivate
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index ae3893dd73..3e6441bfa7 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -1,61 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQML_H
#define QQML_H
#include <QtQml/qqmlprivate.h>
+#include <QtQml/qjsvalue.h>
+#include <QtQml/qqmlregistration.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qmetaobject.h>
+#include <QtCore/qmetacontainer.h>
+#include <QtCore/qversionnumber.h>
#define QML_VERSION 0x020000
#define QML_VERSION_STR "2.0"
-#define QML_PRIVATE_NAMESPACE \
- QT_PREPEND_NAMESPACE(QQmlPrivate)
-
-#define QML_REGISTER_TYPES_AND_REVISIONS \
- QT_PREPEND_NAMESPACE(qmlRegisterTypesAndRevisions)
-
#define QML_DECLARE_TYPE(TYPE) \
- Q_DECLARE_METATYPE(TYPE *) \
+ Q_DECLARE_METATYPE(TYPE*) \
Q_DECLARE_METATYPE(QQmlListProperty<TYPE>)
#define QML_DECLARE_TYPE_HASMETATYPE(TYPE) \
@@ -67,52 +29,6 @@
#define QML_DECLARE_INTERFACE_HASMETATYPE(INTERFACE) \
QML_DECLARE_TYPE_HASMETATYPE(INTERFACE)
-#define QML_ELEMENT \
- Q_CLASSINFO("QML.Element", "auto")
-
-#define QML_ANONYMOUS \
- Q_CLASSINFO("QML.Element", "anonymous")
-
-#define QML_NAMED_ELEMENT(NAME) \
- Q_CLASSINFO("QML.Element", #NAME)
-
-#define QML_UNCREATABLE(REASON) \
- Q_CLASSINFO("QML.Creatable", "false") \
- Q_CLASSINFO("QML.UncreatableReason", REASON)
-
-#define QML_SINGLETON \
- Q_CLASSINFO("QML.Singleton", "true") \
- enum class QmlIsSingleton {yes = true}; \
- template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlSingleton; \
- template<typename T, typename... Args> \
- friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor);
-
-#define QML_ADDED_IN_MINOR_VERSION(VERSION) \
- Q_CLASSINFO("QML.AddedInMinorVersion", #VERSION)
-
-#define QML_REMOVED_IN_MINOR_VERSION(VERSION) \
- Q_CLASSINFO("QML.RemovedInMinorVersion", #VERSION)
-
-#define QML_ATTACHED(ATTACHED_TYPE) \
- Q_CLASSINFO("QML.Attached", #ATTACHED_TYPE) \
- using QmlAttachedType = ATTACHED_TYPE; \
- template<class, class, bool> friend struct QML_PRIVATE_NAMESPACE::QmlAttached; \
- template<class> friend struct QML_PRIVATE_NAMESPACE::QmlAttachedAccessor;
-
-#define QML_EXTENDED(EXTENDED_TYPE) \
- Q_CLASSINFO("QML.Extended", #EXTENDED_TYPE) \
- using QmlExtendedType = EXTENDED_TYPE; \
- template<class, class> friend struct QML_PRIVATE_NAMESPACE::QmlExtended; \
- template<typename T, typename... Args> \
- friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor);
-
-#define QML_FOREIGN(FOREIGN_TYPE) \
- Q_CLASSINFO("QML.Foreign", #FOREIGN_TYPE) \
- using QmlForeignType = FOREIGN_TYPE; \
- template<class, class> friend struct QML_PRIVATE_NAMESPACE::QmlResolved; \
- template<typename T, typename... Args> \
- friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor);
-
enum { /* TYPEINFO flags */
QML_HAS_ATTACHED_PROPERTIES = 0x01
};
@@ -139,18 +55,17 @@ QQmlCustomParser *qmlCreateCustomParser();
template<typename T>
int qmlRegisterAnonymousType(const char *uri, int versionMajor)
{
- QML_GETTYPENAMES
-
QQmlPrivate::RegisterType type = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- 0,
- nullptr,
+ nullptr, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, 0, nullptr, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, 0), nullptr,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -162,37 +77,88 @@ int qmlRegisterAnonymousType(const char *uri, int versionMajor)
nullptr, nullptr,
nullptr,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
+//! \internal
+template<typename T, int metaObjectRevisionMinor>
+int qmlRegisterAnonymousType(const char *uri, int versionMajor)
+{
+ QQmlPrivate::RegisterType type = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ 0,
+ nullptr,
+ nullptr,
+ QString(),
+ QQmlPrivate::ValueType<T, void>::create,
+
+ uri,
+ QTypeRevision::fromVersion(versionMajor, 0),
+ nullptr,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
+
+ QQmlPrivate::attachedPropertiesFunc<T>(),
+ QQmlPrivate::attachedPropertiesMetaObject<T>(),
+
+ QQmlPrivate::StaticCastSelector<T, QQmlParserStatus>::cast(),
+ QQmlPrivate::StaticCastSelector<T, QQmlPropertyValueSource>::cast(),
+ QQmlPrivate::StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
+
+ nullptr,
+ nullptr,
+
+ nullptr,
+ QTypeRevision::fromMinorVersion(metaObjectRevisionMinor),
+ QQmlPrivate::StaticCastSelector<T, QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
-#if QT_DEPRECATED_SINCE(5, 14)
+//! \internal
template<typename T>
-QT_DEPRECATED_VERSION_X_5_14("Use qmlRegisterAnonymousType instead") int qmlRegisterType()
+void qmlRegisterAnonymousTypesAndRevisions(const char *uri, int versionMajor)
{
- return qmlRegisterAnonymousType<T>("", 1);
+ // Anonymous types are not creatable, no need to warn about missing acceptable constructors.
+ QQmlPrivate::qmlRegisterTypeAndRevisions<T, void>(
+ uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(), nullptr,
+ nullptr, true);
}
-#endif
-int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message);
+class QQmlTypeNotAvailable : public QObject
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(TypeNotAvailable)
+ QML_ADDED_IN_VERSION(2, 15)
+ QML_UNCREATABLE("Type not available.")
+};
+
+int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor,
+ const char *qmlName, const QString &message);
template<typename T>
int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
{
- QML_GETTYPENAMES
-
QQmlPrivate::RegisterType type = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- 0,
+ nullptr,
nullptr,
reason,
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -204,7 +170,9 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
nullptr, nullptr,
nullptr,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -213,18 +181,18 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
template<typename T, int metaObjectRevision>
int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
{
- QML_GETTYPENAMES
-
QQmlPrivate::RegisterType type = {
- 1,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
0,
nullptr,
+ nullptr,
reason,
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -236,7 +204,9 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
nullptr, nullptr,
nullptr,
- metaObjectRevision
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -245,8 +215,6 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin
template<typename T, typename E>
int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
{
- QML_GETTYPENAMES
-
QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>();
const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>();
if (!attached) {
@@ -255,15 +223,17 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
}
QQmlPrivate::RegisterType type = {
- 0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
0,
nullptr,
+ nullptr,
reason,
+ QQmlPrivate::ValueType<T, E>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
attached,
attachedMetaObject,
@@ -272,10 +242,12 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
- QQmlPrivate::createParent<E>, &E::staticMetaObject,
+ QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
nullptr,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -284,8 +256,6 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
template<typename T, typename E, int metaObjectRevision>
int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason)
{
- QML_GETTYPENAMES
-
QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>();
const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>();
if (!attached) {
@@ -294,15 +264,17 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
}
QQmlPrivate::RegisterType type = {
- 1,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
0,
nullptr,
+ nullptr,
reason,
+ QQmlPrivate::ValueType<T, E>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
attached,
attachedMetaObject,
@@ -311,10 +283,12 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
- QQmlPrivate::createParent<E>, &E::staticMetaObject,
+ QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
nullptr,
- metaObjectRevision
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -325,17 +299,20 @@ Q_QML_EXPORT int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaO
template<typename T>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
- QML_GETTYPENAMES
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an abstract type with qmlRegisterType. "
+ "Maybe you wanted qmlRegisterUncreatableType or qmlRegisterInterface?");
QQmlPrivate::RegisterType type = {
- 0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -347,7 +324,9 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c
nullptr, nullptr,
nullptr,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -356,17 +335,20 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c
template<typename T, int metaObjectRevision>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
- QML_GETTYPENAMES
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an abstract type with qmlRegisterType. "
+ "Maybe you wanted qmlRegisterUncreatableType or qmlRegisterInterface?");
QQmlPrivate::RegisterType type = {
- 1,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -378,7 +360,9 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c
nullptr, nullptr,
nullptr,
- metaObjectRevision
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -387,17 +371,16 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c
template<typename T, int metaObjectRevision>
int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
{
- QML_GETTYPENAMES
-
QQmlPrivate::RegisterType type = {
- 1,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, nullptr, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), nullptr,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -409,28 +392,36 @@ int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor)
nullptr, nullptr,
nullptr,
- metaObjectRevision
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
-
template<typename T, typename E>
-int qmlRegisterExtendedType()
+int qmlRegisterExtendedType(const char *uri, int versionMajor)
{
- QML_GETTYPENAMES
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an extension to an abstract type with qmlRegisterExtendedType.");
- QQmlPrivate::RegisterType type = {
- 0,
+ static_assert(!std::is_abstract_v<E>,
+ "It is not possible to register an abstract type with qmlRegisterExtendedType. "
+ "Maybe you wanted qmlRegisterExtendedUncreatableType?");
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
+ QQmlPrivate::RegisterType type = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
0,
nullptr,
+ nullptr,
QString(),
+ QQmlPrivate::ValueType<T, E>::create,
- nullptr, 0, 0, nullptr, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, 0), nullptr,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -439,10 +430,12 @@ int qmlRegisterExtendedType()
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
- QQmlPrivate::createParent<E>, &E::staticMetaObject,
+ QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
nullptr,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -452,7 +445,12 @@ template<typename T, typename E>
int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor,
const char *qmlName)
{
- QML_GETTYPENAMES
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an extension to an abstract type with qmlRegisterExtendedType.");
+
+ static_assert(!std::is_abstract_v<E>,
+ "It is not possible to register an abstract type with qmlRegisterExtendedType. "
+ "Maybe you wanted qmlRegisterExtendedUncreatableType?");
QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>();
const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>();
@@ -462,14 +460,15 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor,
}
QQmlPrivate::RegisterType type = {
- 0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, E>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
attached,
attachedMetaObject,
@@ -478,30 +477,30 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor,
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
- QQmlPrivate::createParent<E>, &E::staticMetaObject,
+ QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
nullptr,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
template<typename T>
-int qmlRegisterInterface(const char *typeName)
+int qmlRegisterInterface(const char *uri, int versionMajor)
{
- QByteArray name(typeName);
-
- QByteArray pointerName(name + '*');
- QByteArray listName("QQmlListProperty<" + name + '>');
-
QQmlPrivate::RegisterInterface qmlInterface = {
0,
+ // An interface is not a QObject itself but is typically casted to one.
+ // Therefore, we still want the pointer.
+ QMetaType::fromType<T *>(),
+ QMetaType::fromType<QQmlListProperty<T> >(),
+ qobject_interface_iid<T *>(),
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
-
- qobject_interface_iid<T *>()
+ uri,
+ QTypeRevision::fromVersion(versionMajor, 0)
};
return QQmlPrivate::qmlregister(QQmlPrivate::InterfaceRegistration, &qmlInterface);
@@ -511,17 +510,20 @@ template<typename T>
int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
const char *qmlName, QQmlCustomParser *parser)
{
- QML_GETTYPENAMES
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an abstract type with qmlRegisterCustomType. "
+ "Maybe you wanted qmlRegisterUncreatableType or qmlRegisterInterface?");
QQmlPrivate::RegisterType type = {
- 0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -533,7 +535,9 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
nullptr, nullptr,
parser,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -543,17 +547,20 @@ template<typename T, int metaObjectRevision>
int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
const char *qmlName, QQmlCustomParser *parser)
{
- QML_GETTYPENAMES
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an abstract type with qmlRegisterCustomType. "
+ "Maybe you wanted qmlRegisterUncreatableType or qmlRegisterInterface?");
QQmlPrivate::RegisterType type = {
- 1,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, void>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
QQmlPrivate::attachedPropertiesFunc<T>(),
QQmlPrivate::attachedPropertiesMetaObject<T>(),
@@ -565,7 +572,9 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor,
nullptr, nullptr,
parser,
- metaObjectRevision
+ QTypeRevision::fromMinorVersion(metaObjectRevision),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -575,7 +584,11 @@ template<typename T, typename E>
int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor,
const char *qmlName, QQmlCustomParser *parser)
{
- QML_GETTYPENAMES
+ static_assert(!std::is_abstract_v<T>,
+ "It is not possible to register an extension to an abstract type with qmlRegisterCustomExtendedType.");
+
+ static_assert(!std::is_abstract_v<E>,
+ "It is not possible to register an abstract type with qmlRegisterCustomExtendedType.");
QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>();
const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>();
@@ -585,14 +598,15 @@ int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int version
}
QQmlPrivate::RegisterType type = {
- 0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- sizeof(T), QQmlPrivate::createInto<T>,
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QQmlPrivate::QmlMetaType<T>::self(),
+ QQmlPrivate::QmlMetaType<T>::list(),
+ sizeof(T), QQmlPrivate::Constructors<T>::createInto, nullptr,
QString(),
+ QQmlPrivate::ValueType<T, E>::create,
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
+ uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName,
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
attached,
attachedMetaObject,
@@ -601,10 +615,12 @@ int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int version
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(),
QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(),
- QQmlPrivate::createParent<E>, &E::staticMetaObject,
+ QQmlPrivate::ExtendedType<E>::createParent, QQmlPrivate::ExtendedType<E>::staticMetaObject(),
parser,
- 0
+ QTypeRevision::zero(),
+ QQmlPrivate::StaticCastSelector<T,QQmlFinalizerHook>::cast(),
+ QQmlPrivate::ValueTypeCreationMethod::None,
};
return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
@@ -615,41 +631,34 @@ class QQmlEngine;
class QJSValue;
class QJSEngine;
-#ifndef Q_QDOC
-namespace QtQml {
-#endif
- // declared in namespace to avoid symbol conflicts with QtDeclarative
- Q_QML_EXPORT void qmlExecuteDeferred(QObject *);
- Q_QML_EXPORT QQmlContext *qmlContext(const QObject *);
- Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *);
-#if QT_DEPRECATED_SINCE(5, 14)
- Q_QML_EXPORT QT_DEPRECATED_VERSION_X_5_14("Use qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc, bool")
- QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true);
- Q_QML_EXPORT QT_DEPRECATED_VERSION_X_5_14("Use qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc, bool")
- QObject *qmlAttachedPropertiesObject(
- int *, const QObject *, const QMetaObject *, bool create);
-#endif
- Q_QML_EXPORT QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *,
- const QMetaObject *);
- Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc func,
- bool create = true);
-#ifndef Q_QDOC
-}
-
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_CLANG("-Wheader-hygiene")
-
-// This is necessary to allow for QtQuick1 and QtQuick2 scenes in a single application.
-using namespace QtQml;
-
-QT_WARNING_POP
-
-#endif // Q_QDOC
+Q_QML_EXPORT void qmlExecuteDeferred(QObject *);
+Q_QML_EXPORT QQmlContext *qmlContext(const QObject *);
+Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *);
+Q_QML_EXPORT QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *,
+ const QMetaObject *);
+Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(QObject *, QQmlAttachedPropertiesFunc func,
+ bool create = true);
+Q_QML_EXPORT QObject *qmlExtendedObject(QObject *);
//The C++ version of protected namespaces in qmldir
Q_QML_EXPORT bool qmlProtectModule(const char* uri, int majVersion);
Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor);
+enum QQmlModuleImportSpecialVersions: int {
+ QQmlModuleImportModuleAny = -1,
+ QQmlModuleImportLatest = -1,
+ QQmlModuleImportAuto = -2
+};
+
+Q_QML_EXPORT void qmlRegisterModuleImport(const char *uri, int moduleMajor,
+ const char *import,
+ int importMajor = QQmlModuleImportLatest,
+ int importMinor = QQmlModuleImportLatest);
+Q_QML_EXPORT void qmlUnregisterModuleImport(const char *uri, int moduleMajor,
+ const char *import,
+ int importMajor = QQmlModuleImportLatest,
+ int importMinor = QQmlModuleImportLatest);
+
template<typename T>
QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
{
@@ -661,62 +670,68 @@ QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
return qmlAttachedPropertiesObject(const_cast<QObject *>(obj), func, create);
}
-inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
- QJSValue (*callback)(QQmlEngine *, QJSEngine *))
+#ifdef Q_QDOC
+int qmlRegisterSingletonType(
+ const char *uri, int versionMajor, int versionMinor, const char *typeName,
+ std::function<QJSValue(QQmlEngine *, QJSEngine *)> callback)
+#else
+template<typename F, typename std::enable_if<std::is_convertible<F, std::function<QJSValue(QQmlEngine *, QJSEngine *)>>::value, void>::type* = nullptr>
+int qmlRegisterSingletonType(
+ const char *uri, int versionMajor, int versionMinor, const char *typeName, F &&callback)
+#endif
{
QQmlPrivate::RegisterSingletonType api = {
0,
-
- uri, versionMajor, versionMinor, typeName,
-
- callback, nullptr, nullptr, 0, 0, {}
+ uri,
+ QTypeRevision::fromVersion(versionMajor, versionMinor),
+ typeName,
+ std::forward<F>(callback),
+ nullptr,
+ nullptr,
+ QMetaType(),
+ nullptr, nullptr,
+ QTypeRevision::zero()
};
return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
}
-enum { QmlCurrentSingletonTypeRegistrationVersion = 3 };
+#ifdef Q_QDOC
template <typename T>
-inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
- QObject *(*callback)(QQmlEngine *, QJSEngine *))
-{
- QML_GETTYPENAMES
-
- QQmlPrivate::RegisterSingletonType api = {
- QmlCurrentSingletonTypeRegistrationVersion,
-
- uri, versionMajor, versionMinor, typeName,
-
- nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback
- };
-
- return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
-}
-
-template <typename T, typename F, typename std::enable_if<std::is_convertible<F, std::function<QObject *(QQmlEngine *, QJSEngine *)>>::value
- && !std::is_convertible<F, QObject *(*)(QQmlEngine *, QJSEngine *)>::value, void>::type* = nullptr>
-inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
- F&& callback)
+int qmlRegisterSingletonType(
+ const char *uri, int versionMajor, int versionMinor, const char *typeName,
+ std::function<QObject *(QQmlEngine *, QJSEngine *)> callback)
+#else
+template<typename T, typename F, typename std::enable_if<std::is_convertible<F, std::function<QObject *(QQmlEngine *, QJSEngine *)>>::value, void>::type* = nullptr>
+int qmlRegisterSingletonType(
+ const char *uri, int versionMajor, int versionMinor, const char *typeName, F &&callback)
+#endif
{
-
- QML_GETTYPENAMES
-
QQmlPrivate::RegisterSingletonType api = {
- QmlCurrentSingletonTypeRegistrationVersion,
-
- uri, versionMajor, versionMinor, typeName,
-
- nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback
+ 0,
+ uri,
+ QTypeRevision::fromVersion(versionMajor, versionMinor),
+ typeName,
+ nullptr,
+ std::forward<F>(callback),
+ QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
+ QQmlPrivate::QmlMetaType<T>::self(),
+ nullptr, nullptr,
+ QTypeRevision::zero()
};
return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
}
+#ifdef Q_QDOC
+int qmlRegisterSingletonInstance(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *cppObject)
+#else
template<typename T>
inline auto qmlRegisterSingletonInstance(const char *uri, int versionMajor, int versionMinor,
const char *typeName, T *cppObject) -> typename std::enable_if<std::is_base_of<QObject, T>::value, int>::type
+#endif
{
- QQmlPrivate::RegisterSingletonFunctor registrationFunctor;
+ QQmlPrivate::SingletonInstanceFunctor registrationFunctor;
registrationFunctor.m_object = cppObject;
return qmlRegisterSingletonType<T>(uri, versionMajor, versionMinor, typeName, registrationFunctor);
}
@@ -730,10 +745,10 @@ inline int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versio
}
QQmlPrivate::RegisterCompositeSingletonType type = {
+ 0,
url,
uri,
- versionMajor,
- versionMinor,
+ QTypeRevision::fromVersion(versionMajor, versionMinor),
qmlName
};
@@ -749,59 +764,218 @@ inline int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, i
}
QQmlPrivate::RegisterCompositeType type = {
+ 0,
url,
uri,
- versionMajor,
- versionMinor,
+ QTypeRevision::fromVersion(versionMajor, versionMinor),
qmlName
};
return QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &type);
}
-template<class T, class Resolved, class Extended, bool Singleton>
+template<typename Container>
+inline int qmlRegisterAnonymousSequentialContainer(const char *uri, int versionMajor)
+{
+ static_assert(!std::is_abstract_v<Container>,
+ "It is not possible to register an abstract container with qmlRegisterAnonymousSequentialContainer.");
+
+ QQmlPrivate::RegisterSequentialContainer type = {
+ 0,
+ uri,
+ QTypeRevision::fromMajorVersion(versionMajor),
+ nullptr,
+ QMetaType::fromType<Container>(),
+ QMetaSequence::fromContainer<Container>(),
+ QTypeRevision::zero()
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::SequentialContainerRegistration, &type);
+}
+
+template<class T, class Resolved, class Extended, bool Singleton, bool Interface, bool Sequence, bool Uncreatable>
struct QmlTypeAndRevisionsRegistration;
template<class T, class Resolved, class Extended>
-struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false> {
- static void registerTypeAndRevisions(const char *uri, int versionMajor)
+struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false, false, false> {
+ static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
+ const QMetaObject *extension)
+ {
+#if QT_DEPRECATED_SINCE(6, 4)
+ // ### Qt7: Remove the warnings, and leave only the static asserts below.
+ if constexpr (!QQmlPrivate::QmlMetaType<Resolved>::hasAcceptableCtors()) {
+ QQmlPrivate::qmlRegistrationWarning(QQmlPrivate::UnconstructibleType,
+ QMetaType::fromType<Resolved>());
+ }
+
+ if constexpr (!std::is_base_of_v<QObject, Resolved>
+ && QQmlTypeInfo<T>::hasAttachedProperties) {
+ QQmlPrivate::qmlRegistrationWarning(QQmlPrivate::NonQObjectWithAtached,
+ QMetaType::fromType<Resolved>());
+ }
+#else
+ static_assert(QQmlPrivate::QmlMetaType<Resolved>::hasAcceptableCtors(),
+ "This type is neither a default constructible QObject, nor a default- "
+ "and copy-constructible Q_GADGET, nor marked as uncreatable.\n"
+ "You should not use it as a QML type.");
+ static_assert(std::is_base_of_v<QObject, Resolved>
+ || !QQmlTypeInfo<Resolved>::hasAttachedProperties);
+#endif
+ QQmlPrivate::qmlRegisterTypeAndRevisions<Resolved, Extended>(
+ uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
+ qmlTypeIds, extension);
+ }
+};
+
+template<class T, class Resolved, class Extended>
+struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false, false, true> {
+ static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
+ const QMetaObject *extension)
{
+#if QT_DEPRECATED_SINCE(6, 4)
+ // ### Qt7: Remove the warning, and leave only the static assert below.
+ if constexpr (!std::is_base_of_v<QObject, Resolved>
+ && QQmlTypeInfo<Resolved>::hasAttachedProperties) {
+ QQmlPrivate::qmlRegistrationWarning(QQmlPrivate::NonQObjectWithAtached,
+ QMetaType::fromType<Resolved>());
+ }
+#else
+ static_assert(std::is_base_of_v<QObject, Resolved>
+ || !QQmlTypeInfo<Resolved>::hasAttachedProperties);
+#endif
QQmlPrivate::qmlRegisterTypeAndRevisions<Resolved, Extended>(
- uri, versionMajor, &T::staticMetaObject);
+ uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
+ qmlTypeIds, extension);
}
};
template<class T, class Resolved>
-struct QmlTypeAndRevisionsRegistration<T, Resolved, void, true> {
- static void registerTypeAndRevisions(const char *uri, int versionMajor)
+struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, false, true, true> {
+ static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
+ const QMetaObject *)
+ {
+ // Sequences have to be anonymous for now, which implies uncreatable.
+ QQmlPrivate::qmlRegisterSequenceAndRevisions<Resolved>(
+ uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
+ qmlTypeIds);
+ }
+};
+
+template<class T, class Resolved, class Extended>
+struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false, false, false> {
+ static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
+ const QMetaObject *extension)
{
- QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved>(
- uri, versionMajor, &T::staticMetaObject);
+#if QT_DEPRECATED_SINCE(6, 4)
+ // ### Qt7: Remove the warning, and leave only the static assert below.
+ if constexpr (QQmlPrivate::singletonConstructionMode<Resolved, T>()
+ == QQmlPrivate::SingletonConstructionMode::None) {
+ QQmlPrivate::qmlRegistrationWarning(QQmlPrivate::UnconstructibleSingleton,
+ QMetaType::fromType<Resolved>());
+ }
+#else
+ static_assert(QQmlPrivate::singletonConstructionMode<Resolved, T>()
+ != QQmlPrivate::SingletonConstructionMode::None,
+ "A singleton needs either a default constructor or, when adding a default "
+ "constructor is infeasible, a public static "
+ "create(QQmlEngine *, QJSEngine *) method");
+#endif
+
+ QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved, Extended, T>(
+ uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
+ qmlTypeIds, extension);
}
};
-template<typename T = void, typename... Args>
-void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor);
+template<class T, class Resolved, class Extended>
+struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false, false, true> {
+ static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
+ const QMetaObject *extension)
+ {
+ // An uncreatable singleton makes little sense? OK, you can still use the enums.
+ QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved, Extended, T>(
+ uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(),
+ qmlTypeIds, extension);
+ }
+};
+
+template<class T, class Resolved>
+struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, true, false, false> {
+ static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds,
+ const QMetaObject *)
+ {
+ const int id = qmlRegisterInterface<Resolved>(uri, versionMajor);
+ if (qmlTypeIds)
+ qmlTypeIds->append(id);
+ }
+};
-template<typename T, typename... Args>
-void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor)
+template<typename... T>
+void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds)
{
- QmlTypeAndRevisionsRegistration<
+ (QmlTypeAndRevisionsRegistration<
T, typename QQmlPrivate::QmlResolved<T>::Type,
typename QQmlPrivate::QmlExtended<T>::Type,
- QQmlPrivate::QmlSingleton<T>::Value>
- ::registerTypeAndRevisions(uri, versionMajor);
- qmlRegisterTypesAndRevisions<Args...>(uri, versionMajor);
+ QQmlPrivate::QmlSingleton<T>::Value,
+ QQmlPrivate::QmlInterface<T>::Value,
+ QQmlPrivate::QmlSequence<T>::Value,
+ QQmlPrivate::QmlUncreatable<T>::Value || QQmlPrivate::QmlAnonymous<T>::Value>
+ ::registerTypeAndRevisions(uri, versionMajor, qmlTypeIds,
+ QQmlPrivate::QmlExtendedNamespace<T>::metaObject()), ...);
}
-template<>
-inline void qmlRegisterTypesAndRevisions<>(const char *, int) {}
+inline void qmlRegisterNamespaceAndRevisions(const QMetaObject *metaObject,
+ const char *uri, int versionMajor,
+ QList<int> *qmlTypeIds,
+ const QMetaObject *classInfoMetaObject,
+ const QMetaObject *extensionMetaObject)
+{
+ QQmlPrivate::RegisterTypeAndRevisions type = {
+ 3,
+ QMetaType(),
+ QMetaType(),
+ 0,
+ nullptr,
+ nullptr,
+ nullptr,
+
+ uri,
+ QTypeRevision::fromMajorVersion(versionMajor),
+
+ metaObject,
+ (classInfoMetaObject ? classInfoMetaObject : metaObject),
+
+ nullptr,
+ nullptr,
+
+ -1,
+ -1,
+ -1,
+
+ nullptr,
+ extensionMetaObject,
+
+ &qmlCreateCustomParser<void>,
+ qmlTypeIds,
+ -1,
+ false,
+ QMetaSequence()
+ };
+
+ qmlregister(QQmlPrivate::TypeAndRevisionsRegistration, &type);
+}
+
+inline void qmlRegisterNamespaceAndRevisions(const QMetaObject *metaObject,
+ const char *uri, int versionMajor,
+ QList<int> *qmlTypeIds = nullptr,
+ const QMetaObject *classInfoMetaObject = nullptr)
+{
+ qmlRegisterNamespaceAndRevisions(metaObject, uri, versionMajor, qmlTypeIds,
+ classInfoMetaObject, nullptr);
+}
int Q_QML_EXPORT qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QObject)
-Q_DECLARE_METATYPE(QVariant)
-
#endif // QQML_H
diff --git a/src/qml/qml/qqmlabstractbinding.cpp b/src/qml/qml/qqmlabstractbinding.cpp
index 42891c1a8e..78d1d68f55 100644
--- a/src/qml/qml/qqmlabstractbinding.cpp
+++ b/src/qml/qml/qqmlabstractbinding.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlabstractbinding_p.h"
#include <QtQml/qqmlinfo.h>
#include <private/qqmlbinding_p.h>
#include <private/qqmlvaluetypeproxybinding_p.h>
+#include <private/qqmlvmemetaobject_p.h>
QT_BEGIN_NAMESPACE
@@ -89,7 +54,7 @@ void QQmlAbstractBinding::addToObject()
while (b && (b->targetPropertyIndex().coreIndex() != coreIndex ||
b->targetPropertyIndex().hasValueTypeIndex()))
b = b->nextBinding();
- Q_ASSERT(b && b->isValueTypeProxy());
+ Q_ASSERT(b && b->kind() == QQmlAbstractBinding::ValueTypeProxy);
proxy = static_cast<QQmlValueTypeProxyBinding *>(b);
}
@@ -144,12 +109,13 @@ void QQmlAbstractBinding::removeFromObject()
// Find the value type binding
QQmlAbstractBinding *vtbinding = data->bindings;
- while (vtbinding && (vtbinding->targetPropertyIndex().coreIndex() != coreIndex ||
- vtbinding->targetPropertyIndex().hasValueTypeIndex())) {
+ Q_ASSERT(vtbinding);
+ while (vtbinding->targetPropertyIndex().coreIndex() != coreIndex
+ || vtbinding->targetPropertyIndex().hasValueTypeIndex()) {
vtbinding = vtbinding->nextBinding();
Q_ASSERT(vtbinding);
}
- Q_ASSERT(vtbinding->isValueTypeProxy());
+ Q_ASSERT(vtbinding->kind() == QQmlAbstractBinding::ValueTypeProxy);
QQmlValueTypeProxyBinding *vtproxybinding =
static_cast<QQmlValueTypeProxyBinding *>(vtbinding);
@@ -189,19 +155,133 @@ void QQmlAbstractBinding::removeFromObject()
data->clearBindingBit(coreIndex);
}
-void QQmlAbstractBinding::printBindingLoopError(QQmlProperty &prop)
+void QQmlAbstractBinding::printBindingLoopError(const QQmlProperty &prop)
{
qmlWarning(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name());
}
-QString QQmlAbstractBinding::expression() const
+void QQmlAbstractBinding::getPropertyData(
+ const QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const
{
- return QLatin1String("<Unknown>");
+ Q_ASSERT(propertyData);
+
+ QQmlData *data = QQmlData::get(m_target.data(), false);
+ Q_ASSERT(data);
+
+ if (Q_UNLIKELY(!data->propertyCache))
+ data->propertyCache = QQmlMetaType::propertyCache(m_target->metaObject());
+
+ *propertyData = data->propertyCache->property(m_targetIndex.coreIndex());
+ Q_ASSERT(*propertyData);
+
+ if (Q_UNLIKELY(m_targetIndex.hasValueTypeIndex() && valueTypeData)) {
+ const QMetaObject *valueTypeMetaObject
+ = QQmlMetaType::metaObjectForValueType((*propertyData)->propType());
+ Q_ASSERT(valueTypeMetaObject);
+ QMetaProperty vtProp = valueTypeMetaObject->property(m_targetIndex.valueTypeIndex());
+ valueTypeData->setFlags(QQmlPropertyData::flagsForProperty(vtProp));
+ valueTypeData->setPropType(vtProp.metaType());
+ valueTypeData->setCoreIndex(m_targetIndex.valueTypeIndex());
+ }
+}
+
+void QQmlAbstractBinding::updateCanUseAccessor()
+{
+ setCanUseAccessor(true); // Always use accessors, except when:
+ if (auto interceptorMetaObject = QQmlInterceptorMetaObject::get(targetObject())) {
+ if (!m_targetIndex.isValid() || interceptorMetaObject->intercepts(m_targetIndex))
+ setCanUseAccessor(false);
+ }
+}
+
+void QQmlAbstractBinding::setTarget(const QQmlProperty &prop)
+{
+ auto pd = QQmlPropertyPrivate::get(prop);
+ setTarget(prop.object(), pd->core, &pd->valueTypeData);
+}
+
+bool QQmlAbstractBinding::setTarget(
+ QObject *object, const QQmlPropertyData &core, const QQmlPropertyData *valueType)
+{
+ return setTarget(object, core.coreIndex(), core.isAlias(),
+ valueType ? valueType->coreIndex() : -1);
+}
+
+static const QQmlPropertyData *getObjectPropertyData(QObject *object, int coreIndex)
+{
+ QQmlData *data = QQmlData::get(object, true);
+ if (!data)
+ return nullptr;
+
+ if (!data->propertyCache) {
+ data->propertyCache = QQmlMetaType::propertyCache(object);
+ if (!data->propertyCache)
+ return nullptr;
+ }
+
+ const QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
+ Q_ASSERT(propertyData);
+ return propertyData;
+}
+
+bool QQmlAbstractBinding::setTarget(
+ QObject *object, int coreIndex, bool coreIsAlias, int valueTypeIndex)
+{
+ auto invalidate = [this]() {
+ m_target = nullptr;
+ m_targetIndex = QQmlPropertyIndex();
+ return false;
+ };
+
+ if (!object)
+ return invalidate();
+
+ m_target = object;
+
+ for (bool isAlias = coreIsAlias; isAlias;) {
+ QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
+
+ int aValueTypeIndex;
+ if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) {
+ // can't resolve id (yet)
+ return invalidate();
+ }
+
+ const QQmlPropertyData *propertyData = getObjectPropertyData(object, coreIndex);
+ if (!propertyData)
+ return invalidate();
+
+ if (aValueTypeIndex != -1) {
+ if (propertyData->propType().flags().testFlag(QMetaType::PointerToQObject)) {
+ // deep alias
+ propertyData->readProperty(object, &object);
+ coreIndex = aValueTypeIndex;
+ valueTypeIndex = -1;
+ propertyData = getObjectPropertyData(object, coreIndex);
+ if (!propertyData)
+ return invalidate();
+ } else {
+ valueTypeIndex = aValueTypeIndex;
+ }
+ }
+
+ m_target = object;
+ isAlias = propertyData->isAlias();
+ coreIndex = propertyData->coreIndex();
+ }
+ m_targetIndex = QQmlPropertyIndex(coreIndex, valueTypeIndex);
+
+ QQmlData *data = QQmlData::get(m_target.data(), true);
+ if (!data->propertyCache)
+ data->propertyCache = QQmlMetaType::propertyCache(m_target->metaObject());
+
+ return true;
}
-bool QQmlAbstractBinding::isValueTypeProxy() const
+
+QString QQmlAbstractBinding::expression() const
{
- return false;
+ return QLatin1String("<Unknown>");
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h
index fc53be3e7b..8230c6aa6b 100644
--- a/src/qml/qml/qqmlabstractbinding_p.h
+++ b/src/qml/qml/qqmlabstractbinding_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLABSTRACTBINDING_P_H
#define QQMLABSTRACTBINDING_P_H
@@ -59,19 +23,27 @@
QT_BEGIN_NAMESPACE
class QQmlObjectCreator;
+class QQmlAnyBinding;
-class Q_QML_PRIVATE_EXPORT QQmlAbstractBinding
+class Q_QML_EXPORT QQmlAbstractBinding
{
+ friend class QQmlAnyBinding;
protected:
QQmlAbstractBinding();
public:
+ enum Kind {
+ ValueTypeProxy,
+ QmlBinding,
+ PropertyToPropertyBinding,
+ };
+
virtual ~QQmlAbstractBinding();
typedef QExplicitlySharedDataPointer<QQmlAbstractBinding> Ptr;
virtual QString expression() const;
- virtual bool isValueTypeProxy() const;
+ virtual Kind kind() const = 0;
// Should return the encoded property index for the binding. Should return this value
// even if the binding is not enabled or added to an object.
@@ -82,17 +54,23 @@ public:
// binding is not enabled or added to the object.
QObject *targetObject() const { return m_target.data(); }
+ void setTarget(const QQmlProperty &);
+ bool setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType);
+ bool setTarget(QObject *, int coreIndex, bool coreIsAlias, int valueTypeIndex);
+
virtual void setEnabled(bool e, QQmlPropertyData::WriteFlags f = QQmlPropertyData::DontRemoveBinding) = 0;
void addToObject();
void removeFromObject();
- static void printBindingLoopError(QQmlProperty &prop);
+ static void printBindingLoopError(const QQmlProperty &prop);
inline QQmlAbstractBinding *nextBinding() const;
inline bool canUseAccessor() const
- { return m_nextBinding.flag2(); }
+ { return m_nextBinding.tag().testFlag(CanUseAccessor); }
+ void setCanUseAccessor(bool canUseAccessor)
+ { m_nextBinding.setTag(m_nextBinding.tag().setFlag(CanUseAccessor, canUseAccessor)); }
struct RefCount {
RefCount() {}
@@ -103,6 +81,20 @@ public:
};
RefCount ref;
+ enum TargetTag {
+ NoTargetTag = 0x0,
+ UpdatingBinding = 0x1,
+ BindingEnabled = 0x2
+ };
+ Q_DECLARE_FLAGS(TargetTags, TargetTag)
+
+ enum NextBindingTag {
+ NoBindingTag = 0x0,
+ AddedToObject = 0x1,
+ CanUseAccessor = 0x2
+ };
+ Q_DECLARE_FLAGS(NextBindingTags, NextBindingTag)
+
protected:
friend class QQmlData;
friend class QQmlValueTypeProxyBinding;
@@ -113,27 +105,35 @@ protected:
inline void setNextBinding(QQmlAbstractBinding *);
+ void getPropertyData(
+ const QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const;
+
+ inline bool updatingFlag() const;
+ inline void setUpdatingFlag(bool);
+ inline bool enabledFlag() const;
+ inline void setEnabledFlag(bool);
+ void updateCanUseAccessor();
+
QQmlPropertyIndex m_targetIndex;
// Pointer is the target object to which the binding binds
- // flag1 is the updating flag
- // flag2 is the enabled flag
- QFlagPointer<QObject> m_target;
+ QTaggedPointer<QObject, TargetTags> m_target;
// Pointer to the next binding in the linked list of bindings.
- // flag1 is used for addedToObject
- // flag2 indicates if an accessor is can be used (i.e. there is no interceptor on the target)
- QFlagPointer<QQmlAbstractBinding> m_nextBinding;
+ QTaggedPointer<QQmlAbstractBinding, NextBindingTags> m_nextBinding;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlAbstractBinding::TargetTags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlAbstractBinding::NextBindingTags)
+
void QQmlAbstractBinding::setAddedToObject(bool v)
{
- m_nextBinding.setFlagValue(v);
+ m_nextBinding.setTag(m_nextBinding.tag().setFlag(AddedToObject, v));
}
bool QQmlAbstractBinding::isAddedToObject() const
{
- return m_nextBinding.flag();
+ return m_nextBinding.tag().testFlag(AddedToObject);
}
QQmlAbstractBinding *QQmlAbstractBinding::nextBinding() const
@@ -150,6 +150,26 @@ void QQmlAbstractBinding::setNextBinding(QQmlAbstractBinding *b)
m_nextBinding = b;
}
+bool QQmlAbstractBinding::updatingFlag() const
+{
+ return m_target.tag().testFlag(UpdatingBinding);
+}
+
+void QQmlAbstractBinding::setUpdatingFlag(bool v)
+{
+ m_target.setTag(m_target.tag().setFlag(UpdatingBinding, v));
+}
+
+bool QQmlAbstractBinding::enabledFlag() const
+{
+ return m_target.tag().testFlag(BindingEnabled);
+}
+
+void QQmlAbstractBinding::setEnabledFlag(bool v)
+{
+ m_target.setTag(m_target.tag().setFlag(BindingEnabled, v));
+}
+
QT_END_NAMESPACE
#endif // QQMLABSTRACTBINDING_P_H
diff --git a/src/qml/qml/qqmlabstracturlinterceptor.cpp b/src/qml/qml/qqmlabstracturlinterceptor.cpp
index 3c215bc381..b73af72281 100644
--- a/src/qml/qml/qqmlabstracturlinterceptor.cpp
+++ b/src/qml/qml/qqmlabstracturlinterceptor.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
\class QQmlAbstractUrlInterceptor
diff --git a/src/qml/qml/qqmlabstracturlinterceptor.h b/src/qml/qml/qqmlabstracturlinterceptor.h
index af231f51b2..ca3da059a3 100644
--- a/src/qml/qml/qqmlabstracturlinterceptor.h
+++ b/src/qml/qml/qqmlabstracturlinterceptor.h
@@ -1,50 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLABSTRACTURLINTERCEPTOR_H
#define QQMLABSTRACTURLINTERCEPTOR_H
-#include <QtCore/qurl.h>
#include <QtQml/qtqmlglobal.h>
QT_BEGIN_NAMESPACE
+class QUrl;
+
class Q_QML_EXPORT QQmlAbstractUrlInterceptor
{
public:
diff --git a/src/qml/qml/qqmlanybinding_p.h b/src/qml/qml/qqmlanybinding_p.h
new file mode 100644
index 0000000000..f432d2abae
--- /dev/null
+++ b/src/qml/qml/qqmlanybinding_p.h
@@ -0,0 +1,473 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLANYBINDINGPTR_P_H
+#define QQMLANYBINDINGPTR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qqmlproperty.h>
+#include <private/qqmlpropertybinding_p.h>
+#include <private/qqmlbinding_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// Fully inline so that subsequent prop.isBindable check might get ellided.
+
+/*!
+ \internal
+ \brief QQmlAnyBinding is an abstraction over the various bindings in QML
+
+ QQmlAnyBinding can store both classical bindings (derived from QQmlAbstractBinding)
+ as well as new-style bindings (derived from QPropertyBindingPrivate). For both, it keeps
+ a strong reference to them, and knows how to delete them in case the reference count
+ becomes zero. In that sense it can be thought of as a union of QUntypedPropertyBinding
+ and QQmlAbstractBinding::Ptr.
+
+ It also offers methods to create bindings (from QV4::Function, from translation bindings
+ and from code strings). Moreover, it allows the retrieval, the removal and the
+ installation of bindings on a QQmlProperty.
+
+ Note that the class intentionally does not allow construction from QUntypedProperty and
+ QQmlAbstractBinding::Ptr. This is meant to catch code which doesn't handle bindable properties
+ yet when porting existing code.
+ */
+class QQmlAnyBinding {
+public:
+
+ constexpr QQmlAnyBinding() noexcept = default;
+ QQmlAnyBinding(std::nullptr_t) : d(static_cast<QQmlAbstractBinding *>(nullptr)) {}
+
+ /*!
+ \internal
+ Returns the binding of the property \a prop as a QQmlAnyBinding.
+ The binding continues to be active and set on the property.
+ If there was no binding set, the returned QQmlAnyBinding is null.
+ */
+ static QQmlAnyBinding ofProperty(const QQmlProperty &prop) {
+ QQmlAnyBinding binding;
+ if (prop.isBindable()) {
+ QUntypedBindable bindable = prop.property().bindable(prop.object());
+ binding = bindable.binding();
+ } else {
+ binding = QQmlPropertyPrivate::binding(prop);
+ }
+ return binding;
+ }
+
+ /*!
+ \overload
+
+ \a object must be non-null
+ */
+ static QQmlAnyBinding ofProperty(QObject *object, QQmlPropertyIndex index)
+ {
+ QQmlAnyBinding binding;
+ Q_ASSERT(object);
+ auto coreIndex = index.coreIndex();
+ // we don't support bindable properties on value types so far
+ if (!index.hasValueTypeIndex()
+ && QQmlData::ensurePropertyCache(object)->property(coreIndex)->isBindable()) {
+ auto metaProp = object->metaObject()->property(coreIndex);
+ QUntypedBindable bindable = metaProp.bindable(object);
+ binding = bindable.binding();
+ } else {
+ binding = QQmlPropertyPrivate::binding(object, index);
+ }
+ return binding;
+ }
+
+ /*!
+ Removes the binding from the property \a prop, and returns it as a
+ QQmlAnyBinding if there was any. Otherwise returns a null
+ QQmlAnyBinding.
+ */
+ static QQmlAnyBinding takeFrom(const QQmlProperty &prop)
+ {
+ QQmlAnyBinding binding;
+ if (prop.isBindable()) {
+ QUntypedBindable bindable = prop.property().bindable(prop.object());
+ binding = bindable.takeBinding();
+ } else {
+ auto qmlBinding = QQmlPropertyPrivate::binding(prop);
+ if (qmlBinding) {
+ binding = qmlBinding; // this needs to run before removeFromObject, else the refcount might reach zero
+ qmlBinding->setEnabled(false, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
+ qmlBinding->removeFromObject();
+ }
+ }
+ return binding;
+ }
+
+ /*!
+ \internal
+ Creates a binding for property \a prop from \a function.
+ \a obj is the scope object which shall be used for the function and \a scope its QML scope.
+ The binding is not installed on the property (but if a QQmlBinding is created, it has its
+ target set to \a prop).
+ */
+ static QQmlAnyBinding createFromFunction(const QQmlProperty &prop, QV4::Function *function,
+ QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::ExecutionContext *scope)
+ {
+ QQmlAnyBinding binding;
+ auto propPriv = QQmlPropertyPrivate::get(prop);
+ if (prop.isBindable()) {
+ auto index = QQmlPropertyIndex(propPriv->core.coreIndex(), -1);
+ binding = QQmlPropertyBinding::create(&propPriv->core,
+ function, obj, ctxt,
+ scope, prop.object(), index);
+ } else {
+ auto qmlBinding = QQmlBinding::create(&propPriv->core, function, obj, ctxt, scope);
+ qmlBinding->setTarget(prop);
+ binding = qmlBinding;
+ }
+ return binding;
+ }
+
+ /*!
+ \internal
+ Creates a binding for property \a prop from \a script.
+ \a obj is the scope object which shall be used for the function and \a ctxt its QML scope.
+ The binding is not installed on the property (but if a QQmlBinding is created, it has its
+ target set to \a prop).
+ */
+ static QQmlAnyBinding createFromScriptString(const QQmlProperty &prop, const QQmlScriptString &script,
+ QObject *obj, QQmlContext *ctxt)
+ {
+ QQmlAnyBinding binding;
+ auto propPriv = QQmlPropertyPrivate::get(prop);
+ if (prop.isBindable()) {
+ auto index = QQmlPropertyIndex(propPriv->core.coreIndex(), -1);
+ binding = QQmlPropertyBinding::createFromScriptString(&propPriv->core, script, obj, ctxt, prop.object(), index);
+ } else {
+ auto qmlBinding = QQmlBinding::create(&propPriv->core, script, obj, ctxt);
+ qmlBinding->setTarget(prop);
+ binding = qmlBinding;
+ }
+ return binding;
+ }
+
+
+ /*!
+ \internal
+ Removes the binding from \a prop if there is any.
+ */
+ static void removeBindingFrom(QQmlProperty &prop)
+ {
+ if (prop.isBindable())
+ prop.property().bindable(prop.object()).takeBinding();
+ else
+ QQmlPropertyPrivate::removeBinding(prop);
+ }
+
+ /*!
+ \internal
+ Creates a binding for property \a prop from \a function.
+ \a obj is the scope object which shall be used for the function and \a scope its QML scope.
+ The binding is not installed on the property (but if a QQmlBinding is created, it has its
+ target set to \a prop).
+ */
+ static QQmlAnyBinding createFromCodeString(const QQmlProperty &prop, const QString& code, QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt, const QString &url, quint16 lineNumber) {
+ QQmlAnyBinding binding;
+ auto propPriv = QQmlPropertyPrivate::get(prop);
+ if (prop.isBindable()) {
+ auto index = QQmlPropertyIndex(propPriv->core.coreIndex(), -1);
+ binding = QQmlPropertyBinding::createFromCodeString(&propPriv->core,
+ code, obj, ctxt,
+ url, lineNumber,
+ prop.object(), index);
+ } else {
+ auto qmlBinding = QQmlBinding::create(&propPriv->core, code, obj, ctxt, url, lineNumber);
+ qmlBinding->setTarget(prop);
+ binding = qmlBinding;
+ }
+ return binding;
+ }
+
+ /*!
+ \internal
+ Creates a translattion binding for \a prop from \a compilationUnit and \a transationBinding.
+ \a obj is the context object, \a context the qml context.
+ */
+ static QQmlAnyBinding createTranslationBinding(const QQmlProperty &prop, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *translationBinding, QObject *scopeObject=nullptr, QQmlRefPointer<QQmlContextData> context={})
+ {
+ QQmlAnyBinding binding;
+ auto propPriv = QQmlPropertyPrivate::get(prop);
+ if (prop.isBindable()) {
+ binding = QQmlTranslationPropertyBinding::create(&propPriv->core, compilationUnit, translationBinding);
+ } else {
+ auto qmlBinding = QQmlBinding::createTranslationBinding(compilationUnit, translationBinding, scopeObject, context);
+ binding = qmlBinding;
+ qmlBinding->setTarget(prop);
+ }
+ return binding;
+ }
+
+ /*!
+ \internal
+ Installs the binding referenced by this QQmlAnyBinding on the target.
+ If \a mode is set to RespectInterceptors, interceptors are honored, otherwise
+ writes and binding installation bypass them (the default).
+ Preconditions:
+ - The binding is non-null.
+ - If the binding is QQmlAbstractBinding derived, the target is non-bindable.
+ - If the binding is a QUntypedPropertyBinding, then the target is bindable.
+ */
+ enum InterceptorMode : bool {
+ IgnoreInterceptors,
+ RespectInterceptors
+ };
+
+ void installOn(const QQmlProperty &target, InterceptorMode mode = IgnoreInterceptors)
+ {
+ Q_ASSERT(!d.isNull());
+ if (isAbstractPropertyBinding()) {
+ auto abstractBinding = asAbstractBinding();
+ Q_ASSERT(abstractBinding->targetObject() == target.object() || QQmlPropertyPrivate::get(target)->core.isAlias());
+ Q_ASSERT(!target.isBindable());
+ if (mode == IgnoreInterceptors)
+ QQmlPropertyPrivate::setBinding(abstractBinding, QQmlPropertyPrivate::None, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
+ else
+ QQmlPropertyPrivate::setBinding(abstractBinding);
+ } else {
+ Q_ASSERT(target.isBindable());
+ QUntypedBindable bindable;
+ void *argv[] = {&bindable};
+ if (mode == IgnoreInterceptors) {
+ target.object()->qt_metacall(QMetaObject::BindableProperty, target.index(), argv);
+ } else {
+ QMetaObject::metacall(target.object(), QMetaObject::BindableProperty, target.index(), argv);
+ }
+ bindable.setBinding(asUntypedPropertyBinding());
+ }
+ }
+
+ /*!
+ \internal
+ Returns true if the binding is in an error state (e.g. binding loop), false otherwise.
+
+ \note For ValueTypeProxyBindings, this methods will always return false
+ */
+ bool hasError() {
+ if (isAbstractPropertyBinding()) {
+ auto abstractBinding = asAbstractBinding();
+ if (abstractBinding->kind() != QQmlAbstractBinding::QmlBinding)
+ return false;
+ return static_cast<QQmlBinding *>(abstractBinding)->hasError();
+ } else {
+ return asUntypedPropertyBinding().error().hasError();
+ }
+ }
+
+ /*!
+ Stores a null binding. For purpose of classification, the null bindings is
+ treated as a QQmlAbstractPropertyBindings.
+ */
+ QQmlAnyBinding &operator=(std::nullptr_t)
+ {
+ clear();
+ return *this;
+ }
+
+ operator bool() const{
+ return !d.isNull();
+ }
+
+ /*!
+ \internal
+ Returns true if a binding derived from QQmlAbstractPropertyBinding is stored.
+ The binding migh still be null.
+ */
+ bool isAbstractPropertyBinding() const
+ { return d.isT1(); }
+
+ /*!
+ \internal
+ Returns true if a binding derived from QPropertyBindingPrivate is stored.
+ The binding might still be null.
+ */
+ bool isUntypedPropertyBinding() const
+ { return d.isT2(); }
+
+ /*!
+ \internal
+ Returns the stored QPropertyBindingPrivate as a QUntypedPropertyBinding.
+ If no such binding is currently stored, a null QUntypedPropertyBinding is returned.
+ */
+ QUntypedPropertyBinding asUntypedPropertyBinding() const
+ {
+ if (d.isT1() || d.isNull())
+ return {};
+ auto priv = d.asT2();
+ return QUntypedPropertyBinding {priv};
+ }
+
+ /*!
+ \internal
+ Returns the stored QQmlAbstractBinding.
+ If no such binding is currently stored, a null pointer is returned.
+ */
+ QQmlAbstractBinding *asAbstractBinding() const
+ {
+ if (d.isT2() || d.isNull())
+ return nullptr;
+ return d.asT1();
+ }
+
+ /*!
+ \internal
+ Reevaluates the binding. If the binding was disabled,
+ it gets enabled.
+ */
+ void refresh()
+ {
+ if (d.isNull())
+ return;
+ if (d.isT1()) {
+ auto binding = static_cast<QQmlBinding *>(d.asT1());
+ binding->setEnabledFlag(true);
+ binding->refresh();
+ } else {
+ auto bindingPriv = d.asT2();
+ PendingBindingObserverList bindingObservers;
+ bindingPriv->evaluateRecursive(bindingObservers);
+ bindingPriv->notifyNonRecursive(bindingObservers);
+ }
+
+ }
+
+ /*!
+ \internal
+ Stores \a binding and keeps a reference to it.
+ */
+ QQmlAnyBinding &operator=(QQmlAbstractBinding *binding)
+ {
+ clear();
+ if (binding) {
+ d = binding;
+ binding->ref.ref();
+ }
+ return *this;
+ }
+
+ /*!
+ \internal
+ Stores the binding stored in \a binding and keeps a reference to it.
+ */
+ QQmlAnyBinding &operator=(const QQmlAbstractBinding::Ptr &binding)
+ {
+ clear();
+ if (binding) {
+ d = binding.data();
+ binding->ref.ref();
+ }
+ return *this;
+ }
+
+ /*!
+ \internal
+ Stores \a binding's binding, taking ownership from \a binding.
+ */
+ QQmlAnyBinding &operator=(QQmlAbstractBinding::Ptr &&binding)
+ {
+ clear();
+ if (binding) {
+ d = binding.take();
+ }
+ return *this;
+ }
+
+ /*!
+ \internal
+ Stores the binding stored in \a untypedBinding and keeps a reference to it.
+ */
+ QQmlAnyBinding &operator=(const QUntypedPropertyBinding &untypedBinding)
+ {
+ clear();
+ auto binding = QPropertyBindingPrivate::get(untypedBinding);
+ if (binding) {
+ d = binding;
+ binding->addRef();
+ }
+ return *this;
+ }
+
+ /*!
+ \internal
+ \overload
+ Stores the binding stored in \a untypedBinding, taking ownership from it.
+ */
+ QQmlAnyBinding &operator=(QUntypedPropertyBinding &&untypedBinding)
+ {
+ clear();
+ auto binding = QPropertyBindingPrivate::get(untypedBinding);
+ QPropertyBindingPrivatePtr ptr(binding);
+ if (binding) {
+ d = static_cast<QPropertyBindingPrivate *>(ptr.take());
+ }
+ return *this;
+ }
+
+ QQmlAnyBinding(QQmlAnyBinding &&other) noexcept
+ : d(std::exchange(other.d, QBiPointer<QQmlAbstractBinding, QPropertyBindingPrivate>()))
+ {}
+
+ QQmlAnyBinding(const QQmlAnyBinding &other) noexcept { *this = other; }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QQmlAnyBinding)
+
+ void swap(QQmlAnyBinding &other) noexcept { d.swap(other.d); }
+ friend void swap(QQmlAnyBinding &lhs, QQmlAnyBinding &rhs) noexcept { lhs.swap(rhs); }
+
+ QQmlAnyBinding &operator=(const QQmlAnyBinding &other) noexcept
+ {
+ clear();
+ if (auto abstractBinding = other.asAbstractBinding())
+ *this = abstractBinding;
+ else if (auto untypedBinding = other.asUntypedPropertyBinding(); !untypedBinding.isNull())
+ *this = untypedBinding;
+ return *this;
+ }
+
+ friend inline bool operator==(const QQmlAnyBinding &p1, const QQmlAnyBinding &p2)
+ {
+ return p1.d == p2.d;
+ }
+
+ friend inline bool operator!=(const QQmlAnyBinding &p1, const QQmlAnyBinding &p2)
+ {
+ return p1.d != p2.d;
+ }
+
+ ~QQmlAnyBinding() noexcept { clear(); }
+private:
+ void clear() noexcept {
+ if (d.isNull())
+ return;
+ if (d.isT1()) {
+ QQmlAbstractBinding *qqmlptr = d.asT1();
+ if (!qqmlptr->ref.deref())
+ delete qqmlptr;
+ } else if (d.isT2()) {
+ QPropertyBindingPrivate *priv = d.asT2();
+ if (!priv->deref())
+ QPropertyBindingPrivate::destroyAndFreeMemory(priv);
+ }
+ d = static_cast<QQmlAbstractBinding *>(nullptr);
+ }
+ QBiPointer<QQmlAbstractBinding, QPropertyBindingPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+
+#endif // QQMLANYBINDINGPTR_P_H
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index adb036e2d0..82cc335c8e 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtQml/qqmlfile.h>
#include <QtCore/QCoreApplication>
@@ -43,23 +7,34 @@
#include <QQmlComponent>
#include "qqmlapplicationengine.h"
#include "qqmlapplicationengine_p.h"
-#include "qqmlfileselector.h"
+#include <QtQml/private/qqmlcomponent_p.h>
+#include <QtQml/private/qqmldirdata_p.h>
+#include <QtQml/private/qqmlfileselector_p.h>
QT_BEGIN_NAMESPACE
QQmlApplicationEnginePrivate::QQmlApplicationEnginePrivate(QQmlEngine *e)
: QQmlEnginePrivate(e)
{
+ uiLanguage = QLocale().bcp47Name();
}
QQmlApplicationEnginePrivate::~QQmlApplicationEnginePrivate()
{
}
+void QQmlApplicationEnginePrivate::ensureInitialized()
+{
+ if (!isInitialized) {
+ init();
+ isInitialized = true;
+ }
+}
+
void QQmlApplicationEnginePrivate::cleanUp()
{
Q_Q(QQmlApplicationEngine);
- for (auto obj : qAsConst(objects))
+ for (auto obj : std::as_const(objects))
obj->disconnect(q);
qDeleteAll(objects);
@@ -72,33 +47,41 @@ void QQmlApplicationEnginePrivate::init()
&QCoreApplication::quit, Qt::QueuedConnection);
q->connect(q, &QQmlApplicationEngine::exit, QCoreApplication::instance(),
&QCoreApplication::exit, Qt::QueuedConnection);
+ QObject::connect(q, &QJSEngine::uiLanguageChanged, q, [this](){
+ _q_loadTranslations();
+ });
#if QT_CONFIG(translation)
QTranslator* qtTranslator = new QTranslator(q);
- if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath), QLatin1String(".qm")))
+ if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::path(QLibraryInfo::TranslationsPath), QLatin1String(".qm")))
QCoreApplication::installTranslator(qtTranslator);
else
delete qtTranslator;
#endif
- new QQmlFileSelector(q,q);
+ auto *selector = new QQmlFileSelector(q,q);
+ selector->setExtraSelectors(extraFileSelectors);
QCoreApplication::instance()->setProperty("__qml_using_qqmlapplicationengine", QVariant(true));
}
-void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile)
+void QQmlApplicationEnginePrivate::_q_loadTranslations()
{
#if QT_CONFIG(translation)
- if (rootFile.scheme() != QLatin1String("file") && rootFile.scheme() != QLatin1String("qrc"))
+ Q_Q(QQmlApplicationEngine);
+ if (translationsDirectory.isEmpty())
return;
- QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(rootFile));
-
- Q_Q(QQmlApplicationEngine);
- QTranslator *translator = new QTranslator(q);
- if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"), QLatin1String(".qm")))
- QCoreApplication::installTranslator(translator);
- else
- delete translator;
-#else
- Q_UNUSED(rootFile)
+ auto translator = std::make_unique<QTranslator>();
+ if (!uiLanguage.value().isEmpty()) {
+ QLocale locale(uiLanguage);
+ if (translator->load(locale, QLatin1String("qml"), QLatin1String("_"), translationsDirectory, QLatin1String(".qm"))) {
+ if (activeTranslator)
+ QCoreApplication::removeTranslator(activeTranslator.get());
+ QCoreApplication::installTranslator(translator.get());
+ activeTranslator.swap(translator);
+ }
+ } else {
+ activeTranslator.reset();
+ }
+ q->retranslate();
#endif
}
@@ -106,7 +89,16 @@ void QQmlApplicationEnginePrivate::startLoad(const QUrl &url, const QByteArray &
{
Q_Q(QQmlApplicationEngine);
- loadTranslations(url); //Translations must be loaded before the QML file is
+ ensureInitialized();
+
+ if (url.scheme() == QLatin1String("file") || url.scheme() == QLatin1String("qrc")) {
+ QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(url));
+ translationsDirectory = fi.path() + QLatin1String("/i18n");
+ } else {
+ translationsDirectory.clear();
+ }
+
+ _q_loadTranslations(); //Translations must be loaded before the QML file is
QQmlComponent *c = new QQmlComponent(q, q);
if (dataFlag)
@@ -114,11 +106,40 @@ void QQmlApplicationEnginePrivate::startLoad(const QUrl &url, const QByteArray &
else
c->loadUrl(url);
- if (!c->isLoading()) {
- finishLoad(c);
- return;
+ ensureLoadingFinishes(c);
+}
+
+void QQmlApplicationEnginePrivate::startLoad(QAnyStringView uri, QAnyStringView typeName)
+{
+ Q_Q(QQmlApplicationEngine);
+
+ QQmlComponent *c = new QQmlComponent(q, q);
+
+ ensureInitialized();
+
+ auto *componentPriv = QQmlComponentPrivate::get(c);
+ const auto [status, type] = componentPriv->prepareLoadFromModule(uri, typeName);
+
+ if (type.sourceUrl().isValid()) {
+ const auto qmlDirData = typeLoader.getQmldir(type.sourceUrl());
+ const QUrl url = qmlDirData->finalUrl();
+ if (url.scheme() == QLatin1String("file") || url.scheme() == QLatin1String("qrc")) {
+ QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(url));
+ translationsDirectory = fi.path() + QLatin1String("/i18n");
+ } else {
+ translationsDirectory.clear();
+ }
}
- QObject::connect(c, &QQmlComponent::statusChanged, q, [this, c] { this->finishLoad(c); });
+
+ /* Translations must be loaded before the QML file. They require translationDirectory to
+ * already be resolved. But, in order to resolve the translationDirectory, the type of the
+ * module to load needs to be known. Therefore, loadFromModule is split into resolution and
+ * loading because the translation directory needs to be set in between.
+ */
+ _q_loadTranslations();
+ componentPriv->completeLoadFromModule(uri, typeName, type, status);
+
+ ensureLoadingFinishes(c);
}
void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
@@ -127,11 +148,21 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
switch (c->status()) {
case QQmlComponent::Error:
qWarning() << "QQmlApplicationEngine failed to load component";
- qWarning() << qPrintable(c->errorString());
+ warning(c->errors());
q->objectCreated(nullptr, c->url());
+ q->objectCreationFailed(c->url());
break;
case QQmlComponent::Ready: {
auto newObj = initialProperties.empty() ? c->create() : c->createWithInitialProperties(initialProperties);
+
+ if (c->isError()) {
+ qWarning() << "QQmlApplicationEngine failed to create component";
+ warning(c->errors());
+ q->objectCreated(nullptr, c->url());
+ q->objectCreationFailed(c->url());
+ break;
+ }
+
objects << newObj;
QObject::connect(newObj, &QObject::destroyed, q, [&](QObject *obj) { objects.removeAll(obj); });
q->objectCreated(objects.constLast(), c->url());
@@ -145,6 +176,16 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
c->deleteLater();
}
+void QQmlApplicationEnginePrivate::ensureLoadingFinishes(QQmlComponent *c)
+{
+ Q_Q(QQmlApplicationEngine);
+ if (!c->isLoading()) {
+ finishLoad(c);
+ return;
+ }
+ QObject::connect(c, &QQmlComponent::statusChanged, q, [this, c] { this->finishLoad(c); });
+}
+
/*!
\class QQmlApplicationEngine
\since 5.1
@@ -181,6 +222,7 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
\list
\li Translation files must have "qml_" prefix e.g. qml_ja_JP.qm.
\endlist
+ \li Translations are reloaded when the \c QJSEngine::uiLanguage / \c Qt.uiLanguage property is changed.
\li Automatically sets an incubation controller if the scene contains a QQuickWindow.
\li Automatically sets a \c QQmlFileSelector as the url interceptor, applying file selectors to all
QML files and assets.
@@ -204,14 +246,38 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
*/
/*!
+ \fn QQmlApplicationEngine::objectCreationFailed(const QUrl &url)
+ \since 6.4
+
+ This signal is emitted when loading finishes because an error occurred.
+
+ The \a url to the component that failed to load is provided as an argument.
+
+ \code
+ QGuiApplication app(argc, argv);
+ QQmlApplicationEngine engine;
+
+ // exit on error
+ QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
+ &app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection);
+ engine.load(QUrl());
+ return app.exec();
+ \endcode
+
+ \note If the path to the component was provided as a QString containing a
+ relative path, the \a url will contain a fully resolved path to the file.
+
+ See also \l {QQmlApplicationEngine::objectCreated}, which will be emitted in
+ addition to this signal (even though creation failed).
+*/
+
+/*!
Create a new QQmlApplicationEngine with the given \a parent. You will have to call load() later in
order to load a QML file.
*/
QQmlApplicationEngine::QQmlApplicationEngine(QObject *parent)
: QQmlEngine(*(new QQmlApplicationEnginePrivate(this)), parent)
{
- Q_D(QQmlApplicationEngine);
- d->init();
QJSEnginePrivate::addToDebugServer(this);
}
@@ -226,6 +292,20 @@ QQmlApplicationEngine::QQmlApplicationEngine(const QUrl &url, QObject *parent)
}
/*!
+ Create a new QQmlApplicationEngine and loads the QML type specified by
+ \a uri and \a typeName
+ This is provided as a convenience, and is the same as using the empty constructor and calling
+ loadFromModule afterwards.
+
+ \since 6.5
+*/
+QQmlApplicationEngine::QQmlApplicationEngine(QAnyStringView uri, QAnyStringView typeName, QObject *parent)
+ : QQmlApplicationEngine(parent)
+{
+ loadFromModule(uri, typeName);
+}
+
+/*!
Create a new QQmlApplicationEngine and loads the QML file at the given
\a filePath, which must be a local file path. If a relative path is
given then it will be interpreted as relative to the working directory of the
@@ -279,9 +359,50 @@ void QQmlApplicationEngine::load(const QString &filePath)
}
/*!
+ Loads the QML type \a typeName from the module specified by \a uri.
+ If the type originates from a QML file located at a remote url,
+ the type will be loaded asynchronously.
+ Listen to the \l {QQmlApplicationEngine::objectCreated()}{objectCreated}
+ signal to determine when the object tree is ready.
+
+ If an error occurs, the \l {QQmlApplicationEngine::objectCreated()}{objectCreated}
+ signal is emitted with a null pointer as parameter and error messages are printed
+ with qWarning.
+
+ \code
+ QQmlApplicationEngine engine;
+ engine.loadFromModule("QtQuick", "Rectangle");
+ \endcode
+
+ \note The module identified by \a uri is searched in the
+ \l {QML Import Path}{import path}, in the same way as if
+ you were doing \c{import uri} inside a QML file. If the
+ module cannot be located there, this function will fail.
+
+ \since 6.5
+ \sa QQmlComponent::loadFromModule
+ */
+void QQmlApplicationEngine::loadFromModule(QAnyStringView uri, QAnyStringView typeName)
+{
+ Q_D(QQmlApplicationEngine);
+ d->startLoad(uri, typeName);
+}
+
+/*!
Sets the \a initialProperties with which the QML component gets initialized after
it gets loaded.
+ \code
+ QQmlApplicationEngine engine;
+
+ EventDatabase eventDatabase;
+ EventMonitor eventMonitor;
+
+ engine.setInitialProperties({
+ { "eventDatabase", QVariant::fromValue(&eventDatabase) },
+ { "eventMonitor", QVariant::fromValue(&eventMonitor) }
+ });
+ \endcode
\sa QQmlComponent::setInitialProperties
\sa QQmlApplicationEngine::load
@@ -295,6 +416,26 @@ void QQmlApplicationEngine::setInitialProperties(const QVariantMap &initialPrope
}
/*!
+ Sets the \a extraFileSelectors to be passed to the internal QQmlFileSelector
+ used for resolving URLs to local files. The \a extraFileSelectors are applied
+ when the first QML file is loaded. Setting them afterwards has no effect.
+
+ \sa QQmlFileSelector
+ \sa QFileSelector::setExtraSelectors
+ \since 6.0
+*/
+void QQmlApplicationEngine::setExtraFileSelectors(const QStringList &extraFileSelectors)
+{
+ Q_D(QQmlApplicationEngine);
+ if (d->isInitialized) {
+ qWarning() << "QQmlApplicationEngine::setExtraFileSelectors()"
+ << "called after loading QML files. This has no effect.";
+ } else {
+ d->extraFileSelectors = extraFileSelectors;
+ }
+}
+
+/*!
Loads the QML given in \a data. The object tree defined by \a data is
instantiated immediately.
@@ -323,17 +464,6 @@ QList<QObject *> QQmlApplicationEngine::rootObjects() const
return d->objects;
}
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-/*!
- \overload
- \internal
-*/
-QList<QObject *> QQmlApplicationEngine::rootObjects()
-{
- return qAsConst(*this).rootObjects();
-}
-#endif // < Qt 6
-
QT_END_NAMESPACE
#include "moc_qqmlapplicationengine.cpp"
diff --git a/src/qml/qml/qqmlapplicationengine.h b/src/qml/qml/qqmlapplicationengine.h
index 2b4de91154..69e4a7261c 100644
--- a/src/qml/qml/qqmlapplicationengine.h
+++ b/src/qml/qml/qqmlapplicationengine.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLAPPLICATIONENGINE_H
#define QQMLAPPLICATIONENGINE_H
@@ -55,25 +19,28 @@ class Q_QML_EXPORT QQmlApplicationEngine : public QQmlEngine
public:
QQmlApplicationEngine(QObject *parent = nullptr);
QQmlApplicationEngine(const QUrl &url, QObject *parent = nullptr);
+ explicit QQmlApplicationEngine(QAnyStringView uri, QAnyStringView typeName,
+ QObject *parent = nullptr);
QQmlApplicationEngine(const QString &filePath, QObject *parent = nullptr);
~QQmlApplicationEngine() override;
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- QList<QObject*> rootObjects(); // ### Qt 6: remove
-#endif
QList<QObject*> rootObjects() const;
public Q_SLOTS:
void load(const QUrl &url);
void load(const QString &filePath);
+ void loadFromModule(QAnyStringView uri, QAnyStringView typeName);
void setInitialProperties(const QVariantMap &initialProperties);
+ void setExtraFileSelectors(const QStringList &extraFileSelectors);
void loadData(const QByteArray &data, const QUrl &url = QUrl());
Q_SIGNALS:
void objectCreated(QObject *object, const QUrl &url);
+ void objectCreationFailed(const QUrl &url);
private:
Q_DISABLE_COPY(QQmlApplicationEngine)
+ Q_PRIVATE_SLOT(d_func(), void _q_loadTranslations())
Q_DECLARE_PRIVATE(QQmlApplicationEngine)
};
diff --git a/src/qml/qml/qqmlapplicationengine_p.h b/src/qml/qml/qqmlapplicationengine_p.h
index 1279e400e8..df99783e0a 100644
--- a/src/qml/qml/qqmlapplicationengine_p.h
+++ b/src/qml/qml/qqmlapplicationengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLAPPLICATIONENGINE_P_H
#define QQMLAPPLICATIONENGINE_P_H
@@ -60,20 +24,29 @@
QT_BEGIN_NAMESPACE
class QFileSelector;
-class Q_QML_PRIVATE_EXPORT QQmlApplicationEnginePrivate : public QQmlEnginePrivate
+class Q_QML_EXPORT QQmlApplicationEnginePrivate : public QQmlEnginePrivate
{
Q_DECLARE_PUBLIC(QQmlApplicationEngine)
public:
QQmlApplicationEnginePrivate(QQmlEngine *e);
~QQmlApplicationEnginePrivate();
+ void ensureInitialized();
void init();
void cleanUp();
void startLoad(const QUrl &url, const QByteArray &data = QByteArray(), bool dataFlag = false);
- void loadTranslations(const QUrl &rootFile);
+ void startLoad(QAnyStringView uri, QAnyStringView type);
+ void _q_loadTranslations();
void finishLoad(QQmlComponent *component);
+ void ensureLoadingFinishes(QQmlComponent *component);
QList<QObject *> objects;
QVariantMap initialProperties;
+ QStringList extraFileSelectors;
+ QString translationsDirectory;
+#if QT_CONFIG(translation)
+ std::unique_ptr<QTranslator> activeTranslator;
+#endif
+ bool isInitialized = false;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 112e5b558a..47f8e5c429 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -1,48 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlbinding_p.h"
-#include "qqml.h"
#include "qqmlcontext.h"
-#include "qqmlinfo.h"
#include "qqmldata_p.h"
+
+#include <private/qqmldebugserviceinterfaces_p.h>
+#include <private/qqmldebugconnector_p.h>
+
#include <private/qqmlprofiler_p.h>
#include <private/qqmlexpression_p.h>
#include <private/qqmlscriptstring_p.h>
@@ -53,6 +19,9 @@
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4variantobject_p.h>
#include <private/qv4jscall_p.h>
+#include <private/qjsvalue_p.h>
+
+#include <qtqml_tracepoints_p.h>
#include <QVariant>
#include <QtCore/qdebug.h>
@@ -60,9 +29,12 @@
QT_BEGIN_NAMESPACE
+Q_TRACE_POINT(qtqml, QQmlBinding_entry, const QQmlEngine *engine, const QString &function, const QString &fileName, int line, int column)
+Q_TRACE_POINT(qtqml, QQmlBinding_exit)
+
QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt)
{
- QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property);
+ QQmlBinding *b = newBinding(property);
if (ctxt && !ctxt->isValid())
return b;
@@ -74,19 +46,19 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScr
QString url;
QV4::Function *runtimeFunction = nullptr;
- QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context);
+ QQmlRefPointer<QQmlContextData> ctxtdata = QQmlContextData::get(scriptPrivate->context);
QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
- if (engine && ctxtdata && !ctxtdata->urlString().isEmpty() && ctxtdata->typeCompilationUnit) {
+ if (engine && ctxtdata && !ctxtdata->urlString().isEmpty() && ctxtdata->typeCompilationUnit()) {
url = ctxtdata->urlString();
if (scriptPrivate->bindingId != QQmlBinding::Invalid)
- runtimeFunction = ctxtdata->typeCompilationUnit->runtimeFunctions.at(scriptPrivate->bindingId);
+ runtimeFunction = ctxtdata->typeCompilationUnit()->runtimeFunctions.at(scriptPrivate->bindingId);
}
b->setNotifyOnValueChanged(true);
b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
b->setScopeObject(obj ? obj : scriptPrivate->scope);
- QV4::ExecutionEngine *v4 = b->context()->engine->handle();
+ QV4::ExecutionEngine *v4 = b->engine()->handle();
if (runtimeFunction) {
QV4::Scope scope(v4);
QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxtdata, b->scopeObject()));
@@ -114,10 +86,11 @@ void QQmlBinding::setSourceLocation(const QQmlSourceLocation &location)
}
-QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj,
- QQmlContextData *ctxt, const QString &url, quint16 lineNumber)
+QQmlBinding *QQmlBinding::create(
+ const QQmlPropertyData *property, const QString &str, QObject *obj,
+ const QQmlRefPointer<QQmlContextData> &ctxt, const QString &url, quint16 lineNumber)
{
- QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property);
+ QQmlBinding *b = newBinding(property);
b->setNotifyOnValueChanged(true);
b->QQmlJavaScriptExpression::setContext(ctxt);
@@ -128,10 +101,18 @@ QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString
return b;
}
-QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, QV4::Function *function,
- QObject *obj, QQmlContextData *ctxt, QV4::ExecutionContext *scope)
+QQmlBinding *QQmlBinding::create(
+ const QQmlPropertyData *property, QV4::Function *function, QObject *obj,
+ const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope)
+{
+ return create(property ? property->propType() : QMetaType(), function, obj, ctxt, scope);
+}
+
+QQmlBinding *QQmlBinding::create(QMetaType propertyType, QV4::Function *function, QObject *obj,
+ const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::ExecutionContext *scope)
{
- QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property);
+ QQmlBinding *b = newBinding(propertyType);
b->setNotifyOnValueChanged(true);
b->QQmlJavaScriptExpression::setContext(ctxt);
@@ -148,14 +129,9 @@ QQmlBinding::~QQmlBinding()
delete m_sourceLocation;
}
-void QQmlBinding::setNotifyOnValueChanged(bool v)
-{
- QQmlJavaScriptExpression::setNotifyOnValueChanged(v);
-}
-
void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
{
- if (!enabledFlag() || !context() || !context()->isValid())
+ if (!enabledFlag() || !hasValidContext())
return;
// Check that the target has not been deleted
@@ -164,7 +140,7 @@ void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
// Check for a binding update loop
if (Q_UNLIKELY(updatingFlag())) {
- QQmlPropertyData *d = nullptr;
+ const QQmlPropertyData *d = nullptr;
QQmlPropertyData vtd;
getPropertyData(&d, &vtd);
Q_ASSERT(d);
@@ -176,13 +152,15 @@ void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
DeleteWatcher watcher(this);
- QQmlEngine *engine = context()->engine;
- QV4::Scope scope(engine->handle());
+ QQmlEngine *qmlEngine = engine();
+ QV4::Scope scope(qmlEngine->handle());
if (canUseAccessor())
flags.setFlag(QQmlPropertyData::BypassInterceptor);
- QQmlBindingProfiler prof(QQmlEnginePrivate::get(engine)->profiler, function());
+ Q_TRACE_SCOPE(QQmlBinding, qmlEngine, function() ? function()->name()->toQString() : QString(),
+ sourceLocation().sourceFile, sourceLocation().line, sourceLocation().column);
+ QQmlBindingProfiler prof(QQmlEnginePrivate::get(qmlEngine)->profiler, function());
doUpdate(watcher, flags, scope);
if (!watcher.wasDeleted())
@@ -191,7 +169,7 @@ void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
QV4::ReturnedValue QQmlBinding::evaluate(bool *isUndefined)
{
- QV4::ExecutionEngine *v4 = context()->engine->handle();
+ QV4::ExecutionEngine *v4 = engine()->handle();
int argc = 0;
const QV4::Value *argv = nullptr;
const QV4::Value *thisObject = nullptr;
@@ -205,88 +183,51 @@ QV4::ReturnedValue QQmlBinding::evaluate(bool *isUndefined)
thisObject = &b->d()->boundThis;
}
QV4::Scope scope(v4);
- QV4::JSCallData jsCall(scope, argc, argv, thisObject);
+ QV4::JSCallData jsCall(thisObject, argv, argc);
- return QQmlJavaScriptExpression::evaluate(jsCall.callData(), isUndefined);
+ return QQmlJavaScriptExpression::evaluate(jsCall.callData(scope), isUndefined);
}
-
-// QQmlBindingBinding is for target properties which are of type "binding" (instead of, say, int or
-// double). The reason for being is that GenericBinding::fastWrite needs a compile-time constant
-// expression for the switch for the compiler to generate the optimal code, but
-// qMetaTypeId<QQmlBinding *>() needs to be used for the ID. So QQmlBinding::newBinding uses that
-// to instantiate this class.
-class QQmlBindingBinding: public QQmlBinding
-{
-protected:
- void doUpdate(const DeleteWatcher &,
- QQmlPropertyData::WriteFlags flags, QV4::Scope &) override final
- {
- Q_ASSERT(!m_targetIndex.hasValueTypeIndex());
- QQmlPropertyData *pd = nullptr;
- getPropertyData(&pd, nullptr);
- QQmlBinding *thisPtr = this;
- pd->writeProperty(*m_target, &thisPtr, flags);
- }
-};
-
-// For any target that's not a binding, we have a common doUpdate. However, depending on the type
-// of the target property, there is a specialized write method.
-class QQmlNonbindingBinding: public QQmlBinding
+template<int StaticPropType>
+class GenericBinding: public QQmlBinding
{
protected:
- void doUpdate(const DeleteWatcher &watcher,
- QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) override
+ // Returns true if successful, false if an error description was set on expression
+ Q_ALWAYS_INLINE bool write(void *result, QMetaType type, bool isUndefined,
+ QQmlPropertyData::WriteFlags flags) override final
{
- auto ep = QQmlEnginePrivate::get(scope.engine);
- ep->referenceScarceResources();
-
- bool isUndefined = false;
-
- QV4::ScopedValue result(scope, evaluate(&isUndefined));
-
- bool error = false;
- if (!watcher.wasDeleted() && isAddedToObject() && !hasError())
- error = !write(result, isUndefined, flags);
+ const QQmlPropertyData *pd;
+ QQmlPropertyData vpd;
+ getPropertyData(&pd, &vpd);
+ Q_ASSERT(pd);
- if (!watcher.wasDeleted()) {
+ if (isUndefined || vpd.isValid())
+ return slowWrite(*pd, vpd, result, type, isUndefined, flags);
- if (error) {
- delayedError()->setErrorLocation(sourceLocation());
- delayedError()->setErrorObject(m_target.data());
- }
-
- if (hasError()) {
- if (!delayedError()->addError(ep)) ep->warning(this->error(context()->engine));
- } else {
- clearError();
- }
+ if ((StaticPropType == QMetaType::UnknownType && pd->propType() == type)
+ || StaticPropType == type.id()) {
+ Q_ASSERT(targetObject());
+ return pd->writeProperty(targetObject(), result, flags);
}
- ep->dereferenceScarceResources();
+ // If the type didn't match, we need to do JavaScript conversion. This should be rare.
+ return write(engine()->handle()->metaTypeToJS(type, result), isUndefined, flags);
}
- virtual bool write(const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags) = 0;
-};
-
-template<int StaticPropType>
-class GenericBinding: public QQmlNonbindingBinding
-{
-protected:
// Returns true if successful, false if an error description was set on expression
Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined,
QQmlPropertyData::WriteFlags flags) override final
{
Q_ASSERT(targetObject());
- QQmlPropertyData *pd;
+ const QQmlPropertyData *pd;
QQmlPropertyData vpd;
getPropertyData(&pd, &vpd);
Q_ASSERT(pd);
int propertyType = StaticPropType; // If the binding is specialized to a type, the if and switch below will be constant-folded.
if (propertyType == QMetaType::UnknownType)
- propertyType = pd->propType();
+ propertyType = pd->propType().id();
if (Q_LIKELY(!isUndefined && !vpd.isValid())) {
switch (propertyType) {
@@ -299,7 +240,7 @@ protected:
if (result.isInteger())
return doStore<int>(result.integerValue(), pd, flags);
else if (result.isNumber()) {
- return doStore<int>(QV4::StaticValue::toInteger(result.doubleValue()), pd, flags);
+ return doStore<int>(result.toInt32(), pd, flags);
}
break;
case QMetaType::Double:
@@ -316,7 +257,7 @@ protected:
break;
default:
if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) {
- if (vtw->d()->valueType()->metaType.id() == pd->propType()) {
+ if (vtw->d()->metaType() == pd->propType()) {
return vtw->write(m_target.data(), pd->coreIndex());
}
}
@@ -335,19 +276,19 @@ protected:
}
};
-class QQmlTranslationBinding : public GenericBinding<QMetaType::QString> {
+class QQmlTranslationBinding : public GenericBinding<QMetaType::QString>, public QPropertyObserver {
public:
- QQmlTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
+ QQmlTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
+ : QPropertyObserver(&QQmlTranslationBinding::onLanguageChange)
{
setCompilationUnit(compilationUnit);
- m_binding = binding;
+ setSource(QQmlEnginePrivate::get(compilationUnit->engine)->translationLanguage);
}
- QQmlSourceLocation sourceLocation() const override final
- {
- return QQmlSourceLocation(m_compilationUnit->fileName(), m_binding->valueLocation.line, m_binding->valueLocation.column);
- }
+ virtual QString bindingValue() const = 0;
+ static void onLanguageChange(QPropertyObserver *observer, QUntypedPropertyData *)
+ { static_cast<QQmlTranslationBinding *>(observer)->update(); }
void doUpdate(const DeleteWatcher &watcher,
QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) override final
@@ -358,15 +299,15 @@ public:
if (!isAddedToObject() || hasError())
return;
- const QString result = m_compilationUnit->bindingValueAsString(m_binding);
+ const QString result = this->bindingValue();
Q_ASSERT(targetObject());
- QQmlPropertyData *pd;
+ const QQmlPropertyData *pd;
QQmlPropertyData vpd;
getPropertyData(&pd, &vpd);
Q_ASSERT(pd);
- if (pd->propType() == QMetaType::QString) {
+ if (pd->propType().id() == QMetaType::QString) {
doStore(result, pd, flags);
} else {
QV4::ScopedString value(scope, scope.engine->newString(result));
@@ -375,31 +316,163 @@ public:
}
bool hasDependencies() const override final { return true; }
+};
-private:
+class QQmlTranslationBindingFromBinding : public QQmlTranslationBinding
+{
const QV4::CompiledData::Binding *m_binding;
+
+public:
+ QQmlTranslationBindingFromBinding(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QV4::CompiledData::Binding *binding)
+ : QQmlTranslationBinding(compilationUnit), m_binding(binding)
+ {
+ }
+
+ QString bindingValue() const override
+ {
+ return this->m_compilationUnit->bindingValueAsString(m_binding);
+ }
+
+ QQmlSourceLocation sourceLocation() const override final
+ {
+ return QQmlSourceLocation(m_compilationUnit->fileName(), m_binding->valueLocation.line(),
+ m_binding->valueLocation.column());
+ }
+};
+
+class QQmlTranslationBindingFromTranslationInfo : public QQmlTranslationBinding
+{
+ QQmlTranslation m_translationData;
+
+ quint16 m_line;
+ quint16 m_column;
+
+public:
+ QQmlTranslationBindingFromTranslationInfo(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlTranslation &translationData, quint16 line, quint16 column)
+ : QQmlTranslationBinding(compilationUnit),
+ m_translationData(translationData),
+ m_line(line),
+ m_column(column)
+ {
+ }
+
+ virtual QString bindingValue() const override { return m_translationData.translate(); }
+
+ QQmlSourceLocation sourceLocation() const override final
+ {
+ return QQmlSourceLocation(m_compilationUnit->fileName(), m_line, m_column);
+ }
};
-QQmlBinding *QQmlBinding::createTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, const QV4::CompiledData::Binding *binding, QObject *obj, QQmlContextData *ctxt)
+QQmlBinding *QQmlBinding::createTranslationBinding(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QV4::CompiledData::Binding *binding, QObject *obj,
+ const QQmlRefPointer<QQmlContextData> &ctxt)
{
- QQmlTranslationBinding *b = new QQmlTranslationBinding(unit, binding);
+ QQmlTranslationBinding *b = new QQmlTranslationBindingFromBinding(unit, binding);
b->setNotifyOnValueChanged(true);
b->QQmlJavaScriptExpression::setContext(ctxt);
b->setScopeObject(obj);
+#if QT_CONFIG(translation) && QT_CONFIG(qml_debug)
+ if (QQmlDebugTranslationService *service
+ = QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
+ service->foundTranslationBinding(
+ TranslationBindingInformation::create(unit, binding, b->scopeObject(), ctxt));
+ }
+#endif
+ return b;
+}
+QQmlBinding *QQmlBinding::createTranslationBinding(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QQmlRefPointer<QQmlContextData> &ctxt, const QString &propertyName,
+ const QQmlTranslation &translationData, const QQmlSourceLocation &location, QObject *obj)
+{
+ QQmlTranslationBinding *b = new QQmlTranslationBindingFromTranslationInfo(
+ unit, translationData, location.column, location.line);
+
+ b->setNotifyOnValueChanged(true);
+ b->QQmlJavaScriptExpression::setContext(ctxt);
+ b->setScopeObject(obj);
+
+#if QT_CONFIG(translation) && QT_CONFIG(qml_debug)
+ QString originString;
+ if (QQmlDebugTranslationService *service =
+ QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
+ service->foundTranslationBinding({ unit, b->scopeObject(), ctxt,
+
+ propertyName, translationData,
+
+ location.line, location.column });
+ }
+#else
+ Q_UNUSED(propertyName)
+#endif
return b;
}
+bool QQmlBinding::slowWrite(
+ const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData, const void *result,
+ QMetaType resultType, bool isUndefined, QQmlPropertyData::WriteFlags flags)
+{
+ // The logic in this method is obscure. It follows what the other slowWrite does, minus the type
+ // conversions and the checking for binding functions. If you're writing a C++ type, and
+ // you're passing a binding function wrapped into QJSValue, you probably want it to be assigned.
+
+ if (hasError())
+ return false;
+
+ QQmlEngine *qmlEngine = engine();
+ const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
+ QQmlJavaScriptExpression::DeleteWatcher watcher(this);
+
+ if (core.isVarProperty()) {
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data());
+ Q_ASSERT(vmemo);
+ vmemo->setVMEProperty(core.coreIndex(),
+ qmlEngine->handle()->metaTypeToJS(resultType, result));
+ } else if (isUndefined && core.isResettable()) {
+ void *args[] = { nullptr };
+ QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex(), args);
+ } else if (isUndefined && metaType == QMetaType::fromType<QVariant>()) {
+ QQmlPropertyPrivate::writeValueProperty(
+ m_target.data(), core, valueTypeData, QVariant(), context(), flags);
+ } else if (metaType == QMetaType::fromType<QJSValue>()) {
+ QQmlPropertyPrivate::writeValueProperty(
+ m_target.data(), core, valueTypeData,
+ QVariant(resultType, result), context(), flags);
+ } else if (isUndefined) {
+ const char *name = metaType.name();
+ const QString typeName = name
+ ? QString::fromUtf8(name)
+ : QStringLiteral("[unknown property type]");
+ delayedError()->setErrorDescription(
+ QStringLiteral("Unable to assign [undefined] to ") + typeName);
+ return false;
+ } else if (!QQmlPropertyPrivate::writeValueProperty(
+ m_target.data(), core, valueTypeData, QVariant(resultType, result),
+ context(), flags)) {
+ if (watcher.wasDeleted())
+ return true;
+ handleWriteError(result, resultType, metaType);
+ return false;
+ }
+
+ return true;
+}
+
Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
const QQmlPropertyData &valueTypeData,
const QV4::Value &result,
bool isUndefined, QQmlPropertyData::WriteFlags flags)
{
- QQmlEngine *engine = context()->engine;
- QV4::ExecutionEngine *v4engine = engine->handle();
-
- int type = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
+ const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
+ const int type = metaType.id();
QQmlJavaScriptExpression::DeleteWatcher watcher(this);
@@ -408,13 +481,20 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
if (isUndefined) {
} else if (core.isQList()) {
- value = v4engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
+ if (core.propType().flags() & QMetaType::IsQmlList)
+ value = QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QObject*>>());
+ else
+ value = QV4::ExecutionEngine::toVariant(result, core.propType());
} else if (result.isNull() && core.isQObject()) {
value = QVariant::fromValue((QObject *)nullptr);
- } else if (core.propType() == qMetaTypeId<QList<QUrl> >()) {
- value = QQmlPropertyPrivate::resolvedUrlSequence(v4engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context());
- } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) {
- value = v4engine->toVariant(result, type);
+ } else if (core.propType() == QMetaType::fromType<QList<QUrl>>()) {
+ const QVariant resultVariant
+ = QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QUrl>>());
+ value = QVariant::fromValue(QQmlPropertyPrivate::resolveUrlsOnAssignment()
+ ? QQmlPropertyPrivate::urlSequence(resultVariant, context())
+ : QQmlPropertyPrivate::urlSequence(resultVariant));
+ } else if (!isVarProperty && metaType != QMetaType::fromType<QJSValue>()) {
+ value = QV4::ExecutionEngine::toVariant(result, metaType);
}
if (hasError()) {
@@ -431,24 +511,25 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data());
Q_ASSERT(vmemo);
vmemo->setVMEProperty(core.coreIndex(), result);
- } else if (isUndefined && core.isResettable()) {
- void *args[] = { nullptr };
- QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex(), args);
- } else if (isUndefined && type == qMetaTypeId<QVariant>()) {
+ } else if (isUndefined
+ && (valueTypeData.isValid() ? valueTypeData.isResettable() : core.isResettable())) {
+ QQmlPropertyPrivate::resetValueProperty(
+ m_target.data(), core, valueTypeData, context(), flags);
+ } else if (isUndefined && type == QMetaType::QVariant) {
QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, QVariant(), context(), flags);
- } else if (type == qMetaTypeId<QJSValue>()) {
+ } else if (metaType == QMetaType::fromType<QJSValue>()) {
const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
if (f && f->isBinding()) {
delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
return false;
}
- QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, QVariant::fromValue(
- QJSValue(v4engine, result.asReturnedValue())),
- context(), flags);
+ QQmlPropertyPrivate::writeValueProperty(
+ m_target.data(), core, valueTypeData,
+ QVariant::fromValue(QJSValuePrivate::fromReturnedValue(result.asReturnedValue())),
+ context(), flags);
} else if (isUndefined) {
- const QLatin1String typeName(QMetaType::typeName(type)
- ? QMetaType::typeName(type)
- : "[unknown property type]");
+ const char *name = QMetaType(type).name();
+ const QLatin1String typeName(name ? name : "[unknown property type]");
delayedError()->setErrorDescription(QLatin1String("Unable to assign [undefined] to ")
+ typeName);
return false;
@@ -462,69 +543,61 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
if (watcher.wasDeleted())
return true;
+ handleWriteError(value.constData(), value.metaType(), metaType);
+ return false;
+ }
- const char *valueType = nullptr;
- const char *propertyType = nullptr;
-
- const int userType = value.userType();
- if (userType == QMetaType::QObjectStar) {
- if (QObject *o = *(QObject *const *)value.constData()) {
- valueType = o->metaObject()->className();
+ return true;
+}
- QQmlMetaObject propertyMetaObject = QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate::get(engine), type);
- if (!propertyMetaObject.isNull())
- propertyType = propertyMetaObject.className();
- }
- } else if (userType != QVariant::Invalid) {
- if (userType == QMetaType::Nullptr || userType == QMetaType::VoidStar)
- valueType = "null";
- else
- valueType = QMetaType::typeName(userType);
+void QQmlBinding::handleWriteError(const void *result, QMetaType resultType, QMetaType metaType)
+{
+ const char *valueType = nullptr;
+ const char *propertyType = nullptr;
+
+ if (resultType.flags() & QMetaType::PointerToQObject) {
+ if (QObject *o = *(QObject *const *)result) {
+ valueType = o->metaObject()->className();
+ QQmlMetaObject propertyMetaObject = QQmlPropertyPrivate::rawMetaObjectForType(metaType);
+ if (!propertyMetaObject.isNull())
+ propertyType = propertyMetaObject.className();
+ }
+ } else if (resultType.isValid()) {
+ if (resultType == QMetaType::fromType<std::nullptr_t>()
+ || resultType == QMetaType::fromType<void *>()) {
+ valueType = "null";
+ } else {
+ valueType = resultType.name();
}
-
- if (!valueType)
- valueType = "undefined";
- if (!propertyType)
- propertyType = QMetaType::typeName(type);
- if (!propertyType)
- propertyType = "[unknown property type]";
-
- delayedError()->setErrorDescription(QLatin1String("Unable to assign ") +
- QLatin1String(valueType) +
- QLatin1String(" to ") +
- QLatin1String(propertyType));
- return false;
}
- return true;
+ if (!valueType)
+ valueType = "undefined";
+ if (!propertyType)
+ propertyType = metaType.name();
+ if (!propertyType)
+ propertyType = "[unknown property type]";
+
+ delayedError()->setErrorDescription(QStringLiteral("Unable to assign ")
+ + QString::fromUtf8(valueType)
+ + QStringLiteral(" to ")
+ + QString::fromUtf8(propertyType));
}
QVariant QQmlBinding::evaluate()
{
- QQmlEngine *engine = context()->engine;
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ QQmlEngine *qmlEngine = engine();
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlEngine);
ep->referenceScarceResources();
bool isUndefined = false;
- QV4::Scope scope(engine->handle());
+ QV4::Scope scope(qmlEngine->handle());
QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined));
ep->dereferenceScarceResources();
- return scope.engine->toVariant(result, qMetaTypeId<QList<QObject*> >());
-}
-
-QString QQmlBinding::expressionIdentifier() const
-{
- if (auto f = function()) {
- QString url = f->sourceFile();
- uint lineNumber = f->compiledFunction->location.line;
- uint columnNumber = f->compiledFunction->location.column;
- return url + QString::asprintf(":%u:%u", lineNumber, columnNumber);
- }
-
- return QStringLiteral("[native code]");
+ return QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QObject*> >());
}
void QQmlBinding::expressionChanged()
@@ -542,12 +615,7 @@ void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
const bool wasEnabled = enabledFlag();
setEnabledFlag(e);
setNotifyOnValueChanged(e);
-
- m_nextBinding.setFlag2(); // Always use accessors, only not when:
- if (auto interceptorMetaObject = QQmlInterceptorMetaObject::get(targetObject())) {
- if (!m_targetIndex.isValid() || interceptorMetaObject->intercepts(m_targetIndex))
- m_nextBinding.clearFlag2();
- }
+ updateCanUseAccessor();
if (e && !wasEnabled)
update(flags);
@@ -558,85 +626,6 @@ QString QQmlBinding::expression() const
return QStringLiteral("function() { [native code] }");
}
-void QQmlBinding::setTarget(const QQmlProperty &prop)
-{
- auto pd = QQmlPropertyPrivate::get(prop);
- setTarget(prop.object(), pd->core, &pd->valueTypeData);
-}
-
-bool QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const QQmlPropertyData *valueType)
-{
- m_target = object;
-
- if (!object) {
- m_targetIndex = QQmlPropertyIndex();
- return false;
- }
-
- int coreIndex = core.coreIndex();
- int valueTypeIndex = valueType ? valueType->coreIndex() : -1;
- for (bool isAlias = core.isAlias(); isAlias; ) {
- QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
-
- int aValueTypeIndex;
- if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) {
- // can't resolve id (yet)
- m_target = nullptr;
- m_targetIndex = QQmlPropertyIndex();
- return false;
- }
- if (valueTypeIndex == -1)
- valueTypeIndex = aValueTypeIndex;
-
- QQmlData *data = QQmlData::get(object, false);
- if (!data || !data->propertyCache) {
- m_target = nullptr;
- m_targetIndex = QQmlPropertyIndex();
- return false;
- }
- QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
- Q_ASSERT(propertyData);
-
- m_target = object;
- isAlias = propertyData->isAlias();
- coreIndex = propertyData->coreIndex();
- }
- m_targetIndex = QQmlPropertyIndex(coreIndex, valueTypeIndex);
-
- QQmlData *data = QQmlData::get(*m_target, true);
- if (!data->propertyCache) {
- data->propertyCache = QQmlEnginePrivate::get(context()->engine)->cache(m_target->metaObject());
- data->propertyCache->addref();
- }
-
- return true;
-}
-
-void QQmlBinding::getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const
-{
- Q_ASSERT(propertyData);
-
- QQmlData *data = QQmlData::get(*m_target, false);
- Q_ASSERT(data);
-
- if (Q_UNLIKELY(!data->propertyCache)) {
- data->propertyCache = QQmlEnginePrivate::get(context()->engine)->cache(m_target->metaObject());
- data->propertyCache->addref();
- }
-
- *propertyData = data->propertyCache->property(m_targetIndex.coreIndex());
- Q_ASSERT(*propertyData);
-
- if (Q_UNLIKELY(m_targetIndex.hasValueTypeIndex() && valueTypeData)) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType((*propertyData)->propType());
- Q_ASSERT(valueTypeMetaObject);
- QMetaProperty vtProp = valueTypeMetaObject->property(m_targetIndex.valueTypeIndex());
- valueTypeData->setFlags(QQmlPropertyData::flagsForProperty(vtProp));
- valueTypeData->setPropType(vtProp.userType());
- valueTypeData->setCoreIndex(m_targetIndex.valueTypeIndex());
- }
-}
-
QVector<QQmlProperty> QQmlBinding::dependencies() const
{
QVector<QQmlProperty> dependencies;
@@ -658,33 +647,132 @@ QVector<QQmlProperty> QQmlBinding::dependencies() const
for (int i = 0; i < senderMeta->propertyCount(); i++) {
QMetaProperty property = senderMeta->property(i);
if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) {
- dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(senderObject->metaObject()->property(i).name())));
+ dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(property.name())));
}
}
}
+ for (auto trigger = qpropertyChangeTriggers; trigger; trigger = trigger->next) {
+ QMetaProperty prop = trigger->property();
+ if (prop.isValid())
+ dependencies.push_back(QQmlProperty(trigger->target, QString::fromUtf8(prop.name())));
+ }
+
return dependencies;
}
bool QQmlBinding::hasDependencies() const
{
- return !activeGuards.isEmpty() || translationsCaptured();
+ return !activeGuards.isEmpty() || qpropertyChangeTriggers;
}
-class QObjectPointerBinding: public QQmlNonbindingBinding
+void QQmlBinding::doUpdate(const DeleteWatcher &watcher, QQmlPropertyData::WriteFlags flags, QV4::Scope &scope)
+{
+ auto ep = QQmlEnginePrivate::get(scope.engine);
+ ep->referenceScarceResources();
+
+ bool error = false;
+ auto canWrite = [&]() { return !watcher.wasDeleted() && isAddedToObject() && !hasError(); };
+ const QV4::Function *v4Function = function();
+ if (v4Function && v4Function->kind == QV4::Function::AotCompiled && !hasBoundFunction()) {
+ const auto returnType = v4Function->aotCompiledFunction.types[0];
+ if (returnType == QMetaType::fromType<QVariant>()) {
+ QVariant result;
+ const bool isUndefined = !evaluate(&result, returnType);
+ if (canWrite())
+ error = !write(result.data(), result.metaType(), isUndefined, flags);
+ } else {
+ const auto size = returnType.sizeOf();
+ if (Q_LIKELY(size > 0)) {
+ Q_ALLOCA_VAR(void, result, size);
+ if (returnType.flags() & QMetaType::NeedsConstruction)
+ returnType.construct(result);
+ const bool isUndefined = !evaluate(result, returnType);
+ if (canWrite())
+ error = !write(result, returnType, isUndefined, flags);
+ if (returnType.flags() & QMetaType::NeedsDestruction)
+ returnType.destruct(result);
+ } else if (canWrite()) {
+ error = !write(QV4::Encode::undefined(), true, flags);
+ }
+ }
+ } else {
+ bool isUndefined = false;
+ QV4::ScopedValue result(scope, evaluate(&isUndefined));
+ if (canWrite())
+ error = !write(result, isUndefined, flags);
+ }
+
+ if (!watcher.wasDeleted()) {
+
+ if (error) {
+ delayedError()->setErrorLocation(sourceLocation());
+ delayedError()->setErrorObject(m_target.data());
+ }
+
+ if (hasError()) {
+ if (!delayedError()->addError(ep)) ep->warning(this->error(engine()));
+ } else {
+ clearError();
+ }
+ }
+
+ ep->dereferenceScarceResources();
+}
+
+class QObjectPointerBinding: public QQmlBinding
{
QQmlMetaObject targetMetaObject;
public:
- QObjectPointerBinding(QQmlEnginePrivate *engine, int propertyType)
- : targetMetaObject(QQmlPropertyPrivate::rawMetaObjectForType(engine, propertyType))
+ QObjectPointerBinding(QMetaType propertyType)
+ : targetMetaObject(QQmlPropertyPrivate::rawMetaObjectForType(propertyType))
{}
protected:
+ Q_ALWAYS_INLINE bool write(void *result, QMetaType type, bool isUndefined,
+ QQmlPropertyData::WriteFlags flags) override final
+ {
+ const QQmlPropertyData *pd;
+ QQmlPropertyData vtpd;
+ getPropertyData(&pd, &vtpd);
+ if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
+ return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
+
+ // Check if the result is a QObject:
+ QObject *resultObject = nullptr;
+ QQmlMetaObject resultMo;
+ const auto typeFlags = type.flags();
+ if (!result || ((typeFlags & QMetaType::IsPointer) && !*static_cast<void **>(result))) {
+ // Special case: we can always write a nullptr. Don't bother checking anything else.
+ return pd->writeProperty(targetObject(), &resultObject, flags);
+ } else if (typeFlags & QMetaType::PointerToQObject) {
+ resultObject = *static_cast<QObject **>(result);
+ if (!resultObject)
+ return pd->writeProperty(targetObject(), &resultObject, flags);
+ if (QQmlData *ddata = QQmlData::get(resultObject, false))
+ resultMo = ddata->propertyCache;
+ if (resultMo.isNull())
+ resultMo = resultObject->metaObject();
+ } else if (type == QMetaType::fromType<QVariant>()) {
+ const QVariant value = *static_cast<QVariant *>(result);
+ resultMo = QQmlPropertyPrivate::rawMetaObjectForType(value.metaType());
+ if (resultMo.isNull())
+ return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
+ resultObject = *static_cast<QObject *const *>(value.constData());
+ } else {
+ return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
+ }
+
+ return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
+ return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
+ });
+ }
+
Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined,
QQmlPropertyData::WriteFlags flags) override final
{
- QQmlPropertyData *pd;
+ const QQmlPropertyData *pd;
QQmlPropertyData vtpd;
getPropertyData(&pd, &vtpd);
if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
@@ -706,9 +794,8 @@ protected:
resultMo = resultObject->metaObject();
}
} else if (auto variant = result.as<QV4::VariantObject>()) {
- QVariant value = variant->d()->data();
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context());
- resultMo = QQmlPropertyPrivate::rawMetaObjectForType(ep, value.userType());
+ const QVariant value = variant->d()->data();
+ resultMo = QQmlPropertyPrivate::rawMetaObjectForType(value.metaType());
if (resultMo.isNull())
return slowWrite(*pd, vtpd, result, isUndefined, flags);
resultObject = *static_cast<QObject *const *>(value.constData());
@@ -716,7 +803,18 @@ protected:
return slowWrite(*pd, vtpd, result, isUndefined, flags);
}
- // Compare & set:
+ return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
+ return slowWrite(*pd, vtpd, result, isUndefined, flags);
+ });
+ }
+
+private:
+ using QQmlBinding::slowWrite;
+
+ template<typename SlowWrite>
+ bool compareAndSet(const QQmlMetaObject &resultMo, QObject *resultObject, const QQmlPropertyData *pd,
+ QQmlPropertyData::WriteFlags flags, const SlowWrite &slowWrite) const
+ {
if (QQmlMetaObject::canConvert(resultMo, targetMetaObject)) {
return pd->writeProperty(targetObject(), &resultObject, flags);
} else if (!resultObject && QQmlMetaObject::canConvert(targetMetaObject, resultMo)) {
@@ -725,23 +823,22 @@ protected:
// the property type.
return pd->writeProperty(targetObject(), &resultObject, flags);
} else {
- return slowWrite(*pd, vtpd, result, isUndefined, flags);
+ return slowWrite();
}
}
};
-QQmlBinding *QQmlBinding::newBinding(QQmlEnginePrivate *engine, const QQmlPropertyData *property)
+QQmlBinding *QQmlBinding::newBinding(const QQmlPropertyData *property)
{
- if (property && property->isQObject())
- return new QObjectPointerBinding(engine, property->propType());
-
- const int type = (property && property->isFullyResolved()) ? property->propType() : QMetaType::UnknownType;
+ return newBinding(property ? property->propType() : QMetaType());
+}
- if (type == qMetaTypeId<QQmlBinding *>()) {
- return new QQmlBindingBinding;
- }
+QQmlBinding *QQmlBinding::newBinding(QMetaType propertyType)
+{
+ if (propertyType.flags() & QMetaType::PointerToQObject)
+ return new QObjectPointerBinding(propertyType);
- switch (type) {
+ switch (propertyType.id()) {
case QMetaType::Bool:
return new GenericBinding<QMetaType::Bool>;
case QMetaType::Int:
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index 7f96b4df9f..4031a2655e 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLBINDING_P_H
#define QQMLBINDING_P_H
@@ -51,12 +15,8 @@
// We mean it.
//
-#include "qqml.h"
-#include "qqmlpropertyvaluesource.h"
-#include "qqmlexpression.h"
#include "qqmlproperty.h"
#include "qqmlscriptstring.h"
-#include "qqmlproperty_p.h"
#include <QtCore/QObject>
#include <QtCore/QMetaProperty>
@@ -64,11 +24,12 @@
#include <private/qqmlabstractbinding_p.h>
#include <private/qqmljavascriptexpression_p.h>
#include <private/qv4functionobject_p.h>
+#include <private/qqmltranslation_p.h>
QT_BEGIN_NAMESPACE
class QQmlContext;
-class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression,
+class Q_QML_EXPORT QQmlBinding : public QQmlJavaScriptExpression,
public QQmlAbstractBinding
{
friend class QQmlAbstractBinding;
@@ -76,19 +37,36 @@ public:
typedef QExplicitlySharedDataPointer<QQmlBinding> Ptr;
static QQmlBinding *create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *);
- static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *,
- const QString &url = QString(), quint16 lineNumber = 0);
- static QQmlBinding *create(const QQmlPropertyData *property, QV4::Function *function,
- QObject *obj, QQmlContextData *ctxt, QV4::ExecutionContext *scope);
- static QQmlBinding *createTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, const QV4::CompiledData::Binding *binding,
- QObject *obj, QQmlContextData *ctxt);
- ~QQmlBinding() override;
- void setTarget(const QQmlProperty &);
- bool setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType);
+ static QQmlBinding *create(
+ const QQmlPropertyData *, const QString &, QObject *,
+ const QQmlRefPointer<QQmlContextData> &, const QString &url = QString(),
+ quint16 lineNumber = 0);
+
+ static QQmlBinding *create(
+ const QQmlPropertyData *property, QV4::Function *function, QObject *obj,
+ const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope);
+
+ static QQmlBinding *create(QMetaType propertyType, QV4::Function *function, QObject *obj,
+ const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::ExecutionContext *scope);
+
+ static QQmlBinding *createTranslationBinding(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QV4::CompiledData::Binding *binding, QObject *obj,
+ const QQmlRefPointer<QQmlContextData> &ctxt);
+
+ static QQmlBinding *
+ createTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QQmlRefPointer<QQmlContextData> &ctxt,
+ const QString &propertyName, const QQmlTranslation &translationData,
+ const QQmlSourceLocation &location, QObject *obj);
- void setNotifyOnValueChanged(bool);
+ Kind kind() const final { return QQmlAbstractBinding::QmlBinding; }
+ ~QQmlBinding() override;
+
+ bool mustCaptureBindableProperty() const final {return true;}
void refresh() override;
void setEnabled(bool, QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding) override;
@@ -101,8 +79,11 @@ public:
};
QVariant evaluate();
+ bool evaluate(void *result, QMetaType type)
+ {
+ return QQmlJavaScriptExpression::evaluate(&result, &type, 0);
+ }
- QString expressionIdentifier() const override;
void expressionChanged() override;
QQmlSourceLocation sourceLocation() const override;
@@ -110,6 +91,7 @@ public:
void setBoundFunction(QV4::BoundFunction *boundFunction) {
m_boundFunction.set(boundFunction->engine(), *boundFunction);
}
+ bool hasBoundFunction() const { return m_boundFunction.valueRef(); }
/**
* This method returns a snapshot of the currently tracked dependencies of
@@ -119,52 +101,35 @@ public:
* Call this method from the UI thread.
*/
QVector<QQmlProperty> dependencies() const;
+ // This method is used internally to check whether a binding is constant and can be removed
virtual bool hasDependencies() const;
protected:
virtual void doUpdate(const DeleteWatcher &watcher,
- QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) = 0;
+ QQmlPropertyData::WriteFlags flags, QV4::Scope &scope);
+
+ virtual bool write(const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags) = 0;
+ virtual bool write(void *result, QMetaType type, bool isUndefined, QQmlPropertyData::WriteFlags flags) = 0;
- void getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const;
int getPropertyType() const;
bool slowWrite(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags);
+ bool slowWrite(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
+ const void *result, QMetaType resultType, bool isUndefined,
+ QQmlPropertyData::WriteFlags flags);
QV4::ReturnedValue evaluate(bool *isUndefined);
private:
- inline bool updatingFlag() const;
- inline void setUpdatingFlag(bool);
- inline bool enabledFlag() const;
- inline void setEnabledFlag(bool);
-
- static QQmlBinding *newBinding(QQmlEnginePrivate *engine, const QQmlPropertyData *property);
+ static QQmlBinding *newBinding(const QQmlPropertyData *property);
+ static QQmlBinding *newBinding(QMetaType propertyType);
QQmlSourceLocation *m_sourceLocation = nullptr; // used for Qt.binding() created functions
QV4::PersistentValue m_boundFunction; // used for Qt.binding() that are created from a bound function object
+ void handleWriteError(const void *result, QMetaType resultType, QMetaType metaType);
};
-bool QQmlBinding::updatingFlag() const
-{
- return m_target.flag();
-}
-
-void QQmlBinding::setUpdatingFlag(bool v)
-{
- m_target.setFlagValue(v);
-}
-
-bool QQmlBinding::enabledFlag() const
-{
- return m_target.flag2();
-}
-
-void QQmlBinding::setEnabledFlag(bool v)
-{
- m_target.setFlag2Value(v);
-}
-
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQmlBinding*)
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index ff01e737ca..3f9ce26764 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -1,51 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlboundsignal_p.h"
#include <private/qmetaobject_p.h>
#include <private/qmetaobjectbuilder_p.h>
#include "qqmlengine_p.h"
-#include "qqmlexpression_p.h"
-#include "qqmlcontext_p.h"
-#include "qqml.h"
-#include "qqmlcontext.h"
#include "qqmlglobal_p.h"
#include <private/qqmlprofiler_p.h>
#include <private/qqmldebugconnector_p.h>
@@ -60,14 +20,17 @@
#include <QtCore/qdebug.h>
+#include <qtqml_tracepoints_p.h>
QT_BEGIN_NAMESPACE
-QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
- QQmlContextData *ctxt, QObject *scope, const QString &expression,
- const QString &fileName, quint16 line, quint16 column,
- const QString &handlerName,
- const QString &parameterString)
+Q_TRACE_POINT(qtqml, QQmlHandlingSignal_entry, const QQmlEngine *engine, const QString &function,
+ const QString &fileName, int line, int column)
+Q_TRACE_POINT(qtqml, QQmlHandlingSignal_exit)
+
+QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int index, const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope,
+ const QString &expression, const QString &fileName, quint16 line, quint16 column,
+ const QString &handlerName, const QString &parameterString)
: QQmlJavaScriptExpression(),
m_index(index),
m_target(target)
@@ -104,8 +67,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
setupFunction(context, f->function());
}
-QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scopeObject,
- QV4::Function *function, QV4::ExecutionContext *scope)
+QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int index, const QQmlRefPointer<QQmlContextData> &ctxt,
+ QObject *scopeObject, QV4::Function *function, QV4::ExecutionContext *scope)
: QQmlJavaScriptExpression(),
m_index(index),
m_target(target)
@@ -113,14 +76,9 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
// It's important to call init first, because m_index gets remapped in case of cloned signals.
init(ctxt, scopeObject);
- QV4::ExecutionEngine *engine = ctxt->engine->handle();
+ QV4::ExecutionEngine *engine = ctxt->engine()->handle();
- // If the function is marked as having a nested function, then the user wrote:
- // onSomeSignal: function() { /*....*/ }
- // So take that nested function:
- if (auto closure = function->nestedFunction()) {
- function = closure;
- } else {
+ if (!function->isClosureWrapper()) {
QList<QByteArray> signalParameters = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).parameterNames();
if (!signalParameters.isEmpty()) {
QString error;
@@ -137,10 +95,32 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
QV4::Scoped<QV4::QmlContext> qmlContext(valueScope, scope);
if (!qmlContext)
qmlContext = QV4::QmlContext::create(engine->rootContext(), ctxt, scopeObject);
- setupFunction(qmlContext, function);
+ if (auto closure = function->nestedFunction()) {
+ // If the function is marked as having a nested function, then the user wrote:
+ // onSomeSignal: function() { /*....*/ }
+ // So take that nested function:
+ setupFunction(qmlContext, closure);
+ } else {
+ setupFunction(qmlContext, function);
+
+ // If it's a closure wrapper but we cannot directly access the nested function
+ // we need to run the outer function to get the nested one.
+ if (function->isClosureWrapper()) {
+ bool isUndefined = false;
+ QV4::ScopedFunctionObject result(
+ valueScope, QQmlJavaScriptExpression::evaluate(&isUndefined));
+
+ Q_ASSERT(!isUndefined);
+ Q_ASSERT(result->function());
+ Q_ASSERT(result->function()->compilationUnit == function->compilationUnit);
+
+ QV4::Scoped<QV4::ExecutionContext> callContext(valueScope, result->scope());
+ setupFunction(callContext, result->function());
+ }
+ }
}
-void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope)
+void QQmlBoundSignalExpression::init(const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope)
{
setNotifyOnValueChanged(false);
setContext(ctxt);
@@ -172,79 +152,53 @@ QString QQmlBoundSignalExpression::expression() const
return QString();
}
-// Parts of this function mirror code in QQmlExpressionPrivate::value() and v8value().
+// Parts of this function mirror code in QQmlExpressionPrivate::value() and v4Value().
// Changes made here may need to be made there and vice versa.
void QQmlBoundSignalExpression::evaluate(void **a)
{
- Q_ASSERT (context() && engine());
-
if (!expressionFunctionValid())
return;
QQmlEngine *qmlengine = engine();
+
+ // If there is no engine, we have no way to evaluate anything.
+ // This can happen on destruction.
+ if (!qmlengine)
+ return;
+
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlengine);
QV4::ExecutionEngine *v4 = qmlengine->handle();
QV4::Scope scope(v4);
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
- QQmlMetaObject::ArgTypeStorage storage;
- //TODO: lookup via signal index rather than method index as an optimization
- int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex();
- int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, &storage, nullptr);
- int argCount = argsTypes ? *argsTypes : 0;
-
- QV4::JSCallData jsCall(scope, argCount);
- for (int ii = 0; ii < argCount; ++ii) {
- int type = argsTypes[ii + 1];
- //### ideally we would use metaTypeToJS, however it currently gives different results
- // for several cases (such as QVariant type and QObject-derived types)
- //args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
- if (type == qMetaTypeId<QJSValue>()) {
- if (QV4::Value *v4Value = QJSValuePrivate::valueForData(reinterpret_cast<QJSValue *>(a[ii + 1]), &jsCall->args[ii]))
- jsCall->args[ii] = *v4Value;
- else
- jsCall->args[ii] = QV4::Encode::undefined();
- } else if (type == QMetaType::QVariant) {
- jsCall->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1]));
- } else if (type == QMetaType::Int) {
- //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise
- jsCall->args[ii] = QV4::Value::fromInt32(*reinterpret_cast<const int*>(a[ii + 1]));
- } else if (ep->isQObject(type)) {
- if (!*reinterpret_cast<void* const *>(a[ii + 1]))
- jsCall->args[ii] = QV4::Value::nullValue();
+ if (a) {
+ //TODO: lookup via signal index rather than method index as an optimization
+ const QMetaObject *targetMeta = m_target->metaObject();
+ const QMetaMethod metaMethod = targetMeta->method(
+ QMetaObjectPrivate::signal(targetMeta, m_index).methodIndex());
+
+ int argCount = metaMethod.parameterCount();
+ QQmlMetaObject::ArgTypeStorage<9> storage;
+ storage.reserve(argCount + 1);
+ storage.append(QMetaType()); // We're not interested in the return value
+ for (int i = 0; i < argCount; ++i) {
+ const QMetaType type = metaMethod.parameterMetaType(i);
+ if (!type.isValid())
+ argCount = 0;
+ else if (type.flags().testFlag(QMetaType::IsEnumeration))
+ storage.append(type.underlyingType());
else
- jsCall->args[ii] = QV4::QObjectWrapper::wrap(v4, *reinterpret_cast<QObject* const *>(a[ii + 1]));
- } else {
- jsCall->args[ii] = scope.engine->fromVariant(QVariant(type, a[ii + 1]));
+ storage.append(type);
}
- }
-
- QQmlJavaScriptExpression::evaluate(jsCall.callData(), nullptr);
-
- ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
-}
-
-void QQmlBoundSignalExpression::evaluate(const QList<QVariant> &args)
-{
- Q_ASSERT (context() && engine());
-
- if (!expressionFunctionValid())
- return;
- QQmlEngine *qmlengine = engine();
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlengine);
- QV4::Scope scope(qmlengine->handle());
-
- ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
-
- QV4::JSCallData jsCall(scope, args.count());
- for (int ii = 0; ii < args.count(); ++ii) {
- jsCall->args[ii] = scope.engine->fromVariant(args[ii]);
+ QQmlJavaScriptExpression::evaluate(a, storage.constData(), argCount);
+ } else {
+ void *ignoredResult = nullptr;
+ QMetaType invalidType;
+ QQmlJavaScriptExpression::evaluate(&ignoredResult, &invalidType, 0);
}
- QQmlJavaScriptExpression::evaluate(jsCall.callData(), nullptr);
-
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
@@ -259,7 +213,7 @@ QQmlBoundSignal::QQmlBoundSignal(QObject *target, int signal, QObject *owner,
QQmlEngine *engine)
: QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlBoundSignal),
m_prevSignal(nullptr), m_nextSignal(nullptr),
- m_enabled(true), m_expression(nullptr)
+ m_enabled(true)
{
addToObject(owner);
@@ -301,13 +255,12 @@ void QQmlBoundSignal::removeFromObject()
}
}
-
/*!
Returns the signal expression.
*/
QQmlBoundSignalExpression *QQmlBoundSignal::expression() const
{
- return m_expression;
+ return m_expression.data();
}
/*!
@@ -317,7 +270,7 @@ QQmlBoundSignalExpression *QQmlBoundSignal::expression() const
*/
void QQmlBoundSignal::takeExpression(QQmlBoundSignalExpression *e)
{
- m_expression.take(e);
+ m_expression.adopt(e);
if (m_expression)
m_expression->setNotifyOnValueChanged(false);
}
@@ -352,7 +305,12 @@ void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a)
QQmlEngine *engine;
if (s->m_expression && (engine = s->m_expression->engine())) {
- QQmlHandlingSignalProfiler prof(QQmlEnginePrivate::get(engine)->profiler, s->m_expression);
+ Q_TRACE_SCOPE(QQmlHandlingSignal, engine,
+ s->m_expression->function() ? s->m_expression->function()->name()->toQString() : QString(),
+ s->m_expression->sourceLocation().sourceFile, s->m_expression->sourceLocation().line,
+ s->m_expression->sourceLocation().column);
+ QQmlHandlingSignalProfiler prof(QQmlEnginePrivate::get(engine)->profiler,
+ s->m_expression.data());
s->m_expression->evaluate(a);
if (s->m_expression && s->m_expression->hasError()) {
QQmlEnginePrivate::warning(engine, s->m_expression->error(engine));
@@ -362,48 +320,13 @@ void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a)
////////////////////////////////////////////////////////////////////////
-QQmlBoundSignalExpressionPointer::QQmlBoundSignalExpressionPointer(QQmlBoundSignalExpression *o)
-: o(o)
-{
- if (o) o->addref();
-}
-
-QQmlBoundSignalExpressionPointer::QQmlBoundSignalExpressionPointer(const QQmlBoundSignalExpressionPointer &other)
-: o(other.o)
-{
- if (o) o->addref();
-}
-
-QQmlBoundSignalExpressionPointer::~QQmlBoundSignalExpressionPointer()
-{
- if (o) o->release();
-}
-
-QQmlBoundSignalExpressionPointer &QQmlBoundSignalExpressionPointer::operator=(const QQmlBoundSignalExpressionPointer &other)
-{
- if (other.o) other.o->addref();
- if (o) o->release();
- o = other.o;
- return *this;
-}
-
-QQmlBoundSignalExpressionPointer &QQmlBoundSignalExpressionPointer::operator=(QQmlBoundSignalExpression *other)
-{
- if (other) other->addref();
- if (o) o->release();
- o = other;
- return *this;
-}
-
-/*!
-Takes ownership of \a other. take() does *not* add a reference, as it assumes ownership
-of the callers reference of other.
-*/
-QQmlBoundSignalExpressionPointer &QQmlBoundSignalExpressionPointer::take(QQmlBoundSignalExpression *other)
+QQmlPropertyObserver::QQmlPropertyObserver(QQmlBoundSignalExpression *expr)
+ : QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
+ auto This = static_cast<QQmlPropertyObserver*>(self);
+ This->expression->evaluate(nullptr);
+ })
{
- if (o) o->release();
- o = other;
- return *this;
+ expression.adopt(expr);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h
index d1ec67210e..9eab562f56 100644
--- a/src/qml/qml/qqmlboundsignal_p.h
+++ b/src/qml/qml/qqmlboundsignal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLBOUNDSIGNAL_P_H
#define QQMLBOUNDSIGNAL_P_H
@@ -54,27 +18,26 @@
#include <QtCore/qmetaobject.h>
#include <private/qqmljavascriptexpression_p.h>
-#include <private/qqmlboundsignalexpressionpointer_p.h>
#include <private/qqmlnotifier_p.h>
-#include <private/qflagpointer_p.h>
#include <private/qqmlrefcount_p.h>
-#include <private/qqmlglobal_p.h>
-#include <private/qbitfield_p.h>
+#include <private/qtqmlglobal_p.h>
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpression : public QQmlJavaScriptExpression, public QQmlRefCount
+class Q_QML_EXPORT QQmlBoundSignalExpression final
+ : public QQmlJavaScriptExpression,
+ public QQmlRefCounted<QQmlBoundSignalExpression>
{
+ friend class QQmlRefCounted<QQmlBoundSignalExpression>;
public:
- QQmlBoundSignalExpression(QObject *target, int index,
- QQmlContextData *ctxt, QObject *scope, const QString &expression,
- const QString &fileName, quint16 line, quint16 column,
- const QString &handlerName = QString(),
- const QString &parameterString = QString());
+ QQmlBoundSignalExpression(
+ const QObject *target, int index, const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope,
+ const QString &expression, const QString &fileName, quint16 line, quint16 column,
+ const QString &handlerName = QString(), const QString &parameterString = QString());
- QQmlBoundSignalExpression(QObject *target, int index,
- QQmlContextData *ctxt, QObject *scopeObject, QV4::Function *function,
- QV4::ExecutionContext *scope = nullptr);
+ QQmlBoundSignalExpression(
+ const QObject *target, int index, const QQmlRefPointer<QQmlContextData> &ctxt,
+ QObject *scopeObject, QV4::Function *function, QV4::ExecutionContext *scope = nullptr);
// inherited from QQmlJavaScriptExpression.
QString expressionIdentifier() const override;
@@ -82,25 +45,24 @@ public:
// evaluation of a bound signal expression doesn't return any value
void evaluate(void **a);
- void evaluate(const QList<QVariant> &args);
- QString expression() const;
- QObject *target() const { return m_target; }
+ bool mustCaptureBindableProperty() const final {return true;}
- QQmlEngine *engine() const { return context() ? context()->engine : nullptr; }
+ QString expression() const;
+ const QObject *target() const { return m_target; }
private:
~QQmlBoundSignalExpression() override;
- void init(QQmlContextData *ctxt, QObject *scope);
+ void init(const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope);
bool expressionFunctionValid() const { return function() != nullptr; }
int m_index;
- QObject *m_target;
+ const QObject *m_target;
};
-class Q_QML_PRIVATE_EXPORT QQmlBoundSignal : public QQmlNotifierEndpoint
+class Q_QML_EXPORT QQmlBoundSignal : public QQmlNotifierEndpoint
{
public:
QQmlBoundSignal(QObject *target, int signal, QObject *owner, QQmlEngine *engine);
@@ -126,7 +88,16 @@ private:
bool m_enabled;
- QQmlBoundSignalExpressionPointer m_expression;
+ QQmlRefPointer<QQmlBoundSignalExpression> m_expression;
+};
+
+class QQmlPropertyObserver : public QPropertyObserver
+{
+public:
+ QQmlPropertyObserver(QQmlBoundSignalExpression *expr);
+
+private:
+ QQmlRefPointer<QQmlBoundSignalExpression> expression;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlboundsignalexpressionpointer_p.h b/src/qml/qml/qqmlboundsignalexpressionpointer_p.h
deleted file mode 100644
index eabe6666b4..0000000000
--- a/src/qml/qml/qqmlboundsignalexpressionpointer_p.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLBOUNDSIGNALEXPRESSIONPOINTER_P_H
-#define QQMLBOUNDSIGNALEXPRESSIONPOINTER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-#include <QtQml/qtqmlglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlBoundSignalExpression;
-class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpressionPointer
-{
-public:
- inline QQmlBoundSignalExpressionPointer() {}
- QQmlBoundSignalExpressionPointer(QQmlBoundSignalExpression *);
- QQmlBoundSignalExpressionPointer(const QQmlBoundSignalExpressionPointer &);
- ~QQmlBoundSignalExpressionPointer();
-
- QQmlBoundSignalExpressionPointer &operator=(const QQmlBoundSignalExpressionPointer &o);
- QQmlBoundSignalExpressionPointer &operator=(QQmlBoundSignalExpression *);
-
- inline QQmlBoundSignalExpression* operator->() const { return o; }
- inline QQmlBoundSignalExpression& operator*() const { return *o; }
- inline operator QQmlBoundSignalExpression*() const { return o; }
-
- QQmlBoundSignalExpressionPointer &take(QQmlBoundSignalExpression *);
-
-private:
- QQmlBoundSignalExpression *o = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLBOUNDSIGNALEXPRESSIONPOINTER_P_H
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/qqmlbuiltinfunctions.cpp
index d634a48443..de37cc18be 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/qqmlbuiltinfunctions.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlbuiltinfunctions_p.h"
@@ -84,162 +48,289 @@
QT_BEGIN_NAMESPACE
-using namespace QV4;
+Q_LOGGING_CATEGORY(lcRootProperties, "qt.qml.rootObjectProperties");
+Q_LOGGING_CATEGORY(lcQml, "qml");
+Q_LOGGING_CATEGORY(lcJs, "js");
-DEFINE_OBJECT_VTABLE(QtObject);
+using namespace QV4;
#define THROW_TYPE_ERROR_WITH_MESSAGE(msg) \
do { \
return scope.engine->throwTypeError(QString::fromUtf8(msg)); \
} while (false)
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
+/*!
+\qmltype Qt
+\inqmlmodule QtQml
+//! \instantiates QQmlEnginePrivate
+\ingroup qml-utility-elements
+\keyword QmlGlobalQtObject
+\brief Provides a global object with useful enums and functions from Qt.
-void Heap::QtObject::init(QQmlEngine *qmlEngine)
-{
- Heap::Object::init();
- enumeratorIterator = 0;
- keyIterator = 0;
- Scope scope(internalClass->engine);
- ScopedObject o(scope, this);
+\c Qt is a singleton type that provides utility functions, properties, and
+enums. Here is an example showing how to use this type:
- {
- ScopedString str(scope);
- ScopedValue v(scope);
- o->put((str = scope.engine->newString(QStringLiteral("Asynchronous"))), (v = QV4::Value::fromInt32(0)));
- o->put((str = scope.engine->newString(QStringLiteral("Synchronous"))), (v = QV4::Value::fromInt32(1)));
- }
+\qml
+import QtQuick 2.0
- o->defineDefaultProperty(QStringLiteral("include"), QV4Include::method_include);
- o->defineDefaultProperty(QStringLiteral("isQtObject"), QV4::QtObject::method_isQtObject);
- o->defineDefaultProperty(QStringLiteral("rgba"), QV4::QtObject::method_rgba);
- o->defineDefaultProperty(QStringLiteral("hsla"), QV4::QtObject::method_hsla);
- o->defineDefaultProperty(QStringLiteral("hsva"), QV4::QtObject::method_hsva);
- o->defineDefaultProperty(QStringLiteral("colorEqual"), QV4::QtObject::method_colorEqual);
- o->defineDefaultProperty(QStringLiteral("rect"), QV4::QtObject::method_rect);
- o->defineDefaultProperty(QStringLiteral("point"), QV4::QtObject::method_point);
- o->defineDefaultProperty(QStringLiteral("size"), QV4::QtObject::method_size);
- o->defineDefaultProperty(QStringLiteral("font"), QV4::QtObject::method_font);
-
- o->defineDefaultProperty(QStringLiteral("vector2d"), QV4::QtObject::method_vector2d);
- o->defineDefaultProperty(QStringLiteral("vector3d"), QV4::QtObject::method_vector3d);
- o->defineDefaultProperty(QStringLiteral("vector4d"), QV4::QtObject::method_vector4d);
- o->defineDefaultProperty(QStringLiteral("quaternion"), QV4::QtObject::method_quaternion);
- o->defineDefaultProperty(QStringLiteral("matrix4x4"), QV4::QtObject::method_matrix4x4);
-
- o->defineDefaultProperty(QStringLiteral("formatDate"), QV4::QtObject::method_formatDate);
- o->defineDefaultProperty(QStringLiteral("formatTime"), QV4::QtObject::method_formatTime);
- o->defineDefaultProperty(QStringLiteral("formatDateTime"), QV4::QtObject::method_formatDateTime);
-
- o->defineDefaultProperty(QStringLiteral("openUrlExternally"), QV4::QtObject::method_openUrlExternally);
- o->defineDefaultProperty(QStringLiteral("fontFamilies"), QV4::QtObject::method_fontFamilies);
- o->defineDefaultProperty(QStringLiteral("md5"), QV4::QtObject::method_md5);
- o->defineDefaultProperty(QStringLiteral("btoa"), QV4::QtObject::method_btoa);
- o->defineDefaultProperty(QStringLiteral("atob"), QV4::QtObject::method_atob);
- o->defineDefaultProperty(QStringLiteral("resolvedUrl"), QV4::QtObject::method_resolvedUrl);
-#if QT_CONFIG(qml_locale)
- o->defineDefaultProperty(QStringLiteral("locale"), QV4::QtObject::method_locale);
-#endif
- o->defineDefaultProperty(QStringLiteral("binding"), QV4::QtObject::method_binding);
-
- if (qmlEngine) {
- o->defineDefaultProperty(QStringLiteral("lighter"), QV4::QtObject::method_lighter);
- o->defineDefaultProperty(QStringLiteral("darker"), QV4::QtObject::method_darker);
- o->defineDefaultProperty(QStringLiteral("tint"), QV4::QtObject::method_tint);
- o->defineDefaultProperty(QStringLiteral("quit"), QV4::QtObject::method_quit);
- o->defineDefaultProperty(QStringLiteral("exit"), QV4::QtObject::method_exit);
- o->defineDefaultProperty(QStringLiteral("createQmlObject"), QV4::QtObject::method_createQmlObject);
- o->defineDefaultProperty(QStringLiteral("createComponent"), QV4::QtObject::method_createComponent);
- }
+Text {
+ color: Qt.rgba(1, 0, 0, 1)
+ text: Qt.md5("hello, world")
+}
+\endqml
- o->defineAccessorProperty(QStringLiteral("platform"), QV4::QtObject::method_get_platform, nullptr);
- o->defineAccessorProperty(QStringLiteral("application"), QV4::QtObject::method_get_application, nullptr);
- o->defineAccessorProperty(QStringLiteral("inputMethod"), QV4::QtObject::method_get_inputMethod, nullptr);
- o->defineAccessorProperty(QStringLiteral("styleHints"), QV4::QtObject::method_get_styleHints, nullptr);
- o->defineDefaultProperty(QStringLiteral("callLater"), QV4::QtObject::method_callLater);
-}
+\section1 Enums
-void QtObject::addAll()
-{
- bool dummy = false;
- findAndAdd(nullptr, dummy);
-}
+The Qt object contains the enums available in the \l [QtCore]{Qt}{Qt Namespace}. For example, you can access
+the \l Qt::LeftButton and \l Qt::RightButton enumeration values as \c Qt.LeftButton and \c Qt.RightButton.
-ReturnedValue QtObject::findAndAdd(const QString *name, bool &foundProperty) const
-{
- Scope scope(engine());
- ScopedObject o(scope, this);
- ScopedString key(scope);
- ScopedValue value(scope);
- const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
- for (int enumCount = qtMetaObject->enumeratorCount(); d()->enumeratorIterator < enumCount;
- ++d()->enumeratorIterator) {
- QMetaEnum enumerator = qtMetaObject->enumerator(d()->enumeratorIterator);
- for (int keyCount = enumerator.keyCount(); d()->keyIterator < keyCount; ++d()->keyIterator) {
- key = scope.engine->newString(QString::fromUtf8(enumerator.key(d()->keyIterator)));
- value = QV4::Value::fromInt32(enumerator.value(d()->keyIterator));
- o->put(key, value);
- if (name && key->toQString() == *name) {
- ++d()->keyIterator;
- foundProperty = true;
- return value->asReturnedValue();
- }
- }
- d()->keyIterator = 0;
- }
- d()->enumeratorIterator = Heap::QtObject::Finished;
- foundProperty = false;
- return Encode::undefined();
-}
+\section1 Types
+\target globalqtobjecttypes
+
+The Qt object also contains helper functions for creating objects of specific
+data types. This is primarily useful when setting the properties of an item
+when the property has one of the following types:
+\list
+\li \c rect - use \l{Qt::rect()}{Qt.rect()}
+\li \c point - use \l{Qt::point()}{Qt.point()}
+\li \c size - use \l{Qt::size()}{Qt.size()}
+\endlist
+
+If the \c QtQuick module has been imported, the following helper functions for
+creating objects of specific data types are also available for clients to use:
+\list
+\li \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()}
+\li \c font - use \l{Qt::font()}{Qt.font()}
+\li \c vector2d - use \l{Qt::vector2d()}{Qt.vector2d()}
+\li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
+\li \c vector4d - use \l{Qt::vector4d()}{Qt.vector4d()}
+\li \c quaternion - use \l{Qt::quaternion()}{Qt.quaternion()}
+\li \c matrix4x4 - use \l{Qt::matrix4x4()}{Qt.matrix4x4()}
+\endlist
+
+\section1 Date/Time Formatters
+
+The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
+
+\list
+ \li \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
+ \li \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
+ \li \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
+\endlist
+
+The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
+
+
+\section1 Dynamic Object Creation
+The following functions on the global object allow you to dynamically create QML
+items from files or strings. See \l{Dynamic QML Object Creation from JavaScript} for an overview
+of their use.
+
+\list
+ \li \l{Qt::createComponent()}{object Qt.createComponent(url)}
+ \li \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
+\endlist
+
+
+\section1 Other Functions
+
+The following functions are also on the Qt object.
+
+\list
+ \li \l{Qt::quit()}{Qt.quit()}
+ \li \l{Qt::md5()}{Qt.md5(string)}
+ \li \l{Qt::btoa()}{string Qt.btoa(string)}
+ \li \l{Qt::atob()}{string Qt.atob(string)}
+ \li \l{Qt::binding()}{object Qt.binding(function)}
+ \li \l{Qt::locale()}{object Qt.locale()}
+ \li \l{Qt::resolvedUrl()}{string Qt.resolvedUrl(string)}
+ \li \l{Qt::openUrlExternally()}{Qt.openUrlExternally(string)}
+ \li \l{Qt::fontFamilies()}{list<string> Qt.fontFamilies()}
+\endlist
+*/
+
+/*!
+ \qmlproperty object Qt::platform
+ \since 5.1
+
+ The \c platform object provides info about the underlying platform.
+
+ Its properties are:
+
+ \table
+ \row
+ \li \c platform.os
+ \li
+
+ This read-only property contains the name of the operating system.
+
+ Possible values are:
+
+ \list
+ \li \c "android" - Android
+ \li \c "ios" - iOS
+ \li \c "tvos" - tvOS
+ \li \c "linux" - Linux
+ \li \c "osx" - \macos
+ \li \c "qnx" - QNX (since Qt 5.9.3)
+ \li \c "unix" - Other Unix-based OS
+ \li \c "windows" - Windows
+ \li \c "wasm" - WebAssembly
+ \endlist
+
+ \row
+ \li \c platform.pluginName
+ \li This is the name of the platform set on the QGuiApplication instance
+ as returned by \l QGuiApplication::platformName()
+
+ \endtable
+*/
+
+/*!
+ \qmlproperty Application Qt::application
+ \since 5.1
+
+ The \c application object provides access to global application state
+ properties shared by many QML components.
+
+ It is the same as the \l Application singleton.
+
+ The following example uses the \c application object to indicate
+ whether the application is currently active:
+
+ \snippet qml/application.qml document
-ReturnedValue QtObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
+ \note When using QML without a QGuiApplication, the following properties will be undefined:
+ \list
+ \li application.active
+ \li application.state
+ \li application.layoutDirection
+ \li application.font
+ \endlist
+*/
+
+/*!
+ \qmlproperty InputMethod Qt::inputMethod
+ \since 5.0
+
+ It is the same as the \l InputMethod singleton.
+
+ The \c inputMethod object allows access to application's QInputMethod object
+ and all its properties and slots. See the QInputMethod documentation for
+ further details.
+*/
+
+/*!
+ \qmlproperty object Qt::styleHints
+ \since 5.5
+
+ The \c styleHints object provides platform-specific style hints and settings.
+ See the \l QStyleHints documentation for further details.
+
+ You should access StyleHints via \l Application::styleHints instead.
+
+ \note The \c styleHints object is only available when using the Qt Quick module.
+*/
+
+/*!
+\qmlmethod object Qt::include(string url, jsobject callback)
+\deprecated
+
+This method should not be used. Use ECMAScript modules, and the native
+JavaScript \c import and \c export statements instead.
+
+Includes another JavaScript file. This method can only be used from within JavaScript files,
+and not regular QML files.
+
+This imports all functions from \a url into the current script's namespace.
+
+Qt.include() returns an object that describes the status of the operation. The object has
+a single property, \c {status}, that is set to one of the following values:
+
+\table
+\header \li Symbol \li Value \li Description
+\row \li result.OK \li 0 \li The include completed successfully.
+\row \li result.LOADING \li 1 \li Data is being loaded from the network.
+\row \li result.NETWORK_ERROR \li 2 \li A network error occurred while fetching the url.
+\row \li result.EXCEPTION \li 3 \li A JavaScript exception occurred while executing the included code.
+An additional \c exception property will be set in this case.
+\endtable
+
+The \c status property will be updated as the operation progresses.
+
+If provided, \a callback is invoked when the operation completes. The callback is passed
+the same object as is returned from the Qt.include() call.
+
+\warning Using this function is strict mode does not actually put identifier into the
+current context.
+*/
+// Qt.include() is implemented in qv4include.cpp
+
+QtObject::QtObject(ExecutionEngine *engine)
+ : m_engine(engine)
{
- bool hasProp = false;
- if (hasProperty == nullptr) {
- hasProperty = &hasProp;
- }
+}
- ReturnedValue ret = QV4::Object::virtualGet(m, id, receiver, hasProperty);
- if (*hasProperty) {
- return ret;
- }
+QtObject::Contexts QtObject::getContexts() const
+{
+ QQmlEngine *engine = qmlEngine();
+ if (!engine)
+ return {};
- auto that = static_cast<const QtObject*>(m);
- if (!that->d()->isComplete()) {
- const QString key = id.toQString();
- ret = that->findAndAdd(&key, *hasProperty);
- }
+ QQmlRefPointer<QQmlContextData> context = v4Engine()->callingQmlContext();
+ if (!context)
+ context = QQmlContextData::get(QQmlEnginePrivate::get(engine)->rootContext);
- return ret;
+ Q_ASSERT(context);
+ QQmlRefPointer<QQmlContextData> effectiveContext
+ = context->isPragmaLibraryContext() ? nullptr : context;
+ return {context, effectiveContext};
}
-OwnPropertyKeyIterator *QtObject::virtualOwnPropertyKeys(const Object *m, Value *target)
+QtObject *QtObject::create(QQmlEngine *, QJSEngine *jsEngine)
{
- auto that = static_cast<const QtObject*>(m);
- if (!that->d()->isComplete())
- const_cast<QtObject *>(that)->addAll();
+ QV4::ExecutionEngine *v4 = jsEngine->handle();
+ QV4::Scope scope(v4);
+ ScopedObject globalObject(scope, v4->globalObject);
+ ScopedString qtName(scope, v4->newString(QStringLiteral("Qt")));
+ QV4::ScopedValue result(scope, globalObject->get(qtName->toPropertyKey()));
+ return qobject_cast<QtObject *>(result->as<QV4::QObjectWrapper>()->object());
+}
- return Object::virtualOwnPropertyKeys(m, target);
+QJSValue QtObject::include(const QString &url, const QJSValue &callback) const
+{
+ return QV4Include::method_include(v4Engine(), v4Engine()->resolvedUrl(url), callback);
}
+
/*!
\qmlmethod bool Qt::isQtObject(object)
Returns \c true if \a object is a valid reference to a Qt or QML object,
\c false otherwise.
*/
-ReturnedValue QtObject::method_isQtObject(const FunctionObject *, const Value *, const Value *argv, int argc)
+bool QtObject::isQtObject(const QJSValue &value) const
{
- if (argc == 0)
- RETURN_RESULT(QV4::Encode(false));
+ return qjsvalue_cast<QObject *>(value) != nullptr;
+}
+
+/*!
+ \qmlmethod color Qt::color(string name)
- return QV4::Encode(argv[0].as<QV4::QObjectWrapper>() != nullptr);
+ Returns the color corresponding to the given \a name (i.e. red or #ff0000).
+ If there is no such color, \c null is returned.
+*/
+QVariant QtObject::color(const QString &name) const
+{
+ bool ok = false;
+ const QVariant v = QQmlStringConverters::colorFromString(name, &ok);
+ if (ok)
+ return v;
+
+ v4Engine()->throwError(QStringLiteral("\"%1\" is not a valid color name").arg(name));
+ return QVariant::fromValue(nullptr);
}
/*!
@@ -248,17 +339,8 @@ ReturnedValue QtObject::method_isQtObject(const FunctionObject *, const Value *,
Returns a color with the specified \a red, \a green, \a blue, and \a alpha
components. All components should be in the range 0-1 (inclusive).
*/
-ReturnedValue QtObject::method_rgba(const FunctionObject *f, const Value *, const Value *argv, int argc)
+QVariant QtObject::rgba(double r, double g, double b, double a) const
{
- QV4::Scope scope(f);
- if (argc < 3 || argc > 4)
- THROW_GENERIC_ERROR("Qt.rgba(): Invalid arguments");
-
- double r = argv[0].toNumber();
- double g = argv[1].toNumber();
- double b = argv[2].toNumber();
- double a = (argc == 4) ? argv[3].toNumber() : 1;
-
if (r < 0.0) r=0.0;
if (r > 1.0) r=1.0;
if (g < 0.0) g=0.0;
@@ -268,7 +350,7 @@ ReturnedValue QtObject::method_rgba(const FunctionObject *f, const Value *, cons
if (a < 0.0) a=0.0;
if (a > 1.0) a=1.0;
- return scope.engine->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a));
+ return QQml_colorProvider()->fromRgbF(r, g, b, a);
}
/*!
@@ -277,18 +359,8 @@ ReturnedValue QtObject::method_rgba(const FunctionObject *f, const Value *, cons
Returns a color with the specified \a hue, \a saturation, \a lightness, and \a alpha
components. All components should be in the range 0-1 (inclusive).
*/
-ReturnedValue QtObject::method_hsla(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::hsla(double h, double s, double l, double a) const
{
- QV4::Scope scope(b);
- int argCount = argc;
- if (argCount < 3 || argCount > 4)
- THROW_GENERIC_ERROR("Qt.hsla(): Invalid arguments");
-
- double h = argv[0].toNumber();
- double s = argv[1].toNumber();
- double l = argv[2].toNumber();
- double a = (argCount == 4) ? argv[3].toNumber() : 1;
-
if (h < 0.0) h=0.0;
if (h > 1.0) h=1.0;
if (s < 0.0) s=0.0;
@@ -298,7 +370,7 @@ ReturnedValue QtObject::method_hsla(const FunctionObject *b, const Value *, cons
if (a < 0.0) a=0.0;
if (a > 1.0) a=1.0;
- return scope.engine->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a));
+ return QQml_colorProvider()->fromHslF(h, s, l, a);
}
/*!
@@ -309,24 +381,14 @@ ReturnedValue QtObject::method_hsla(const FunctionObject *b, const Value *, cons
components. All components should be in the range 0-1 (inclusive).
*/
-ReturnedValue QtObject::method_hsva(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::hsva(double h, double s, double v, double a) const
{
- QV4::Scope scope(b);
- int argCount = argc;
- if (argCount < 3 || argCount > 4)
- THROW_GENERIC_ERROR("Qt.hsva(): Invalid arguments");
-
- double h = argv[0].toNumber();
- double s = argv[1].toNumber();
- double v = argv[2].toNumber();
- double a = (argCount == 4) ? argv[3].toNumber() : 1;
-
h = qBound(0.0, h, 1.0);
s = qBound(0.0, s, 1.0);
v = qBound(0.0, v, 1.0);
a = qBound(0.0, a, 1.0);
- return scope.engine->fromVariant(QQml_colorProvider()->fromHsvF(h, s, v, a));
+ return QQml_colorProvider()->fromHsvF(h, s, v, a);
}
/*!
@@ -335,91 +397,67 @@ ReturnedValue QtObject::method_hsva(const FunctionObject *b, const Value *, cons
Returns \c true if both \a lhs and \a rhs yield equal color values. Both
arguments may be either color values or string values. If a string value
is supplied it must be convertible to a color, as described for the
- \l{colorbasictypedocs}{color} basic type.
+ \l{colorvaluetypedocs}{color} value type.
*/
-ReturnedValue QtObject::method_colorEqual(const FunctionObject *b, const Value *, const Value *argv, int argc)
+bool QtObject::colorEqual(const QVariant &lhs, const QVariant &rhs) const
{
- QV4::Scope scope(b);
- if (argc != 2)
- THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments");
-
bool ok = false;
- QVariant lhs = scope.engine->toVariant(argv[0], -1);
- if (lhs.userType() == QVariant::String) {
- lhs = QQmlStringConverters::colorFromString(lhs.toString(), &ok);
+ QVariant color1 = lhs;
+ if (color1.userType() == QMetaType::QString) {
+ color1 = QQmlStringConverters::colorFromString(color1.toString(), &ok);
if (!ok) {
- THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid color name");
+ v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid color name"));
+ return false;
}
- } else if (lhs.userType() != QVariant::Color) {
- THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments");
+ } else if (color1.userType() != QMetaType::QColor) {
+ v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid arguments"));
+ return false;
}
- QVariant rhs = scope.engine->toVariant(argv[1], -1);
- if (rhs.userType() == QVariant::String) {
- rhs = QQmlStringConverters::colorFromString(rhs.toString(), &ok);
+ QVariant color2 = rhs;
+ if (color2.userType() == QMetaType::QString) {
+ color2 = QQmlStringConverters::colorFromString(color2.toString(), &ok);
if (!ok) {
- THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid color name");
+ v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid color name"));
+ return false;
}
- } else if (rhs.userType() != QVariant::Color) {
- THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments");
+ } else if (color2.userType() != QMetaType::QColor) {
+ v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid arguments"));
+ return false;
}
- bool equal = (lhs == rhs);
- return QV4::Encode(equal);
+ return color1 == color2;
}
/*!
- \qmlmethod rect Qt::rect(int x, int y, int width, int height)
+ \qmlmethod rect Qt::rect(real x, real y, real width, real height)
Returns a rect with the top-left corner at \a x, \a y and the specified \a width and \a height.
*/
-ReturnedValue QtObject::method_rect(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QRectF QtObject::rect(double x, double y, double width, double height) const
{
- QV4::Scope scope(b);
- if (argc != 4)
- THROW_GENERIC_ERROR("Qt.rect(): Invalid arguments");
-
- double x = argv[0].toNumber();
- double y = argv[1].toNumber();
- double w = argv[2].toNumber();
- double h = argv[3].toNumber();
-
- return scope.engine->fromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
+ return QRectF(x, y, width, height);
}
/*!
- \qmlmethod point Qt::point(int x, int y)
+ \qmlmethod point Qt::point(real x, real y)
Returns a point with the specified \a x and \a y coordinates.
*/
-ReturnedValue QtObject::method_point(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QPointF QtObject::point(double x, double y) const
{
- QV4::Scope scope(b);
- if (argc != 2)
- THROW_GENERIC_ERROR("Qt.point(): Invalid arguments");
-
- double x = argv[0].toNumber();
- double y = argv[1].toNumber();
-
- return scope.engine->fromVariant(QVariant::fromValue(QPointF(x, y)));
+ return QPointF(x, y);
}
/*!
- \qmlmethod size Qt::size(int width, int height)
+ \qmlmethod size Qt::size(real width, real height)
Returns a size with the specified \a width and \a height.
*/
-ReturnedValue QtObject::method_size(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QSizeF QtObject::size(double w, double h) const
{
- QV4::Scope scope(b);
- if (argc != 2)
- THROW_GENERIC_ERROR("Qt.size(): Invalid arguments");
-
- double w = argv[0].toNumber();
- double h = argv[1].toNumber();
-
- return scope.engine->fromVariant(QVariant::fromValue(QSizeF(w, h)));
+ return QSizeF(w, h);
}
/*!
@@ -427,43 +465,67 @@ ReturnedValue QtObject::method_size(const FunctionObject *b, const Value *, cons
Returns a font with the properties specified in the \a fontSpecifier object
or the nearest matching font. The \a fontSpecifier object should contain
- key-value pairs where valid keys are the \l{fontbasictypedocs}{font} type's
+ key-value pairs where valid keys are the \l{fontvaluetypedocs}{font} type's
subproperty names, and the values are valid values for each subproperty.
Invalid keys will be ignored.
*/
-ReturnedValue QtObject::method_font(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::font(const QJSValue &fontSpecifier) const
{
- QV4::Scope scope(b);
- if (argc != 1 || !argv[0].isObject())
- THROW_GENERIC_ERROR("Qt.font(): Invalid arguments");
+ if (!fontSpecifier.isObject()) {
+ v4Engine()->throwError(QStringLiteral("Qt.font(): Invalid arguments"));
+ return QVariant();
+ }
- QV4::ExecutionEngine *v4 = scope.engine;
- bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, argv[0], v4, &ok);
- if (!ok)
- THROW_GENERIC_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified");
- return scope.engine->fromVariant(v);
+ {
+ const QVariant v = QQmlValueTypeProvider::createValueType(
+ fontSpecifier, QMetaType(QMetaType::QFont));
+ if (v.isValid())
+ return v;
+ }
+
+ v4Engine()->throwError(QStringLiteral("Qt.font(): Invalid argument: "
+ "no valid font subproperties specified"));
+ return QVariant();
}
+template<typename T>
+void addParameters(QJSEngine *e, QJSValue &result, int i, T parameter)
+{
+ result.setProperty(i, e->toScriptValue(parameter));
+}
+template<>
+void addParameters<double>(QJSEngine *, QJSValue &result, int i, double parameter)
+{
+ result.setProperty(i, QJSValue(parameter));
+}
+
+template<typename T, typename ...Others>
+void addParameters(QJSEngine *e, QJSValue &result, int i, T parameter, Others... others)
+{
+ addParameters<T>(e, result, i, parameter);
+ addParameters<Others...>(e, result, ++i, others...);
+}
+
+template<typename ...T>
+static QVariant constructFromJSValue(QJSEngine *e, QMetaType type, T... parameters)
+{
+ if (!e)
+ return QVariant();
+ QJSValue params = e->newArray(sizeof...(parameters));
+ addParameters(e, params, 0, parameters...);
+ const QVariant variant = QQmlValueTypeProvider::createValueType(params, type);
+ return variant.isValid() ? variant : QVariant(type);
+}
/*!
\qmlmethod vector2d Qt::vector2d(real x, real y)
Returns a vector2d with the specified \a x and \a y values.
*/
-ReturnedValue QtObject::method_vector2d(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::vector2d(double x, double y) const
{
- QV4::Scope scope(b);
- if (argc != 2)
- THROW_GENERIC_ERROR("Qt.vector2d(): Invalid arguments");
-
- float xy[3]; // qvector2d uses float internally
- xy[0] = argv[0].toNumber();
- xy[1] = argv[1].toNumber();
-
- const void *params[] = { xy };
- return scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector2D, 1, params));
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QVector2D), x, y);
}
/*!
@@ -471,19 +533,9 @@ ReturnedValue QtObject::method_vector2d(const FunctionObject *b, const Value *,
Returns a vector3d with the specified \a x, \a y, and \a z values.
*/
-ReturnedValue QtObject::method_vector3d(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::vector3d(double x, double y, double z) const
{
- QV4::Scope scope(b);
- if (argc != 3)
- THROW_GENERIC_ERROR("Qt.vector3d(): Invalid arguments");
-
- float xyz[3]; // qvector3d uses float internally
- xyz[0] = argv[0].toNumber();
- xyz[1] = argv[1].toNumber();
- xyz[2] = argv[2].toNumber();
-
- const void *params[] = { xyz };
- return scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector3D, 1, params));
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QVector3D), x, y, z);
}
/*!
@@ -491,20 +543,9 @@ ReturnedValue QtObject::method_vector3d(const FunctionObject *b, const Value *,
Returns a vector4d with the specified \a x, \a y, \a z, and \a w values.
*/
-ReturnedValue QtObject::method_vector4d(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::vector4d(double x, double y, double z, double w) const
{
- QV4::Scope scope(b);
- if (argc != 4)
- THROW_GENERIC_ERROR("Qt.vector4d(): Invalid arguments");
-
- float xyzw[4]; // qvector4d uses float internally
- xyzw[0] = argv[0].toNumber();
- xyzw[1] = argv[1].toNumber();
- xyzw[2] = argv[2].toNumber();
- xyzw[3] = argv[3].toNumber();
-
- const void *params[] = { xyzw };
- return scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector4D, 1, params));
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QVector4D), x, y, z, w);
}
/*!
@@ -512,20 +553,50 @@ ReturnedValue QtObject::method_vector4d(const FunctionObject *b, const Value *,
Returns a quaternion with the specified \a scalar, \a x, \a y, and \a z values.
*/
-ReturnedValue QtObject::method_quaternion(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::quaternion(double scalar, double x, double y, double z) const
{
- QV4::Scope scope(b);
- if (argc != 4)
- THROW_GENERIC_ERROR("Qt.quaternion(): Invalid arguments");
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QQuaternion), scalar, x, y, z);
+}
- qreal sxyz[4]; // qquaternion uses qreal internally
- sxyz[0] = argv[0].toNumber();
- sxyz[1] = argv[1].toNumber();
- sxyz[2] = argv[2].toNumber();
- sxyz[3] = argv[3].toNumber();
+/*!
+ \qmlmethod matrix4x4 Qt::matrix4x4()
- const void *params[] = { sxyz };
- return scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QQuaternion, 1, params));
+ Returns an identity matrix4x4.
+ */
+QVariant QtObject::matrix4x4() const
+{
+ const QMetaType metaType(QMetaType::QMatrix4x4);
+ const QVariant variant = QQmlValueTypeProvider::createValueType(QJSValue(), metaType);
+ return variant.isValid() ? variant : QVariant(metaType);
+}
+
+/*!
+ \qmlmethod matrix4x4 Qt::matrix4x4(var values)
+
+ Returns a matrix4x4 with the specified \a values. \a values is expected to
+ be a JavaScript array with 16 entries.
+
+ The array indices correspond to positions in the matrix as follows:
+
+ \table
+ \row \li 0 \li 1 \li 2 \li 3
+ \row \li 4 \li 5 \li 6 \li 7
+ \row \li 8 \li 9 \li 10 \li 11
+ \row \li 12 \li 13 \li 14 \li 15
+ \endtable
+*/
+QVariant QtObject::matrix4x4(const QJSValue &value) const
+{
+ if (value.isObject()) {
+ QVariant v = QQmlValueTypeProvider::createValueType(
+ value, QMetaType(QMetaType::QMatrix4x4));
+ if (v.isValid())
+ return v;
+ }
+
+ v4Engine()->throwError(QStringLiteral("Qt.matrix4x4(): Invalid argument: "
+ "not a valid matrix4x4 values array"));
+ return QVariant();
}
/*!
@@ -541,53 +612,34 @@ ReturnedValue QtObject::method_quaternion(const FunctionObject *b, const Value *
\row \li \a m31 \li \a m32 \li \a m33 \li \a m34
\row \li \a m41 \li \a m42 \li \a m43 \li \a m44
\endtable
-
- Alternatively, the function may be called with a single argument
- where that argument is a JavaScript array which contains the sixteen
- matrix values.
-
- Finally, the function may be called with no arguments and the resulting
- matrix will be the identity matrix.
*/
-ReturnedValue QtObject::method_matrix4x4(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::matrix4x4(double m11, double m12, double m13, double m14,
+ double m21, double m22, double m23, double m24,
+ double m31, double m32, double m33, double m34,
+ double m41, double m42, double m43, double m44) const
{
- QV4::Scope scope(b);
-
- if (argc == 0) {
- return scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 0, nullptr));
- }
+ return constructFromJSValue(jsEngine(), QMetaType(QMetaType::QMatrix4x4),
+ m11, m12, m13, m14, m21, m22, m23, m24,
+ m31, m32, m33, m34, m41, m42, m43, m44);
+}
- if (argc == 1 && argv[0].isObject()) {
- bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, argv[0], scope.engine, &ok);
- if (!ok)
- THROW_GENERIC_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array");
- return scope.engine->fromVariant(v);
+static QVariant colorVariantFromJSValue(const QJSValue &color, bool *ok)
+{
+ QVariant v;
+ if (color.isString()) {
+ v = QQmlStringConverters::colorFromString(color.toString(), ok);
+ if (!(*ok))
+ return QVariant::fromValue(nullptr);
+ } else {
+ v = color.toVariant();
+ if (v.userType() != QMetaType::QColor) {
+ *ok = false;
+ return QVariant::fromValue(nullptr);
+ }
}
- if (argc != 16)
- THROW_GENERIC_ERROR("Qt.matrix4x4(): Invalid arguments");
-
- qreal vals[16]; // qmatrix4x4 uses qreal internally
- vals[0] = argv[0].toNumber();
- vals[1] = argv[1].toNumber();
- vals[2] = argv[2].toNumber();
- vals[3] = argv[3].toNumber();
- vals[4] = argv[4].toNumber();
- vals[5] = argv[5].toNumber();
- vals[6] = argv[6].toNumber();
- vals[7] = argv[7].toNumber();
- vals[8] = argv[8].toNumber();
- vals[9] = argv[9].toNumber();
- vals[10] = argv[10].toNumber();
- vals[11] = argv[11].toNumber();
- vals[12] = argv[12].toNumber();
- vals[13] = argv[13].toNumber();
- vals[14] = argv[14].toNumber();
- vals[15] = argv[15].toNumber();
-
- const void *params[] = { vals };
- return scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 1, params));
+ *ok = true;
+ return v;
}
/*!
@@ -605,28 +657,11 @@ ReturnedValue QtObject::method_matrix4x4(const FunctionObject *b, const Value *,
If \a factor is not supplied, returns a color that is 50% lighter than \a baseColor (factor 1.5).
*/
-ReturnedValue QtObject::method_lighter(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::lighter(const QJSValue &color, double factor) const
{
- QV4::Scope scope(b);
- if (argc != 1 && argc != 2)
- THROW_GENERIC_ERROR("Qt.lighter(): Invalid arguments");
-
- QVariant v = scope.engine->toVariant(argv[0], -1);
- if (v.userType() == QVariant::String) {
- bool ok = false;
- v = QQmlStringConverters::colorFromString(v.toString(), &ok);
- if (!ok) {
- return QV4::Encode::null();
- }
- } else if (v.userType() != QVariant::Color) {
- return QV4::Encode::null();
- }
-
- qreal factor = 1.5;
- if (argc == 2)
- factor = argv[1].toNumber();
-
- return scope.engine->fromVariant(QQml_colorProvider()->lighter(v, factor));
+ bool ok;
+ const QVariant v = colorVariantFromJSValue(color, &ok);
+ return ok ? QQml_colorProvider()->lighter(v, factor) : v;
}
/*!
@@ -645,28 +680,25 @@ ReturnedValue QtObject::method_lighter(const FunctionObject *b, const Value *, c
If \a factor is not supplied, returns a color that is 50% darker than \a baseColor (factor 2.0).
*/
-ReturnedValue QtObject::method_darker(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::darker(const QJSValue &color, double factor) const
{
- QV4::Scope scope(b);
- if (argc != 1 && argc != 2)
- THROW_GENERIC_ERROR("Qt.darker(): Invalid arguments");
+ bool ok;
+ const QVariant v = colorVariantFromJSValue(color, &ok);
+ return ok ? QQml_colorProvider()->darker(v, factor) : v;
+}
- QVariant v = scope.engine->toVariant(argv[0], -1);
- if (v.userType() == QVariant::String) {
- bool ok = false;
- v = QQmlStringConverters::colorFromString(v.toString(), &ok);
- if (!ok) {
- return QV4::Encode::null();
- }
- } else if (v.userType() != QVariant::Color) {
- return QV4::Encode::null();
- }
+/*!
+ \qmlmethod color Qt::alpha(color baseColor, real value)
- qreal factor = 2.0;
- if (argc == 2)
- factor = argv[1].toNumber();
+ Returns \a baseColor with an alpha value of \a value.
- return scope.engine->fromVariant(QQml_colorProvider()->darker(v, factor));
+ \a value is a real ranging from 0 (completely transparent) to 1 (completely opaque).
+*/
+QVariant QtObject::alpha(const QJSValue &baseColor, double value) const
+{
+ bool ok;
+ const QVariant v = colorVariantFromJSValue(baseColor, &ok);
+ return ok ? QQml_colorProvider()->alpha(v, value) : v;
}
/*!
@@ -695,151 +727,279 @@ ReturnedValue QtObject::method_darker(const FunctionObject *b, const Value *, co
Tint is most useful when a subtle change is intended to be conveyed due to some event;
you can then use tinting to more effectively tune the visible color.
*/
-ReturnedValue QtObject::method_tint(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QVariant QtObject::tint(const QJSValue &baseColor, const QJSValue &tintColor) const
{
- QV4::Scope scope(b);
- if (argc != 2)
- THROW_GENERIC_ERROR("Qt.tint(): Invalid arguments");
+ bool ok;
// base color
- QVariant v1 = scope.engine->toVariant(argv[0], -1);
- if (v1.userType() == QVariant::String) {
- bool ok = false;
- v1 = QQmlStringConverters::colorFromString(v1.toString(), &ok);
- if (!ok) {
- return QV4::Encode::null();
- }
- } else if (v1.userType() != QVariant::Color) {
- return QV4::Encode::null();
- }
+ const QVariant v1 = colorVariantFromJSValue(baseColor, &ok);
+ if (!ok)
+ return v1;
// tint color
- QVariant v2 = scope.engine->toVariant(argv[1], -1);
- if (v2.userType() == QVariant::String) {
- bool ok = false;
- v2 = QQmlStringConverters::colorFromString(v2.toString(), &ok);
- if (!ok) {
- return QV4::Encode::null();
- }
- } else if (v2.userType() != QVariant::Color) {
- return QV4::Encode::null();
+ const QVariant v2 = colorVariantFromJSValue(tintColor, &ok);
+
+ return ok ? QQml_colorProvider()->tint(v1, v2) : v2;
+}
+
+namespace {
+template <typename T>
+QString formatDateTimeObjectUsingDateFormat(T formatThis, Qt::DateFormat format) {
+ switch (format) {
+ case Qt::TextDate:
+ case Qt::ISODate:
+ case Qt::RFC2822Date:
+ case Qt::ISODateWithMs:
+ return formatThis.toString(format);
+ default: // ### Qt 6: remove once qtbase has removed the rest of the enum !
+ break;
}
+ // Q_UNREACHABLE(); // ### Qt 6: restore once the default is gone
+ return QString();
+}
+}
- return scope.engine->fromVariant(QQml_colorProvider()->tint(v1, v2));
+static QTime dateTimeToTime(const QDateTime &dateTime)
+{
+ return dateTime.toLocalTime().time();
}
/*!
-\qmlmethod string Qt::formatDate(datetime date, variant format)
+\qmlmethod string Qt::formatDate(datetime date, variant format, variant localeFormatOption)
-Returns a string representation of \a date, optionally formatted according
-to \a format.
+Returns a string representation of \a date, optionally formatted using \a format.
The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
-property, a QDate, or QDateTime value. The \a format parameter may be any of
-the possible format values as described for
+property, a QDate, or QDateTime value. The \a format and \a localeFormatOption
+parameter may be any of the possible format values as described for
\l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}.
If \a format is not specified, \a date is formatted using
-\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
+\l {QLocale::FormatType}{Locale.ShortFormat} using the
+default locale.
\sa Locale
*/
-ReturnedValue QtObject::method_formatDate(const FunctionObject *b, const Value *, const Value *argv, int argc)
+static std::optional<QDate> dateFromString(const QString &string, QV4::ExecutionEngine *engine)
{
- QV4::Scope scope(b);
- if (argc < 1 || argc > 2)
- THROW_GENERIC_ERROR("Qt.formatDate(): Invalid arguments");
-
- Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QDate date = scope.engine->toVariant(argv[0], -1).toDateTime().date();
- QString formattedDate;
- if (argc == 2) {
- QV4::ScopedString s(scope, argv[1]);
- if (s) {
- QString format = s->toQString();
- formattedDate = date.toString(format);
- } else if (argv[1].isNumber()) {
- quint32 intFormat = argv[1].asDouble();
- Qt::DateFormat format = Qt::DateFormat(intFormat);
- formattedDate = date.toString(format);
- } else {
- THROW_GENERIC_ERROR("Qt.formatDate(): Invalid date format");
+ {
+ const QDate date = QDate::fromString(string, Qt::ISODate);
+ if (date.isValid())
+ return date;
+ }
+
+ {
+ // For historical reasons, the string argument is parsed as datetime, not as only date
+ const QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate);
+ if (dateTime.isValid()) {
+ qCWarning(lcRootProperties())
+ << string << "is a date/time string being passed to formatDate()."
+ << "You should only pass date strings to formatDate().";
+ return dateTime.date();
}
- } else {
- formattedDate = date.toString(enumFormat);
}
- return Encode(scope.engine->newString(formattedDate));
+ {
+ // Since we can coerce QDate to QString, allow the resulting string format here.
+ const QDateTime dateTime = DateObject::stringToDateTime(string, engine);
+ if (dateTime.isValid())
+ return DateObject::dateTimeToDate(dateTime);
+ }
+
+ engine->throwError(QStringLiteral("Invalid argument passed to formatDate(): %1").arg(string));
+ return std::nullopt;
}
+QString QtObject::formatDate(QDate date, const QString &format) const
+{
+ return date.toString(format);
+}
+
+QString QtObject::formatDate(QDate date, Qt::DateFormat format) const
+{
+ return formatDateTimeObjectUsingDateFormat(date, format);
+}
+
+QString QtObject::formatDate(const QDateTime &dateTime, const QString &format) const
+{
+ return DateObject::dateTimeToDate(dateTime).toString(format);
+}
+
+QString QtObject::formatDate(const QString &string, const QString &format) const
+{
+ if (const auto qDate = dateFromString(string, v4Engine()))
+ return formatDate(qDate.value(), format);
+
+ return QString();
+}
+
+QString QtObject::formatDate(const QDateTime &dateTime, Qt::DateFormat format) const
+{
+ return formatDateTimeObjectUsingDateFormat(DateObject::dateTimeToDate(dateTime), format);
+}
+
+QString QtObject::formatDate(const QString &string, Qt::DateFormat format) const
+{
+ if (const auto qDate = dateFromString(string, v4Engine()))
+ return formatDate(qDate.value(), format);
+
+ return QString();
+}
+
+#if QT_CONFIG(qml_locale)
+QString QtObject::formatDate(QDate date, const QLocale &locale,
+ QLocale::FormatType formatType) const
+{
+ return locale.toString(date, formatType);
+}
+
+QString QtObject::formatDate(const QDateTime &dateTime, const QLocale &locale,
+ QLocale::FormatType formatType) const
+{
+ return locale.toString(DateObject::dateTimeToDate(dateTime), formatType);
+}
+
+QString QtObject::formatDate(const QString &string, const QLocale &locale,
+ QLocale::FormatType formatType) const
+{
+ if (const auto qDate = dateFromString(string, v4Engine()))
+ return locale.toString(qDate.value(), formatType);
+
+ return QString();
+}
+#endif
+
/*!
-\qmlmethod string Qt::formatTime(datetime time, variant format)
+\qmlmethod string Qt::formatTime(datetime time, variant format, variant localeFormatOption)
-Returns a string representation of \a time, optionally formatted according to
-\a format.
+Returns a string representation of \a time, optionally formatted using
+\a format, and, if provided, \a localeFormatOption.
The \a time parameter may be a JavaScript \c Date object, a QTime, or QDateTime
-value. The \a format parameter may be any of the possible format values as
-described for \l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}.
+value. The \a format and \a localeFormatOption parameter may be any of the
+possible format values as described for
+\l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}.
If \a format is not specified, \a time is formatted using
-\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
+\l {QLocale::FormatType}{Locale.ShortFormat} using the default locale.
\sa Locale
*/
-ReturnedValue QtObject::method_formatTime(const FunctionObject *b, const Value *, const Value *argv, int argc)
+static std::optional<QTime> timeFromString(const QString &string, QV4::ExecutionEngine *engine)
{
- QV4::Scope scope(b);
- if (argc < 1 || argc > 2)
- THROW_GENERIC_ERROR("Qt.formatTime(): Invalid arguments");
-
- QVariant argVariant = scope.engine->toVariant(argv[0], -1);
- QTime time;
- if (argv[0].as<DateObject>() || (argVariant.type() == QVariant::String))
- time = argVariant.toDateTime().time();
- else // if (argVariant.type() == QVariant::Time), or invalid.
- time = argVariant.toTime();
-
- Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QString formattedTime;
- if (argc == 2) {
- QV4::ScopedString s(scope, argv[1]);
- if (s) {
- QString format = s->toQString();
- formattedTime = time.toString(format);
- } else if (argv[1].isNumber()) {
- quint32 intFormat = argv[1].asDouble();
- Qt::DateFormat format = Qt::DateFormat(intFormat);
- formattedTime = time.toString(format);
- } else {
- THROW_GENERIC_ERROR("Qt.formatTime(): Invalid time format");
+ {
+ const QTime time = QTime::fromString(string, Qt::ISODate);
+ if (time.isValid())
+ return time;
+ }
+
+ {
+ // For historical reasons, the string argument is parsed as datetime, not as only time
+ const QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate);
+ if (dateTime.isValid()) {
+ qCWarning(lcRootProperties())
+ << string << "is a date/time string being passed to formatTime()."
+ << "You should only pass time strings to formatTime().";
+ return dateTime.time();
}
- } else {
- formattedTime = time.toString(enumFormat);
}
- return Encode(scope.engine->newString(formattedTime));
+ {
+ // Since we can coerce QTime to QString, allow the resulting string format here.
+ const QDateTime dateTime = DateObject::stringToDateTime(string, engine);
+ if (dateTime.isValid())
+ return dateTimeToTime(dateTime);
+ }
+
+ engine->throwError(QStringLiteral("Invalid argument passed to formatTime(): %1").arg(string));
+ return std::nullopt;
+}
+
+QString QtObject::formatTime(QTime time, const QString &format) const
+{
+ return time.toString(format);
+}
+
+QString QtObject::formatTime(const QDateTime &dateTime, const QString &format) const
+{
+ return dateTimeToTime(dateTime).toString(format);
+}
+
+QString QtObject::formatTime(const QString &time, const QString &format) const
+{
+
+ if (auto qTime = timeFromString(time, v4Engine()))
+ return formatTime(qTime.value(), format);
+
+ return QString();
+}
+
+QString QtObject::formatTime(QTime time, Qt::DateFormat format) const
+{
+ return formatDateTimeObjectUsingDateFormat(time, format);
+}
+
+QString QtObject::formatTime(const QDateTime &dateTime, Qt::DateFormat format) const
+{
+ return formatDateTimeObjectUsingDateFormat(dateTimeToTime(dateTime), format);
+}
+
+QString QtObject::formatTime(const QString &time, Qt::DateFormat format) const
+{
+ if (auto qTime = timeFromString(time, v4Engine()))
+ return formatTime(qTime.value(), format);
+
+ return QString();
+}
+
+#if QT_CONFIG(qml_locale)
+QString QtObject::formatTime(QTime time, const QLocale &locale,
+ QLocale::FormatType formatType) const
+{
+ return locale.toString(time, formatType);
+}
+
+QString QtObject::formatTime(const QDateTime &dateTime, const QLocale &locale,
+ QLocale::FormatType formatType) const
+{
+ return locale.toString(dateTimeToTime(dateTime), formatType);
+}
+
+QString QtObject::formatTime(const QString &time, const QLocale &locale,
+ QLocale::FormatType formatType) const
+{
+ if (auto qTime = timeFromString(time, v4Engine()))
+ return locale.toString(qTime.value(), formatType);
+
+ return QString();
}
+#endif
/*!
-\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format)
+\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format, variant localeFormatOption)
-Returns a string representation of \a dateTime, optionally formatted according to
-\a format.
+Returns a string representation of \a dateTime, optionally formatted using
+\a format and \a localeFormatOption.
The \a dateTime parameter may be a JavaScript \c Date object, a \l{date}{date}
property, a QDate, QTime, or QDateTime value.
If \a format is not provided, \a dateTime is formatted using
-\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. Otherwise,
-\a format should be either:
+\l {QLocale::FormatType}{Locale.ShortFormat} using the
+default locale. Otherwise, \a format should be either:
\list
\li One of the Qt::DateFormat enumeration values, such as
- \c Qt.DefaultLocaleShortDate or \c Qt.ISODate
+ \c Qt.RFC2822Date or \c Qt.ISODate.
\li A string that specifies the format of the returned string, as detailed below.
+\li A \c locale object.
\endlist
+If \a format specifies a locale object, \dateTime is formatted
+with \l{QLocale::toString}. In this case, \a localeFormatOption can hold a value
+of type \l {QLocale::FormatType} to further tune the formatting. If none is
+provided, \l {QLocale::FormatType}{Locale.ShortFormat} is used.
+
If \a format specifies a format string, it should use the following expressions
to specify the date:
@@ -913,34 +1073,71 @@ with the \a format values below to produce the following results:
\sa Locale
*/
-ReturnedValue QtObject::method_formatDateTime(const FunctionObject *b, const Value *, const Value *argv, int argc)
+static std::optional<QDateTime> dateTimeFromString(const QString &string, QV4::ExecutionEngine *engine)
{
- QV4::Scope scope(b);
- if (argc < 1 || argc > 2)
- THROW_GENERIC_ERROR("Qt.formatDateTime(): Invalid arguments");
-
- Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QDateTime dt = scope.engine->toVariant(argv[0], -1).toDateTime();
- QString formattedDt;
- if (argc == 2) {
- QV4::ScopedString s(scope, argv[1]);
- if (s) {
- QString format = s->toQString();
- formattedDt = dt.toString(format);
- } else if (argv[1].isNumber()) {
- quint32 intFormat = argv[1].asDouble();
- Qt::DateFormat format = Qt::DateFormat(intFormat);
- formattedDt = dt.toString(format);
- } else {
- THROW_GENERIC_ERROR("Qt.formatDateTime(): Invalid datetime format");
- }
- } else {
- formattedDt = dt.toString(enumFormat);
+ {
+ const QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate);
+ if (dateTime.isValid())
+ return dateTime;
}
- return Encode(scope.engine->newString(formattedDt));
+ {
+ // Since we can coerce QDateTime to QString, allow the resulting string format here.
+ const QDateTime dateTime = DateObject::stringToDateTime(string, engine);
+ if (dateTime.isValid())
+ return dateTime;
+ }
+
+ engine->throwError(QStringLiteral("Invalid argument passed to formatDateTime(): %1").arg(string));
+ return std::nullopt;
+}
+
+QString QtObject::formatDateTime(const QDateTime &dateTime, const QString &format) const
+{
+ return dateTime.toString(format);
}
+QString QtObject::formatDateTime(const QString &string, const QString &format) const
+{
+
+ if (const auto qDateTime = dateTimeFromString(string, v4Engine()))
+ return formatDateTime(qDateTime.value(), format);
+
+ return QString();
+}
+
+QString QtObject::formatDateTime(const QDateTime &dateTime, Qt::DateFormat format) const
+{
+ return formatDateTimeObjectUsingDateFormat(dateTime, format);
+}
+
+QString QtObject::formatDateTime(const QString &string, Qt::DateFormat format) const
+{
+
+ if (const auto qDateTime = dateTimeFromString(string, v4Engine()))
+ return formatDateTime(qDateTime.value(), format);
+
+ return QString();
+}
+
+#if QT_CONFIG(qml_locale)
+QString QtObject::formatDateTime(const QDateTime &dateTime, const QLocale &locale,
+ QLocale::FormatType formatType) const
+{
+ return locale.toString(dateTime, formatType);
+}
+
+QString QtObject::formatDateTime(const QString &string, const QLocale &locale,
+ QLocale::FormatType formatType) const
+{
+
+ if (const auto qDateTime = dateTimeFromString(string, v4Engine()))
+ return formatDateTime(qDateTime.value(), locale, formatType);
+
+ return QString();
+}
+#endif
+
/*!
\qmlmethod bool Qt::openUrlExternally(url target)
@@ -952,41 +1149,67 @@ ReturnedValue QtObject::method_formatDateTime(const FunctionObject *b, const Val
still fail to launch or fail to open the requested URL. This result will not be reported back
to the application.
*/
-ReturnedValue QtObject::method_openUrlExternally(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+bool QtObject::openUrlExternally(const QUrl &url) const
{
- QV4::Scope scope(b);
- if (argc != 1)
- return QV4::Encode(false);
+ return QQml_guiProvider()->openUrlExternally(resolvedUrl(url));
+}
- ScopedValue result(scope, method_resolvedUrl(b, thisObject, argv, argc));
- QUrl url(result->toQStringNoThrow());
- return scope.engine->fromVariant(QQml_guiProvider()->openUrlExternally(url));
+/*!
+ \qmlmethod url Qt::url(url url)
+
+ Returns \a url verbatim. This can be used to force a type coercion to \c url.
+ In contrast to Qt.resolvedUrl() this retains any relative URLs. As strings
+ are implicitly converted to urls, the function can be called with a string
+ as argument, and will then return a url.
+
+ \sa resolvedUrl()
+*/
+QUrl QtObject::url(const QUrl &url) const
+{
+ return url;
}
/*!
\qmlmethod url Qt::resolvedUrl(url url)
Returns \a url resolved relative to the URL of the caller.
+
+ If there is no caller or the caller is not associated with a QML context,
+ returns \a url resolved relative to the QML engine's base URL. If the QML
+ engine has no base URL, just returns \a url.
+
+ \sa url()
*/
-ReturnedValue QtObject::method_resolvedUrl(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QUrl QtObject::resolvedUrl(const QUrl &url) const
{
- QV4::Scope scope(b);
- if (argc != 1)
- return Encode::undefined();
-
- QUrl url = scope.engine->toVariant(argv[0], -1).toUrl();
- QQmlEngine *e = scope.engine->qmlEngine();
- QQmlEnginePrivate *p = nullptr;
- if (e) p = QQmlEnginePrivate::get(e);
- if (p) {
- QQmlContextData *ctxt = scope.engine->callingQmlContext();
- if (ctxt)
- return Encode(scope.engine->newString(ctxt->resolvedUrl(url).toString()));
- else
- return Encode(scope.engine->newString(url.toString()));
+ if (QQmlRefPointer<QQmlContextData> ctxt = v4Engine()->callingQmlContext())
+ return ctxt->resolvedUrl(url);
+ if (QQmlEngine *engine = qmlEngine())
+ return engine->baseUrl().resolved(url);
+ return url;
+}
+
+/*!
+ \qmlmethod url Qt::resolvedUrl(url url, object context)
+
+ Returns \a url resolved relative to the URL of the QML context of
+ \a context. If \a context is not associated with a QML context,
+ returns \a url resolved relative to the QML engine's base URL. If
+ the QML engine has no base URL, just returns \a url.
+
+ \sa url()
+*/
+QUrl QtObject::resolvedUrl(const QUrl &url, QObject *context) const
+{
+ if (context) {
+ QQmlData *data = QQmlData::get(context);
+ if (data && data->outerContext)
+ return data->outerContext->resolvedUrl(url);
}
- return Encode(scope.engine->newString(e->baseUrl().resolved(url).toString()));
+ if (QQmlEngine *engine = qmlEngine())
+ return engine->baseUrl().resolved(url);
+ return url;
}
/*!
@@ -994,96 +1217,71 @@ ReturnedValue QtObject::method_resolvedUrl(const FunctionObject *b, const Value
Returns a list of the font families available to the application.
*/
-ReturnedValue QtObject::method_fontFamilies(const FunctionObject *b, const Value *, const Value *, int argc)
+QStringList QtObject::fontFamilies() const
{
- QV4::Scope scope(b);
- if (argc != 0)
- THROW_GENERIC_ERROR("Qt.fontFamilies(): Invalid arguments");
-
- return scope.engine->fromVariant(QVariant(QQml_guiProvider()->fontFamilies()));
+ return QQml_guiProvider()->fontFamilies();
}
/*!
\qmlmethod string Qt::md5(data)
Returns a hex string of the md5 hash of \a data.
*/
-ReturnedValue QtObject::method_md5(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QString QtObject::md5(const QString &data) const
{
- QV4::Scope scope(b);
- if (argc != 1)
- THROW_GENERIC_ERROR("Qt.md5(): Invalid arguments");
-
- QByteArray data = argv[0].toQStringNoThrow().toUtf8();
- QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
- return Encode(scope.engine->newString(QLatin1String(result.toHex())));
+ return QLatin1String(QCryptographicHash::hash(data.toUtf8(), QCryptographicHash::Md5).toHex());
}
/*!
\qmlmethod string Qt::btoa(data)
Binary to ASCII - this function returns a base64 encoding of \a data.
*/
-ReturnedValue QtObject::method_btoa(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QString QtObject::btoa(const QString &data) const
{
- QV4::Scope scope(b);
- if (argc != 1)
- THROW_GENERIC_ERROR("Qt.btoa(): Invalid arguments");
-
- QByteArray data = argv[0].toQStringNoThrow().toUtf8();
-
- return Encode(scope.engine->newString(QLatin1String(data.toBase64())));
+ return QLatin1String(data.toUtf8().toBase64());
}
/*!
\qmlmethod string Qt::atob(data)
ASCII to binary - this function decodes the base64 encoded \a data string and returns it.
*/
-ReturnedValue QtObject::method_atob(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QString QtObject::atob(const QString &data) const
{
- QV4::Scope scope(b);
- if (argc != 1)
- THROW_GENERIC_ERROR("Qt.atob(): Invalid arguments");
-
- QByteArray data = argv[0].toQStringNoThrow().toLatin1();
-
- return Encode(scope.engine->newString(QString::fromUtf8(QByteArray::fromBase64(data))));
+ return QString::fromUtf8(QByteArray::fromBase64(data.toLatin1()));
}
/*!
-\qmlmethod Qt::quit()
-This function causes the QQmlEngine::quit() signal to be emitted.
-Within the \l {Prototyping with qmlscene}, this causes the launcher application to exit;
-to quit a C++ application when this method is called, connect the
-QQmlEngine::quit() signal to the QCoreApplication::quit() slot.
+ \qmlmethod Qt::quit()
-\sa exit()
+ This function causes the QQmlEngine::quit() signal to be emitted.
+ Within the \l {Prototyping with the QML Runtime Tool}{qml tool},
+ this causes the launcher application to exit; to quit a C++ application
+ when this method is called, connect the QQmlEngine::quit() signal to the
+ QCoreApplication::quit() slot.
+
+ \sa exit()
*/
-ReturnedValue QtObject::method_quit(const FunctionObject *b, const Value *, const Value *, int)
+void QtObject::quit() const
{
- QQmlEnginePrivate::get(b->engine()->qmlEngine())->sendQuit();
- return Encode::undefined();
+ if (QQmlEngine *engine = qmlEngine())
+ QQmlEnginePrivate::get(engine)->sendQuit();
}
/*!
\qmlmethod Qt::exit(int retCode)
This function causes the QQmlEngine::exit(int) signal to be emitted.
- Within the \l {Prototyping with qmlscene}, this causes the launcher application to exit
+ Within the \l {Prototyping with the QML Runtime Tool}{qml tool},
+ this causes the launcher application to exit with
the specified return code (\a retCode). To exit from the event loop with a specified
return code when this method is called, a C++ application can connect the
QQmlEngine::exit(int) signal to the QCoreApplication::exit(int) slot.
\sa quit()
*/
-ReturnedValue QtObject::method_exit(const FunctionObject *b, const Value *, const Value *argv, int argc)
+void QtObject::exit(int retCode) const
{
- QV4::Scope scope(b);
- if (argc != 1)
- THROW_GENERIC_ERROR("Qt.exit(): Invalid arguments");
-
- int retCode = argv[0].toNumber();
-
- QQmlEnginePrivate::get(scope.engine->qmlEngine())->sendExit(retCode);
- return QV4::Encode::undefined();
+ if (QQmlEngine *engine = qmlEngine())
+ QQmlEnginePrivate::get(engine)->sendExit(retCode);
}
/*!
@@ -1098,23 +1296,31 @@ Example (where \c parentItem is the id of an existing QML item):
\snippet qml/createQmlObject.qml 0
-In the case of an error, a \l {Qt Script} Error object is thrown. This object has an additional property,
+In the case of an error, a QQmlError object is thrown. This object has an additional property,
\c qmlErrors, which is an array of the errors encountered.
Each object in this array has the members \c lineNumber, \c columnNumber, \c fileName and \c message.
For example, if the above snippet had misspelled color as 'colro' then the array would contain an object like the following:
{ "lineNumber" : 1, "columnNumber" : 32, "fileName" : "dynamicSnippet1", "message" : "Cannot assign to non-existent property \"colro\""}.
-Note that this function returns immediately, and therefore may not work if
+\note This function returns immediately, and therefore may not work if
the \a qml string loads new components (that is, external QML files that have not yet been loaded).
If this is the case, consider using \l{QtQml::Qt::createComponent()}{Qt.createComponent()} instead.
+\warning This function is extremely slow since it has to compile the passed QML string every time
+it is invoked. Furthermore, it's very easy to produce invalid QML when programmatically constructing
+QML code. It's much better to keep your QML components as separate files and add properties and
+methods to customize their behavior than to produce new components by string manipulation.
+
See \l {Dynamic QML Object Creation from JavaScript} for more information on using this function.
*/
-ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QObject *QtObject::createQmlObject(const QString &qml, QObject *parent, const QUrl &url) const
{
- QV4::Scope scope(b);
- if (argc < 2 || argc > 3)
- THROW_GENERIC_ERROR("Qt.createQmlObject(): Invalid arguments");
+ QQmlEngine *engine = qmlEngine();
+ if (!engine) {
+ v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): "
+ "Can only be called on a QML engine."));
+ return nullptr;
+ }
struct Error {
static ReturnedValue create(QV4::ExecutionEngine *v4, const QList<QQmlError> &errors) {
@@ -1127,7 +1333,7 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va
QV4::ScopedObject qmlerror(scope);
QV4::ScopedString s(scope);
QV4::ScopedValue v(scope);
- for (int ii = 0; ii < errors.count(); ++ii) {
+ for (int ii = 0; ii < errors.size(); ++ii) {
const QQmlError &error = errors.at(ii);
errorstr += QLatin1String("\n ") + error.toString();
qmlerror = v4->newObject();
@@ -1145,60 +1351,54 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va
}
};
- QQmlEngine *engine = scope.engine->qmlEngine();
+ QQmlRefPointer<QQmlContextData> context = v4Engine()->callingQmlContext();
+ if (!context)
+ context = QQmlContextData::get(QQmlEnginePrivate::get(engine)->rootContext);
- QQmlContextData *context = scope.engine->callingQmlContext();
- if (!context) {
- QQmlEngine *qmlEngine = scope.engine->qmlEngine();
- if (qmlEngine)
- context = QQmlContextData::get(QQmlEnginePrivate::get(qmlEngine)->rootContext);
- }
Q_ASSERT(context);
QQmlContext *effectiveContext = nullptr;
- if (context->isPragmaLibraryContext)
+ if (context->isPragmaLibraryContext())
effectiveContext = engine->rootContext();
else
effectiveContext = context->asQQmlContext();
Q_ASSERT(effectiveContext);
- QString qml = argv[0].toQStringNoThrow();
if (qml.isEmpty())
- RETURN_RESULT(Encode::null());
-
- QUrl url;
- if (argc > 2)
- url = QUrl(argv[2].toQStringNoThrow());
- else
- url = QUrl(QLatin1String("inline"));
+ return nullptr;
+ QUrl resolvedUrl = url;
if (url.isValid() && url.isRelative())
- url = context->resolvedUrl(url);
+ resolvedUrl = context->resolvedUrl(url);
- QObject *parentArg = nullptr;
- QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, argv[1]);
- if (!!qobjectWrapper)
- parentArg = qobjectWrapper->object();
- if (!parentArg)
- THROW_GENERIC_ERROR("Qt.createQmlObject(): Missing parent object");
+ if (!parent) {
+ v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): Missing parent object"));
+ return nullptr;
+ }
QQmlRefPointer<QQmlTypeData> typeData = QQmlEnginePrivate::get(engine)->typeLoader.getType(
- qml.toUtf8(), url, QQmlTypeLoader::Synchronous);
+ qml.toUtf8(), resolvedUrl, QQmlTypeLoader::Synchronous);
Q_ASSERT(typeData->isCompleteOrError());
QQmlComponent component(engine);
QQmlComponentPrivate *componentPrivate = QQmlComponentPrivate::get(&component);
componentPrivate->fromTypeData(typeData);
componentPrivate->progress = 1.0;
+ Scope scope(v4Engine());
if (component.isError()) {
ScopedValue v(scope, Error::create(scope.engine, component.errors()));
- RETURN_RESULT(scope.engine->throwError(v));
+ scope.engine->throwError(v);
+ return nullptr;
}
- if (!component.isReady())
- THROW_GENERIC_ERROR("Qt.createQmlObject(): Component is not ready");
+ if (!component.isReady()) {
+ v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): Component is not ready"));
+ return nullptr;
+ }
if (!effectiveContext->isValid()) {
- THROW_GENERIC_ERROR("Qt.createQmlObject(): Cannot create a component in an invalid context");
+ v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): Cannot create a component "
+ "in an invalid context"));
+ return nullptr;
}
QObject *obj = component.beginCreate(effectiveContext);
@@ -1206,12 +1406,11 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va
QQmlData::get(obj, true)->explicitIndestructibleSet = false;
QQmlData::get(obj)->indestructible = false;
-
- obj->setParent(parentArg);
+ obj->setParent(parent);
QList<QQmlPrivate::AutoParentFunction> functions = QQmlMetaType::parentFunctions();
- for (int ii = 0; ii < functions.count(); ++ii) {
- if (QQmlPrivate::Parented == functions.at(ii)(obj, parentArg))
+ for (int ii = 0; ii < functions.size(); ++ii) {
+ if (QQmlPrivate::Parented == functions.at(ii)(obj, parent))
break;
}
}
@@ -1219,16 +1418,16 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va
if (component.isError()) {
ScopedValue v(scope, Error::create(scope.engine, component.errors()));
- return scope.engine->throwError(v);
+ scope.engine->throwError(v);
+ return nullptr;
}
Q_ASSERT(obj);
-
- return QV4::QObjectWrapper::wrap(scope.engine, obj);
+ return obj;
}
/*!
-\qmlmethod object Qt::createComponent(url, mode, parent)
+\qmlmethod Component Qt::createComponent(url url, enumeration mode, QtObject parent)
Returns a \l Component object created using the QML file at the specified \a url,
or \c null if an empty string was given.
@@ -1271,73 +1470,120 @@ See \l {Dynamic QML Object Creation from JavaScript} for more information on usi
To create a QML object from an arbitrary string of QML (instead of a file),
use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}.
*/
-ReturnedValue QtObject::method_createComponent(const FunctionObject *b, const Value *, const Value *argv, int argc)
-{
- QV4::Scope scope(b);
- if (argc < 1 || argc > 3)
- THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments");
- QQmlEngine *engine = scope.engine->qmlEngine();
+/*!
+\qmlmethod Component Qt::createComponent(string moduleUri, string typeName, enumeration mode, QtObject parent)
+\overload
+Returns a \l Component object created for the type specified by \a moduleUri and \a typeName.
+\qml
+import QtQuick
+QtObject {
+ id: root
+ property Component myComponent: Qt.createComponent("QtQuick", "Rectangle", Component.Asynchronous, root)
+}
+\endqml
+This overload mostly behaves as the \c url based version, but can be used
+to instantiate types which do not have an URL (e.g. C++ types registered
+via \l {QML_ELEMENT}).
+\note In some cases, passing \c Component.Asynchronous won't have any
+effect:
+\list
+\li The type is implemented in C++
+\li The type is an inline component.
+\endlist
+If the optional \a parent parameter is given, it should refer to the object
+that will become the parent for the created \l Component object. If no mode
+was passed, this can be the second argument.
+*/
- QQmlContextData *context = scope.engine->callingQmlContext();
- if (!context) {
- QQmlEngine *qmlEngine = scope.engine->qmlEngine();
- if (qmlEngine)
- context = QQmlContextData::get(QQmlEnginePrivate::get(qmlEngine)->rootContext);
+QQmlComponent *QtObject::createComponent(const QUrl &url, QObject *parent) const
+{
+ return createComponent(url, QQmlComponent::PreferSynchronous, parent);
+}
+
+QQmlComponent *QtObject::createComponent(const QUrl &url, QQmlComponent::CompilationMode mode,
+ QObject *parent) const
+{
+ if (mode != QQmlComponent::Asynchronous && mode != QQmlComponent::PreferSynchronous) {
+ v4Engine()->throwError(QStringLiteral("Invalid compilation mode %1").arg(mode));
+ return nullptr;
}
- Q_ASSERT(context);
- QQmlContextData *effectiveContext = context;
- if (context->isPragmaLibraryContext)
- effectiveContext = nullptr;
-
- QString arg = argv[0].toQStringNoThrow();
- if (arg.isEmpty())
- RETURN_RESULT(QV4::Encode::null());
-
- QQmlComponent::CompilationMode compileMode = QQmlComponent::PreferSynchronous;
- QObject *parentArg = nullptr;
-
- int consumedCount = 1;
- if (argc > 1) {
- ScopedValue lastArg(scope, argv[argc-1]);
-
- // The second argument could be the mode enum
- if (argv[1].isInteger()) {
- int mode = argv[1].integerValue();
- if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous))
- THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments");
- compileMode = QQmlComponent::CompilationMode(mode);
- consumedCount += 1;
- } else {
- // The second argument could be the parent only if there are exactly two args
- if ((argc != 2) || !(lastArg->isObject() || lastArg->isNull()))
- THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments");
- }
- if (consumedCount < argc) {
- if (lastArg->isObject()) {
- Scoped<QObjectWrapper> qobjectWrapper(scope, lastArg);
- if (qobjectWrapper)
- parentArg = qobjectWrapper->object();
- if (!parentArg)
- THROW_GENERIC_ERROR("Qt.createComponent(): Invalid parent object");
- } else if (lastArg->isNull()) {
- parentArg = nullptr;
- } else {
- THROW_GENERIC_ERROR("Qt.createComponent(): Invalid parent object");
- }
- }
+ if (url.isEmpty())
+ return nullptr;
+
+ QQmlEngine *engine = qmlEngine();
+ if (!engine)
+ return nullptr;
+
+ auto [context, effectiveContext] = getContexts();
+ if (!context)
+ return nullptr;
+
+ QQmlComponent *c = new QQmlComponent(engine, context->resolvedUrl(url), mode, parent);
+ QQmlComponentPrivate::get(c)->creationContext = effectiveContext;
+ QQmlData::get(c, true)->explicitIndestructibleSet = false;
+ QQmlData::get(c)->indestructible = false;
+ return c;
+}
+
+QQmlComponent *QtObject::createComponent(const QString &moduleUri, const QString &typeName,
+ QObject *parent) const
+{
+ return createComponent(moduleUri, typeName, QQmlComponent::PreferSynchronous, parent);
+}
+
+QQmlComponent *QtObject::createComponent(const QString &moduleUri, const QString &typeName, QQmlComponent::CompilationMode mode, QObject *parent) const
+{
+ if (mode != QQmlComponent::Asynchronous && mode != QQmlComponent::PreferSynchronous) {
+ v4Engine()->throwError(QStringLiteral("Invalid compilation mode %1").arg(mode));
+ return nullptr;
}
- QUrl url = context->resolvedUrl(QUrl(arg));
- QQmlComponent *c = new QQmlComponent(engine, url, compileMode, parentArg);
+ QQmlEngine *engine = qmlEngine();
+ if (!engine)
+ return nullptr;
+
+ if (moduleUri.isEmpty() || typeName.isEmpty())
+ return nullptr;
+
+ auto [context, effectiveContext] = getContexts();
+ if (!context)
+ return nullptr;
+
+ QQmlComponent *c = new QQmlComponent(engine, moduleUri, typeName, mode, parent);
+ if (c->isError() && !parent && moduleUri.endsWith(u".qml")) {
+ v4Engine()->throwTypeError(
+ QStringLiteral("Invalid arguments; did you swap mode and parent"));
+ }
QQmlComponentPrivate::get(c)->creationContext = effectiveContext;
QQmlData::get(c, true)->explicitIndestructibleSet = false;
QQmlData::get(c)->indestructible = false;
+ return c;
+}
+
+#if QT_CONFIG(translation)
+QString QtObject::uiLanguage() const
+{
+ if (const QJSEngine *e = jsEngine())
+ return e->uiLanguage();
+ return QString();
+}
- return QV4::QObjectWrapper::wrap(scope.engine, c);
+void QtObject::setUiLanguage(const QString &uiLanguage)
+{
+ if (QJSEngine *e = jsEngine())
+ e->setUiLanguage(uiLanguage);
}
+QBindable<QString> QtObject::uiLanguageBindable()
+{
+ if (QJSEngine *e = jsEngine())
+ return QBindable<QString>(&QJSEnginePrivate::get(e)->uiLanguage);
+ return QBindable<QString>();
+}
+#endif
+
#if QT_CONFIG(qml_locale)
/*!
\qmlmethod Qt::locale(name)
@@ -1359,19 +1605,14 @@ ReturnedValue QtObject::method_createComponent(const FunctionObject *b, const Va
\sa Locale
*/
-ReturnedValue QtObject::method_locale(const FunctionObject *b, const Value *, const Value *argv, int argc)
+QLocale QtObject::locale() const
{
- QV4::Scope scope(b);
- QString code;
- if (argc > 1)
- THROW_GENERIC_ERROR("locale() requires 0 or 1 argument");
- if (argc == 1 && !argv[0].isString())
- THROW_TYPE_ERROR_WITH_MESSAGE("locale(): argument (locale code) must be a string");
-
- if (argc == 1)
- code = argv[0].toQStringNoThrow();
+ return QLocale();
+}
- return QQmlLocale::locale(scope.engine, code);
+QLocale QtObject::locale(const QString &name) const
+{
+ return QLocale(name);
}
#endif
@@ -1435,68 +1676,53 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction);
\since 5.0
*/
-ReturnedValue QtObject::method_binding(const FunctionObject *b, const Value *, const Value *argv, int argc)
-{
- QV4::Scope scope(b);
- if (argc != 1)
- THROW_GENERIC_ERROR("binding() requires 1 argument");
- const QV4::FunctionObject *f = argv[0].as<FunctionObject>();
- if (!f)
- THROW_TYPE_ERROR_WITH_MESSAGE("binding(): argument (binding expression) must be a function");
+QJSValue QtObject::binding(const QJSValue &function) const
+{
+ const QV4::FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(&function);
+ QV4::ExecutionEngine *e = v4Engine();
+ if (!f) {
+ return QJSValuePrivate::fromReturnedValue(
+ e->throwError(
+ QStringLiteral(
+ "binding(): argument (binding expression) must be a function")));
+ }
- return Encode(scope.engine->memoryManager->allocate<QQmlBindingFunction>(f));
+ return QJSValuePrivate::fromReturnedValue(
+ Encode(e->memoryManager->allocate<QQmlBindingFunction>(f)));
}
-
-ReturnedValue QtObject::method_get_platform(const FunctionObject *b, const Value *thisObject, const Value *, int)
+void QtObject::callLater(QQmlV4FunctionPtr args)
{
- QV4::Scope scope(b);
- // ### inefficient. Should be just a value based getter
- const Object *o = thisObject->as<Object>();
- if (!o)
- THROW_TYPE_ERROR();
- const QtObject *qt = o->as<QtObject>();
- if (!qt)
- THROW_TYPE_ERROR();
+ m_engine->delayedCallQueue()->addUniquelyAndExecuteLater(m_engine, args);
+}
- if (!qt->d()->platform)
- // Only allocate a platform object once
- qt->d()->platform = new QQmlPlatform(scope.engine->jsEngine());
- return QV4::QObjectWrapper::wrap(scope.engine, qt->d()->platform);
+QQmlPlatform *QtObject::platform()
+{
+ if (!m_platform)
+ m_platform = new QQmlPlatform(this);
+ return m_platform;
}
-ReturnedValue QtObject::method_get_application(const FunctionObject *b, const Value *thisObject, const Value *, int)
+QQmlApplication *QtObject::application()
{
- QV4::Scope scope(b);
- // ### inefficient. Should be just a value based getter
- const Object *o = thisObject->as<Object>();
- if (!o)
- THROW_TYPE_ERROR();
- const QtObject *qt = o->as<QtObject>();
- if (!qt)
- THROW_TYPE_ERROR();
-
- if (!qt->d()->application)
+ if (!m_application)
// Only allocate an application object once
- qt->d()->application = QQml_guiProvider()->application(scope.engine->jsEngine());
+ m_application = QQml_guiProvider()->application(this);
- return QV4::QObjectWrapper::wrap(scope.engine, qt->d()->application);
+ return m_application;
}
-ReturnedValue QtObject::method_get_inputMethod(const FunctionObject *b, const Value *, const Value *, int)
+QObject *QtObject::inputMethod() const
{
- QObject *o = QQml_guiProvider()->inputMethod();
- return QV4::QObjectWrapper::wrap(b->engine(), o);
+ return QQml_guiProvider()->inputMethod();
}
-ReturnedValue QtObject::method_get_styleHints(const FunctionObject *b, const Value *, const Value *, int)
+QObject *QtObject::styleHints() const
{
- QObject *o = QQml_guiProvider()->styleHints();
- return QV4::QObjectWrapper::wrap(b->engine(), o);
+ return QQml_guiProvider()->styleHints();
}
-
void QV4::Heap::ConsoleObject::init()
{
Object::init();
@@ -1530,21 +1756,22 @@ enum ConsoleLogTypes {
static QString jsStack(QV4::ExecutionEngine *engine) {
QString stack;
- QVector<QV4::StackFrame> stackTrace = engine->stackTrace(10);
-
- for (int i = 0; i < stackTrace.count(); i++) {
- const QV4::StackFrame &frame = stackTrace.at(i);
-
+ int i = 0;
+ for (CppStackFrame *f = engine->currentStackFrame; f && i < 10; f = f->parentFrame(), ++i) {
QString stackFrame;
- if (frame.column >= 0)
- stackFrame = QStringLiteral("%1 (%2:%3:%4)").arg(frame.function,
- frame.source,
- QString::number(frame.line),
- QString::number(frame.column));
- else
- stackFrame = QStringLiteral("%1 (%2:%3)").arg(frame.function,
- frame.source,
- QString::number(frame.line));
+
+ if (f->isJSTypesFrame() && static_cast<JSTypesStackFrame *>(f)->isTailCalling()) {
+ stackFrame = QStringLiteral("[elided tail calls]");
+ } else {
+ const int line = f->lineNumber();
+ if (line != f->missingLineNumber()) {
+ stackFrame = QStringLiteral("%1 (%2:%3)").arg(
+ f->function(), f->source(), QString::number(qAbs(line)));
+ } else {
+ stackFrame = QStringLiteral("%1 (%2)").arg(
+ f->function(), f->source());
+ }
+ }
if (i)
stack += QLatin1Char('\n');
@@ -1553,11 +1780,12 @@ static QString jsStack(QV4::ExecutionEngine *engine) {
return stack;
}
-static QString serializeArray(Object *array, ExecutionEngine *v4) {
+static QString serializeArray(Object *array, ExecutionEngine *v4, QSet<QV4::Heap::Object *> &alreadySeen) {
Scope scope(v4);
ScopedValue val(scope);
QString result;
+ alreadySeen.insert(array->d());
result += QLatin1Char('[');
const uint length = array->getLength();
for (uint i = 0; i < length; ++i) {
@@ -1565,19 +1793,22 @@ static QString serializeArray(Object *array, ExecutionEngine *v4) {
result += QLatin1Char(',');
val = array->get(i);
if (val->isManaged() && val->managed()->isArrayLike())
- result += serializeArray(val->objectValue(), v4);
+ if (!alreadySeen.contains(val->objectValue()->d()))
+ result += serializeArray(val->objectValue(), v4, alreadySeen);
+ else
+ result += QLatin1String("[Circular]");
else
result += val->toQStringNoThrow();
}
result += QLatin1Char(']');
-
+ alreadySeen.remove(array->d());
return result;
};
-static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, const Value *argv, int argc,
+static ReturnedValue writeToConsole(const FunctionObject *b, const Value *argv, int argc,
ConsoleLogTypes logType, bool printStack = false)
{
- QLoggingCategory *loggingCategory = nullptr;
+ const QLoggingCategory *loggingCategory = nullptr;
QString result;
QV4::Scope scope(b);
QV4::ExecutionEngine *v4 = scope.engine;
@@ -1600,8 +1831,9 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, cons
if (i != start)
result.append(QLatin1Char(' '));
+ QSet<QV4::Heap::Object *> alreadySeenElements;
if (argv[i].isManaged() && argv[i].managed()->isArrayLike())
- result.append(serializeArray(argv[i].objectValue(), v4));
+ result.append(serializeArray(argv[i].objectValue(), v4, alreadySeenElements));
else
result.append(argv[i].toQStringNoThrow());
}
@@ -1609,15 +1841,13 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, cons
if (printStack)
result += QLatin1Char('\n') + jsStack(v4);
- static QLoggingCategory qmlLoggingCategory("qml");
- static QLoggingCategory jsLoggingCategory("js");
-
if (!loggingCategory)
- loggingCategory = v4->qmlEngine() ? &qmlLoggingCategory : &jsLoggingCategory;
+ loggingCategory = v4->qmlEngine() ? &lcQml() : &lcJs();
QV4::CppStackFrame *frame = v4->currentStackFrame;
- const QByteArray baSource = frame->source().toUtf8();
- const QByteArray baFunction = frame->function().toUtf8();
- QMessageLogger logger(baSource.constData(), frame->lineNumber(), baFunction.constData(), loggingCategory->categoryName());
+ const QByteArray baSource = frame ? frame->source().toUtf8() : QByteArray();
+ const QByteArray baFunction = frame ? frame->function().toUtf8() : QByteArray();
+ QMessageLogger logger(baSource.constData(), frame ? frame->lineNumber() : 0,
+ baFunction.constData(), loggingCategory->categoryName());
switch (logType) {
case Log:
@@ -1645,22 +1875,22 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, cons
DEFINE_OBJECT_VTABLE(ConsoleObject);
-ReturnedValue ConsoleObject::method_error(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue ConsoleObject::method_error(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
- return writeToConsole(b, thisObject, argv, argc, Error);
+ return writeToConsole(b, argv, argc, Error);
}
-ReturnedValue ConsoleObject::method_log(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue ConsoleObject::method_log(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
//console.log
//console.debug
//print
- return writeToConsole(b, thisObject, argv, argc, Log);
+ return writeToConsole(b, argv, argc, Log);
}
-ReturnedValue ConsoleObject::method_info(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue ConsoleObject::method_info(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
- return writeToConsole(b, thisObject, argv, argc, Info);
+ return writeToConsole(b, argv, argc, Info);
}
ReturnedValue ConsoleObject::method_profile(const FunctionObject *b, const Value *, const Value *, int)
@@ -1767,14 +1997,14 @@ ReturnedValue ConsoleObject::method_trace(const FunctionObject *b, const Value *
QV4::CppStackFrame *frame = v4->currentStackFrame;
QMessageLogger(frame->source().toUtf8().constData(), frame->lineNumber(),
frame->function().toUtf8().constData())
- .debug("%s", qPrintable(stack));
+ .debug(v4->qmlEngine() ? lcQml : lcJs, "%s", qPrintable(stack));
return QV4::Encode::undefined();
}
-ReturnedValue ConsoleObject::method_warn(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue ConsoleObject::method_warn(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
- return writeToConsole(b, thisObject, argv, argc, Warn);
+ return writeToConsole(b, argv, argc, Warn);
}
ReturnedValue ConsoleObject::method_assert(const FunctionObject *b, const Value *, const Value *argv, int argc)
@@ -1805,17 +2035,15 @@ ReturnedValue ConsoleObject::method_assert(const FunctionObject *b, const Value
return QV4::Encode::undefined();
}
-ReturnedValue ConsoleObject::method_exception(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue ConsoleObject::method_exception(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
QV4::Scope scope(b);
if (argc == 0)
THROW_GENERIC_ERROR("console.exception(): Missing argument");
- return writeToConsole(b, thisObject, argv, argc, Error, true);
+ return writeToConsole(b, argv, argc, Error, true);
}
-
-
void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions extensions)
{
ExecutionEngine *v4 = globalObject->engine();
@@ -1830,6 +2058,12 @@ void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions ext
globalObject->defineDefaultProperty(QStringLiteral("qsTrId"), QV4::GlobalExtensions::method_qsTrId);
globalObject->defineDefaultProperty(QStringLiteral("QT_TRID_NOOP"), QV4::GlobalExtensions::method_qsTrIdNoOp);
+ // Initialize the Qt global object for the uiLanguage property
+ ScopedString qtName(scope, v4->newString(QStringLiteral("Qt")));
+ ScopedObject qt(scope, globalObject->get(qtName));
+ if (!qt)
+ v4->createQtObject();
+
// string prototype extension
scope.engine->stringPrototype()->defineDefaultProperty(QStringLiteral("arg"), QV4::GlobalExtensions::method_string_arg);
#endif
@@ -1865,7 +2099,7 @@ void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions ext
Example:
\snippet qml/qsTranslate.qml 0
- \sa {Internationalization and Localization with Qt Quick}
+ \sa {Internationalization with Qt}
*/
ReturnedValue GlobalExtensions::method_qsTranslate(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -1926,7 +2160,7 @@ ReturnedValue GlobalExtensions::method_qsTranslate(const FunctionObject *b, cons
Example:
\snippet qml/qtTranslateNoOp.qml 0
- \sa {Internationalization and Localization with Qt Quick}
+ \sa {Internationalization with Qt}
*/
ReturnedValue GlobalExtensions::method_qsTranslateNoOp(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -1937,6 +2171,46 @@ ReturnedValue GlobalExtensions::method_qsTranslateNoOp(const FunctionObject *b,
return argv[1].asReturnedValue();
}
+QString GlobalExtensions::currentTranslationContext(ExecutionEngine *engine)
+{
+ QString context;
+ CppStackFrame *frame = engine->currentStackFrame;
+
+ // The first non-empty source URL in the call stack determines the translation context.
+ while (frame && context.isEmpty()) {
+ if (ExecutableCompilationUnit *unit = frame->v4Function->executableCompilationUnit()) {
+ auto translationContextIndex = unit->unitData()->translationContextIndex();
+ if (translationContextIndex)
+ context = unit->stringAt(*translationContextIndex);
+ if (!context.isEmpty())
+ break;
+ QString fileName = unit->fileName();
+ QUrl url(unit->fileName());
+ if (url.isValid() && url.isRelative()) {
+ context = url.fileName();
+ } else {
+ context = QQmlFile::urlToLocalFileOrQrc(fileName);
+ if (context.isEmpty() && fileName.startsWith(QLatin1String(":/")))
+ context = fileName;
+ }
+ context = QFileInfo(context).completeBaseName();
+ }
+ frame = frame->parentFrame();
+ }
+
+ if (context.isEmpty()) {
+ if (QQmlRefPointer<QQmlContextData> ctxt = engine->callingQmlContext()) {
+ QString path = ctxt->urlString();
+ int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ int lastDot = path.lastIndexOf(QLatin1Char('.'));
+ int length = lastDot - (lastSlash + 1);
+ context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString();
+ }
+ }
+
+ return context;
+}
+
/*!
\qmlmethod string Qt::qsTr(string sourceText, string disambiguation, int n)
@@ -1952,7 +2226,7 @@ ReturnedValue GlobalExtensions::method_qsTranslateNoOp(const FunctionObject *b,
Example:
\snippet qml/qsTr.qml 0
- \sa {Internationalization and Localization with Qt Quick}
+ \sa {Internationalization with Qt}
*/
ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -1966,43 +2240,10 @@ ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value
if ((argc > 2) && !argv[2].isNumber())
THROW_GENERIC_ERROR("qsTr(): third argument (n) must be a number");
- QString context;
- CppStackFrame *frame = scope.engine->currentStackFrame;
- // The first non-empty source URL in the call stack determines the translation context.
- while (frame && context.isEmpty()) {
- if (CompiledData::CompilationUnitBase *baseUnit = frame->v4Function->compilationUnit) {
- const auto *unit = static_cast<const CompiledData::CompilationUnit *>(baseUnit);
- QString fileName = unit->fileName();
- QUrl url(unit->fileName());
- if (url.isValid() && url.isRelative()) {
- context = url.fileName();
- } else {
- context = QQmlFile::urlToLocalFileOrQrc(fileName);
- if (context.isEmpty() && fileName.startsWith(QLatin1String(":/")))
- context = fileName;
- }
- context = QFileInfo(context).baseName();
- }
- frame = frame->parent;
- }
-
- if (context.isEmpty()) {
- if (QQmlContextData *ctxt = scope.engine->callingQmlContext()) {
- QString path = ctxt->urlString();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- int lastDot = path.lastIndexOf(QLatin1Char('.'));
- int length = lastDot - (lastSlash + 1);
- context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString();
- }
- }
-
- QString text = argv[0].toQStringNoThrow();
- QString comment;
- if (argc > 1)
- comment = argv[1].toQStringNoThrow();
- int n = -1;
- if (argc > 2)
- n = argv[2].toInt32();
+ const QString context = currentTranslationContext(scope.engine);
+ const QString text = argv[0].toQStringNoThrow();
+ const QString comment = argc > 1 ? argv[1].toQStringNoThrow() : QString();
+ const int n = argc > 2 ? argv[2].toInt32() : -1;
if (QQmlEnginePrivate *ep = (scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : nullptr))
if (ep->propertyCapture)
@@ -2034,7 +2275,7 @@ ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value
Example:
\snippet qml/qtTrNoOp.qml 0
- \sa {Internationalization and Localization with Qt Quick}
+ \sa {Internationalization with Qt}
*/
ReturnedValue GlobalExtensions::method_qsTrNoOp(const FunctionObject *, const Value *, const Value *argv, int argc)
{
@@ -2072,7 +2313,7 @@ ReturnedValue GlobalExtensions::method_qsTrNoOp(const FunctionObject *, const Va
Creating binary translation (QM) files suitable for use with this function requires passing
the \c -idbased option to the \c lrelease tool.
- \sa QT_TRID_NOOP(), {Internationalization and Localization with Qt Quick}
+ \sa QT_TRID_NOOP(), {Internationalization with Qt}
*/
ReturnedValue GlobalExtensions::method_qsTrId(const FunctionObject *b, const Value *, const Value *argv, int argc)
{
@@ -2109,7 +2350,7 @@ ReturnedValue GlobalExtensions::method_qsTrId(const FunctionObject *b, const Val
Example:
\snippet qml/qtTrIdNoOp.qml 0
- \sa qsTrId(), {Internationalization and Localization with Qt Quick}
+ \sa qsTrId(), {Internationalization with Qt}
*/
ReturnedValue GlobalExtensions::method_qsTrIdNoOp(const FunctionObject *, const Value *, const Value *argv, int argc)
{
@@ -2120,16 +2361,23 @@ ReturnedValue GlobalExtensions::method_qsTrIdNoOp(const FunctionObject *, const
}
#endif // translation
+/*!
+ \qmlmethod void Qt::gc()
+
+ Runs the garbage collector.
+ This is equivalent to calling QJSEngine::collectGarbage().
+
+ \sa {Garbage Collection}
+*/
ReturnedValue GlobalExtensions::method_gc(const FunctionObject *b, const Value *, const Value *, int)
{
- b->engine()->memoryManager->runGC();
+ auto mm = b->engine()->memoryManager;
+ mm->runFullGC();
return QV4::Encode::undefined();
}
-
-
ReturnedValue GlobalExtensions::method_string_arg(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
QV4::Scope scope(b);
@@ -2169,10 +2417,7 @@ be passed on to the function invoked. Note that if redundant calls
are eliminated, then only the last set of arguments will be passed to the
function.
*/
-ReturnedValue QtObject::method_callLater(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
-{
- return b->engine()->delayedCallQueue()->addUniquelyAndExecuteLater(b, thisObject, argv, argc);
-}
QT_END_NAMESPACE
+#include "moc_qqmlbuiltinfunctions_p.cpp"
diff --git a/src/qml/qml/qqmlbuiltinfunctions_p.h b/src/qml/qml/qqmlbuiltinfunctions_p.h
new file mode 100644
index 0000000000..9ceedad28b
--- /dev/null
+++ b/src/qml/qml/qqmlbuiltinfunctions_p.h
@@ -0,0 +1,265 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLBUILTINFUNCTIONS_P_H
+#define QQMLBUILTINFUNCTIONS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qjsengine_p.h>
+#include <private/qqmlglobal_p.h>
+#include <private/qqmlplatform_p.h>
+#include <private/qv4functionobject_p.h>
+
+#include <QtCore/qnamespace.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qpoint.h>
+
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlengine.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_EXPORT QtObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlApplication *application READ application CONSTANT)
+ Q_PROPERTY(QQmlPlatform *platform READ platform CONSTANT)
+ Q_PROPERTY(QObject *inputMethod READ inputMethod CONSTANT)
+ Q_PROPERTY(QObject *styleHints READ styleHints CONSTANT)
+
+#if QT_CONFIG(translation)
+ Q_PROPERTY(QString uiLanguage READ uiLanguage WRITE setUiLanguage BINDABLE uiLanguageBindable)
+#endif
+
+ QML_NAMED_ELEMENT(Qt)
+ QML_SINGLETON
+ QML_EXTENDED_NAMESPACE(Qt)
+ QML_ADDED_IN_VERSION(2, 0)
+
+ Q_CLASSINFO("QML.StrictArguments", "true")
+
+public:
+ enum LoadingMode { Asynchronous = 0, Synchronous = 1 };
+ Q_ENUM(LoadingMode);
+
+ static QtObject *create(QQmlEngine *, QJSEngine *jsEngine);
+
+ Q_INVOKABLE QJSValue include(const QString &url, const QJSValue &callback = QJSValue()) const;
+ Q_INVOKABLE bool isQtObject(const QJSValue &value) const;
+
+ Q_INVOKABLE QVariant color(const QString &name) const;
+ Q_INVOKABLE QVariant rgba(double r, double g, double b, double a = 1) const;
+ Q_INVOKABLE QVariant hsla(double h, double s, double l, double a = 1) const;
+ Q_INVOKABLE QVariant hsva(double h, double s, double v, double a = 1) const;
+ Q_INVOKABLE bool colorEqual(const QVariant &lhs, const QVariant &rhs) const;
+
+ Q_INVOKABLE QRectF rect(double x, double y, double width, double height) const;
+ Q_INVOKABLE QPointF point(double x, double y) const;
+ Q_INVOKABLE QSizeF size(double width, double height) const;
+ Q_INVOKABLE QVariant vector2d(double x, double y) const;
+ Q_INVOKABLE QVariant vector3d(double x, double y, double z) const;
+ Q_INVOKABLE QVariant vector4d(double x, double y, double z, double w) const;
+ Q_INVOKABLE QVariant quaternion(double scalar, double x, double y, double z) const;
+
+ Q_INVOKABLE QVariant matrix4x4() const;
+ Q_INVOKABLE QVariant matrix4x4(double m11, double m12, double m13, double m14,
+ double m21, double m22, double m23, double m24,
+ double m31, double m32, double m33, double m34,
+ double m41, double m42, double m43, double m44) const;
+ Q_INVOKABLE QVariant matrix4x4(const QJSValue &value) const;
+
+ Q_INVOKABLE QVariant lighter(const QJSValue &color, double factor = 1.5) const;
+ Q_INVOKABLE QVariant darker(const QJSValue &color, double factor = 2.0) const;
+ Q_INVOKABLE QVariant alpha(const QJSValue &baseColor, double value) const;
+ Q_INVOKABLE QVariant tint(const QJSValue &baseColor, const QJSValue &tintColor) const;
+
+ Q_INVOKABLE QString formatDate(QDate date, const QString &format) const;
+ Q_INVOKABLE QString formatDate(const QDateTime &dateTime, const QString &format) const;
+ Q_INVOKABLE QString formatDate(const QString &string, const QString &format) const;
+ Q_INVOKABLE QString formatDate(QDate date, Qt::DateFormat format) const;
+ Q_INVOKABLE QString formatDate(const QDateTime &dateTime, Qt::DateFormat format) const;
+ Q_INVOKABLE QString formatDate(const QString &string, Qt::DateFormat format) const;
+
+ Q_INVOKABLE QString formatTime(QTime time, const QString &format) const;
+ Q_INVOKABLE QString formatTime(const QDateTime &dateTime, const QString &format) const;
+ Q_INVOKABLE QString formatTime(const QString &time, const QString &format) const;
+ Q_INVOKABLE QString formatTime(QTime time, Qt::DateFormat format) const;
+ Q_INVOKABLE QString formatTime(const QDateTime &dateTime, Qt::DateFormat format) const;
+ Q_INVOKABLE QString formatTime(const QString &time, Qt::DateFormat format) const;
+
+ Q_INVOKABLE QString formatDateTime(const QDateTime &date, const QString &format) const;
+ Q_INVOKABLE QString formatDateTime(const QString &string, const QString &format) const;
+ Q_INVOKABLE QString formatDateTime(const QDateTime &date, Qt::DateFormat format) const;
+ Q_INVOKABLE QString formatDateTime(const QString &string, Qt::DateFormat format) const;
+
+#if QT_CONFIG(qml_locale)
+ Q_INVOKABLE QString formatDate(QDate date, const QLocale &locale = QLocale(),
+ QLocale::FormatType formatType = QLocale::ShortFormat) const;
+ Q_INVOKABLE QString formatDate(const QDateTime &dateTime, const QLocale &locale = QLocale(),
+ QLocale::FormatType formatType = QLocale::ShortFormat) const;
+ Q_INVOKABLE QString formatDate(const QString &string, const QLocale &locale = QLocale(),
+ QLocale::FormatType formatType = QLocale::ShortFormat) const;
+ Q_INVOKABLE QString formatTime(QTime time, const QLocale &locale = QLocale(),
+ QLocale::FormatType formatType = QLocale::ShortFormat) const;
+ Q_INVOKABLE QString formatTime(const QDateTime &dateTime, const QLocale &locale = QLocale(),
+ QLocale::FormatType formatType = QLocale::ShortFormat) const;
+ Q_INVOKABLE QString formatTime(const QString &time, const QLocale &locale = QLocale(),
+ QLocale::FormatType formatType = QLocale::ShortFormat) const;
+ Q_INVOKABLE QString formatDateTime(const QDateTime &date, const QLocale &locale = QLocale(),
+ QLocale::FormatType formatType = QLocale::ShortFormat) const;
+ Q_INVOKABLE QString formatDateTime(const QString &string, const QLocale &locale = QLocale(),
+ QLocale::FormatType formatType = QLocale::ShortFormat) const;
+ Q_INVOKABLE QLocale locale() const;
+ Q_INVOKABLE QLocale locale(const QString &name) const;
+#endif
+
+ Q_INVOKABLE QUrl url(const QUrl &url) const;
+ Q_INVOKABLE QUrl resolvedUrl(const QUrl &url) const;
+ Q_INVOKABLE QUrl resolvedUrl(const QUrl &url, QObject *context) const;
+ Q_INVOKABLE bool openUrlExternally(const QUrl &url) const;
+
+ Q_INVOKABLE QVariant font(const QJSValue &fontSpecifier) const;
+ Q_INVOKABLE QStringList fontFamilies() const;
+
+ Q_INVOKABLE QString md5(const QString &data) const;
+ Q_INVOKABLE QString btoa(const QString &data) const;
+ Q_INVOKABLE QString atob(const QString &data) const;
+
+ Q_INVOKABLE void quit() const;
+ Q_INVOKABLE void exit(int retCode) const;
+
+ Q_INVOKABLE QObject *createQmlObject(const QString &qml, QObject *parent,
+ const QUrl &url = QUrl(QStringLiteral("inline"))) const;
+ Q_INVOKABLE QQmlComponent *createComponent(const QUrl &url, QObject *parent) const;
+ Q_INVOKABLE QQmlComponent *createComponent(
+ const QUrl &url, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous,
+ QObject *parent = nullptr) const;
+
+ Q_INVOKABLE QQmlComponent *createComponent(const QString &moduleUri,
+ const QString &typeName, QObject *parent) const;
+ Q_INVOKABLE QQmlComponent *createComponent(const QString &moduleUri, const QString &typeName,
+ QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous,
+ QObject *parent = nullptr) const;
+
+ Q_INVOKABLE QJSValue binding(const QJSValue &function) const;
+ Q_INVOKABLE void callLater(QQmlV4FunctionPtr args);
+
+#if QT_CONFIG(translation)
+ QString uiLanguage() const;
+ void setUiLanguage(const QString &uiLanguage);
+ QBindable<QString> uiLanguageBindable();
+#endif
+
+ // Not const because created on first use, and parented to this.
+ QQmlPlatform *platform();
+ QQmlApplication *application();
+
+ QObject *inputMethod() const;
+ QObject *styleHints() const;
+
+private:
+ friend struct QV4::ExecutionEngine;
+
+ QtObject(QV4::ExecutionEngine *engine);
+
+ QQmlEngine *qmlEngine() const { return m_engine->qmlEngine(); }
+ QJSEngine *jsEngine() const { return m_engine->jsEngine(); }
+ QV4::ExecutionEngine *v4Engine() const { return m_engine; }
+
+ struct Contexts {
+ QQmlRefPointer<QQmlContextData> context;
+ QQmlRefPointer<QQmlContextData> effectiveContext;
+ };
+ Contexts getContexts() const;
+
+ QQmlPlatform *m_platform = nullptr;
+ QQmlApplication *m_application = nullptr;
+
+ QV4::ExecutionEngine *m_engine = nullptr;
+};
+
+namespace QV4 {
+
+namespace Heap {
+
+struct ConsoleObject : Object {
+ void init();
+};
+
+#define QQmlBindingFunctionMembers(class, Member) \
+ Member(class, Pointer, FunctionObject *, bindingFunction)
+DECLARE_HEAP_OBJECT(QQmlBindingFunction, FunctionObject) {
+ DECLARE_MARKOBJECTS(QQmlBindingFunction)
+ void init(const QV4::FunctionObject *bindingFunction);
+};
+
+}
+
+struct ConsoleObject : Object
+{
+ V4_OBJECT2(ConsoleObject, Object)
+
+ static ReturnedValue method_error(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_log(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_info(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_profile(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_profileEnd(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_time(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_timeEnd(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_count(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_trace(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_warn(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_assert(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_exception(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+
+};
+
+struct Q_QML_EXPORT GlobalExtensions {
+ static void init(Object *globalObject, QJSEngine::Extensions extensions);
+
+#if QT_CONFIG(translation)
+ static QString currentTranslationContext(ExecutionEngine *engine);
+ static ReturnedValue method_qsTranslate(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_qsTranslateNoOp(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_qsTr(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_qsTrNoOp(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_qsTrId(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_qsTrIdNoOp(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+#endif
+ static ReturnedValue method_gc(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+
+ // on String:prototype
+ static ReturnedValue method_string_arg(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+
+};
+
+struct QQmlBindingFunction : public QV4::FunctionObject
+{
+ V4_OBJECT2(QQmlBindingFunction, FunctionObject)
+
+ Heap::FunctionObject *bindingFunction() const { return d()->bindingFunction; }
+ QQmlSourceLocation currentLocation() const; // from caller stack trace
+};
+
+inline bool FunctionObject::isBinding() const
+{
+ return d()->vtable() == QQmlBindingFunction::staticVTable();
+}
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLBUILTINFUNCTIONS_P_H
diff --git a/src/qml/qml/qqmlcleanup.cpp b/src/qml/qml/qqmlcleanup.cpp
deleted file mode 100644
index 0d57ef5fe8..0000000000
--- a/src/qml/qml/qqmlcleanup.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlcleanup_p.h"
-
-#include "qqmlengine_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
-\internal
-\class QQmlCleanup
-\brief The QQmlCleanup provides a callback when a QQmlEngine is deleted.
-
-Any object that needs cleanup to occur before the QQmlEngine's V8 engine is
-destroyed should inherit from QQmlCleanup. The clear() virtual method will be
-called by QQmlEngine just before it destroys the context.
-*/
-
-
-/*
-Create a QQmlCleanup that is not associated with any engine.
-*/
-QQmlCleanup::QQmlCleanup()
-: prev(nullptr), next(nullptr), engine(nullptr)
-{
-}
-
-/*!
-Create a QQmlCleanup for \a engine
-*/
-QQmlCleanup::QQmlCleanup(QQmlEngine *engine)
-: prev(nullptr), next(nullptr), engine(nullptr)
-{
- if (!engine)
- return;
-
- addToEngine(engine);
-}
-
-/*!
-Adds this object to \a engine's cleanup list. hasEngine() must be false
-before calling this method.
-*/
-void QQmlCleanup::addToEngine(QQmlEngine *engine)
-{
- Q_ASSERT(engine);
- Q_ASSERT(QQmlEnginePrivate::isEngineThread(engine));
-
- this->engine = engine;
-
- QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine);
-
- if (p->cleanup) next = p->cleanup;
- p->cleanup = this;
- prev = &p->cleanup;
- if (next) next->prev = &next;
-}
-
-/*!
-\fn bool QQmlCleanup::hasEngine() const
-
-Returns true if this QQmlCleanup is associated with an engine, otherwise false.
-*/
-
-/*!
-\internal
-*/
-QQmlCleanup::~QQmlCleanup()
-{
- Q_ASSERT(!prev || engine);
- Q_ASSERT(!prev || QQmlEnginePrivate::isEngineThread(engine));
-
- if (prev) *prev = next;
- if (next) next->prev = prev;
- prev = nullptr;
- next = nullptr;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcleanup_p.h b/src/qml/qml/qqmlcleanup_p.h
deleted file mode 100644
index 0e15c28b9d..0000000000
--- a/src/qml/qml/qqmlcleanup_p.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLCLEANUP_P_H
-#define QQMLCLEANUP_P_H
-
-#include <private/qtqmlglobal_p.h>
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-QT_BEGIN_NAMESPACE
-
-class QQmlEngine;
-
-class Q_QML_PRIVATE_EXPORT QQmlCleanup
-{
-public:
- QQmlCleanup();
- QQmlCleanup(QQmlEngine *);
- virtual ~QQmlCleanup();
-
- bool hasEngine() const { return prev != nullptr; }
- void addToEngine(QQmlEngine *);
-protected:
- virtual void clear() = 0;
-
-private:
- friend class QQmlEnginePrivate;
- QQmlCleanup **prev;
- QQmlCleanup *next;
-
- // Only used for asserts
- QQmlEngine *engine;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLCLEANUP_P_H
-
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 1d5f974d5c..e063418de4 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1,55 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlcomponent.h"
#include "qqmlcomponent_p.h"
#include "qqmlcomponentattached_p.h"
-#include "qqmlcontext_p.h"
#include "qqmlengine_p.h"
#include "qqmlvme_p.h"
#include "qqml.h"
#include "qqmlengine.h"
-#include "qqmlbinding_p.h"
#include "qqmlincubator.h"
#include "qqmlincubator_p.h"
#include <private/qqmljavascriptexpression_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4script_p.h>
@@ -63,12 +26,18 @@
#include <QStringList>
#include <QThreadStorage>
#include <QtCore/qdebug.h>
+#include <QtCore/qloggingcategory.h>
#include <qqmlinfo.h>
+
+using namespace Qt::Literals::StringLiterals;
+
namespace {
- QThreadStorage<int> creationDepth;
+ Q_CONSTINIT thread_local int creationDepth = 0;
}
+Q_LOGGING_CATEGORY(lcQmlComponentGeneral, "qt.qml.qmlcomponent")
+
QT_BEGIN_NAMESPACE
class QQmlComponentExtension : public QV4::ExecutionEngine::Deletable
@@ -155,11 +124,12 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
{
// ...
component = new QQmlComponent(engine, QUrl("http://www.example.com/main.qml"));
- if (component->isLoading())
- QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
- this, SLOT(continueLoading()));
- else
+ if (component->isLoading()) {
+ QObject::connect(component, &QQmlComponent::statusChanged,
+ this, &MyApplication::continueLoading);
+ } else {
continueLoading();
+ }
}
void MyApplication::continueLoading()
@@ -248,9 +218,8 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
execute script code at startup, once the full QML environment has been
established.
- The corresponding handler is \c onCompleted. It can be declared on
- any object. The order of running the \c onCompleted handlers is
- undefined.
+ The \c onCompleted signal handler can be declared on any object. The order
+ of running the handlers is undefined.
\qml
Rectangle {
@@ -269,9 +238,8 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
work done in response to the \l {completed}{completed()} signal, or other
imperative code in your application.
- The corresponding handler is \c onDestruction. It can be declared on
- any object. The order of running the \c onDestruction handlers is
- undefined.
+ The \c onDestruction signal handler can be declared on any object. The
+ order of running the handlers is undefined.
\qml
Rectangle {
@@ -282,7 +250,7 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
}
\endqml
- \sa {Qt QML}
+ \sa {Qt Qml}
*/
/*!
@@ -302,7 +270,7 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
Specifies whether the QQmlComponent should load the component immediately, or asynchonously.
\value PreferSynchronous Prefer loading/compiling the component immediately, blocking the thread.
- This is not always possible; for example, remote URLs will always load asynchronously.
+ This is not always possible; for example, remote URLs will always load asynchronously.
\value Asynchronous Load/compile the component in a background thread.
*/
@@ -313,7 +281,7 @@ void QQmlComponentPrivate::typeDataReady(QQmlTypeData *)
Q_ASSERT(typeData);
fromTypeData(typeData);
- typeData = nullptr;
+ typeData.reset();
progress = 1.0;
emit q->statusChanged(q->status());
@@ -332,32 +300,31 @@ void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p)
void QQmlComponentPrivate::fromTypeData(const QQmlRefPointer<QQmlTypeData> &data)
{
url = data->finalUrl();
- compilationUnit = data->compilationUnit();
+ if (auto cu = data->compilationUnit())
+ compilationUnit = engine->handle()->executableCompilationUnit(std::move(cu));
if (!compilationUnit) {
Q_ASSERT(data->isError());
- state.errors = data->errors();
+ state.errors.clear();
+ state.appendErrors(data->errors());
}
}
-RequiredProperties &QQmlComponentPrivate::requiredProperties()
-{
- return state.creator->requiredProperties();
-}
-
-bool QQmlComponentPrivate::hadRequiredProperties() const
+bool QQmlComponentPrivate::hadTopLevelRequiredProperties() const
{
- return state.creator->componentHadRequiredProperties();
+ return state.creator()->componentHadTopLevelRequiredProperties();
}
void QQmlComponentPrivate::clear()
{
if (typeData) {
typeData->unregisterCallback(this);
- typeData = nullptr;
+ typeData.reset();
}
- compilationUnit = nullptr;
+ compilationUnit.reset();
+ loadedType = {};
+ inlineComponentName.reset();
}
QObject *QQmlComponentPrivate::doBeginCreate(QQmlComponent *q, QQmlContext *context)
@@ -372,18 +339,93 @@ QObject *QQmlComponentPrivate::doBeginCreate(QQmlComponent *q, QQmlContext *cont
return q->beginCreate(context);
}
-bool QQmlComponentPrivate::setInitialProperty(QObject *component, const QString& name, const QVariant &value)
+static void removePendingQPropertyBinding(
+ QV4::Value *object, const QString &propertyName, QQmlObjectCreator *creator)
{
- QQmlProperty prop = QQmlComponentPrivate::removePropertyFromRequired(component, name, requiredProperties());
+ if (!creator)
+ return;
+
+ QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>();
+ if (!wrapper)
+ return;
+
+ QObject *o = wrapper->object();
+ if (!o)
+ return;
+
+ if (QQmlData *ddata = QQmlData::get(o)) {
+ const QQmlPropertyData *propData = ddata->propertyCache->property(
+ propertyName, o, ddata->outerContext);
+ if (propData && propData->isBindable())
+ creator->removePendingBinding(o, propData->coreIndex());
+ return;
+ }
+
+ const QMetaObject *meta = o->metaObject();
+ Q_ASSERT(meta);
+ const int index = meta->indexOfProperty(propertyName.toUtf8());
+ if (index != -1 && meta->property(index).isBindable())
+ creator->removePendingBinding(o, index);
+}
+
+bool QQmlComponentPrivate::setInitialProperty(
+ QObject *base, const QString &name, const QVariant &value)
+{
+ const QStringList properties = name.split(u'.');
+
+ if (properties.size() > 1) {
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedObject object(scope, QV4::QObjectWrapper::wrap(scope.engine, base));
+ QV4::ScopedString segment(scope);
+
+ for (int i = 0; i < properties.size() - 1; ++i) {
+ segment = scope.engine->newString(properties.at(i));
+ object = object->get(segment);
+ if (scope.engine->hasException)
+ break;
+ }
+ const QString lastProperty = properties.last();
+ segment = scope.engine->newString(lastProperty);
+ object->put(segment, scope.engine->metaTypeToJS(value.metaType(), value.constData()));
+ if (scope.engine->hasException) {
+ qmlWarning(base, scope.engine->catchExceptionAsQmlError());
+ scope.engine->hasException = false;
+ return false;
+ }
+
+ removePendingQPropertyBinding(object, lastProperty, state.creator());
+ return true;
+ }
+
+ QQmlProperty prop;
+ if (state.hasUnsetRequiredProperties())
+ prop = QQmlComponentPrivate::removePropertyFromRequired(
+ base, name, state.requiredProperties(), engine);
+ else
+ prop = QQmlProperty(base, name, engine);
QQmlPropertyPrivate *privProp = QQmlPropertyPrivate::get(prop);
- if (!prop.isValid() || !privProp->writeValueProperty(value, nullptr)) {
+ const bool isValid = prop.isValid();
+ if (isValid && privProp->writeValueProperty(value, {})) {
+ if (prop.isBindable()) {
+ if (QQmlObjectCreator *creator = state.creator())
+ creator->removePendingBinding(prop.object(), prop.index());
+ }
+ } else {
QQmlError error{};
error.setUrl(url);
- error.setDescription(QLatin1String("Could not set property %1").arg(name));
- state.errors.push_back(error);
+ if (isValid) {
+ error.setDescription(QStringLiteral("Could not set initial property %1").arg(name));
+ } else {
+ error.setDescription(QStringLiteral("Setting initial properties failed: "
+ "%2 does not have a property called %1")
+ .arg(name, QQmlMetaType::prettyTypeName(base)));
+ }
+ qmlWarning(base, error);
return false;
- } else
- return true;
+ }
+
+ return true;
+
}
/*!
@@ -401,35 +443,37 @@ QQmlComponent::~QQmlComponent()
{
Q_D(QQmlComponent);
- if (d->state.completePending) {
+ if (d->state.isCompletePending()) {
qWarning("QQmlComponent: Component destroyed while completion pending");
if (isError()) {
qWarning() << "This may have been caused by one of the following errors:";
- for (const QQmlError &error : qAsConst(d->state.errors))
- qWarning().nospace().noquote() << QLatin1String(" ") << error;
+ for (const QQmlComponentPrivate::AnnotatedQmlError &e : std::as_const(d->state.errors))
+ qWarning().nospace().noquote() << QLatin1String(" ") << e.error;
}
- d->completeCreate();
+ // we might not have the creator anymore if the engine is gone
+ if (d->state.hasCreator())
+ d->completeCreate();
}
if (d->typeData) {
d->typeData->unregisterCallback(d);
- d->typeData = nullptr;
+ d->typeData.reset();
}
}
/*!
\qmlproperty enumeration Component::status
+
This property holds the status of component loading. The status can be one of the
following:
- \list
- \li Component.Null - no data is available for the component
- \li Component.Ready - the component has been loaded, and can be used to create instances.
- \li Component.Loading - the component is currently being loaded
- \li Component.Error - an error occurred while loading the component.
- Calling errorString() will provide a human-readable description of any errors.
- \endlist
+
+ \value Component.Null no data is available for the component
+ \value Component.Ready the component has been loaded, and can be used to create instances.
+ \value Component.Loading the component is currently being loaded
+ \value Component.Error an error occurred while loading the component.
+ Calling \l errorString() will provide a human-readable description of any errors.
*/
/*!
@@ -444,7 +488,7 @@ QQmlComponent::Status QQmlComponent::status() const
return Loading;
else if (!d->state.errors.isEmpty())
return Error;
- else if (d->engine && d->compilationUnit)
+ else if (d->engine && (d->compilationUnit || d->loadedType.isValid()))
return Ready;
else
return Null;
@@ -483,6 +527,18 @@ bool QQmlComponent::isLoading() const
}
/*!
+ Returns true if the component was created in a QML files that specifies
+ \c{pragma ComponentBehavior: Bound}, otherwise returns false.
+
+ \since 6.5
+ */
+bool QQmlComponent::isBound() const
+{
+ Q_D(const QQmlComponent);
+ return d->isBound();
+}
+
+/*!
\qmlproperty real Component::progress
The progress of loading the component, from 0.0 (nothing loaded)
to 1.0 (finished).
@@ -522,6 +578,10 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent)
{
Q_D(QQmlComponent);
d->engine = engine;
+ QObject::connect(engine, &QObject::destroyed, this, [d]() {
+ d->state.clear();
+ d->engine = nullptr;
+ });
}
/*!
@@ -555,6 +615,36 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMod
}
/*!
+ Create a QQmlComponent from the given \a uri and \a typeName and give it
+ the specified \a parent and \a engine. If possible, the component will
+ be loaded synchronously.
+
+ \sa loadFromModule()
+ \since 6.5
+ \overload
+*/
+QQmlComponent::QQmlComponent(QQmlEngine *engine, QAnyStringView uri, QAnyStringView typeName, QObject *parent)
+ : QQmlComponent(engine, uri, typeName, QQmlComponent::PreferSynchronous, parent)
+{
+
+}
+
+/*!
+ Create a QQmlComponent from the given \a uri and \a typeName and give it
+ the specified \a parent and \a engine. If \a mode is \l Asynchronous,
+ the component will be loaded and compiled asynchronously.
+
+ \sa loadFromModule()
+ \since 6.5
+ \overload
+*/
+QQmlComponent::QQmlComponent(QQmlEngine *engine, QAnyStringView uri, QAnyStringView typeName, CompilationMode mode, QObject *parent)
+ : QQmlComponent(engine, parent)
+{
+ loadFromModule(uri, typeName, mode);
+}
+
+/*!
Create a QQmlComponent from the given \a fileName and give it the specified
\a parent and \a engine.
@@ -578,8 +668,12 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
: QQmlComponent(engine, parent)
{
Q_D(QQmlComponent);
- const QUrl url = QDir::isAbsolutePath(fileName) ? QUrl::fromLocalFile(fileName) : QUrl(fileName);
- d->loadUrl(url, mode);
+ if (fileName.startsWith(u':'))
+ d->loadUrl(QUrl(QLatin1String("qrc") + fileName), mode);
+ else if (QDir::isAbsolutePath(fileName))
+ d->loadUrl(QUrl::fromLocalFile(fileName), mode);
+ else
+ d->loadUrl(QUrl(fileName), mode);
}
/*!
@@ -590,7 +684,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QV4::ExecutableCompilationUnit
: QQmlComponent(engine, parent)
{
Q_D(QQmlComponent);
- d->compilationUnit = compilationUnit;
+ d->compilationUnit.reset(compilationUnit);
d->start = start;
d->url = compilationUnit->finalUrl();
d->progress = 1.0;
@@ -636,7 +730,7 @@ void QQmlComponent::setData(const QByteArray &data, const QUrl &url)
QQmlContext *QQmlComponent::creationContext() const
{
Q_D(const QQmlComponent);
- if(d->creationContext)
+ if (!d->creationContext.isNull())
return d->creationContext->asQQmlContext();
return qmlContext(this);
@@ -700,7 +794,7 @@ void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::Compilatio
if (newUrl.isEmpty()) {
QQmlError error;
error.setDescription(QQmlComponent::tr("Invalid empty URL"));
- state.errors << error;
+ state.errors.emplaceBack(error);
return;
}
@@ -712,7 +806,6 @@ void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::Compilatio
QQmlTypeLoader::Mode loaderMode = (mode == QQmlComponent::Asynchronous)
? QQmlTypeLoader::Asynchronous
: QQmlTypeLoader::PreferSynchronous;
-
QQmlRefPointer<QQmlTypeData> data = QQmlEnginePrivate::get(engine)->typeLoader.getType(url, loaderMode);
if (data->isCompleteOrError()) {
@@ -736,10 +829,11 @@ void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::Compilatio
QList<QQmlError> QQmlComponent::errors() const
{
Q_D(const QQmlComponent);
- if (isError())
- return d->state.errors;
- else
- return QList<QQmlError>();
+ QList<QQmlError> errors;
+ errors.reserve(d->state.errors.size());
+ for (const QQmlComponentPrivate::AnnotatedQmlError &annotated : d->state.errors)
+ errors.emplaceBack(annotated.error);
+ return errors;
}
/*!
@@ -755,7 +849,7 @@ QList<QQmlError> QQmlComponent::errors() const
/*!
\internal
- errorString is only meant as a way to get the errors in script
+ errorString() is only meant as a way to get the errors from QML side.
*/
QString QQmlComponent::errorString() const
{
@@ -763,7 +857,8 @@ QString QQmlComponent::errorString() const
QString ret;
if(!isError())
return ret;
- for (const QQmlError &e : d->state.errors) {
+ for (const QQmlComponentPrivate::AnnotatedQmlError &annotated : d->state.errors) {
+ const QQmlError &e = annotated.error;
ret += e.url().toString() + QLatin1Char(':') +
QString::number(e.line()) + QLatin1Char(' ') +
e.description() + QLatin1Char('\n');
@@ -796,9 +891,8 @@ QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent)
}
/*!
- Create an object instance from this component. Returns \nullptr if creation
- failed. \a context specifies the context within which to create the object
- instance.
+ Create an object instance from this component, within the specified \a context.
+ Returns \nullptr if creation failed.
If \a context is \nullptr (the default), it will create the instance in the
\l {QQmlEngine::rootContext()}{root context} of the engine.
@@ -815,21 +909,20 @@ QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent)
QObject *QQmlComponent::create(QQmlContext *context)
{
Q_D(QQmlComponent);
-
- QObject *rv = d->doBeginCreate(this, context);
- if (rv)
- completeCreate();
- if (rv && !d->requiredProperties().empty()) {
- delete rv;
- return nullptr;
- }
- return rv;
+ return d->createWithProperties(nullptr, QVariantMap {}, context);
}
/*!
- Create an object instance of this component, and initialize its toplevel
- properties with \a initialProperties. \a context specifies the context
- where the object instance is to be created.
+ Create an object instance of this component, within the specified \a context,
+ and initialize its top-level properties with \a initialProperties.
+
+ \omit
+ TODO: also mention errorString() when QTBUG-93239 is fixed
+ \endomit
+
+ If any of the \a initialProperties cannot be set, a warning is issued. If
+ there are unset required properties, the object creation fails and returns
+ \c nullptr, in which case \l isError() will return \c true.
\sa QQmlComponent::create
\since 5.14
@@ -837,34 +930,65 @@ QObject *QQmlComponent::create(QQmlContext *context)
QObject *QQmlComponent::createWithInitialProperties(const QVariantMap& initialProperties, QQmlContext *context)
{
Q_D(QQmlComponent);
+ return d->createWithProperties(nullptr, initialProperties, context);
+}
- QObject *rv = d->doBeginCreate(this, context);
- if (rv) {
- setInitialProperties(rv, initialProperties);
- completeCreate();
- }
- if (!d->requiredProperties().empty()) {
- d->requiredProperties().clear();
+static void QQmlComponent_setQmlParent(QObject *me, QObject *parent); // forward declaration
+
+/*! \internal
+ */
+QObject *QQmlComponentPrivate::createWithProperties(QObject *parent, const QVariantMap &properties,
+ QQmlContext *context, CreateBehavior behavior)
+{
+ Q_Q(QQmlComponent);
+
+ QObject *rv = doBeginCreate(q, context);
+ if (!rv) {
+ if (state.isCompletePending()) {
+ // overridden completCreate might assume that
+ // the object has actually been created
+ ++creationDepth;
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ complete(ep, &state);
+ --creationDepth;
+ }
return nullptr;
}
+
+ QQmlComponent_setQmlParent(rv, parent); // internally checks if parent is nullptr
+
+ q->setInitialProperties(rv, properties);
+ q->completeCreate();
+
+ if (state.hasUnsetRequiredProperties()) {
+ if (behavior == CreateWarnAboutRequiredProperties) {
+ for (const auto &unsetRequiredProperty : std::as_const(*state.requiredProperties())) {
+ const QQmlError error = unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
+ qmlWarning(rv, error);
+ }
+ }
+ delete rv;
+ rv = nullptr;
+ }
return rv;
}
/*!
- This method provides advanced control over component instance creation.
+ Create an object instance from this component, within the specified \a context.
+ Returns \nullptr if creation failed.
+
+ \note This method provides advanced control over component instance creation.
In general, programmers should use QQmlComponent::create() to create object
instances.
- Create an object instance from this component. Returns \nullptr if creation
- failed. \a publicContext specifies the context within which to create the object
- instance.
-
When QQmlComponent constructs an instance, it occurs in three steps:
+
\list 1
\li The object hierarchy is created, and constant values are assigned.
\li Property bindings are evaluated for the first time.
\li If applicable, QQmlParserStatus::componentComplete() is called on objects.
\endlist
+
QQmlComponent::beginCreate() differs from QQmlComponent::create() in that it
only performs step 1. QQmlComponent::completeCreate() must be called to
complete steps 2 and 3.
@@ -875,22 +999,34 @@ QObject *QQmlComponent::createWithInitialProperties(const QVariantMap& initialPr
The ownership of the returned object instance is transferred to the caller.
+ \note The categorization of bindings into constant values and actual
+ bindings is intentionally unspecified and may change between versions of Qt
+ and depending on whether and how you are using \l{qmlcachegen}. You should
+ not rely on any particular binding to be evaluated either before or after
+ beginCreate() returns. For example a constant expression like
+ \e{MyType.EnumValue} may be recognized as such at compile time or deferred
+ to be executed as binding. The same holds for constant expressions like
+ \e{-(5)} or \e{"a" + " constant string"}.
+
\sa completeCreate(), QQmlEngine::ObjectOwnership
*/
-QObject *QQmlComponent::beginCreate(QQmlContext *publicContext)
+QObject *QQmlComponent::beginCreate(QQmlContext *context)
{
Q_D(QQmlComponent);
-
- Q_ASSERT(publicContext);
- QQmlContextData *context = QQmlContextData::get(publicContext);
-
- return d->beginCreate(context);
+ Q_ASSERT(context);
+ return d->beginCreate(QQmlContextData::get(context));
}
-QObject *
-QQmlComponentPrivate::beginCreate(QQmlContextData *context)
+QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> context)
{
Q_Q(QQmlComponent);
+ auto cleanup = qScopeGuard([this] {
+ if (!state.errors.isEmpty() && lcQmlComponentGeneral().isDebugEnabled()) {
+ for (const auto &e : std::as_const(state.errors)) {
+ qCDebug(lcQmlComponentGeneral) << "QQmlComponent: " << e.error.toString();
+ }
+ }
+ });
if (!context) {
qWarning("QQmlComponent: Cannot create a component in a null context");
return nullptr;
@@ -901,16 +1037,21 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
return nullptr;
}
- if (context->engine != engine) {
+ if (context->engine() != engine) {
qWarning("QQmlComponent: Must create component in context from the same QQmlEngine");
return nullptr;
}
- if (state.completePending) {
+ if (state.isCompletePending()) {
qWarning("QQmlComponent: Cannot create new component instance before completing the previous");
return nullptr;
}
+ // filter out temporary errors as they do not really affect component's
+ // state (they are not part of the document compilation)
+ state.errors.removeIf([](const auto &e) { return e.isTransient; });
+ state.clearRequiredProperties();
+
if (!q->isReady()) {
qWarning("QQmlComponent: Component is not ready");
return nullptr;
@@ -918,7 +1059,7 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
// Do not create infinite recursion in object creation
static const int maxCreationDepth = 10;
- if (creationDepth.localData() >= maxCreationDepth) {
+ if (creationDepth >= maxCreationDepth) {
qWarning("QQmlComponent: Component creation is recursing - aborting");
return nullptr;
}
@@ -927,21 +1068,59 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
enginePriv->inProgressCreations++;
state.errors.clear();
- state.completePending = true;
+ state.setCompletePending(true);
- enginePriv->referenceScarceResources();
QObject *rv = nullptr;
- state.creator.reset(new QQmlObjectCreator(context, compilationUnit, creationContext));
- rv = state.creator->create(start);
- if (!rv)
- state.errors = state.creator->errors;
- enginePriv->dereferenceScarceResources();
+
+ if (!loadedType.isValid()) {
+ enginePriv->referenceScarceResources();
+ state.initCreator(std::move(context), compilationUnit, creationContext);
+
+ QQmlObjectCreator::CreationFlags flags;
+ if (const QString *icName = inlineComponentName.get()) {
+ flags = QQmlObjectCreator::InlineComponent;
+ if (start == -1)
+ start = compilationUnit->inlineComponentId(*icName);
+ Q_ASSERT(start > 0);
+ } else {
+ flags = QQmlObjectCreator::NormalObject;
+ }
+
+ rv = state.creator()->create(start, nullptr, nullptr, flags);
+ if (!rv)
+ state.appendCreatorErrors();
+ enginePriv->dereferenceScarceResources();
+ } else {
+ // TODO: extract into function
+ rv = loadedType.createWithQQmlData();
+ QQmlPropertyCache::ConstPtr propertyCache = QQmlData::ensurePropertyCache(rv);
+ QQmlParserStatus *parserStatus = nullptr;
+ const int parserStatusCast = loadedType.parserStatusCast();
+ if (parserStatusCast != -1) {
+ parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(rv) + parserStatusCast);
+ parserStatus->classBegin();
+ }
+ for (int i = 0, propertyCount = propertyCache->propertyCount(); i < propertyCount; ++i) {
+ if (const QQmlPropertyData *propertyData = propertyCache->property(i); propertyData->isRequired()) {
+ state.ensureRequiredPropertyStorage();
+ RequiredPropertyInfo info;
+ info.propertyName = propertyData->name(rv);
+ state.addPendingRequiredProperty(rv, propertyData, info);
+ }
+ }
+ if (parserStatus)
+ parserStatus->componentComplete();
+ if (const int finalizerCast = loadedType.finalizerCast(); finalizerCast != -1) {
+ auto* hook = reinterpret_cast<QQmlFinalizerHook *>(reinterpret_cast<char *>(rv) + finalizerCast);
+ hook->componentFinalized();
+ }
+ }
if (rv) {
QQmlData *ddata = QQmlData::get(rv);
Q_ASSERT(ddata);
- //top level objects should never get JS ownership.
- //if JS ownership is needed this needs to be explicitly undone (like in component.createObject())
+ // top-level objects should never get JS ownership.
+ // if JS ownership is needed this needs to be explicitly undone (like in createObject())
ddata->indestructible = true;
ddata->explicitIndestructibleSet = true;
ddata->rootObjectInCreation = false;
@@ -956,38 +1135,40 @@ void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv,
QQmlData *ddata = QQmlData::get(object);
Q_ASSERT(!ddata->deferredData.isEmpty());
- deferredState->constructionStates.reserve(ddata->deferredData.size());
+ deferredState->reserve(ddata->deferredData.size());
- for (QQmlData::DeferredData *deferredData : qAsConst(ddata->deferredData)) {
+ for (QQmlData::DeferredData *deferredData : std::as_const(ddata->deferredData)) {
enginePriv->inProgressCreations++;
- ConstructionState *state = new ConstructionState;
- state->completePending = true;
+ ConstructionState state;
+ state.setCompletePending(true);
- QQmlContextData *creationContext = nullptr;
- state->creator.reset(new QQmlObjectCreator(deferredData->context->parent, deferredData->compilationUnit, creationContext));
+ auto creator = state.initCreator(
+ deferredData->context->parent(),
+ deferredData->compilationUnit,
+ QQmlRefPointer<QQmlContextData>());
- if (!state->creator->populateDeferredProperties(object, deferredData))
- state->errors << state->creator->errors;
+ if (!creator->populateDeferredProperties(object, deferredData))
+ state.appendCreatorErrors();
deferredData->bindings.clear();
- deferredState->constructionStates += state;
+ deferredState->push_back(std::move(state));
}
}
void QQmlComponentPrivate::completeDeferred(QQmlEnginePrivate *enginePriv, QQmlComponentPrivate::DeferredState *deferredState)
{
- for (ConstructionState *state : qAsConst(deferredState->constructionStates))
- complete(enginePriv, state);
+ for (ConstructionState &state : *deferredState)
+ complete(enginePriv, &state);
}
void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionState *state)
{
- if (state->completePending) {
+ if (state->isCompletePending()) {
QQmlInstantiationInterrupt interrupt;
- state->creator->finalize(interrupt);
+ state->creator()->finalize(interrupt);
- state->completePending = false;
+ state->setCompletePending(false);
enginePriv->inProgressCreations--;
@@ -1000,28 +1181,32 @@ void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionS
}
/*!
- * \internal
- * Finds the matching toplevel property with name \a name of the component \a createdComponent.
- * If it was a required property or an alias to a required property contained in \a
- * requiredProperties, it is removed from it.
- *
- * If wasInRequiredProperties is non-null, the referenced boolean is set to true iff the property
- * was found in requiredProperties.
- *
- * Returns the QQmlProperty with name \a name (which might be invalid if there is no such property),
- * for further processing (for instance, actually setting the property value).
- *
- * Note: This method is used in QQmlComponent and QQmlIncubator to manage required properties. Most
- * classes which create components should not need it and should only need to call
- * setInitialProperties.
+ \internal
+ Finds the matching top-level property with name \a name of the component \a createdComponent.
+ If it was a required property or an alias to a required property contained in \a
+ requiredProperties, it is removed from it.
+ \a requiredProperties must be non-null.
+
+ If wasInRequiredProperties is non-null, the referenced boolean is set to true iff the property
+ was found in requiredProperties.
+
+ Returns the QQmlProperty with name \a name (which might be invalid if there is no such property),
+ for further processing (for instance, actually setting the property value).
+
+ Note: This method is used in QQmlComponent and QQmlIncubator to manage required properties. Most
+ classes which create components should not need it and should only need to call
+ setInitialProperties.
*/
-QQmlProperty QQmlComponentPrivate::removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties &requiredProperties, bool* wasInRequiredProperties)
+QQmlProperty QQmlComponentPrivate::removePropertyFromRequired(
+ QObject *createdComponent, const QString &name, RequiredProperties *requiredProperties,
+ QQmlEngine *engine, bool *wasInRequiredProperties)
{
- QQmlProperty prop(createdComponent, name);
+ Q_ASSERT(requiredProperties);
+ QQmlProperty prop(createdComponent, name, engine);
auto privProp = QQmlPropertyPrivate::get(prop);
if (prop.isValid()) {
// resolve outstanding required properties
- auto targetProp = &privProp->core;
+ const QQmlPropertyData *targetProp = &privProp->core;
if (targetProp->isAlias()) {
auto target = createdComponent;
QQmlPropertyIndex originalIndex(targetProp->coreIndex());
@@ -1037,11 +1222,11 @@ QQmlProperty QQmlComponentPrivate::removePropertyFromRequired(QObject *createdCo
Q_ASSERT(data && data->propertyCache);
targetProp = data->propertyCache->property(targetProp->coreIndex());
}
- auto it = requiredProperties.find(targetProp);
- if (it != requiredProperties.end()) {
+ auto it = requiredProperties->constFind({createdComponent, targetProp});
+ if (it != requiredProperties->cend()) {
if (wasInRequiredProperties)
*wasInRequiredProperties = true;
- requiredProperties.erase(it);
+ requiredProperties->erase(it);
} else {
if (wasInRequiredProperties)
*wasInRequiredProperties = false;
@@ -1069,30 +1254,39 @@ void QQmlComponent::completeCreate()
void QQmlComponentPrivate::completeCreate()
{
- const RequiredProperties& unsetRequiredProperties = requiredProperties();
- for (const auto& unsetRequiredProperty: unsetRequiredProperties) {
- QQmlError error = unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
- state.errors.push_back(error);
+ if (state.hasUnsetRequiredProperties()) {
+ for (const auto& unsetRequiredProperty: std::as_const(*state.requiredProperties())) {
+ QQmlError error = unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
+ state.errors.push_back(QQmlComponentPrivate::AnnotatedQmlError { error, true });
+ }
}
- if (state.completePending) {
- ++creationDepth.localData();
+ if (loadedType.isValid()) {
+ /*
+ We can directly set completePending to false, as finalize is only concerned
+ with setting up pending bindings, but that cannot happen here, as we're
+ dealing with a pure C++ type, which cannot have pending bindings
+ */
+ state.setCompletePending(false);
+ QQmlEnginePrivate::get(engine)->inProgressCreations--;
+ } else if (state.isCompletePending()) {
+ ++creationDepth;
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
complete(ep, &state);
- --creationDepth.localData();
+ --creationDepth;
}
}
QQmlComponentAttached::QQmlComponentAttached(QObject *parent)
-: QObject(parent), prev(nullptr), next(nullptr)
+: QObject(parent), m_prev(nullptr), m_next(nullptr)
{
}
QQmlComponentAttached::~QQmlComponentAttached()
{
- if (prev) *prev = next;
- if (next) next->prev = prev;
- prev = nullptr;
- next = nullptr;
+ if (m_prev) *m_prev = m_next;
+ if (m_next) m_next->m_prev = m_prev;
+ m_prev = nullptr;
+ m_next = nullptr;
}
/*!
@@ -1108,30 +1302,138 @@ QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine);
if (p->activeObjectCreator) { // XXX should only be allowed during begin
- a->add(p->activeObjectCreator->componentAttachment());
+ a->insertIntoList(p->activeObjectCreator->componentAttachment());
} else {
QQmlData *d = QQmlData::get(obj);
Q_ASSERT(d);
Q_ASSERT(d->context);
- a->add(&d->context->componentAttached);
+ d->context->addComponentAttached(a);
}
return a;
}
/*!
+ Load the QQmlComponent for \a typeName in the module \a uri.
+ If the type is implemented via a QML file, \a mode is used to
+ load it. Types backed by C++ are always loaded synchronously.
+
+ \code
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadFromModule("QtQuick", "Item");
+ // once the component is ready
+ std::unique_ptr<QObject> item(component.create());
+ Q_ASSERT(item->metaObject() == &QQuickItem::staticMetaObject);
+ \endcode
+
+ \since 6.5
+ \sa loadUrl()
+ */
+void QQmlComponent::loadFromModule(QAnyStringView uri, QAnyStringView typeName,
+ QQmlComponent::CompilationMode mode)
+{
+ Q_D(QQmlComponent);
+ auto [status, type] = d->prepareLoadFromModule(uri, typeName);
+ d->completeLoadFromModule(uri, typeName, type, status, mode);
+}
+
+LoadHelper::ResolveTypeResult QQmlComponentPrivate::prepareLoadFromModule(QAnyStringView uri,
+ QAnyStringView typeName)
+{
+ auto enginePriv = QQmlEnginePrivate::get(engine);
+ // LoadHelper must be on the Heap as it derives from QQmlRefCount
+ auto loadHelper = QQml::makeRefPointer<LoadHelper>(&enginePriv->typeLoader, uri);
+
+ return loadHelper->resolveType(typeName);
+}
+
+void QQmlComponentPrivate::completeLoadFromModule(QAnyStringView uri, QAnyStringView typeName, QQmlType type,
+ LoadHelper::ResolveTypeResult::Status moduleStatus,
+ QQmlComponent::CompilationMode mode)
+{
+ Q_Q(QQmlComponent);
+
+ // we always mimic the progressChanged behavior from loadUrl
+ auto reportError = [&](QString msg) {
+ QQmlError error;
+ error.setDescription(msg);
+ state.errors.push_back(std::move(error));
+ progress = 1;
+ emit q->progressChanged(1);
+ emit q->statusChanged(q->Error);
+ };
+ auto emitProgressReset = [&](){
+ if (progress != 0) {
+ progress = 0;
+ emit q->progressChanged(0);
+ }
+ };
+ auto emitComplete = [&]() {
+ progress = 1;
+ emit q->progressChanged(1);
+ emit q->statusChanged(q->status());
+ };
+ emitProgressReset();
+ if (moduleStatus == LoadHelper::ResolveTypeResult::NoSuchModule) {
+ reportError(QLatin1String(R"(No module named "%1" found)").arg(uri.toString()));
+ } else if (!type.isValid()) {
+ reportError(QLatin1String(R"(Module "%1" contains no type named "%2")")
+ .arg(uri.toString(), typeName.toString()));
+ } else if (type.isCreatable()) {
+ clear();
+ loadedType = type;
+ emitComplete();
+ } else if (type.isComposite()) {
+ // loadUrl takes care of signal emission
+ loadUrl(type.sourceUrl(), mode);
+ } else if (type.isInlineComponentType()) {
+ auto baseUrl = type.sourceUrl();
+ baseUrl.setFragment(QString());
+ {
+ // we don't want to emit status changes from the "helper" loadUrl below
+ // because it would signal success to early
+ QSignalBlocker blockSignals(q);
+ // we really need to continue in a synchronous way, otherwise we can't check the CU
+ loadUrl(baseUrl, QQmlComponent::PreferSynchronous);
+ }
+ if (q->isError()) {
+ emitComplete();
+ return;
+ }
+ QString elementName = type.elementName();
+ if (compilationUnit->inlineComponentId(elementName) == -1) {
+ QString realTypeName = typeName.toString();
+ realTypeName.truncate(realTypeName.indexOf(u'.'));
+ QString errorMessage = R"(Type "%1" from module "%2" contains no inline component named "%3".)"_L1.arg(
+ realTypeName, uri.toString(), elementName);
+ if (elementName == u"qml")
+ errorMessage += " To load the type \"%1\", drop the \".qml\" extension."_L1.arg(realTypeName);
+ reportError(std::move(errorMessage));
+ } else {
+ inlineComponentName = std::make_unique<QString>(std::move(elementName));
+ emitComplete();
+ }
+ } else if (type.isSingleton() || type.isCompositeSingleton()) {
+ reportError(QLatin1String(R"(%1 is a singleton, and cannot be loaded)").arg(typeName.toString()));
+ } else {
+ reportError(QLatin1String("Could not load %1, as the type is uncreatable").arg(typeName.toString()));
+ }
+}
+
+/*!
Create an object instance from this component using the provided
\a incubator. \a context specifies the context within which to create the object
instance.
- If \a context is 0 (the default), it will create the instance in the
+ If \a context is \nullptr (by default), it will create the instance in the
engine's \l {QQmlEngine::rootContext()}{root context}.
\a forContext specifies a context that this object creation depends upon.
If the \a forContext is being created asynchronously, and the
\l QQmlIncubator::IncubationMode is \l QQmlIncubator::AsynchronousIfNested,
- this object will also be created asynchronously. If \a forContext is 0
- (the default), the \a context will be used for this decision.
+ this object will also be created asynchronously.
+ If \a forContext is \nullptr (by default), the \a context will be used for this decision.
The created object and its creation status are available via the
\a incubator.
@@ -1139,24 +1441,23 @@ QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
\sa QQmlIncubator
*/
-void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
- QQmlContext *forContext)
+void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, QQmlContext *forContext)
{
Q_D(QQmlComponent);
if (!context)
context = d->engine->rootContext();
- QQmlContextData *contextData = QQmlContextData::get(context);
- QQmlContextData *forContextData = contextData;
- if (forContext) forContextData = QQmlContextData::get(forContext);
+ QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(context);
+ QQmlRefPointer<QQmlContextData> forContextData =
+ forContext ? QQmlContextData::get(forContext) : contextData;
if (!contextData->isValid()) {
qWarning("QQmlComponent: Cannot create a component in an invalid context");
return;
}
- if (contextData->engine != d->engine) {
+ if (contextData->engine() != d->engine) {
qWarning("QQmlComponent: Must create component in context from the same QQmlEngine");
return;
}
@@ -1169,6 +1470,14 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
incubator.clear();
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> p(incubator.d);
+ if (d->loadedType.isValid()) {
+ // there isn't really an incubation process for C++ backed types
+ // so just create the object and signal that we are ready
+
+ p->incubateCppBasedComponent(this, context);
+ return;
+ }
+
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(d->engine);
p->compilationUnit = d->compilationUnit;
@@ -1180,8 +1489,7 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
}
/*!
- Set toplevel \a properties of the \a component.
-
+ Set top-level \a properties of the \a component.
This method provides advanced control over component instance creation.
In general, programmers should use
@@ -1210,8 +1518,8 @@ void QQmlComponentPrivate::incubateObject(
QQmlIncubator *incubationTask,
QQmlComponent *component,
QQmlEngine *engine,
- QQmlContextData *context,
- QQmlContextData *forContext)
+ const QQmlRefPointer<QQmlContextData> &context,
+ const QQmlRefPointer<QQmlContextData> &forContext)
{
QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubationTask);
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
@@ -1220,6 +1528,13 @@ void QQmlComponentPrivate::incubateObject(
incubatorPriv->compilationUnit = componentPriv->compilationUnit;
incubatorPriv->enginePriv = enginePriv;
incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->compilationUnit, componentPriv->creationContext));
+
+ if (start == -1) {
+ if (const QString *icName = componentPriv->inlineComponentName.get()) {
+ start = compilationUnit->inlineComponentId(*icName);
+ Q_ASSERT(start > 0);
+ }
+ }
incubatorPriv->subComponentToCreate = componentPriv->start;
enginePriv->incubate(*incubationTask, forContext);
@@ -1234,14 +1549,14 @@ namespace QV4 {
namespace Heap {
#define QmlIncubatorObjectMembers(class, Member) \
- Member(class, HeapValue, HeapValue, valuemap) \
+ Member(class, HeapValue, HeapValue, valuemapOrObject) \
Member(class, HeapValue, HeapValue, statusChanged) \
Member(class, Pointer, QmlContext *, qmlContext) \
Member(class, NoMark, QQmlComponentIncubator *, incubator) \
- Member(class, NoMark, QQmlQPointer<QObject>, parent)
+ Member(class, NoMark, QV4QPointer<QObject>, parent)
DECLARE_HEAP_OBJECT(QmlIncubatorObject, Object) {
- DECLARE_MARKOBJECTS(QmlIncubatorObject);
+ DECLARE_MARKOBJECTS(QmlIncubatorObject)
void init(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous);
inline void destroy();
@@ -1261,7 +1576,7 @@ struct QmlIncubatorObject : public QV4::Object
static ReturnedValue method_forceCompletion(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
void statusChanged(QQmlIncubator::Status);
- void setInitialState(QObject *, RequiredProperties &requiredProperties);
+ void setInitialState(QObject *, RequiredProperties *requiredProperties);
};
}
@@ -1302,7 +1617,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
QList<APF> functions = QQmlMetaType::parentFunctions();
bool needParent = false;
- for (int ii = 0; ii < functions.count(); ++ii) {
+ for (int ii = 0; ii < functions.size(); ++ii) {
QQmlPrivate::AutoParentResult res = functions.at(ii)(me, parent);
if (res == QQmlPrivate::Parented) {
needParent = false;
@@ -1312,13 +1627,12 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
}
}
if (needParent)
- qWarning("QQmlComponent: Created graphical object was not "
- "placed in the graphics scene.");
+ qmlWarning(me) << "Created graphical object was not placed in the graphics scene.";
}
}
/*!
- \qmlmethod object Component::createObject(QtObject parent, object properties)
+ \qmlmethod QtObject Component::createObject(QtObject parent, object properties)
Creates and returns an object instance of this component that will have
the given \a parent and \a properties. The \a properties argument is optional.
@@ -1346,11 +1660,12 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
The \a properties argument is specified as a map of property-value items. For example, the code
below creates an object with initial \c x and \c y values of 100 and 100, respectively:
- \js
- var component = Qt.createComponent("Button.qml");
- if (component.status == Component.Ready)
- component.createObject(parent, {x: 100, y: 100});
- \endjs
+ \qml
+ const component = Qt.createComponent("Button.qml");
+ if (component.status === Component.Ready) {
+ component.createObject(parent, { x: 100, y: 100 });
+ }
+ \endqml
Dynamically created instances can be deleted with the \c destroy() method.
See \l {Dynamic QML Object Creation from JavaScript} for more information.
@@ -1359,7 +1674,10 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
*/
-void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v, RequiredProperties &requiredProperties, QObject *createdComponent)
+void QQmlComponentPrivate::setInitialProperties(
+ QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o,
+ const QV4::Value &v, RequiredProperties *requiredProperties, QObject *createdComponent,
+ QQmlObjectCreator *creator)
{
QV4::Scope scope(engine);
QV4::ScopedObject object(scope);
@@ -1370,7 +1688,8 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV
if (engine->hasException)
return;
- QV4::ScopedStackFrame frame(scope, qmlContext->d());
+ // js modules (mjs) have no qmlContext
+ QV4::ScopedStackFrame frame(scope, qmlContext ? qmlContext : engine->scriptContext());
while (1) {
name = it.nextPropertyNameAsString(val);
@@ -1379,25 +1698,37 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV
object = o;
const QStringList properties = name->toQString().split(QLatin1Char('.'));
bool isTopLevelProperty = properties.size() == 1;
- for (int i = 0; i < properties.length() - 1; ++i) {
+ for (int i = 0; i < properties.size() - 1; ++i) {
name = engine->newString(properties.at(i));
object = object->get(name);
if (engine->hasException || !object) {
break;
}
}
- if (engine->hasException || !object) {
- engine->hasException = false;
+ if (engine->hasException) {
+ qmlWarning(createdComponent, engine->catchExceptionAsQmlError());
+ continue;
+ }
+ if (!object) {
+ QQmlError error;
+ error.setUrl(qmlContext ? qmlContext->qmlContext()->url() : QUrl());
+ error.setDescription(QLatin1String("Cannot resolve property \"%1\".")
+ .arg(properties.join(u'.')));
+ qmlWarning(createdComponent, error);
continue;
}
- name = engine->newString(properties.last());
+ const QString lastProperty = properties.last();
+ name = engine->newString(lastProperty);
object->put(name, val);
if (engine->hasException) {
- engine->hasException = false;
+ qmlWarning(createdComponent, engine->catchExceptionAsQmlError());
continue;
- } else if (isTopLevelProperty) {
- auto prop = removePropertyFromRequired(createdComponent, name->toQString(), requiredProperties);
+ } else if (isTopLevelProperty && requiredProperties) {
+ auto prop = removePropertyFromRequired(createdComponent, name->toQString(),
+ requiredProperties, engine->qmlEngine());
}
+
+ removePendingQPropertyBinding(object, lastProperty, creator);
}
engine->hasException = false;
@@ -1424,20 +1755,27 @@ QQmlError QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(const RequiredP
}
error.setDescription(description);
error.setUrl(unsetRequiredProperty.fileUrl);
- error.setLine(unsetRequiredProperty.location.line);
- error.setColumn(unsetRequiredProperty.location.column);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(
+ unsetRequiredProperty.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(
+ unsetRequiredProperty.location.column()));
return error;
}
+#if QT_DEPRECATED_SINCE(6, 3)
/*!
\internal
*/
-void QQmlComponent::createObject(QQmlV4Function *args)
+void QQmlComponent::createObject(QQmlV4FunctionPtr args)
{
Q_D(QQmlComponent);
Q_ASSERT(d->engine);
Q_ASSERT(args);
+ qmlWarning(this) << "Unsuitable arguments passed to createObject(). The first argument should "
+ "be a QObject* or null, and the second argument should be a JavaScript "
+ "object or a QVariantMap";
+
QObject *parent = nullptr;
QV4::ExecutionEngine *v4 = args->v4engine();
QV4::Scope scope(v4);
@@ -1476,11 +1814,13 @@ void QQmlComponent::createObject(QQmlV4Function *args)
if (!valuemap->isUndefined()) {
QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->qmlContext());
- QQmlComponentPrivate::setInitialProperties(v4, qmlContext, object, valuemap, d->requiredProperties(), rv);
+ QQmlComponentPrivate::setInitialProperties(
+ v4, qmlContext, object, valuemap, d->state.requiredProperties(), rv,
+ d->state.creator());
}
- if (!d->requiredProperties().empty()) {
+ if (d->state.hasUnsetRequiredProperties()) {
QList<QQmlError> errors;
- for (const auto &requiredProperty: d->requiredProperties()) {
+ for (const auto &requiredProperty: std::as_const(*d->state.requiredProperties())) {
errors.push_back(QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(requiredProperty));
}
qmlWarning(rv, errors);
@@ -1497,9 +1837,28 @@ void QQmlComponent::createObject(QQmlV4Function *args)
args->setReturnValue(object->asReturnedValue());
}
+#endif
/*!
- \qmlmethod object Component::incubateObject(Item parent, object properties, enumeration mode)
+ \internal
+ */
+QObject *QQmlComponent::createObject(QObject *parent, const QVariantMap &properties)
+{
+ Q_D(QQmlComponent);
+ Q_ASSERT(d->engine);
+ QObject *rv = d->createWithProperties(parent, properties, creationContext(),
+ QQmlComponentPrivate::CreateWarnAboutRequiredProperties);
+ if (rv) {
+ QQmlData *qmlData = QQmlData::get(rv);
+ Q_ASSERT(qmlData);
+ qmlData->explicitIndestructibleSet = false;
+ qmlData->indestructible = false;
+ }
+ return rv;
+}
+
+/*!
+ \qmlmethod object Component::incubateObject(QtObject parent, object properties, enumeration mode)
Creates an incubator for an instance of this component. Incubators allow new component
instances to be instantiated asynchronously and do not cause freezes in the UI.
@@ -1521,31 +1880,31 @@ void QQmlComponent::createObject(QQmlV4Function *args)
properties:
\list
- \li status The status of the incubator. Valid values are Component.Ready, Component.Loading and
+ \li \c status - The status of the incubator. Valid values are Component.Ready, Component.Loading and
Component.Error.
- \li object The created object instance. Will only be available once the incubator is in the
+ \li \c object - The created object instance. Will only be available once the incubator is in the
Ready status.
- \li onStatusChanged Specifies a callback function to be invoked when the status changes. The
+ \li \c onStatusChanged - Specifies a callback function to be invoked when the status changes. The
status is passed as a parameter to the callback.
- \li forceCompletion() Call to complete incubation synchronously.
+ \li \c{forceCompletion()} - Call to complete incubation synchronously.
\endlist
The following example demonstrates how to use an incubator:
- \js
- var component = Qt.createComponent("Button.qml");
+ \qml
+ const component = Qt.createComponent("Button.qml");
- var incubator = component.incubateObject(parent, { x: 10, y: 10 });
- if (incubator.status != Component.Ready) {
+ const incubator = component.incubateObject(parent, { x: 10, y: 10 });
+ if (incubator.status !== Component.Ready) {
incubator.onStatusChanged = function(status) {
- if (status == Component.Ready) {
- print ("Object", incubator.object, "is now ready!");
+ if (status === Component.Ready) {
+ print("Object", incubator.object, "is now ready!");
}
- }
+ };
} else {
- print ("Object", incubator.object, "is ready immediately!");
+ print("Object", incubator.object, "is ready immediately!");
}
- \endjs
+ \endqml
Dynamically created instances can be deleted with the \c destroy() method.
See \l {Dynamic QML Object Creation from JavaScript} for more information.
@@ -1556,7 +1915,7 @@ void QQmlComponent::createObject(QQmlV4Function *args)
/*!
\internal
*/
-void QQmlComponent::incubateObject(QQmlV4Function *args)
+void QQmlComponent::incubateObject(QQmlV4FunctionPtr args)
{
Q_D(QQmlComponent);
Q_ASSERT(d->engine);
@@ -1603,7 +1962,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args)
r->setPrototypeOf(p);
if (!valuemap->isUndefined())
- r->d()->valuemap.set(scope.engine, valuemap);
+ r->d()->valuemapOrObject.set(scope.engine, valuemap);
r->d()->qmlContext.set(scope.engine, v4->qmlContext());
r->d()->parent = parent;
@@ -1618,7 +1977,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args)
}
// XXX used by QSGLoader
-void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties &requiredProperties)
+void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties *requiredProperties)
{
QV4::ExecutionEngine *v4engine = engine->handle();
QV4::Scope scope(v4engine);
@@ -1626,8 +1985,10 @@ void QQmlComponentPrivate::initializeObjectWithInitialProperties(QV4::QmlContext
QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(v4engine, toCreate));
Q_ASSERT(object->as<QV4::Object>());
- if (!valuemap.isUndefined())
- setInitialProperties(v4engine, qmlContext, object, valuemap, requiredProperties, toCreate);
+ if (!valuemap.isUndefined()) {
+ setInitialProperties(
+ v4engine, qmlContext, object, valuemap, requiredProperties, toCreate, state.creator());
+ }
}
QQmlComponentExtension::QQmlComponentExtension(QV4::ExecutionEngine *v4)
@@ -1704,7 +2065,7 @@ QQmlComponentExtension::~QQmlComponentExtension()
void QV4::Heap::QmlIncubatorObject::init(QQmlIncubator::IncubationMode m)
{
Object::init();
- valuemap.set(internalClass->engine, QV4::Value::undefinedValue());
+ valuemapOrObject.set(internalClass->engine, QV4::Value::undefinedValue());
statusChanged.set(internalClass->engine, QV4::Value::undefinedValue());
parent.init();
qmlContext.set(internalClass->engine, nullptr);
@@ -1717,36 +2078,43 @@ void QV4::Heap::QmlIncubatorObject::destroy() {
Object::destroy();
}
-void QV4::QmlIncubatorObject::setInitialState(QObject *o, RequiredProperties &requiredProperties)
+void QV4::QmlIncubatorObject::setInitialState(QObject *o, RequiredProperties *requiredProperties)
{
QQmlComponent_setQmlParent(o, d()->parent);
- if (!d()->valuemap.isUndefined()) {
+ if (!d()->valuemapOrObject.isUndefined()) {
QV4::ExecutionEngine *v4 = engine();
QV4::Scope scope(v4);
QV4::ScopedObject obj(scope, QV4::QObjectWrapper::wrap(v4, o));
QV4::Scoped<QV4::QmlContext> qmlCtxt(scope, d()->qmlContext);
- QQmlComponentPrivate::setInitialProperties(v4, qmlCtxt, obj, d()->valuemap, requiredProperties, o);
+ QQmlComponentPrivate::setInitialProperties(
+ v4, qmlCtxt, obj, d()->valuemapOrObject, requiredProperties, o,
+ QQmlIncubatorPrivate::get(d()->incubator)->creator.data());
}
}
void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
{
QV4::Scope scope(engine());
- // hold the incubated object in a scoped value to prevent it's destruction before this method returns
- QV4::ScopedObject incubatedObject(scope, QV4::QObjectWrapper::wrap(scope.engine, d()->incubator->object()));
+
+ QObject *object = d()->incubator->object();
if (s == QQmlIncubator::Ready) {
- Q_ASSERT(QQmlData::get(d()->incubator->object()));
- QQmlData::get(d()->incubator->object())->explicitIndestructibleSet = false;
- QQmlData::get(d()->incubator->object())->indestructible = false;
+ // We don't need the arguments anymore, but we still want to hold on to the object so
+ // that it doesn't get gc'd
+ d()->valuemapOrObject.set(scope.engine, QV4::QObjectWrapper::wrap(scope.engine, object));
+
+ QQmlData *ddata = QQmlData::get(object);
+ Q_ASSERT(ddata);
+ ddata->explicitIndestructibleSet = false;
+ ddata->indestructible = false;
}
QV4::ScopedFunctionObject f(scope, d()->statusChanged);
if (f) {
- QV4::JSCallData jsCallData(scope, 1);
- *jsCallData->thisObject = this;
- jsCallData->args[0] = QV4::Value::fromUInt32(s);
+ QV4::JSCallArguments jsCallData(scope, 1);
+ *jsCallData.thisObject = this;
+ jsCallData.args[0] = QV4::Value::fromUInt32(s);
f->call(jsCallData);
if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
@@ -1763,3 +2131,4 @@ void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
QT_END_NAMESPACE
#include "moc_qqmlcomponent.cpp"
+#include "moc_qqmlcomponentattached_p.cpp"
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index cb5d5a787c..2d68c47c11 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -1,45 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCOMPONENT_H
#define QQMLCOMPONENT_H
+#include <QtCore/qvariant.h>
+#include <QtCore/qmap.h>
+
#include <QtQml/qqml.h>
#include <QtQml/qqmlerror.h>
@@ -54,7 +21,6 @@ class QByteArray;
class QQmlEngine;
class QQmlComponent;
class QQmlIncubator;
-class QQmlV4Function;
class QQmlComponentPrivate;
class QQmlComponentAttached;
@@ -70,9 +36,6 @@ class Q_QML_EXPORT QQmlComponent : public QObject
Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(QUrl url READ url CONSTANT)
- QML_NAMED_ELEMENT(Component)
- QML_ATTACHED(QQmlComponentAttached)
- Q_CLASSINFO("QML.Builtin", "QML")
public:
enum CompilationMode { PreferSynchronous, Asynchronous };
@@ -84,6 +47,10 @@ public:
QQmlComponent(QQmlEngine *, const QString &fileName, CompilationMode mode, QObject *parent = nullptr);
QQmlComponent(QQmlEngine *, const QUrl &url, QObject *parent = nullptr);
QQmlComponent(QQmlEngine *, const QUrl &url, CompilationMode mode, QObject *parent = nullptr);
+
+ explicit QQmlComponent(QQmlEngine *engine, QAnyStringView uri, QAnyStringView typeName, QObject *parent = nullptr);
+ explicit QQmlComponent(QQmlEngine *engine, QAnyStringView uri, QAnyStringView typeName, CompilationMode mode, QObject *parent = nullptr);
+
~QQmlComponent() override;
enum Status { Null, Ready, Loading, Error };
@@ -95,6 +62,8 @@ public:
bool isError() const;
bool isLoading() const;
+ bool isBound() const;
+
QList<QQmlError> errors() const;
Q_INVOKABLE QString errorString() const;
@@ -119,6 +88,8 @@ public:
public Q_SLOTS:
void loadUrl(const QUrl &url);
void loadUrl(const QUrl &url, CompilationMode mode);
+ void loadFromModule(QAnyStringView uri, QAnyStringView typeName,
+ QQmlComponent::CompilationMode mode = PreferSynchronous);
void setData(const QByteArray &, const QUrl &baseUrl);
Q_SIGNALS:
@@ -127,8 +98,15 @@ Q_SIGNALS:
protected:
QQmlComponent(QQmlComponentPrivate &dd, QObject* parent);
- Q_INVOKABLE void createObject(QQmlV4Function *);
- Q_INVOKABLE void incubateObject(QQmlV4Function *);
+
+#if QT_DEPRECATED_SINCE(6, 3)
+ QT_DEPRECATED_X("Use the overload with proper arguments")
+ Q_INVOKABLE void createObject(QQmlV4FunctionPtr);
+#endif
+
+ Q_INVOKABLE QObject *createObject(
+ QObject *parent = nullptr, const QVariantMap &properties = {});
+ Q_INVOKABLE void incubateObject(QQmlV4FunctionPtr);
private:
QQmlComponent(QQmlEngine *, QV4::ExecutableCompilationUnit *compilationUnit, int,
@@ -160,8 +138,6 @@ struct OverridableAttachedType<QQmlComponent, QQmlComponentAttached>
} // namespace QQmlPrivate
-
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlComponent)
#endif // QQMLCOMPONENT_H
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index a919eb45c0..21fdee3f7a 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCOMPONENT_P_H
#define QQMLCOMPONENT_P_H
@@ -54,17 +18,15 @@
#include "qqmlcomponent.h"
#include "qqmlengine_p.h"
-#include "qqmltypeloader_p.h"
-#include <private/qbitfield_p.h>
-#include "qqmlvme_p.h"
#include "qqmlerror.h"
-#include "qqml.h"
#include <private/qqmlobjectcreator_p.h>
#include <private/qqmltypedata_p.h>
+#include <private/qqmlguardedcontextdata_p.h>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QList>
+#include <QtCore/qtclasshelpermacros.h>
#include <private/qobject_p.h>
@@ -74,28 +36,31 @@ class QQmlComponent;
class QQmlEngine;
class QQmlComponentAttached;
-class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public QQmlTypeData::TypeDataCallback
+class Q_QML_EXPORT QQmlComponentPrivate : public QObjectPrivate, public QQmlTypeData::TypeDataCallback
{
Q_DECLARE_PUBLIC(QQmlComponent)
public:
QQmlComponentPrivate()
- : progress(0.), start(-1), engine(nullptr), creationContext(nullptr) {}
+ : progress(0.), start(-1), engine(nullptr) {}
void loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous);
- QObject *beginCreate(QQmlContextData *);
+ QObject *beginCreate(QQmlRefPointer<QQmlContextData>);
void completeCreate();
- void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties &requiredProperties);
- static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v, RequiredProperties &requiredProperties, QObject *createdComponent);
+ void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate, RequiredProperties *requiredProperties);
+ static void setInitialProperties(
+ QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o,
+ const QV4::Value &v, RequiredProperties *requiredProperties, QObject *createdComponent,
+ QQmlObjectCreator *creator);
static QQmlError unsetRequiredPropertyToQQmlError(const RequiredPropertyInfo &unsetRequiredProperty);
virtual void incubateObject(
QQmlIncubator *incubationTask,
QQmlComponent *component,
QQmlEngine *engine,
- QQmlContextData *context,
- QQmlContextData *forContext);
+ const QQmlRefPointer<QQmlContextData> &context,
+ const QQmlRefPointer<QQmlContextData> &forContext);
QQmlRefPointer<QQmlTypeData> typeData;
void typeDataReady(QQmlTypeData *) override;
@@ -105,39 +70,83 @@ public:
QUrl url;
qreal progress;
+ std::unique_ptr<QString> inlineComponentName;
+ /* points to the sub-object in a QML file that should be instantiated
+ used create instances of QtQml's Component type and indirectly for inline components */
int start;
- RequiredProperties& requiredProperties();
- bool hadRequiredProperties() const;
+
+ bool hadTopLevelRequiredProperties() const;
+ // TODO: merge compilation unit and type
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
+ QQmlType loadedType;
- struct ConstructionState {
- ConstructionState()
- : completePending(false)
- {}
- ~ConstructionState()
+ struct AnnotatedQmlError
+ {
+ AnnotatedQmlError() = default;
+
+ AnnotatedQmlError(QQmlError error)
+ : error(std::move(error))
{
}
- QScopedPointer<QQmlObjectCreator> creator;
- QList<QQmlError> errors;
- bool completePending;
+
+ AnnotatedQmlError(QQmlError error, bool transient)
+ : error(std::move(error)), isTransient(transient)
+ {
+ }
+ QQmlError error;
+ bool isTransient = false; // tells if the error is temporary (e.g. unset required property)
};
- ConstructionState state;
- struct DeferredState {
- ~DeferredState() {
- qDeleteAll(constructionStates);
- constructionStates.clear();
+ struct ConstructionState {
+ ConstructionState() = default;
+ inline ~ConstructionState();
+ Q_DISABLE_COPY(ConstructionState)
+ inline ConstructionState(ConstructionState &&other) noexcept;
+
+ void swap(ConstructionState &other)
+ {
+ m_creatorOrRequiredProperties.swap(other.m_creatorOrRequiredProperties);
}
- QVector<ConstructionState *> constructionStates;
+
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QQmlComponentPrivate::ConstructionState);
+
+ inline void ensureRequiredPropertyStorage();
+ inline RequiredProperties *requiredProperties();
+ inline void addPendingRequiredProperty(
+ const QObject *object, const QQmlPropertyData *propData,
+ const RequiredPropertyInfo &info);
+ inline bool hasUnsetRequiredProperties() const;
+ inline void clearRequiredProperties();
+
+ inline void appendErrors(const QList<QQmlError> &qmlErrors);
+ inline void appendCreatorErrors();
+
+ inline QQmlObjectCreator *creator();
+ inline const QQmlObjectCreator *creator() const;
+ inline void clear();
+ inline bool hasCreator() const;
+ inline QQmlObjectCreator *initCreator(QQmlRefPointer<QQmlContextData> parentContext,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlRefPointer<QQmlContextData> &creationContext);
+
+ QList<AnnotatedQmlError> errors;
+ inline bool isCompletePending() const;
+ inline void setCompletePending(bool isPending);
+
+ private:
+ QBiPointer<QQmlObjectCreator, RequiredProperties> m_creatorOrRequiredProperties;
};
+ ConstructionState state;
+ using DeferredState = std::vector<ConstructionState>;
static void beginDeferred(QQmlEnginePrivate *enginePriv, QObject *object, DeferredState* deferredState);
static void completeDeferred(QQmlEnginePrivate *enginePriv, DeferredState *deferredState);
static void complete(QQmlEnginePrivate *enginePriv, ConstructionState *state);
- static QQmlProperty removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties& requiredProperties, bool *wasInRequiredProperties = nullptr);
+ static QQmlProperty removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties *requiredProperties,
+ QQmlEngine *engine, bool *wasInRequiredProperties = nullptr);
QQmlEngine *engine;
QQmlGuardedContextData creationContext;
@@ -150,8 +159,150 @@ public:
QObject *doBeginCreate(QQmlComponent *q, QQmlContext *context);
bool setInitialProperty(QObject *component, const QString &name, const QVariant& value);
+
+ enum CreateBehavior {
+ CreateDefault,
+ CreateWarnAboutRequiredProperties,
+ };
+ QObject *createWithProperties(QObject *parent, const QVariantMap &properties,
+ QQmlContext *context, CreateBehavior behavior = CreateDefault);
+
+ bool isBound() const { return compilationUnit && (compilationUnit->componentsAreBound()); }
+ LoadHelper::ResolveTypeResult prepareLoadFromModule(QAnyStringView uri,
+ QAnyStringView typeName);
+ void completeLoadFromModule(QAnyStringView uri, QAnyStringView typeName, QQmlType type,
+ LoadHelper::ResolveTypeResult::Status moduleStatus,
+ QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous);
};
+QQmlComponentPrivate::ConstructionState::~ConstructionState()
+{
+ if (m_creatorOrRequiredProperties.isT1())
+ delete m_creatorOrRequiredProperties.asT1();
+ else
+ delete m_creatorOrRequiredProperties.asT2();
+}
+
+QQmlComponentPrivate::ConstructionState::ConstructionState(ConstructionState &&other) noexcept
+{
+ errors = std::move(other.errors);
+ m_creatorOrRequiredProperties = std::exchange(other.m_creatorOrRequiredProperties, {});
+}
+
+/*!
+ \internal A list of pending required properties that need
+ to be set in order for object construction to be successful.
+ */
+inline RequiredProperties *QQmlComponentPrivate::ConstructionState::requiredProperties() {
+ if (m_creatorOrRequiredProperties.isNull())
+ return nullptr;
+ else if (m_creatorOrRequiredProperties.isT1())
+ return m_creatorOrRequiredProperties.asT1()->requiredProperties();
+ else
+ return m_creatorOrRequiredProperties.asT2();
+}
+
+inline void QQmlComponentPrivate::ConstructionState::addPendingRequiredProperty(
+ const QObject *object, const QQmlPropertyData *propData, const RequiredPropertyInfo &info)
+{
+ Q_ASSERT(requiredProperties());
+ requiredProperties()->insert({object, propData}, info);
+}
+
+inline bool QQmlComponentPrivate::ConstructionState::hasUnsetRequiredProperties() const {
+ auto properties = const_cast<ConstructionState *>(this)->requiredProperties();
+ return properties && !properties->isEmpty();
+}
+
+inline void QQmlComponentPrivate::ConstructionState::clearRequiredProperties()
+{
+ if (auto reqProps = requiredProperties())
+ reqProps->clear();
+}
+
+inline void QQmlComponentPrivate::ConstructionState::appendErrors(const QList<QQmlError> &qmlErrors)
+{
+ for (const QQmlError &e : qmlErrors)
+ errors.emplaceBack(e);
+}
+
+//! \internal Moves errors from creator into construction state itself
+inline void QQmlComponentPrivate::ConstructionState::appendCreatorErrors()
+{
+ if (!hasCreator())
+ return;
+ auto creatorErrorCount = creator()->errors.size();
+ if (creatorErrorCount == 0)
+ return;
+ auto existingErrorCount = errors.size();
+ errors.resize(existingErrorCount + creatorErrorCount);
+ for (qsizetype i = 0; i < creatorErrorCount; ++i)
+ errors[existingErrorCount + i] = AnnotatedQmlError { std::move(creator()->errors[i]) };
+ creator()->errors.clear();
+}
+
+inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::creator()
+{
+ if (m_creatorOrRequiredProperties.isT1())
+ return m_creatorOrRequiredProperties.asT1();
+ return nullptr;
+}
+
+inline const QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::creator() const
+{
+ if (m_creatorOrRequiredProperties.isT1())
+ return m_creatorOrRequiredProperties.asT1();
+ return nullptr;
+}
+
+inline bool QQmlComponentPrivate::ConstructionState::hasCreator() const
+{
+ return creator() != nullptr;
+}
+
+inline void QQmlComponentPrivate::ConstructionState::clear()
+{
+ if (m_creatorOrRequiredProperties.isT1()) {
+ delete m_creatorOrRequiredProperties.asT1();
+ m_creatorOrRequiredProperties = static_cast<QQmlObjectCreator *>(nullptr);
+ }
+}
+
+inline QQmlObjectCreator *QQmlComponentPrivate::ConstructionState::initCreator(QQmlRefPointer<QQmlContextData> parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QQmlRefPointer<QQmlContextData> &creationContext)
+{
+ if (m_creatorOrRequiredProperties.isT1())
+ delete m_creatorOrRequiredProperties.asT1();
+ else
+ delete m_creatorOrRequiredProperties.asT2();
+ m_creatorOrRequiredProperties = new QQmlObjectCreator(
+ std::move(parentContext), compilationUnit,
+ creationContext);
+ return m_creatorOrRequiredProperties.asT1();
+}
+
+inline bool QQmlComponentPrivate::ConstructionState::isCompletePending() const
+{
+ return m_creatorOrRequiredProperties.flag();
+}
+
+inline void QQmlComponentPrivate::ConstructionState::setCompletePending(bool isPending)
+{
+ m_creatorOrRequiredProperties.setFlagValue(isPending);
+}
+
+/*!
+ \internal
+ This is meant to be used in the context of QQmlComponent::loadFromModule,
+ when dealing with a C++ type. In that case, we do not have a creator,
+ and need a separate storage for required properties.
+ */
+inline void QQmlComponentPrivate::ConstructionState::ensureRequiredPropertyStorage()
+{
+ Q_ASSERT(m_creatorOrRequiredProperties.isT2() || m_creatorOrRequiredProperties.isNull());
+ if (m_creatorOrRequiredProperties.isNull())
+ m_creatorOrRequiredProperties = new RequiredProperties;
+}
+
QT_END_NAMESPACE
#endif // QQMLCOMPONENT_P_H
diff --git a/src/qml/qml/qqmlcomponentandaliasresolver_p.h b/src/qml/qml/qqmlcomponentandaliasresolver_p.h
new file mode 100644
index 0000000000..a2758d385c
--- /dev/null
+++ b/src/qml/qml/qqmlcomponentandaliasresolver_p.h
@@ -0,0 +1,480 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QQMLCOMPONENTANDALIASRESOLVER_P_H
+#define QQMLCOMPONENTANDALIASRESOLVER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlerror.h>
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qhash.h>
+
+#include <private/qqmltypeloader_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcQmlTypeCompiler);
+
+// This class primarily resolves component boundaries in a document.
+// With the information about boundaries, it then goes on to resolve aliases and generalized
+// group properties. Both rely on IDs as first part of their expressions and the IDs have
+// to be located in surrounding components. That's why we have to do this with the component
+// boundaries in mind.
+
+template<typename ObjectContainer>
+class QQmlComponentAndAliasResolver
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlComponentAndAliasResolver)
+public:
+ using CompiledObject = typename ObjectContainer::CompiledObject;
+ using CompiledBinding = typename ObjectContainer::CompiledBinding;
+
+ QQmlComponentAndAliasResolver(
+ ObjectContainer *compiler,
+ QQmlEnginePrivate *enginePrivate,
+ QQmlPropertyCacheVector *propertyCaches);
+
+ [[nodiscard]] QQmlError resolve(int root = 0);
+
+private:
+ enum AliasResolutionResult {
+ NoAliasResolved,
+ SomeAliasesResolved,
+ AllAliasesResolved
+ };
+
+ // To be specialized for each container
+ void allocateNamedObjects(CompiledObject *object) const;
+ void setObjectId(int index) const;
+ [[nodiscard]] bool markAsComponent(int index) const;
+ [[nodiscard]] AliasResolutionResult resolveAliasesInObject(
+ const CompiledObject &component, int objectIndex, QQmlError *error);
+ void resolveGeneralizedGroupProperty(const CompiledObject &component, CompiledBinding *binding);
+ [[nodiscard]] bool wrapImplicitComponent(CompiledBinding *binding);
+
+ [[nodiscard]] QQmlError findAndRegisterImplicitComponents(
+ const CompiledObject *obj, const QQmlPropertyCache::ConstPtr &propertyCache);
+ [[nodiscard]] QQmlError collectIdsAndAliases(int objectIndex);
+ [[nodiscard]] QQmlError resolveAliases(int componentIndex);
+ void resolveGeneralizedGroupProperties(int componentIndex);
+ [[nodiscard]] QQmlError resolveComponentsInInlineComponentRoot(int root);
+
+ QString stringAt(int idx) const { return m_compiler->stringAt(idx); }
+ QV4::ResolvedTypeReference *resolvedType(int id) const { return m_compiler->resolvedType(id); }
+
+ [[nodiscard]] QQmlError error(
+ const QV4::CompiledData::Location &location,
+ const QString &description)
+ {
+ QQmlError error;
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
+ error.setDescription(description);
+ error.setUrl(m_compiler->url());
+ return error;
+ }
+
+ template<typename Token>
+ [[nodiscard]] QQmlError error(Token token, const QString &description)
+ {
+ return error(token->location, description);
+ }
+
+ static bool isUsableComponent(const QMetaObject *metaObject)
+ {
+ // The metaObject is a component we're interested in if it either is a QQmlComponent itself
+ // or if any of its parents is a QQmlAbstractDelegateComponent. We don't want to include
+ // qqmldelegatecomponent_p.h because it belongs to QtQmlModels.
+
+ if (metaObject == &QQmlComponent::staticMetaObject)
+ return true;
+
+ for (; metaObject; metaObject = metaObject->superClass()) {
+ if (qstrcmp(metaObject->className(), "QQmlAbstractDelegateComponent") == 0)
+ return true;
+ }
+
+ return false;
+ }
+
+ ObjectContainer *m_compiler = nullptr;
+ QQmlEnginePrivate *m_enginePrivate = nullptr;
+
+ // Implicit component insertion may have added objects and thus we also need
+ // to extend the symmetric propertyCaches. Therefore, non-const propertyCaches.
+ QQmlPropertyCacheVector *m_propertyCaches = nullptr;
+
+ // indices of the objects that are actually Component {}
+ QVector<quint32> m_componentRoots;
+ QVector<int> m_objectsWithAliases;
+ QVector<CompiledBinding *> m_generalizedGroupProperties;
+ typename ObjectContainer::IdToObjectMap m_idToObjectIndex;
+};
+
+template<typename ObjectContainer>
+QQmlComponentAndAliasResolver<ObjectContainer>::QQmlComponentAndAliasResolver(
+ ObjectContainer *compiler,
+ QQmlEnginePrivate *enginePrivate,
+ QQmlPropertyCacheVector *propertyCaches)
+ : m_compiler(compiler)
+ , m_enginePrivate(enginePrivate)
+ , m_propertyCaches(propertyCaches)
+{
+}
+
+template<typename ObjectContainer>
+QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::findAndRegisterImplicitComponents(
+ const CompiledObject *obj, const QQmlPropertyCache::ConstPtr &propertyCache)
+{
+ QQmlPropertyResolver propertyResolver(propertyCache);
+
+ const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1
+ ? propertyCache->parent()->defaultProperty()
+ : propertyCache->defaultProperty();
+
+ for (auto binding = obj->bindingsBegin(), end = obj->bindingsEnd(); binding != end; ++binding) {
+ if (binding->type() != QV4::CompiledData::Binding::Type_Object)
+ continue;
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject))
+ continue;
+
+ auto targetObject = m_compiler->objectAt(binding->value.objectIndex);
+ auto typeReference = resolvedType(targetObject->inheritedTypeNameIndex);
+ Q_ASSERT(typeReference);
+
+ const QMetaObject *firstMetaObject = nullptr;
+ const auto type = typeReference->type();
+ if (type.isValid())
+ firstMetaObject = type.metaObject();
+ else if (const auto compilationUnit = typeReference->compilationUnit())
+ firstMetaObject = compilationUnit->rootPropertyCache()->firstCppMetaObject();
+ if (isUsableComponent(firstMetaObject))
+ continue;
+
+ // if here, not a QQmlComponent, so needs wrapping
+ const QQmlPropertyData *pd = nullptr;
+ if (binding->propertyNameIndex != quint32(0)) {
+ bool notInRevision = false;
+ pd = propertyResolver.property(stringAt(binding->propertyNameIndex), &notInRevision);
+ } else {
+ pd = defaultProperty;
+ }
+ if (!pd || !pd->isQObject())
+ continue;
+
+ // If the version is given, use it and look up by QQmlType.
+ // Otherwise, make sure we look up by metaobject.
+ // TODO: Is this correct?
+ QQmlPropertyCache::ConstPtr pc = pd->typeVersion().hasMinorVersion()
+ ? QQmlMetaType::rawPropertyCacheForType(pd->propType(), pd->typeVersion())
+ : QQmlMetaType::rawPropertyCacheForType(pd->propType());
+ const QMetaObject *mo = pc ? pc->firstCppMetaObject() : nullptr;
+ while (mo) {
+ if (mo == &QQmlComponent::staticMetaObject)
+ break;
+ mo = mo->superClass();
+ }
+
+ if (!mo)
+ continue;
+
+ if (!wrapImplicitComponent(binding))
+ return error(binding, tr("Cannot wrap implicit component"));
+ }
+
+ return QQmlError();
+}
+
+template<typename ObjectContainer>
+QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::resolveComponentsInInlineComponentRoot(
+ int root)
+{
+ // Find implicit components in the inline component itself. Also warn about inline
+ // components being explicit components.
+
+ const auto rootObj = m_compiler->objectAt(root);
+ Q_ASSERT(rootObj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot));
+
+ if (const int typeName = rootObj->inheritedTypeNameIndex) {
+ const auto *tref = resolvedType(typeName);
+ Q_ASSERT(tref);
+ if (tref->type().metaObject() == &QQmlComponent::staticMetaObject) {
+ qCWarning(lcQmlTypeCompiler).nospace().noquote()
+ << m_compiler->url().toString() << ":" << rootObj->location.line() << ":"
+ << rootObj->location.column()
+ << ": Using a Component as the root of an inline component is deprecated: "
+ "inline components are "
+ "automatically wrapped into Components when needed.";
+ return QQmlError();
+ }
+ }
+
+ const QQmlPropertyCache::ConstPtr rootCache = m_propertyCaches->at(root);
+ Q_ASSERT(rootCache);
+
+ return findAndRegisterImplicitComponents(rootObj, rootCache);
+}
+
+// Resolve ignores everything relating to inline components, except for implicit components.
+template<typename ObjectContainer>
+QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::resolve(int root)
+{
+ // Detect real Component {} objects as well as implicitly defined components, such as
+ // someItemDelegate: Item {}
+ // In the implicit case Item is surrounded by a synthetic Component {} because the property
+ // on the left hand side is of QQmlComponent type.
+ const int objCountWithoutSynthesizedComponents = m_compiler->objectCount();
+
+ if (root != 0) {
+ const QQmlError error = resolveComponentsInInlineComponentRoot(root);
+ if (error.isValid())
+ return error;
+ }
+
+ // root+1, as ic root is handled at the end
+ const int startObjectIndex = root == 0 ? root : root+1;
+
+ for (int i = startObjectIndex; i < objCountWithoutSynthesizedComponents; ++i) {
+ auto obj = m_compiler->objectAt(i);
+ const bool isInlineComponentRoot
+ = obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot);
+ const bool isPartOfInlineComponent
+ = obj->hasFlag(QV4::CompiledData::Object::IsPartOfInlineComponent);
+ QQmlPropertyCache::ConstPtr cache = m_propertyCaches->at(i);
+
+ if (root == 0) {
+ // normal component root, skip over anything inline component related
+ if (isInlineComponentRoot || isPartOfInlineComponent)
+ continue;
+ } else if (!isPartOfInlineComponent || isInlineComponentRoot) {
+ // When handling an inline component, stop where the inline component ends
+ // Note: We do not support nested inline components. Therefore, isInlineComponentRoot
+ // tells us that the element after the current inline component is again an
+ // inline component
+ break;
+ }
+
+ if (obj->inheritedTypeNameIndex == 0 && !cache)
+ continue;
+
+ bool isExplicitComponent = false;
+ if (obj->inheritedTypeNameIndex) {
+ auto *tref = resolvedType(obj->inheritedTypeNameIndex);
+ Q_ASSERT(tref);
+ if (tref->type().metaObject() == &QQmlComponent::staticMetaObject)
+ isExplicitComponent = true;
+ }
+
+ if (!isExplicitComponent) {
+ if (cache) {
+ const QQmlError error = findAndRegisterImplicitComponents(obj, cache);
+ if (error.isValid())
+ return error;
+ }
+ continue;
+ }
+
+ if (!markAsComponent(i))
+ return error(obj, tr("Cannot mark object as component"));
+
+ // check if this object is the root
+ if (i == 0) {
+ if (isExplicitComponent)
+ qCWarning(lcQmlTypeCompiler).nospace().noquote()
+ << m_compiler->url().toString() << ":" << obj->location.line() << ":"
+ << obj->location.column()
+ << ": Using a Component as the root of a QML document is deprecated: types "
+ "defined in qml documents are "
+ "automatically wrapped into Components when needed.";
+ }
+
+ if (obj->functionCount() > 0)
+ return error(obj, tr("Component objects cannot declare new functions."));
+ if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
+ return error(obj, tr("Component objects cannot declare new properties."));
+ if (obj->signalCount() > 0)
+ return error(obj, tr("Component objects cannot declare new signals."));
+
+ if (obj->bindingCount() == 0)
+ return error(obj, tr("Cannot create empty component specification"));
+
+ const auto rootBinding = obj->bindingsBegin();
+ const auto bindingsEnd = obj->bindingsEnd();
+
+ // Produce the more specific "no properties" error rather than the "invalid body" error
+ // where possible.
+ for (auto b = rootBinding; b != bindingsEnd; ++b) {
+ if (b->propertyNameIndex == 0)
+ continue;
+
+ return error(b, tr("Component elements may not contain properties other than id"));
+ }
+
+ if (auto b = rootBinding;
+ b->type() != QV4::CompiledData::Binding::Type_Object || ++b != bindingsEnd) {
+ return error(obj, tr("Invalid component body specification"));
+ }
+
+ // For the root object, we are going to collect ids/aliases and resolve them for as a
+ // separate last pass.
+ if (i != 0)
+ m_componentRoots.append(i);
+ }
+
+ for (int i = 0; i < m_componentRoots.size(); ++i) {
+ CompiledObject *component = m_compiler->objectAt(m_componentRoots.at(i));
+ const auto rootBinding = component->bindingsBegin();
+
+ m_idToObjectIndex.clear();
+ m_objectsWithAliases.clear();
+ m_generalizedGroupProperties.clear();
+
+ if (const QQmlError error = collectIdsAndAliases(rootBinding->value.objectIndex);
+ error.isValid()) {
+ return error;
+ }
+
+ allocateNamedObjects(component);
+
+ if (const QQmlError error = resolveAliases(m_componentRoots.at(i)); error.isValid())
+ return error;
+
+ resolveGeneralizedGroupProperties(m_componentRoots.at(i));
+ }
+
+ // Collect ids and aliases for root
+ m_idToObjectIndex.clear();
+ m_objectsWithAliases.clear();
+ m_generalizedGroupProperties.clear();
+
+ if (const QQmlError error = collectIdsAndAliases(root); error.isValid())
+ return error;
+
+ allocateNamedObjects(m_compiler->objectAt(root));
+ if (const QQmlError error = resolveAliases(root); error.isValid())
+ return error;
+
+ resolveGeneralizedGroupProperties(root);
+ return QQmlError();
+}
+
+template<typename ObjectContainer>
+QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::collectIdsAndAliases(int objectIndex)
+{
+ auto obj = m_compiler->objectAt(objectIndex);
+
+ if (obj->idNameIndex != 0) {
+ if (m_idToObjectIndex.contains(obj->idNameIndex))
+ return error(obj->locationOfIdProperty, tr("id is not unique"));
+ setObjectId(objectIndex);
+ m_idToObjectIndex.insert(obj->idNameIndex, objectIndex);
+ }
+
+ if (obj->aliasCount() > 0)
+ m_objectsWithAliases.append(objectIndex);
+
+ // Stop at Component boundary
+ if (obj->hasFlag(QV4::CompiledData::Object::IsComponent) && objectIndex != /*root object*/0)
+ return QQmlError();
+
+ for (auto binding = obj->bindingsBegin(), end = obj->bindingsEnd();
+ binding != end; ++binding) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_GroupProperty: {
+ const auto *inner = m_compiler->objectAt(binding->value.objectIndex);
+ if (m_compiler->stringAt(inner->inheritedTypeNameIndex).isEmpty()) {
+ const auto cache = m_propertyCaches->at(objectIndex);
+ if (!cache || !cache->property(
+ m_compiler->stringAt(binding->propertyNameIndex), nullptr, nullptr)) {
+ m_generalizedGroupProperties.append(binding);
+ }
+ }
+ }
+ Q_FALLTHROUGH();
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ if (const QQmlError error = collectIdsAndAliases(binding->value.objectIndex);
+ error.isValid()) {
+ return error;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return QQmlError();
+}
+
+template<typename ObjectContainer>
+QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::resolveAliases(int componentIndex)
+{
+ if (m_objectsWithAliases.isEmpty())
+ return QQmlError();
+
+ QQmlPropertyCacheAliasCreator<ObjectContainer> aliasCacheCreator(m_propertyCaches, m_compiler);
+
+ bool atLeastOneAliasResolved;
+ do {
+ atLeastOneAliasResolved = false;
+ QVector<int> pendingObjects;
+
+ for (int objectIndex: std::as_const(m_objectsWithAliases)) {
+
+ QQmlError error;
+ const auto &component = *m_compiler->objectAt(componentIndex);
+ const auto result = resolveAliasesInObject(component, objectIndex, &error);
+ if (error.isValid())
+ return error;
+
+ if (result == AllAliasesResolved) {
+ QQmlError error = aliasCacheCreator.appendAliasesToPropertyCache(
+ component, objectIndex, m_enginePrivate);
+ if (error.isValid())
+ return error;
+ atLeastOneAliasResolved = true;
+ } else if (result == SomeAliasesResolved) {
+ atLeastOneAliasResolved = true;
+ pendingObjects.append(objectIndex);
+ } else {
+ pendingObjects.append(objectIndex);
+ }
+ }
+ qSwap(m_objectsWithAliases, pendingObjects);
+ } while (!m_objectsWithAliases.isEmpty() && atLeastOneAliasResolved);
+
+ if (!atLeastOneAliasResolved && !m_objectsWithAliases.isEmpty()) {
+ const CompiledObject *obj = m_compiler->objectAt(m_objectsWithAliases.first());
+ for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
+ if (!alias->hasFlag(QV4::CompiledData::Alias::Resolved))
+ return error(alias->location, tr("Circular alias reference detected"));
+ }
+ }
+
+ return QQmlError();
+}
+
+template<typename ObjectContainer>
+void QQmlComponentAndAliasResolver<ObjectContainer>::resolveGeneralizedGroupProperties(
+ int componentIndex)
+{
+ const auto &component = *m_compiler->objectAt(componentIndex);
+ for (CompiledBinding *binding : m_generalizedGroupProperties)
+ resolveGeneralizedGroupProperty(component, binding);
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLCOMPONENTANDALIASRESOLVER_P_H
diff --git a/src/qml/qml/qqmlcomponentattached_p.h b/src/qml/qml/qqmlcomponentattached_p.h
index 8ecd9da17d..303fea7b46 100644
--- a/src/qml/qml/qqmlcomponentattached_p.h
+++ b/src/qml/qml/qqmlcomponentattached_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCOMPONENTATTACHED_P_H
#define QQMLCOMPONENTATTACHED_P_H
@@ -52,44 +16,53 @@
//
#include <QtQml/qqml.h>
+#include <QtQml/qqmlcomponent.h>
#include <private/qtqmlglobal_p.h>
#include <QtCore/QObject>
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlComponentAttached : public QObject
+// implemented in qqmlcomponent.cpp
+class Q_QML_EXPORT QQmlComponentAttached : public QObject
{
Q_OBJECT
-
- // Used as attached object for QQmlComponent. We want qqmlcomponentattached_p.h to be #include'd
- // when registering QQmlComponent, but we cannot #include it from qqmlcomponent.h. Therefore we
- // force an anonymous type registration here.
- QML_ANONYMOUS
public:
QQmlComponentAttached(QObject *parent = nullptr);
~QQmlComponentAttached();
- void add(QQmlComponentAttached **a) {
- prev = a; next = *a; *a = this;
- if (next) next->prev = &next;
+ void insertIntoList(QQmlComponentAttached **listHead)
+ {
+ m_prev = listHead;
+ m_next = *listHead;
+ *listHead = this;
+ if (m_next)
+ m_next->m_prev = &m_next;
}
- void rem() {
- if (next) next->prev = prev;
- *prev = next;
- next = nullptr; prev = nullptr;
+
+ void removeFromList()
+ {
+ *m_prev = m_next;
+ if (m_next)
+ m_next->m_prev = m_prev;
+ m_next = nullptr;
+ m_prev = nullptr;
}
- QQmlComponentAttached **prev;
- QQmlComponentAttached *next;
+
+ QQmlComponentAttached *next() const { return m_next; }
Q_SIGNALS:
void completed();
void destruction();
private:
- friend class QQmlContextData;
+ QQmlComponentAttached **m_prev;
+ QQmlComponentAttached *m_next;
};
QT_END_NAMESPACE
+// TODO: We still need this because we cannot properly use QML_ATTACHED with QML_FOREIGN.
+QML_DECLARE_TYPEINFO(QQmlComponent, QML_HAS_ATTACHED_PROPERTIES)
+
#endif // QQMLCOMPONENTATTACHED_P_H
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 254b6cc3db..cf6736deb9 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -1,43 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlcontext.h"
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
#include "qqmlcontext_p.h"
#include "qqmlcomponentattached_p.h"
@@ -55,40 +18,49 @@
QT_BEGIN_NAMESPACE
-QQmlContextPrivate::QQmlContextPrivate()
-: data(nullptr), notifyIndex(-1)
-{
-}
-
/*!
\class QQmlContext
\brief The QQmlContext class defines a context within a QML engine.
\inmodule QtQml
- Contexts allow data to be exposed to the QML components instantiated by the
- QML engine.
+ Contexts hold the objects identified by \e id in a QML document. You
+ can use \l{nameForObject()} and \l{objectForName()} to retrieve them.
+
+ \note It is the responsibility of the creator to delete any QQmlContext it
+ constructs. If a QQmlContext is no longer needed, it must be destroyed
+ explicitly. The simplest way to ensure this is to give the QQmlContext a
+ \l{QObject::setParent()}{parent}.
+
+ \section2 The Context Hierarchy
+
+ Contexts form a hierarchy. The root of this hierarchy is the QML engine's
+ \l {QQmlEngine::rootContext()}{root context}. Each QML component creates its
+ own context when instantiated and some QML elements create extra contexts
+ for themselves.
+
+ While QML objects instantiated in a context are not strictly owned by that
+ context, their bindings are. If a context is destroyed, the property bindings of
+ outstanding QML objects will stop evaluating.
+
+ \section2 Context Properties
+
+ Contexts also allow data to be exposed to the QML components instantiated
+ by the QML engine. Such data is invisible to any tooling, including the
+ \l{Qt Quick Compiler} and to future readers of the QML documents in
+ question. It will only be exposed if the QML component is instantiated in
+ the specific C++ context you are envisioning. In other places, different
+ context data may be exposed instead.
+
+ Instead of using the QML context to expose data to your QML components, you
+ should either create additional object properties to hold the data or use
+ \l{QML_SINGLETON}{singletons}. See
+ \l{qtqml-cppintegration-exposecppstate.html}{Exposing C++ State to QML} for
+ a detailed explanation.
Each QQmlContext contains a set of properties, distinct from its QObject
properties, that allow data to be explicitly bound to a context by name. The
- context properties are defined and updated by calling
- QQmlContext::setContextProperty(). The following example shows a Qt model
- being bound to a context and then accessed from a QML file.
-
- \code
- QQmlEngine engine;
- QStringListModel modelData;
- QQmlContext *context = new QQmlContext(engine.rootContext());
- context->setContextProperty("myModel", &modelData);
-
- QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
- QObject *window = component.create(context);
- \endcode
-
- Note it is the responsibility of the creator to delete any QQmlContext it
- constructs. If the \c context object in the example is no longer needed when the
- \c window component instance is destroyed, the \c context must be destroyed explicitly.
- The simplest way to ensure this is to set \c window as the parent of \c context.
+ context properties can be defined and updated by calling
+ QQmlContext::setContextProperty().
To simplify binding and maintaining larger data sets, a context object can be set
on a QQmlContext. All the properties of the context object are available
@@ -97,59 +69,17 @@ QQmlContextPrivate::QQmlContextPrivate()
detected through the property's notify signal. Setting a context object is both
faster and easier than manually adding and maintaining context property values.
- The following example has the same effect as the previous one, but it uses a context
- object.
-
- \code
- class MyDataSet : ... {
- ...
- Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged)
- ...
- };
-
- MyDataSet myDataSet;
- QQmlEngine engine;
- QQmlContext *context = new QQmlContext(engine.rootContext());
- context->setContextObject(&myDataSet);
-
- QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
- component.create(context);
- \endcode
-
All properties added explicitly by QQmlContext::setContextProperty() take
precedence over the context object's properties.
- \section2 The Context Hierarchy
-
- Contexts form a hierarchy. The root of this hierarchy is the QML engine's
- \l {QQmlEngine::rootContext()}{root context}. Child contexts inherit
- the context properties of their parents; if a child context sets a context property
- that already exists in its parent, the new context property overrides that of the
- parent.
-
- The following example defines two contexts - \c context1 and \c context2. The
- second context overrides the "b" context property inherited from the first with a
- new value.
-
- \code
- QQmlEngine engine;
- QQmlContext *context1 = new QQmlContext(engine.rootContext());
- QQmlContext *context2 = new QQmlContext(context1);
+ Child contexts inherit the context properties of their parents; if a child
+ context sets a context property that already exists in its parent, the new
+ context property overrides that of the parent.
- context1->setContextProperty("a", 12);
- context1->setContextProperty("b", 12);
-
- context2->setContextProperty("b", 15);
- \endcode
-
- While QML objects instantiated in a context are not strictly owned by that
- context, their bindings are. If a context is destroyed, the property bindings of
- outstanding QML objects will stop evaluating.
-
- \warning Setting the context object or adding new context properties after an object
- has been created in that context is an expensive operation (essentially forcing all bindings
- to reevaluate). Thus whenever possible you should complete "setup" of the context
+ \warning Setting the context object or adding new context properties after
+ an object has been created in that context is an expensive operation
+ (essentially forcing all bindings to re-evaluate). Thus, if you need to use
+ context properties, you should at least complete the "setup" of the context
before using it to create any objects.
\sa {qtqml-cppintegration-exposecppattributes.html}{Exposing Attributes of C++ Types to QML}
@@ -157,13 +87,8 @@ QQmlContextPrivate::QQmlContextPrivate()
/*! \internal */
QQmlContext::QQmlContext(QQmlEngine *e, bool)
-: QObject(*(new QQmlContextPrivate))
+ : QObject(*(new QQmlContextPrivate(this, QQmlRefPointer<QQmlContextData>(), e)))
{
- Q_D(QQmlContext);
- d->data = new QQmlContextData(this);
- ++d->data->refCount;
-
- d->data->engine = e;
}
/*!
@@ -171,13 +96,10 @@ QQmlContext::QQmlContext(QQmlEngine *e, bool)
QObject \a parent.
*/
QQmlContext::QQmlContext(QQmlEngine *engine, QObject *parent)
-: QObject(*(new QQmlContextPrivate), parent)
+ : QObject(*(new QQmlContextPrivate(this, engine
+ ? QQmlContextData::get(engine->rootContext())
+ : QQmlRefPointer<QQmlContextData>())), parent)
{
- Q_D(QQmlContext);
- d->data = new QQmlContextData(this);
- ++d->data->refCount;
-
- d->data->setParent(engine?QQmlContextData::get(engine->rootContext()):nullptr);
}
/*!
@@ -185,24 +107,18 @@ QQmlContext::QQmlContext(QQmlEngine *engine, QObject *parent)
QObject \a parent.
*/
QQmlContext::QQmlContext(QQmlContext *parentContext, QObject *parent)
-: QObject(*(new QQmlContextPrivate), parent)
+ : QObject(*(new QQmlContextPrivate(this, parentContext
+ ? QQmlContextData::get(parentContext)
+ : QQmlRefPointer<QQmlContextData>())), parent)
{
- Q_D(QQmlContext);
- d->data = new QQmlContextData(this);
- ++d->data->refCount;
-
- d->data->setParent(parentContext?QQmlContextData::get(parentContext):nullptr);
}
/*!
\internal
*/
-QQmlContext::QQmlContext(QQmlContextData *data)
-: QObject(*(new QQmlContextPrivate), nullptr)
+QQmlContext::QQmlContext(QQmlContextPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
{
- Q_D(QQmlContext);
- d->data = data;
- // don't add a refcount here, as the data owns this context
}
/*!
@@ -215,10 +131,7 @@ QQmlContext::QQmlContext(QQmlContextData *data)
QQmlContext::~QQmlContext()
{
Q_D(QQmlContext);
-
- d->data->publicContext = nullptr;
- if (!--d->data->refCount)
- d->data->destroy();
+ d->m_data->clearPublicContext();
}
/*!
@@ -230,92 +143,104 @@ QQmlContext::~QQmlContext()
bool QQmlContext::isValid() const
{
Q_D(const QQmlContext);
- return d->data && d->data->isValid();
+ return d->m_data->isValid();
}
/*!
- Return the context's QQmlEngine, or 0 if the context has no QQmlEngine or the
+ Return the context's QQmlEngine, or \nullptr if the context has no QQmlEngine or the
QQmlEngine was destroyed.
*/
QQmlEngine *QQmlContext::engine() const
{
Q_D(const QQmlContext);
- return d->data->engine;
+ return d->m_data->engine();
}
/*!
- Return the context's parent QQmlContext, or 0 if this context has no
+ Return the context's parent QQmlContext, or \nullptr if this context has no
parent or if the parent has been destroyed.
*/
QQmlContext *QQmlContext::parentContext() const
{
Q_D(const QQmlContext);
- return d->data->parent?d->data->parent->asQQmlContext():nullptr;
+
+ if (QQmlRefPointer<QQmlContextData> parent = d->m_data->parent())
+ return parent->asQQmlContext();
+ return nullptr;
}
/*!
- Return the context object, or 0 if there is no context object.
+ Return the context object, or \nullptr if there is no context object.
*/
QObject *QQmlContext::contextObject() const
{
Q_D(const QQmlContext);
- return d->data->contextObject;
+ return d->m_data->contextObject();
}
/*!
Set the context \a object.
+
+ \note You should not use context objects to inject values into your QML
+ components. Use singletons or regular object properties instead.
*/
void QQmlContext::setContextObject(QObject *object)
{
Q_D(QQmlContext);
- QQmlContextData *data = d->data;
+ QQmlRefPointer<QQmlContextData> data = d->m_data;
- if (data->isInternal) {
+ if (data->isInternal()) {
qWarning("QQmlContext: Cannot set context object for internal context.");
return;
}
- if (!isValid()) {
+ if (!data->isValid()) {
qWarning("QQmlContext: Cannot set context object on invalid context.");
return;
}
- data->contextObject = object;
+ data->setContextObject(object);
data->refreshExpressions();
}
/*!
Set a the \a value of the \a name property on this context.
+
+ \note You should not use context properties to inject values into your QML
+ components. Use singletons or regular object properties instead.
*/
void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
{
Q_D(QQmlContext);
- if (d->notifyIndex == -1)
- d->notifyIndex = QMetaObjectPrivate::absoluteSignalCount(&QQmlContext::staticMetaObject);
+ if (d->notifyIndex() == -1)
+ d->setNotifyIndex(QMetaObjectPrivate::absoluteSignalCount(&QQmlContext::staticMetaObject));
- QQmlContextData *data = d->data;
+ QQmlRefPointer<QQmlContextData> data = d->m_data;
- if (data->isInternal) {
+ if (data->isInternal()) {
qWarning("QQmlContext: Cannot set property on internal context.");
return;
}
- if (!isValid()) {
+ if (!data->isValid()) {
qWarning("QQmlContext: Cannot set property on invalid context.");
return;
}
- QV4::IdentifierHash &properties = data->detachedPropertyNames();
- int idx = properties.value(name);
- if (idx == -1) {
- properties.add(name, data->idValueCount + d->propertyValues.count());
- d->propertyValues.append(value);
+ if (bool isNumber = false; name.toUInt(&isNumber), isNumber) {
+ qWarning("QQmlContext: Using numbers as context properties will be disallowed in a future Qt version.");
+ QT7_ONLY(return;)
+ }
+ int idx = data->propertyIndex(name);
+ if (idx == -1) {
+ data->addPropertyNameAndIndex(name, data->numIdValues() + d->numPropertyValues());
+ d->appendPropertyValue(value);
data->refreshExpressions();
} else {
- d->propertyValues[idx] = value;
- QMetaObject::activate(this, d->notifyIndex, idx, nullptr);
+ d->setPropertyValue(idx, value);
+ QMetaObject::activate(this, d->notifyIndex(), idx, nullptr);
}
if (auto *obj = qvariant_cast<QObject *>(value)) {
@@ -329,6 +254,9 @@ void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
Set the \a value of the \a name property on this context.
QQmlContext does \b not take ownership of \a value.
+
+ \note You should not use context properties to inject values into your QML
+ components. Use singletons or regular object properties instead.
*/
void QQmlContext::setContextProperty(const QString &name, QObject *value)
{
@@ -344,26 +272,24 @@ void QQmlContext::setContextProperty(const QString &name, QObject *value)
refreshing expressions, and is therefore recommended
instead of calling \l setContextProperty() for each individual property.
+ \note You should not use context properties to inject values into your QML
+ components. Use singletons or regular object properties instead.
+
\sa QQmlContext::setContextProperty()
*/
-void QQmlContext::setContextProperties(const QVector<PropertyPair> &properties)
+void QQmlContext::setContextProperties(const QList<PropertyPair> &properties)
{
Q_D(const QQmlContext);
- QQmlContextData *data = d->data;
-
- QQmlJavaScriptExpression *expressions = data->expressions;
- QQmlContextData *childContexts = data->childContexts;
-
- data->expressions = nullptr;
- data->childContexts = nullptr;
+ QQmlRefPointer<QQmlContextData> data = d->m_data;
+ QQmlJavaScriptExpression *expressions = data->takeExpressions();
+ QQmlRefPointer<QQmlContextData> childContexts = data->takeChildContexts();
for (const auto &property : properties)
setContextProperty(property.name, property.value);
- data->expressions = expressions;
- data->childContexts = childContexts;
-
+ data->setExpressions(expressions);
+ data->setChildContexts(childContexts);
data->refreshExpressions();
}
@@ -379,97 +305,121 @@ void QQmlContext::setContextProperties(const QVector<PropertyPair> &properties)
\sa QQmlContext::setContextProperties()
*/
+static bool readObjectProperty(
+ const QQmlRefPointer<QQmlContextData> &data, QObject *object, const QString &name,
+ QVariant *target)
+{
+ QQmlPropertyData local;
+ if (const QQmlPropertyData *property = QQmlPropertyCache::property(object, name, data, &local)) {
+ *target = object->metaObject()->property(property->coreIndex()).read(object);
+ return true;
+ }
+ return false;
+}
+
/*!
- Returns the value of the \a name property for this context
- as a QVariant.
+ Returns the value of the \a name property for this context as a QVariant.
+ If you know that the property you're looking for is a QObject assigned using
+ a QML id in the current context, \l objectForName() is more convenient and
+ faster. In contrast to \l objectForName() and \l nameForObject(), this method
+ does traverse the context hierarchy and searches in parent contexts if the
+ \a name is not found in the current one. It also considers any
+ \l contextObject() you may have set.
+
+ \sa objectForName(), nameForObject(), contextObject()
*/
QVariant QQmlContext::contextProperty(const QString &name) const
{
Q_D(const QQmlContext);
- QVariant value;
- int idx = -1;
-
- QQmlContextData *data = d->data;
- const QV4::IdentifierHash &properties = data->propertyNames();
- if (properties.count())
- idx = properties.value(name);
+ const QQmlRefPointer<QQmlContextData> data = d->m_data;
+ const int idx = data->propertyIndex(name);
if (idx == -1) {
- if (data->contextObject) {
- QObject *obj = data->contextObject;
- QQmlPropertyData local;
- QQmlPropertyData *property =
- QQmlPropertyCache::property(data->engine, obj, name, data, local);
-
- if (property) value = obj->metaObject()->property(property->coreIndex()).read(obj);
+ if (QObject *obj = data->contextObject()) {
+ QVariant value;
+ if (readObjectProperty(data, obj, name, &value))
+ return value;
}
- if (!value.isValid() && parentContext())
- value = parentContext()->contextProperty(name);
+
+ if (parentContext())
+ return parentContext()->contextProperty(name);
} else {
- if (idx >= d->propertyValues.count())
- value = QVariant::fromValue(data->idValues[idx - d->propertyValues.count()].data());
+ if (idx >= d->numPropertyValues())
+ return QVariant::fromValue(data->idValue(idx - d->numPropertyValues()));
else
- value = d->propertyValues[idx];
+ return d->propertyValue(idx);
}
- return value;
+ return QVariant();
}
/*!
-Returns the name of \a object in this context, or an empty string if \a object
-is not named in the context. Objects are named by setContextProperty(), or by ids in
-the case of QML created contexts.
+ Returns the name of \a object in this context, or an empty string if \a object
+ is not named in the context. Objects are named by \l setContextProperty(), or
+ as properties of a context object, or by ids in the case of QML created
+ contexts.
+
+ If the object has multiple names, the first is returned.
+
+ In contrast to \l contextProperty(), this method does not traverse the
+ context hierarchy. If the name is not found in the current context, an empty
+ String is returned.
-If the object has multiple names, the first is returned.
+ \sa contextProperty(), objectForName()
*/
-QString QQmlContext::nameForObject(QObject *object) const
+QString QQmlContext::nameForObject(const QObject *object) const
{
Q_D(const QQmlContext);
- return d->data->findObjectId(object);
+ return d->m_data->findObjectId(object);
}
/*!
- Resolves the URL \a src relative to the URL of the
- containing component.
+ \since 6.2
- \sa QQmlEngine::baseUrl(), setBaseUrl()
+ Returns the object for a given \a name in this context. Returns nullptr if
+ \a name is not available in the context or if the value associated with
+ \a name is not a QObject. Objects are named by \l setContextProperty(),
+ or as properties of a context object, or by ids in the case of QML created
+ contexts. In contrast to \l contextProperty(), this method does not traverse
+ the context hierarchy. If the name is not found in the current context,
+ nullptr is returned.
+
+ \sa contextProperty(), nameForObject()
*/
-QUrl QQmlContext::resolvedUrl(const QUrl &src)
+QObject *QQmlContext::objectForName(const QString &name) const
{
- Q_D(QQmlContext);
- return d->data->resolvedUrl(src);
-}
+ Q_D(const QQmlContext);
-QUrl QQmlContextData::resolvedUrl(const QUrl &src)
-{
- QUrl resolved;
- if (src.isRelative() && !src.isEmpty()) {
- QQmlContextData *ctxt = this;
- do {
- if (ctxt->url().isValid())
- break;
- else
- ctxt = ctxt->parent;
- } while (ctxt);
-
- if (ctxt)
- resolved = ctxt->url().resolved(src);
- else if (engine)
- resolved = engine->baseUrl().resolved(src);
- } else {
- resolved = src;
+ QQmlRefPointer<QQmlContextData> data = d->m_data;
+ if (const int propertyIndex = data->propertyIndex(name); propertyIndex >= 0) {
+ const int numPropertyValues = d->numPropertyValues();
+ if (propertyIndex < numPropertyValues)
+ return qvariant_cast<QObject *>(d->propertyValue(propertyIndex));
+ return data->idValue(propertyIndex - numPropertyValues);
}
- if (resolved.isEmpty()) //relative but no ctxt
- return resolved;
+ if (QObject *obj = data->contextObject()) {
+ QVariant result;
+ if (readObjectProperty(data, obj, name, &result))
+ return qvariant_cast<QObject *>(result);
+ }
- if (engine && engine->urlInterceptor())
- resolved = engine->urlInterceptor()->intercept(resolved, QQmlAbstractUrlInterceptor::UrlString);
- return resolved;
+ return nullptr;
}
+/*!
+ Resolves the URL \a src relative to the URL of the
+ containing component.
+
+ \sa QQmlEngine::baseUrl(), setBaseUrl()
+*/
+QUrl QQmlContext::resolvedUrl(const QUrl &src) const
+{
+ Q_D(const QQmlContext);
+ return d->m_data->resolvedUrl(src);
+}
/*!
Explicitly sets the url resolvedUrl() will use for relative references to \a baseUrl.
@@ -482,9 +432,8 @@ QUrl QQmlContextData::resolvedUrl(const QUrl &src)
void QQmlContext::setBaseUrl(const QUrl &baseUrl)
{
Q_D(QQmlContext);
-
- d->data->baseUrl = baseUrl;
- d->data->baseUrlString = baseUrl.toString();
+ d->m_data->setBaseUrl(baseUrl);
+ d->m_data->setBaseUrlString(baseUrl.toString());
}
/*!
@@ -494,410 +443,76 @@ void QQmlContext::setBaseUrl(const QUrl &baseUrl)
QUrl QQmlContext::baseUrl() const
{
Q_D(const QQmlContext);
- const QQmlContextData* data = d->data;
- while (data && data->url().isEmpty())
- data = data->parent;
+ return d->m_data->baseUrl();
+}
- if (data)
- return data->url();
- else
- return QUrl();
+/*!
+ * \internal
+ */
+QJSValue QQmlContext::importedScript(const QString &name) const
+{
+ Q_D(const QQmlContext);
+
+ QQmlTypeNameCache::Result r = d->m_data->imports()->query(name, QQmlTypeLoader::get(engine()));
+ QV4::Scope scope(engine()->handle());
+ QV4::ScopedObject scripts(scope, d->m_data->importedScripts().valueRef());
+ return scripts ? QJSValuePrivate::fromReturnedValue(scripts->get(r.scriptIndex))
+ : QJSValue(QJSValue::UndefinedValue);
}
-int QQmlContextPrivate::context_count(QQmlListProperty<QObject> *prop)
+qsizetype QQmlContextPrivate::context_count(QQmlListProperty<QObject> *prop)
{
QQmlContext *context = static_cast<QQmlContext*>(prop->object);
QQmlContextPrivate *d = QQmlContextPrivate::get(context);
int contextProperty = (int)(quintptr)prop->data;
- if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
+ if (d->propertyValue(contextProperty).userType() != qMetaTypeId<QList<QObject*> >())
return 0;
- } else {
- return ((const QList<QObject> *)d->propertyValues.at(contextProperty).constData())->count();
- }
+ else
+ return ((const QList<QObject> *)d->propertyValue(contextProperty).constData())->size();
}
-QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, int index)
+QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, qsizetype index)
{
QQmlContext *context = static_cast<QQmlContext*>(prop->object);
QQmlContextPrivate *d = QQmlContextPrivate::get(context);
int contextProperty = (int)(quintptr)prop->data;
- if (d->propertyValues.at(contextProperty).userType() != qMetaTypeId<QList<QObject*> >()) {
+ if (d->propertyValue(contextProperty).userType() != qMetaTypeId<QList<QObject*> >())
return nullptr;
- } else {
- return ((const QList<QObject*> *)d->propertyValues.at(contextProperty).constData())->at(index);
- }
+ else
+ return ((const QList<QObject*> *)d->propertyValue(contextProperty).constData())->at(index);
}
void QQmlContextPrivate::dropDestroyedQObject(const QString &name, QObject *destroyed)
{
- const int idx = data->propertyNames().value(name);
- Q_ASSERT(idx >= 0);
- if (qvariant_cast<QObject *>(propertyValues[idx]) != destroyed)
+ if (!m_data->isValid())
return;
- propertyValues[idx] = QVariant::fromValue<QObject *>(nullptr);
- QMetaObject::activate(q_func(), notifyIndex, idx, nullptr);
-}
-
-
-QQmlContextData::QQmlContextData()
- : QQmlContextData(nullptr)
-{
-}
-
-QQmlContextData::QQmlContextData(QQmlContext *ctxt)
- : engine(nullptr), isInternal(false), isJSContext(false),
- isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
- stronglyReferencedByParent(false), hasExtraObject(false), publicContext(ctxt), incubator(nullptr), componentObjectIndex(-1),
- contextObject(nullptr), nextChild(nullptr), prevChild(nullptr),
- expressions(nullptr), contextObjects(nullptr), idValues(nullptr), idValueCount(0),
- componentAttached(nullptr)
-{
-}
-
-void QQmlContextData::emitDestruction()
-{
- if (!hasEmittedDestruction) {
- hasEmittedDestruction = true;
-
- // Emit the destruction signal - must be emitted before invalidate so that the
- // context is still valid if bindings or resultant expression evaluation requires it
- if (engine) {
- while (componentAttached) {
- QQmlComponentAttached *a = componentAttached;
- componentAttached = a->next;
- if (componentAttached) componentAttached->prev = &componentAttached;
-
- a->next = nullptr;
- a->prev = nullptr;
-
- emit a->destruction();
- }
-
- QQmlContextData * child = childContexts;
- while (child) {
- child->emitDestruction();
- child = child->nextChild;
- }
- }
- }
-}
-
-void QQmlContextData::invalidate()
-{
- emitDestruction();
-
- while (childContexts) {
- Q_ASSERT(childContexts != this);
- if (childContexts->stronglyReferencedByParent && !--childContexts->refCount)
- childContexts->destroy();
- else
- childContexts->invalidate();
- }
-
- if (prevChild) {
- *prevChild = nextChild;
- if (nextChild) nextChild->prevChild = prevChild;
- nextChild = nullptr;
- prevChild = nullptr;
- }
-
- importedScripts.clear();
-
- engine = nullptr;
- parent = nullptr;
-}
-
-void QQmlContextData::clearContextRecursively()
-{
- clearContext();
-
- for (auto ctxIt = childContexts; ctxIt; ctxIt = ctxIt->nextChild)
- ctxIt->clearContextRecursively();
-}
-
-void QQmlContextData::clearContext()
-{
- emitDestruction();
-
- QQmlJavaScriptExpression *expression = expressions;
- while (expression) {
- QQmlJavaScriptExpression *nextExpression = expression->m_nextExpression;
-
- expression->m_prevExpression = nullptr;
- expression->m_nextExpression = nullptr;
-
- expression->setContext(nullptr);
-
- expression = nextExpression;
- }
- expressions = nullptr;
-}
-
-void QQmlContextData::destroy()
-{
- Q_ASSERT(refCount == 0);
- linkedContext = nullptr;
-
- // avoid recursion
- ++refCount;
- if (engine)
- invalidate();
-
- Q_ASSERT(refCount == 1);
- clearContext();
- Q_ASSERT(refCount == 1);
-
- while (contextObjects) {
- QQmlData *co = contextObjects;
- contextObjects = contextObjects->nextContextObject;
-
- if (co->context == this)
- co->context = nullptr;
- co->outerContext = nullptr;
- co->nextContextObject = nullptr;
- co->prevContextObject = nullptr;
- }
- Q_ASSERT(refCount == 1);
-
- QQmlGuardedContextData *contextGuard = contextGuards;
- while (contextGuard) {
- QQmlGuardedContextData *next = contextGuard->m_next;
- contextGuard->m_next = nullptr;
- contextGuard->m_prev = nullptr;
- contextGuard->m_contextData = nullptr;
- contextGuard = next;
- }
- contextGuards = nullptr;
- Q_ASSERT(refCount == 1);
-
- delete [] idValues;
- idValues = nullptr;
-
- Q_ASSERT(refCount == 1);
- if (publicContext) {
- // the QQmlContext destructor will remove one ref again
- ++refCount;
- delete publicContext;
- }
-
- Q_ASSERT(refCount == 1);
- --refCount;
- Q_ASSERT(refCount == 0);
-
- delete this;
-}
-
-void QQmlContextData::setParent(QQmlContextData *p, bool stronglyReferencedByParent)
-{
- if (p == parent)
+ const int idx = m_data->propertyIndex(name);
+ Q_ASSERT(idx >= 0);
+ if (qvariant_cast<QObject *>(propertyValue(idx)) != destroyed)
return;
- if (p) {
- Q_ASSERT(!parent);
- parent = p;
- this->stronglyReferencedByParent = stronglyReferencedByParent;
- if (stronglyReferencedByParent)
- ++refCount; // balanced in QQmlContextData::invalidate()
- engine = p->engine;
- nextChild = p->childContexts;
- if (nextChild) nextChild->prevChild = &nextChild;
- prevChild = &p->childContexts;
- p->childContexts = this;
- }
-}
-
-void QQmlContextData::refreshExpressionsRecursive(QQmlJavaScriptExpression *expression)
-{
- QQmlJavaScriptExpression::DeleteWatcher w(expression);
-
- if (expression->m_nextExpression)
- refreshExpressionsRecursive(expression->m_nextExpression);
-
- if (!w.wasDeleted())
- expression->refresh();
-}
-
-QQmlContextData::~QQmlContextData()
-{
-}
-
-static inline bool expressions_to_run(QQmlContextData *ctxt, bool isGlobalRefresh)
-{
- return ctxt->expressions && (!isGlobalRefresh || ctxt->unresolvedNames);
-}
-
-void QQmlContextData::refreshExpressionsRecursive(bool isGlobal)
-{
- // For efficiency, we try and minimize the number of guards we have to create
- if (expressions_to_run(this, isGlobal) && (nextChild || childContexts)) {
- QQmlGuardedContextData guard(this);
-
- if (childContexts)
- childContexts->refreshExpressionsRecursive(isGlobal);
-
- if (guard.isNull()) return;
-
- if (nextChild)
- nextChild->refreshExpressionsRecursive(isGlobal);
-
- if (guard.isNull()) return;
-
- if (expressions_to_run(this, isGlobal))
- refreshExpressionsRecursive(expressions);
-
- } else if (expressions_to_run(this, isGlobal)) {
-
- refreshExpressionsRecursive(expressions);
-
- } else if (nextChild && childContexts) {
- QQmlGuardedContextData guard(this);
-
- childContexts->refreshExpressionsRecursive(isGlobal);
-
- if (!guard.isNull() && nextChild)
- nextChild->refreshExpressionsRecursive(isGlobal);
-
- } else if (nextChild) {
-
- nextChild->refreshExpressionsRecursive(isGlobal);
-
- } else if (childContexts) {
-
- childContexts->refreshExpressionsRecursive(isGlobal);
-
- }
-}
-
-// Refreshes all expressions that could possibly depend on this context. Refreshing flushes all
-// context-tree dependent caches in the expressions, and should occur every time the context tree
-// *structure* (not values) changes.
-void QQmlContextData::refreshExpressions()
-{
- bool isGlobal = (parent == nullptr);
-
- // For efficiency, we try and minimize the number of guards we have to create
- if (expressions_to_run(this, isGlobal) && childContexts) {
- QQmlGuardedContextData guard(this);
-
- childContexts->refreshExpressionsRecursive(isGlobal);
-
- if (!guard.isNull() && expressions_to_run(this, isGlobal))
- refreshExpressionsRecursive(expressions);
-
- } else if (expressions_to_run(this, isGlobal)) {
-
- refreshExpressionsRecursive(expressions);
-
- } else if (childContexts) {
-
- childContexts->refreshExpressionsRecursive(isGlobal);
-
- }
-}
-
-void QQmlContextData::addObject(QQmlData *data)
-{
- if (data->outerContext) {
- if (data->nextContextObject)
- data->nextContextObject->prevContextObject = data->prevContextObject;
- if (data->prevContextObject)
- *data->prevContextObject = data->nextContextObject;
- else if (data->outerContext->contextObjects == data)
- data->outerContext->contextObjects = data->nextContextObject;
- }
-
- data->outerContext = this;
-
- data->nextContextObject = contextObjects;
- if (data->nextContextObject)
- data->nextContextObject->prevContextObject = &data->nextContextObject;
- data->prevContextObject = &contextObjects;
- contextObjects = data;
-}
-
-void QQmlContextData::setIdProperty(int idx, QObject *obj)
-{
- idValues[idx] = obj;
- idValues[idx].context = this;
-}
-
-QString QQmlContextData::findObjectId(const QObject *obj) const
-{
- const QV4::IdentifierHash &properties = propertyNames();
- if (propertyNameCache.isEmpty())
- return QString();
-
- for (int ii = 0; ii < idValueCount; ii++) {
- if (idValues[ii] == obj)
- return properties.findId(ii);
- }
-
- if (publicContext) {
- QQmlContextPrivate *p = QQmlContextPrivate::get(publicContext);
- for (int ii = 0; ii < p->propertyValues.count(); ++ii)
- if (p->propertyValues.at(ii) == QVariant::fromValue(const_cast<QObject *>(obj)))
- return properties.findId(ii);
- }
-
- if (linkedContext)
- return linkedContext->findObjectId(obj);
- return QString();
-}
-
-QQmlContext *QQmlContextData::asQQmlContext()
-{
- if (!publicContext)
- publicContext = new QQmlContext(this);
- return publicContext;
-}
-
-QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
-{
- return QQmlContextPrivate::get(asQQmlContext());
-}
-
-void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, int subComponentIndex)
-{
- typeCompilationUnit = unit;
- componentObjectIndex = subComponentIndex == -1 ? /*root object*/0 : subComponentIndex;
- Q_ASSERT(!idValues);
- idValueCount = typeCompilationUnit->objectAt(componentObjectIndex)->nNamedObjectsInComponent;
- idValues = new ContextGuard[idValueCount];
-}
-
-const QV4::IdentifierHash &QQmlContextData::propertyNames() const
-{
- if (propertyNameCache.isEmpty()) {
- if (typeCompilationUnit)
- propertyNameCache = typeCompilationUnit->namedObjectsPerComponent(componentObjectIndex);
- else
- propertyNameCache = QV4::IdentifierHash(engine->handle());
- }
- return propertyNameCache;
-}
-
-QV4::IdentifierHash &QQmlContextData::detachedPropertyNames()
-{
- propertyNames();
- propertyNameCache.detach();
- return propertyNameCache;
+ setPropertyValue(idx, QVariant::fromValue<QObject *>(nullptr));
+ QMetaObject::activate(q_func(), notifyIndex(), idx, nullptr);
}
-QUrl QQmlContextData::url() const
+void QQmlContextPrivate::emitDestruction()
{
- if (typeCompilationUnit)
- return typeCompilationUnit->finalUrl();
- return baseUrl;
+ m_data->emitDestruction();
}
-QString QQmlContextData::urlString() const
+// m_data is owned by the public context. When the public context is reset to nullptr, it will be
+// deref'd. It's OK to pass a half-created publicContext here. We will not dereference it during
+// construction.
+QQmlContextPrivate::QQmlContextPrivate(
+ QQmlContext *publicContext, const QQmlRefPointer<QQmlContextData> &parent,
+ QQmlEngine *engine) :
+ m_data(new QQmlContextData(QQmlContextData::OwnedByPublicContext, publicContext,
+ parent, engine))
{
- if (typeCompilationUnit)
- return typeCompilationUnit->finalUrlString();
- return baseUrlString;
+ Q_ASSERT(publicContext != nullptr);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h
index 7ed70c7619..b02aefe1d6 100644
--- a/src/qml/qml/qqmlcontext.h
+++ b/src/qml/qml/qqmlcontext.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCONTEXT_H
#define QQMLCONTEXT_H
@@ -53,7 +17,6 @@ QT_BEGIN_NAMESPACE
class QString;
class QQmlEngine;
-class QQmlRefCount;
class QQmlContextPrivate;
class QQmlCompositeTypeData;
class QQmlContextData;
@@ -81,16 +44,18 @@ public:
QVariant contextProperty(const QString &) const;
void setContextProperty(const QString &, QObject *);
void setContextProperty(const QString &, const QVariant &);
- void setContextProperties(const QVector<PropertyPair> &properties);
+ void setContextProperties(const QList<PropertyPair> &properties);
- // ### Qt 6: no need for a mutable object, this should become a const QObject pointer
- QString nameForObject(QObject *) const;
+ QString nameForObject(const QObject *) const;
+ QObject *objectForName(const QString &) const;
- QUrl resolvedUrl(const QUrl &);
+ QUrl resolvedUrl(const QUrl &) const;
void setBaseUrl(const QUrl &);
QUrl baseUrl() const;
+ QJSValue importedScript(const QString &name) const;
+
private:
friend class QQmlEngine;
friend class QQmlEnginePrivate;
@@ -100,12 +65,10 @@ private:
friend class QQmlComponentPrivate;
friend class QQmlScriptPrivate;
friend class QQmlContextData;
- QQmlContext(QQmlContextData *);
+ QQmlContext(QQmlContextPrivate &dd, QObject *parent = nullptr);
QQmlContext(QQmlEngine *, bool);
Q_DISABLE_COPY(QQmlContext)
};
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QList<QObject*>)
-
#endif // QQMLCONTEXT_H
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index f93393a11b..aeaa1a3cd5 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCONTEXT_P_H
#define QQMLCONTEXT_P_H
@@ -51,342 +15,78 @@
// We mean it.
//
-#include "qqmlcontext.h"
+#include <QtCore/qlist.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qpointer.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmllist.h>
-#include "qqmldata_p.h"
-#include "qqmltypenamecache_p.h"
-#include "qqmlnotifier_p.h"
-#include "qqmllist.h"
-
-#include <QtCore/qhash.h>
-#include <QtQml/qjsvalue.h>
-#include <QtCore/qset.h>
-
-#include <private/qobject_p.h>
-#include <private/qflagpointer_p.h>
-#include <private/qqmlguard_p.h>
-
-#include <private/qv4executablecompilationunit_p.h>
-#include <private/qv4identifier_p.h>
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/qtaggedpointer.h>
+#include <QtQml/private/qqmlrefcount_p.h>
QT_BEGIN_NAMESPACE
-class QQmlContext;
-class QQmlExpression;
-class QQmlEngine;
-class QQmlExpression;
-class QQmlExpressionPrivate;
-class QQmlJavaScriptExpression;
class QQmlContextData;
-class QQmlGuardedContextData;
-class QQmlIncubatorPrivate;
class QQmlContextPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQmlContext)
public:
- QQmlContextPrivate();
-
- QQmlContextData *data;
-
- QList<QVariant> propertyValues;
- int notifyIndex;
-
static QQmlContextPrivate *get(QQmlContext *context) {
return static_cast<QQmlContextPrivate *>(QObjectPrivate::get(context));
}
+
static QQmlContext *get(QQmlContextPrivate *context) {
return static_cast<QQmlContext *>(context->q_func());
}
- // Only used for debugging
- QList<QPointer<QObject> > instances;
-
- static int context_count(QQmlListProperty<QObject> *);
- static QObject *context_at(QQmlListProperty<QObject> *, int);
+ static qsizetype context_count(QQmlListProperty<QObject> *);
+ static QObject *context_at(QQmlListProperty<QObject> *, qsizetype);
void dropDestroyedQObject(const QString &name, QObject *destroyed);
-};
-
-class QQmlComponentAttached;
-class Q_QML_PRIVATE_EXPORT QQmlContextData
-{
-public:
- QQmlContextData();
- QQmlContextData(QQmlContext *);
- void emitDestruction();
- void clearContext();
- void clearContextRecursively();
- void invalidate();
+ int notifyIndex() const { return m_notifyIndex; }
+ void setNotifyIndex(int notifyIndex) { m_notifyIndex = notifyIndex; }
- inline bool isValid() const {
- return engine && (!isInternal || !contextObject || !QObjectPrivate::get(contextObject)->wasDeleted);
+ int numPropertyValues() const {
+ auto size = m_propertyValues.size();
+ Q_ASSERT(size <= std::numeric_limits<int>::max());
+ return int(size);
}
+ void appendPropertyValue(const QVariant &value) { m_propertyValues.append(value); }
+ void setPropertyValue(int index, const QVariant &value) { m_propertyValues[index] = value; }
+ QVariant propertyValue(int index) const { return m_propertyValues[index]; }
- // My parent context and engine
- QQmlContextData *parent = nullptr;
- QQmlEngine *engine;
-
- void setParent(QQmlContextData *, bool stronglyReferencedByParent = false);
- void refreshExpressions();
-
- void addObject(QQmlData *data);
-
- QUrl resolvedUrl(const QUrl &);
-
- // My containing QQmlContext. If isInternal is true this owns publicContext.
- // If internal is false publicContext owns this.
- QQmlContext *asQQmlContext();
- QQmlContextPrivate *asQQmlContextPrivate();
- quint32 refCount = 0;
- quint32 isInternal:1;
- quint32 isJSContext:1;
- quint32 isPragmaLibraryContext:1;
- quint32 unresolvedNames:1; // True if expressions in this context failed to resolve a toplevel name
- quint32 hasEmittedDestruction:1;
- quint32 isRootObjectInCreation:1;
- quint32 stronglyReferencedByParent:1;
- quint32 hasExtraObject:1; // used in QQmlDelegateModelItem::dataForObject to find the corresponding QQmlDelegateModelItem of an object
- quint32 dummy:24;
- QQmlContext *publicContext;
-
- union {
- // The incubator that is constructing this context if any
- QQmlIncubatorPrivate *incubator;
- // a pointer to extra data, currently only used in QQmlDelegateModel
- QObject *extraObject;
- };
-
- // Compilation unit for contexts that belong to a compiled type.
- QQmlRefPointer<QV4::ExecutableCompilationUnit> typeCompilationUnit;
-
- // object index in CompiledData::Unit to component that created this context
- int componentObjectIndex;
-
- void initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, int subComponentIndex);
-
- // flag indicates whether the context owns the cache (after mutation) or not.
- mutable QV4::IdentifierHash propertyNameCache;
- const QV4::IdentifierHash &propertyNames() const;
- QV4::IdentifierHash &detachedPropertyNames();
-
- // Context object
- QObject *contextObject;
-
- // Any script blocks that exist on this context
- QV4::PersistentValue importedScripts; // This is a JS Array
-
- QUrl baseUrl;
- QString baseUrlString;
-
- QUrl url() const;
- QString urlString() const;
-
- // List of imports that apply to this context
- QQmlRefPointer<QQmlTypeNameCache> imports;
-
- // My children
- QQmlContextData *childContexts = nullptr;
-
- // My peers in parent's childContexts list
- QQmlContextData *nextChild;
- QQmlContextData **prevChild;
-
- // Expressions that use this context
- QQmlJavaScriptExpression *expressions;
-
- // Doubly-linked list of objects that are owned by this context
- QQmlData *contextObjects;
-
- // Doubly-linked list of context guards (XXX merge with contextObjects)
- QQmlGuardedContextData *contextGuards = nullptr;
-
- // id guards
- struct ContextGuard : public QQmlGuard<QObject>
+ QList<QPointer<QObject>> instances() const { return m_instances; }
+ void appendInstance(QObject *instance) { m_instances.append(instance); }
+ void cleanInstances()
{
- inline ContextGuard();
- inline ContextGuard &operator=(QObject *obj);
- inline void objectDestroyed(QObject *) override;
-
- inline bool wasSet() const;
-
- QFlagPointer<QQmlContextData> context;
- QQmlNotifier bindings;
- };
- ContextGuard *idValues;
- int idValueCount;
- void setIdProperty(int, QObject *);
-
- // Linked contexts. this owns linkedContext.
- QQmlContextDataRef linkedContext;
-
- // Linked list of uses of the Component attached property in this
- // context
- QQmlComponentAttached *componentAttached;
-
- // Return the outermost id for obj, if any.
- QString findObjectId(const QObject *obj) const;
-
- static QQmlContextData *get(QQmlContext *context) {
- return QQmlContextPrivate::get(context)->data;
+ for (auto it = m_instances.begin(); it != m_instances.end();
+ it->isNull() ? (it = m_instances.erase(it)) : ++it) {}
}
-private:
- friend class QQmlContextDataRef;
- friend class QQmlContext; // needs to do manual refcounting :/
- void refreshExpressionsRecursive(bool isGlobal);
- void refreshExpressionsRecursive(QQmlJavaScriptExpression *);
- ~QQmlContextData();
- void destroy();
-};
-
-
-class QQmlGuardedContextData
-{
-public:
- inline QQmlGuardedContextData() = default;
- inline QQmlGuardedContextData(QQmlContextData *data)
- { setContextData(data); }
- inline ~QQmlGuardedContextData()
- { clear(); }
-
- inline QQmlContextData *contextData() const
- { return m_contextData; }
- inline void setContextData(QQmlContextData *);
-
- inline bool isNull() const { return !m_contextData; }
-
- inline operator QQmlContextData*() const { return m_contextData; }
- inline QQmlContextData* operator->() const { return m_contextData; }
- inline QQmlGuardedContextData &operator=(QQmlContextData *d) {
- setContextData(d); return *this;
- }
+ void emitDestruction();
private:
- QQmlGuardedContextData &operator=(const QQmlGuardedContextData &) = delete;
- QQmlGuardedContextData(const QQmlGuardedContextData &) = delete;
friend class QQmlContextData;
- inline void clear();
-
- QQmlContextData *m_contextData = nullptr;
- QQmlGuardedContextData *m_next = nullptr;
- QQmlGuardedContextData **m_prev = nullptr;
-};
-
-
-void QQmlGuardedContextData::setContextData(QQmlContextData *contextData)
- {
- if (m_contextData == contextData)
- return;
- clear();
+ QQmlContextPrivate(QQmlContextData *data) : m_data(data) {}
+ QQmlContextPrivate(QQmlContext *publicContext, const QQmlRefPointer<QQmlContextData> &parent,
+ QQmlEngine *engine = nullptr);
- if (contextData) {
- m_contextData = contextData;
- m_next = contextData->contextGuards;
- if (m_next) m_next->m_prev = &m_next;
- m_prev = &contextData->contextGuards;
- contextData->contextGuards = this;
- }
-}
-
-void QQmlGuardedContextData::clear()
-{
- if (m_prev) {
- *m_prev = m_next;
- if (m_next) m_next->m_prev = m_prev;
- m_contextData = nullptr;
- m_next = nullptr;
- m_prev = nullptr;
- }
-}
-
-QQmlContextDataRef::QQmlContextDataRef()
- : m_contextData(nullptr)
-{
-}
+ // Intentionally a bare pointer. QQmlContextData knows whether it owns QQmlContext or vice
+ // versa. If QQmlContext is the owner, QQmlContextData keeps an extra ref for its publicContext.
+ // The publicContext ref is released when doing QQmlContextData::setPublicContext(nullptr).
+ QQmlContextData *m_data;
-QQmlContextDataRef::QQmlContextDataRef(const QQmlContextDataRef &other)
- : m_contextData(other.m_contextData)
-{
- if (m_contextData)
- ++m_contextData->refCount;
-}
-
-QQmlContextDataRef::QQmlContextDataRef(QQmlContextData *data)
- : m_contextData(data)
-{
- if (m_contextData)
- ++m_contextData->refCount;
-}
-
-QQmlContextDataRef::~QQmlContextDataRef()
-{
- clear();
-}
+ QList<QVariant> m_propertyValues;
+ int m_notifyIndex = -1;
-void QQmlContextDataRef::setContextData(QQmlContextData *contextData)
-{
- if (m_contextData == contextData)
- return;
- clear();
-
- if (contextData) {
- m_contextData = contextData;
- ++m_contextData->refCount;
- }
-}
-
-QQmlContextData *QQmlContextDataRef::contextData() const
-{
- return m_contextData;
-}
-
-void QQmlContextDataRef::clear()
-{
- if (m_contextData && !--m_contextData->refCount)
- m_contextData->destroy();
- m_contextData = nullptr;
-}
-
-QQmlContextDataRef &
-QQmlContextDataRef::operator=(QQmlContextData *d)
-{
- setContextData(d);
- return *this;
-}
-
-QQmlContextDataRef &
-QQmlContextDataRef::operator=(const QQmlContextDataRef &other)
-{
- setContextData(other.m_contextData);
- return *this;
-}
-
-QQmlContextData::ContextGuard::ContextGuard()
-: context(nullptr)
-{
-}
-
-QQmlContextData::ContextGuard &QQmlContextData::ContextGuard::operator=(QObject *obj)
-{
- QQmlGuard<QObject>::operator=(obj);
- context.setFlag();
- bindings.notify(); // For alias connections
- return *this;
-}
-
-void QQmlContextData::ContextGuard::objectDestroyed(QObject *)
-{
- if (context->contextObject && !QObjectPrivate::get(context->contextObject)->wasDeleted)
- bindings.notify();
-}
-
-bool QQmlContextData::ContextGuard::wasSet() const
-{
- return context.flag();
-}
+ // Only used for debugging
+ QList<QPointer<QObject>> m_instances;
+};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcontextdata.cpp b/src/qml/qml/qqmlcontextdata.cpp
new file mode 100644
index 0000000000..8667a1ce81
--- /dev/null
+++ b/src/qml/qml/qqmlcontextdata.cpp
@@ -0,0 +1,346 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmlcontextdata_p.h"
+
+#include <QtQml/qqmlengine.h>
+#include <QtQml/private/qqmlcomponentattached_p.h>
+#include <QtQml/private/qqmljavascriptexpression_p.h>
+#include <QtQml/private/qqmlguardedcontextdata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQmlContextData::installContext(QQmlData *ddata, QQmlContextData::QmlObjectKind kind)
+{
+ Q_ASSERT(ddata);
+ if (kind == QQmlContextData::DocumentRoot) {
+ if (ddata->context) {
+ Q_ASSERT(ddata->context != this);
+ Q_ASSERT(ddata->outerContext);
+ Q_ASSERT(ddata->outerContext != this);
+ QQmlRefPointer<QQmlContextData> c = ddata->context;
+ while (QQmlRefPointer<QQmlContextData> linked = c->linkedContext())
+ c = linked;
+ c->setLinkedContext(this);
+ } else {
+ ddata->context = this;
+ }
+ ddata->ownContext.reset(ddata->context);
+ } else if (!ddata->context) {
+ ddata->context = this;
+ }
+
+ addOwnedObject(ddata);
+}
+
+QUrl QQmlContextData::resolvedUrl(const QUrl &src) const
+{
+ QUrl resolved;
+ if (src.isRelative() && !src.isEmpty()) {
+ const QUrl ownUrl = url();
+ if (ownUrl.isValid()) {
+ resolved = ownUrl.resolved(src);
+ } else {
+ for (QQmlRefPointer<QQmlContextData> ctxt = parent(); ctxt; ctxt = ctxt->parent()) {
+ const QUrl ctxtUrl = ctxt->url();
+ if (ctxtUrl.isValid()) {
+ resolved = ctxtUrl.resolved(src);
+ break;
+ }
+ }
+
+ if (m_engine && resolved.isEmpty())
+ resolved = m_engine->baseUrl().resolved(src);
+ }
+ } else {
+ resolved = src;
+ }
+
+ if (resolved.isEmpty()) //relative but no ctxt
+ return resolved;
+
+ return m_engine ? m_engine->interceptUrl(resolved, QQmlAbstractUrlInterceptor::UrlString)
+ : resolved;
+}
+
+void QQmlContextData::emitDestruction()
+{
+ if (!m_hasEmittedDestruction) {
+ m_hasEmittedDestruction = true;
+
+ // Emit the destruction signal - must be emitted before invalidate so that the
+ // context is still valid if bindings or resultant expression evaluation requires it
+ if (m_engine) {
+ while (m_componentAttacheds) {
+ QQmlComponentAttached *attached = m_componentAttacheds;
+ attached->removeFromList();
+ emit attached->destruction();
+ }
+
+ for (QQmlRefPointer<QQmlContextData> child = m_childContexts; !child.isNull(); child = child->m_nextChild)
+ child->emitDestruction();
+ }
+ }
+}
+
+void QQmlContextData::invalidate()
+{
+ emitDestruction();
+
+ while (m_childContexts) {
+ Q_ASSERT(m_childContexts != this);
+ m_childContexts->invalidate();
+ }
+
+ if (m_prevChild) {
+ *m_prevChild = m_nextChild;
+ if (m_nextChild) m_nextChild->m_prevChild = m_prevChild;
+ m_nextChild = nullptr;
+ m_prevChild = nullptr;
+ }
+
+ m_importedScripts.clear();
+
+ m_engine = nullptr;
+ clearParent();
+}
+
+void QQmlContextData::clearContextRecursively()
+{
+ clearContext();
+
+ for (auto ctxIt = m_childContexts; ctxIt; ctxIt = ctxIt->m_nextChild)
+ ctxIt->clearContextRecursively();
+}
+
+void QQmlContextData::clearContext()
+{
+ emitDestruction();
+
+ QQmlJavaScriptExpression *expression = m_expressions;
+ while (expression) {
+ QQmlJavaScriptExpression *nextExpression = expression->m_nextExpression;
+
+ expression->m_prevExpression = nullptr;
+ expression->m_nextExpression = nullptr;
+
+ expression->setContext(nullptr);
+
+ expression = nextExpression;
+ }
+ m_expressions = nullptr;
+}
+
+QQmlContextData::~QQmlContextData()
+{
+ Q_ASSERT(refCount() == 0);
+
+ // avoid recursion
+ addref();
+ if (m_engine)
+ invalidate();
+ m_linkedContext.reset();
+
+ Q_ASSERT(refCount() == 1);
+ clearContext();
+ Q_ASSERT(refCount() == 1);
+
+ while (m_ownedObjects) {
+ QQmlData *co = m_ownedObjects;
+ m_ownedObjects = m_ownedObjects->nextContextObject;
+
+ if (co->context == this)
+ co->context = nullptr;
+ co->outerContext = nullptr;
+ co->nextContextObject = nullptr;
+ co->prevContextObject = nullptr;
+ }
+ Q_ASSERT(refCount() == 1);
+
+ QQmlGuardedContextData *contextGuard = m_contextGuards;
+ while (contextGuard) {
+ // TODO: Is this dead code? Why?
+ QQmlGuardedContextData *next = contextGuard->next();
+ contextGuard->setContextData({});
+ contextGuard = next;
+ }
+ m_contextGuards = nullptr;
+ Q_ASSERT(refCount() == 1);
+
+ delete [] m_idValues;
+ m_idValues = nullptr;
+
+ Q_ASSERT(refCount() == 1);
+ if (m_publicContext)
+ delete m_publicContext;
+
+ Q_ASSERT(refCount() == 1);
+}
+
+void QQmlContextData::refreshExpressionsRecursive(QQmlJavaScriptExpression *expression)
+{
+ QQmlJavaScriptExpression::DeleteWatcher w(expression);
+
+ if (expression->m_nextExpression)
+ refreshExpressionsRecursive(expression->m_nextExpression);
+
+ if (!w.wasDeleted())
+ expression->refresh();
+}
+
+void QQmlContextData::refreshExpressionsRecursive(bool isGlobal)
+{
+ // For efficiency, we try and minimize the number of guards we have to create
+ if (hasExpressionsToRun(isGlobal) && (m_nextChild || m_childContexts)) {
+ QQmlGuardedContextData guard(this);
+
+ if (m_childContexts)
+ m_childContexts->refreshExpressionsRecursive(isGlobal);
+
+ if (guard.isNull()) return;
+
+ if (m_nextChild)
+ m_nextChild->refreshExpressionsRecursive(isGlobal);
+
+ if (guard.isNull()) return;
+
+ if (hasExpressionsToRun(isGlobal))
+ refreshExpressionsRecursive(m_expressions);
+
+ } else if (hasExpressionsToRun(isGlobal)) {
+ refreshExpressionsRecursive(m_expressions);
+ } else if (m_nextChild && m_childContexts) {
+ QQmlGuardedContextData guard(this);
+ m_childContexts->refreshExpressionsRecursive(isGlobal);
+ if (!guard.isNull() && m_nextChild)
+ m_nextChild->refreshExpressionsRecursive(isGlobal);
+ } else if (m_nextChild) {
+ m_nextChild->refreshExpressionsRecursive(isGlobal);
+ } else if (m_childContexts) {
+ m_childContexts->refreshExpressionsRecursive(isGlobal);
+ }
+}
+
+// Refreshes all expressions that could possibly depend on this context. Refreshing flushes all
+// context-tree dependent caches in the expressions, and should occur every time the context tree
+// *structure* (not values) changes.
+void QQmlContextData::refreshExpressions()
+{
+ bool isGlobal = (m_parent == nullptr);
+
+ // For efficiency, we try and minimize the number of guards we have to create
+ if (hasExpressionsToRun(isGlobal) && m_childContexts) {
+ QQmlGuardedContextData guard(this);
+ m_childContexts->refreshExpressionsRecursive(isGlobal);
+ if (!guard.isNull() && hasExpressionsToRun(isGlobal))
+ refreshExpressionsRecursive(m_expressions);
+ } else if (hasExpressionsToRun(isGlobal)) {
+ refreshExpressionsRecursive(m_expressions);
+ } else if (m_childContexts) {
+ m_childContexts->refreshExpressionsRecursive(isGlobal);
+ }
+}
+
+void QQmlContextData::addOwnedObject(QQmlData *data)
+{
+ if (data->outerContext) {
+ if (data->nextContextObject)
+ data->nextContextObject->prevContextObject = data->prevContextObject;
+ if (data->prevContextObject)
+ *data->prevContextObject = data->nextContextObject;
+ else if (data->outerContext->m_ownedObjects == data)
+ data->outerContext->m_ownedObjects = data->nextContextObject;
+ }
+
+ data->outerContext = this;
+
+ data->nextContextObject = m_ownedObjects;
+ if (data->nextContextObject)
+ data->nextContextObject->prevContextObject = &data->nextContextObject;
+ data->prevContextObject = &m_ownedObjects;
+ m_ownedObjects = data;
+}
+
+void QQmlContextData::setIdValue(int idx, QObject *obj)
+{
+ m_idValues[idx] = obj;
+ m_idValues[idx].setContext(this);
+}
+
+QString QQmlContextData::findObjectId(const QObject *obj) const
+{
+ for (int ii = 0; ii < m_idValueCount; ii++) {
+ if (m_idValues[ii] == obj)
+ return propertyName(ii);
+ }
+
+ const QVariant objVariant = QVariant::fromValue(obj);
+ if (m_publicContext) {
+ QQmlContextPrivate *p = QQmlContextPrivate::get(m_publicContext);
+ for (int ii = 0; ii < p->numPropertyValues(); ++ii)
+ if (p->propertyValue(ii) == objVariant)
+ return propertyName(ii);
+ }
+
+ if (m_contextObject) {
+ // This is expensive, but nameForObject should really mirror contextProperty()
+ for (const QMetaObject *metaObject = m_contextObject->metaObject();
+ metaObject; metaObject = metaObject->superClass()) {
+ for (int i = metaObject->propertyOffset(), end = metaObject->propertyCount();
+ i != end; ++i) {
+ const QMetaProperty prop = metaObject->property(i);
+ if (prop.metaType().flags() & QMetaType::PointerToQObject
+ && prop.read(m_contextObject) == objVariant) {
+ return QString::fromUtf8(prop.name());
+ }
+ }
+ }
+ }
+
+ return QString();
+}
+
+void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, int subComponentIndex)
+{
+ m_typeCompilationUnit = unit;
+ m_componentObjectIndex = subComponentIndex == -1 ? /*root object*/0 : subComponentIndex;
+ Q_ASSERT(!m_idValues);
+ m_idValueCount = m_typeCompilationUnit->objectAt(m_componentObjectIndex)
+ ->nNamedObjectsInComponent;
+ m_idValues = new ContextGuard[m_idValueCount];
+}
+
+void QQmlContextData::addComponentAttached(QQmlComponentAttached *attached)
+{
+ attached->insertIntoList(&m_componentAttacheds);
+}
+
+void QQmlContextData::addExpression(QQmlJavaScriptExpression *expression)
+{
+ expression->insertIntoList(&m_expressions);
+}
+
+void QQmlContextData::initPropertyNames() const
+{
+ if (m_typeCompilationUnit)
+ m_propertyNameCache = m_typeCompilationUnit->namedObjectsPerComponent(m_componentObjectIndex);
+ else
+ m_propertyNameCache = QV4::IdentifierHash(m_engine->handle());
+ Q_ASSERT(!m_propertyNameCache.isEmpty());
+}
+
+QUrl QQmlContextData::url() const
+{
+ if (m_typeCompilationUnit)
+ return m_typeCompilationUnit->finalUrl();
+ return m_baseUrl;
+}
+
+QString QQmlContextData::urlString() const
+{
+ if (m_typeCompilationUnit)
+ return m_typeCompilationUnit->finalUrlString();
+ return m_baseUrlString;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcontextdata_p.h b/src/qml/qml/qqmlcontextdata_p.h
new file mode 100644
index 0000000000..c8e362ec8d
--- /dev/null
+++ b/src/qml/qml/qqmlcontextdata_p.h
@@ -0,0 +1,468 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLCONTEXTDATA_P_H
+#define QQMLCONTEXTDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/private/qtqmlglobal_p.h>
+#include <QtQml/private/qqmlcontext_p.h>
+#include <QtQml/private/qqmlguard_p.h>
+#include <QtQml/private/qqmltypenamecache_p.h>
+#include <QtQml/private/qqmlnotifier_p.h>
+#include <QtQml/private/qv4identifierhash_p.h>
+#include <QtQml/private/qv4executablecompilationunit_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlComponentAttached;
+class QQmlGuardedContextData;
+class QQmlJavaScriptExpression;
+class QQmlIncubatorPrivate;
+
+class Q_QML_EXPORT QQmlContextData
+{
+public:
+ static QQmlRefPointer<QQmlContextData> createRefCounted(
+ const QQmlRefPointer<QQmlContextData> &parent)
+ {
+ return QQmlRefPointer<QQmlContextData>(new QQmlContextData(RefCounted, nullptr, parent),
+ QQmlRefPointer<QQmlContextData>::Adopt);
+ }
+
+ // Owned by the parent. When the parent is reset to nullptr, it will be deref'd.
+ static QQmlRefPointer<QQmlContextData> createChild(
+ const QQmlRefPointer<QQmlContextData> &parent)
+ {
+ Q_ASSERT(!parent.isNull());
+ return QQmlRefPointer<QQmlContextData>(new QQmlContextData(OwnedByParent, nullptr, parent));
+ }
+
+ void addref() const { ++m_refCount; }
+ void release() const { if (--m_refCount == 0) delete this; }
+ int count() const { return m_refCount; }
+ int refCount() const { return m_refCount; }
+
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> typeCompilationUnit() const
+ {
+ return m_typeCompilationUnit;
+ }
+ void initFromTypeCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ int subComponentIndex);
+
+ static QQmlRefPointer<QQmlContextData> get(QQmlContext *context) {
+ return QQmlContextPrivate::get(context)->m_data;
+ }
+
+ void emitDestruction();
+ void clearContext();
+ void clearContextRecursively();
+ void invalidate();
+
+ bool isValid() const
+ {
+ return m_engine && (!m_isInternal || !m_contextObject
+ || !QObjectPrivate::get(m_contextObject)->wasDeleted);
+ }
+
+ bool isInternal() const { return m_isInternal; }
+ void setInternal(bool isInternal) { m_isInternal = isInternal; }
+
+ bool isJSContext() const { return m_isJSContext; }
+ void setJSContext(bool isJSContext) { m_isJSContext = isJSContext; }
+
+ bool isPragmaLibraryContext() const { return m_isPragmaLibraryContext; }
+ void setPragmaLibraryContext(bool library) { m_isPragmaLibraryContext = library; }
+
+ QQmlRefPointer<QQmlContextData> parent() const { return m_parent; }
+ void clearParent()
+ {
+ if (!m_parent)
+ return;
+
+ m_parent = nullptr;
+ if (m_ownedByParent) {
+ m_ownedByParent = false;
+ release();
+ }
+ }
+
+ void refreshExpressions();
+
+ void addOwnedObject(QQmlData *ownedObject);
+ QQmlData *ownedObjects() const { return m_ownedObjects; }
+ void setOwnedObjects(QQmlData *ownedObjects) { m_ownedObjects = ownedObjects; }
+
+ enum QmlObjectKind {
+ OrdinaryObject,
+ DocumentRoot,
+ };
+ void installContext(QQmlData *ddata, QmlObjectKind kind);
+
+ QUrl resolvedUrl(const QUrl &) const;
+
+ // My containing QQmlContext. If isInternal is true this owns publicContext.
+ // If internal is false publicContext owns this.
+ QQmlContext *asQQmlContext()
+ {
+ if (!m_publicContext)
+ m_publicContext = new QQmlContext(*new QQmlContextPrivate(this));
+ return m_publicContext;
+ }
+
+ QQmlContextPrivate *asQQmlContextPrivate()
+ {
+ return QQmlContextPrivate::get(asQQmlContext());
+ }
+
+ QObject *contextObject() const { return m_contextObject; }
+ void setContextObject(QObject *contextObject) { m_contextObject = contextObject; }
+
+ template<typename HandleSelf, typename HandleLinked>
+ void deepClearContextObject(
+ QObject *contextObject, HandleSelf &&handleSelf, HandleLinked &&handleLinked) {
+ for (QQmlContextData *lc = m_linkedContext.data(); lc; lc = lc->m_linkedContext.data()) {
+ handleLinked(lc);
+ if (lc->m_contextObject == contextObject)
+ lc->m_contextObject = nullptr;
+ }
+
+ handleSelf(this);
+ if (m_contextObject == contextObject)
+ m_contextObject = nullptr;
+ }
+
+ void deepClearContextObject(QObject *contextObject)
+ {
+ deepClearContextObject(
+ contextObject,
+ [](QQmlContextData *self) { self->emitDestruction(); },
+ [](QQmlContextData *){});
+ }
+
+ QQmlEngine *engine() const { return m_engine; }
+ void setEngine(QQmlEngine *engine) { m_engine = engine; }
+
+ QQmlContext *publicContext() const { return m_publicContext; }
+ void clearPublicContext()
+ {
+ if (!m_publicContext)
+ return;
+
+ m_publicContext = nullptr;
+ if (m_ownedByPublicContext) {
+ m_ownedByPublicContext = false;
+ release();
+ }
+ }
+
+ int propertyIndex(const QString &name) const
+ {
+ ensurePropertyNames();
+ return m_propertyNameCache.value(name);
+ }
+
+ int propertyIndex(QV4::String *name) const
+ {
+ ensurePropertyNames();
+ return m_propertyNameCache.value(name);
+ }
+
+ QString propertyName(int index) const
+ {
+ ensurePropertyNames();
+ return m_propertyNameCache.findId(index);
+ }
+
+ void addPropertyNameAndIndex(const QString &name, int index)
+ {
+ Q_ASSERT(!m_propertyNameCache.isEmpty());
+ m_propertyNameCache.add(name, index);
+ }
+
+ void setExpressions(QQmlJavaScriptExpression *expressions) { m_expressions = expressions; }
+ QQmlJavaScriptExpression *takeExpressions()
+ {
+ QQmlJavaScriptExpression *expressions = m_expressions;
+ m_expressions = nullptr;
+ return expressions;
+ }
+
+ void setChildContexts(const QQmlRefPointer<QQmlContextData> &childContexts)
+ {
+ m_childContexts = childContexts.data();
+ }
+ QQmlRefPointer<QQmlContextData> childContexts() const { return m_childContexts; }
+ QQmlRefPointer<QQmlContextData> takeChildContexts()
+ {
+ QQmlRefPointer<QQmlContextData> childContexts = m_childContexts;
+ m_childContexts = nullptr;
+ return childContexts;
+ }
+ QQmlRefPointer<QQmlContextData> nextChild() const { return m_nextChild; }
+
+ int numIdValues() const { return m_idValueCount; }
+ void setIdValue(int index, QObject *idValue);
+ bool isIdValueSet(int index) const { return m_idValues[index].wasSet(); }
+ QQmlNotifier *idValueBindings(int index) const { return m_idValues[index].bindings(); }
+ QObject *idValue(int index) const { return m_idValues[index].data(); }
+
+ // Return the outermost id for obj, if any.
+ QString findObjectId(const QObject *obj) const;
+
+ // url() and urlString() prefer the CU's URL over explicitly set baseUrls. They
+ // don't search the context hierarchy.
+ // baseUrl() and baseUrlString() search the context hierarchy and prefer explicit
+ // base URLs over CU Urls.
+
+ QUrl url() const;
+ QString urlString() const;
+
+ void setBaseUrlString(const QString &baseUrlString) { m_baseUrlString = baseUrlString; }
+ QString baseUrlString() const
+ {
+ for (const QQmlContextData *data = this; data; data = data->m_parent) {
+ if (!data->m_baseUrlString.isEmpty())
+ return data->m_baseUrlString;
+ if (data->m_typeCompilationUnit)
+ return data->m_typeCompilationUnit->finalUrlString();
+ }
+ return QString();
+ }
+
+ void setBaseUrl(const QUrl &baseUrl) { m_baseUrl = baseUrl; }
+ QUrl baseUrl() const
+ {
+ for (const QQmlContextData *data = this; data; data = data->m_parent) {
+ if (!data->m_baseUrl.isEmpty())
+ return data->m_baseUrl;
+ if (data->m_typeCompilationUnit)
+ return data->m_typeCompilationUnit->finalUrl();
+ }
+ return QUrl();
+ }
+
+ QQmlRefPointer<QQmlTypeNameCache> imports() const { return m_imports; }
+ void setImports(const QQmlRefPointer<QQmlTypeNameCache> &imports) { m_imports = imports; }
+
+ QQmlIncubatorPrivate *incubator() const { return m_hasExtraObject ? nullptr : m_incubator; }
+ void setIncubator(QQmlIncubatorPrivate *incubator)
+ {
+ Q_ASSERT(!m_hasExtraObject || m_extraObject == nullptr);
+ m_hasExtraObject = false;
+ m_incubator = incubator;
+ }
+
+ QObject *extraObject() const { return m_hasExtraObject ? m_extraObject : nullptr; }
+ void setExtraObject(QObject *extraObject)
+ {
+ Q_ASSERT(m_hasExtraObject || m_incubator == nullptr);
+ m_hasExtraObject = true;
+ m_extraObject = extraObject;
+ }
+
+ bool isRootObjectInCreation() const { return m_isRootObjectInCreation; }
+ void setRootObjectInCreation(bool rootInCreation) { m_isRootObjectInCreation = rootInCreation; }
+
+ QV4::PersistentValue importedScripts() const { return m_importedScripts; }
+ void setImportedScripts(const QV4::PersistentValue &scripts) { m_importedScripts = scripts; }
+
+ QQmlRefPointer<QQmlContextData> linkedContext() const { return m_linkedContext; }
+ void setLinkedContext(const QQmlRefPointer<QQmlContextData> &context) { m_linkedContext = context; }
+
+ bool hasUnresolvedNames() const { return m_unresolvedNames; }
+ void setUnresolvedNames(bool hasUnresolvedNames) { m_unresolvedNames = hasUnresolvedNames; }
+
+ QQmlComponentAttached *componentAttacheds() const { return m_componentAttacheds; }
+ void addComponentAttached(QQmlComponentAttached *attached);
+
+ void addExpression(QQmlJavaScriptExpression *expression);
+
+ bool valueTypesAreAddressable() const {
+ return m_typeCompilationUnit && m_typeCompilationUnit->valueTypesAreAddressable();
+ }
+
+private:
+ friend class QQmlGuardedContextData;
+ friend class QQmlContextPrivate;
+
+ enum Ownership {
+ RefCounted,
+ OwnedByParent,
+ OwnedByPublicContext
+ };
+
+ // id guards
+ struct ContextGuard : public QQmlGuard<QObject>
+ {
+ enum Tag {
+ NoTag,
+ ObjectWasSet
+ };
+
+ inline ContextGuard() : QQmlGuard<QObject>(&ContextGuard::objectDestroyedImpl, nullptr), m_context(nullptr) {}
+ inline ContextGuard &operator=(QObject *obj);
+
+ inline bool wasSet() const;
+
+ QQmlNotifier *bindings() { return &m_bindings; }
+ void setContext(const QQmlRefPointer<QQmlContextData> &context)
+ {
+ m_context = context.data();
+ }
+
+ private:
+ inline static void objectDestroyedImpl(QQmlGuardImpl *);
+ // Not refcounted, as it always belongs to the QQmlContextData.
+ QTaggedPointer<QQmlContextData, Tag> m_context;
+ QQmlNotifier m_bindings;
+ };
+
+ // It's OK to pass a half-created publicContext here. We will not dereference it during
+ // construction.
+ QQmlContextData(
+ Ownership ownership, QQmlContext *publicContext,
+ const QQmlRefPointer<QQmlContextData> &parent, QQmlEngine *engine = nullptr)
+ : m_parent(parent.data()),
+ m_engine(engine ? engine : (parent.isNull() ? nullptr : parent->engine())),
+ m_isInternal(false), m_isJSContext(false), m_isPragmaLibraryContext(false),
+ m_unresolvedNames(false), m_hasEmittedDestruction(false), m_isRootObjectInCreation(false),
+ m_ownedByParent(ownership == OwnedByParent),
+ m_ownedByPublicContext(ownership == OwnedByPublicContext), m_hasExtraObject(false),
+ m_dummy(0), m_publicContext(publicContext), m_incubator(nullptr)
+ {
+ Q_ASSERT(!m_ownedByParent || !m_ownedByPublicContext);
+ if (!m_parent)
+ return;
+
+ m_nextChild = m_parent->m_childContexts;
+ if (m_nextChild)
+ m_nextChild->m_prevChild = &m_nextChild;
+ m_prevChild = &m_parent->m_childContexts;
+ m_parent->m_childContexts = this;
+ }
+
+ ~QQmlContextData();
+
+ bool hasExpressionsToRun(bool isGlobalRefresh) const
+ {
+ return m_expressions && (!isGlobalRefresh || m_unresolvedNames);
+ }
+
+ void refreshExpressionsRecursive(bool isGlobal);
+ void refreshExpressionsRecursive(QQmlJavaScriptExpression *);
+ void initPropertyNames() const;
+
+ void ensurePropertyNames() const
+ {
+ if (m_propertyNameCache.isEmpty())
+ initPropertyNames();
+ Q_ASSERT(!m_propertyNameCache.isEmpty());
+ }
+
+ // My parent context and engine
+ QQmlContextData *m_parent = nullptr;
+ QQmlEngine *m_engine = nullptr;
+
+ mutable quint32 m_refCount = 1;
+ quint32 m_isInternal:1;
+ quint32 m_isJSContext:1;
+ quint32 m_isPragmaLibraryContext:1;
+ quint32 m_unresolvedNames:1; // True if expressions in this context failed to resolve a toplevel name
+ quint32 m_hasEmittedDestruction:1;
+ quint32 m_isRootObjectInCreation:1;
+ quint32 m_ownedByParent:1;
+ quint32 m_ownedByPublicContext:1;
+ quint32 m_hasExtraObject:1; // used in QQmlDelegateModelItem::dataForObject to find the corresponding QQmlDelegateModelItem of an object
+ Q_DECL_UNUSED_MEMBER quint32 m_dummy:23;
+ QQmlContext *m_publicContext = nullptr;
+
+ union {
+ // The incubator that is constructing this context if any
+ QQmlIncubatorPrivate *m_incubator;
+ // a pointer to extra data, currently only used in QQmlDelegateModel
+ QObject *m_extraObject;
+ };
+
+ // Compilation unit for contexts that belong to a compiled type.
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> m_typeCompilationUnit;
+
+ // object index in CompiledData::Unit to component that created this context
+ int m_componentObjectIndex = -1;
+
+ // flag indicates whether the context owns the cache (after mutation) or not.
+ mutable QV4::IdentifierHash m_propertyNameCache;
+
+ // Context object
+ QObject *m_contextObject = nullptr;
+
+ // Any script blocks that exist on this context
+ QV4::PersistentValue m_importedScripts; // This is a JS Array
+
+ QUrl m_baseUrl;
+ QString m_baseUrlString;
+
+ // List of imports that apply to this context
+ QQmlRefPointer<QQmlTypeNameCache> m_imports;
+
+ // My children, not refcounted as that would create cyclic references
+ QQmlContextData *m_childContexts = nullptr;
+
+ // My peers in parent's childContexts list; not refcounted
+ QQmlContextData *m_nextChild = nullptr;
+ QQmlContextData **m_prevChild = nullptr;
+
+ // Expressions that use this context
+ QQmlJavaScriptExpression *m_expressions = nullptr;
+
+ // Doubly-linked list of objects that are owned by this context
+ QQmlData *m_ownedObjects = nullptr;
+
+ // Doubly-linked list of context guards (XXX merge with contextObjects)
+ QQmlGuardedContextData *m_contextGuards = nullptr;
+
+ ContextGuard *m_idValues = nullptr;
+ int m_idValueCount = 0;
+
+ // Linked contexts. this owns linkedContext.
+ QQmlRefPointer<QQmlContextData> m_linkedContext;
+
+ // Linked list of uses of the Component attached property in this context
+ QQmlComponentAttached *m_componentAttacheds = nullptr;
+};
+
+QQmlContextData::ContextGuard &QQmlContextData::ContextGuard::operator=(QObject *obj)
+{
+ QQmlGuard<QObject>::operator=(obj);
+ m_context.setTag(ObjectWasSet);
+ m_bindings.notify(); // For alias connections
+ return *this;
+}
+
+ void QQmlContextData::ContextGuard::objectDestroyedImpl(QQmlGuardImpl *impl)
+{
+ auto This = static_cast<QQmlContextData::ContextGuard *>(impl);
+ if (QObject *contextObject = This->m_context->contextObject()) {
+ if (!QObjectPrivate::get(contextObject)->wasDeleted)
+ This->m_bindings.notify();
+ }
+}
+
+bool QQmlContextData::ContextGuard::wasSet() const
+{
+ return m_context.tag() == ObjectWasSet;
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLCONTEXTDATA_P_H
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index a5f34dafdf..bd632d25a6 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -1,45 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qml/qqmlpropertyvalidator_p.h"
#include "qqmlcustomparser_p.h"
#include <private/qv4compileddata_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
#include <QtCore/qdebug.h>
@@ -100,20 +66,14 @@ void QQmlCustomParser::clearErrors()
*/
void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description)
{
- QQmlJS::DiagnosticMessage error;
- error.line = location.line;
- error.column = location.column;
- error.message = description;
+ QQmlError error;
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
+ error.setDescription(description);
exceptions << error;
}
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
-
/*!
If \a script is a simple enumeration expression (eg. Text.AlignLeft),
returns the integer equivalent (eg. 1), and sets \a ok to true.
@@ -122,7 +82,7 @@ struct StaticQtMetaObject : public QObject
A valid \a ok must be provided, or the function will assert.
*/
-int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
+int QQmlCustomParser::evaluateEnum(const QString &script, bool *ok) const
{
Q_ASSERT_X(ok, "QQmlCustomParser::evaluateEnum", "ok must not be a null pointer");
*ok = false;
@@ -131,43 +91,104 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
// * <TypeName>.<EnumValue>
// * <TypeName>.<ScopedEnumName>.<EnumValue>
- int dot = script.indexOf('.');
- if (dot == -1 || dot == script.length()-1)
+ auto nextDot = [&](int dot) {
+ const int nextDot = script.indexOf(u'.', dot + 1);
+ return (nextDot == script.size() - 1) ? -1 : nextDot;
+ };
+
+ int dot = nextDot(-1);
+ if (dot == -1)
return -1;
- QString scope = QString::fromUtf8(script.left(dot));
+ const QString scope = script.left(dot);
if (scope != QLatin1String("Qt")) {
- if (imports.isNull())
+ if (!engine || imports.isNull())
return -1;
QQmlType type;
+ QQmlTypeLoader *typeLoader = QQmlTypeLoader::get(engine);
+ Q_ASSERT(typeLoader);
+
if (imports.isT1()) {
- imports.asT1()->resolveType(scope, &type, nullptr, nullptr, nullptr);
+ QQmlImportNamespace *ns = nullptr;
+
+ // Pass &recursionDetected to resolveType because that implicitly allows recursion.
+ // This way we can find the QQmlType of the document we're currently validating.
+ bool recursionDetected = false;
+
+ if (!imports.asT1()->resolveType(
+ typeLoader, scope, &type, nullptr, &ns, nullptr,
+ QQmlType::AnyRegistrationType, &recursionDetected)) {
+ return -1;
+ }
+
+ if (!type.isValid() && ns != nullptr) {
+ dot = nextDot(dot);
+ if (dot == -1 || !imports.asT1()->resolveType(
+ typeLoader, script.left(dot), &type, nullptr, nullptr, nullptr,
+ QQmlType::AnyRegistrationType, &recursionDetected)) {
+ return -1;
+ }
+ }
} else {
- QQmlTypeNameCache::Result result = imports.asT2()->query(scope);
- if (result.isValid())
+ // Allow recursion so that we can find enums from the same document.
+ const QQmlTypeNameCache::Result result
+ = imports.asT2()->query<QQmlImport::AllowRecursion>(scope, typeLoader);
+ if (result.isValid()) {
type = result.type;
+ } else if (result.importNamespace) {
+ dot = nextDot(dot);
+ if (dot != -1) {
+ type = imports.asT2()->query<QQmlImport::AllowRecursion>(
+ script.left(dot), typeLoader).type;
+ }
+ }
}
if (!type.isValid())
return -1;
- int dot2 = script.indexOf('.', dot+1);
- const bool dot2Valid = dot2 != -1 && dot2 != script.length()-1;
- QByteArray enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1);
- QByteArray scopedEnumName = (dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QByteArray());
+ const int dot2 = nextDot(dot);
+ const bool dot2Valid = (dot2 != -1);
+ const QString enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1);
+ const QString scopedEnumName = dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QString();
+
+ // If we're currently validating the same document, we won't be able to find its enums using
+ // the QQmlType. However, we do have the property cache already, and that one contains the
+ // enums.
+ const QUrl documentUrl = validator ? validator->documentSourceUrl() : QUrl();
+ if (documentUrl.isValid() && documentUrl == type.sourceUrl()) {
+ Q_ASSERT(validator);
+ const QQmlPropertyCache::ConstPtr rootCache = validator->rootPropertyCache();
+ const int count = rootCache->qmlEnumCount();
+ for (int ii = 0; ii < count; ++ii) {
+ const QQmlEnumData *enumData = rootCache->qmlEnum(ii);
+ if (!scopedEnumName.isEmpty() && scopedEnumName != enumData->name)
+ continue;
+
+ for (int jj = 0; jj < enumData->values.size(); ++jj) {
+ const QQmlEnumValue value = enumData->values.at(jj);
+ if (value.namedValue == enumValue) {
+ *ok = true;
+ return value.value;
+ }
+ }
+ }
+ return -1;
+ }
+
if (!scopedEnumName.isEmpty())
return type.scopedEnumValue(engine, scopedEnumName, enumValue, ok);
else
- return type.enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok);
+ return type.enumValue(engine, enumValue, ok);
}
- QByteArray enumValue = script.mid(dot + 1);
- const QMetaObject *mo = StaticQtMetaObject::get();
+ const QString enumValue = script.mid(dot + 1);
+ const QMetaObject *mo = &Qt::staticMetaObject;
int i = mo->enumeratorCount();
while (i--) {
- int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
+ int v = mo->enumerator(i).keyToValue(enumValue.toUtf8().constData(), ok);
if (*ok)
return v;
}
@@ -180,10 +201,10 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
*/
const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const
{
- if (!imports.isT1())
+ if (!engine || !imports.isT1())
return nullptr;
QQmlType qmltype;
- if (!imports.asT1()->resolveType(name, &qmltype, nullptr, nullptr, nullptr))
+ if (!imports.asT1()->resolveType(QQmlTypeLoader::get(engine), name, &qmltype, nullptr, nullptr))
return nullptr;
return qmltype.metaObject();
}
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index df8cbc9072..4a3628fdb1 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCUSTOMPARSER_H
#define QQMLCUSTOMPARSER_H
@@ -51,19 +15,18 @@
// We mean it.
//
-#include "qqmlerror.h"
-#include "qqmlbinding_p.h"
+#include <QtQml/qqmlerror.h>
+#include <QtQml/private/qqmlbinding_p.h>
#include <private/qv4compileddata_p.h>
#include <QtCore/qbytearray.h>
-#include <QtCore/qxmlstream.h>
QT_BEGIN_NAMESPACE
class QQmlPropertyValidator;
class QQmlEnginePrivate;
-class Q_QML_PRIVATE_EXPORT QQmlCustomParser
+class Q_QML_EXPORT QQmlCustomParser
{
public:
enum Flag {
@@ -83,7 +46,7 @@ public:
virtual void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0;
virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0;
- QVector<QQmlJS::DiagnosticMessage> errors() const { return exceptions; }
+ QVector<QQmlError> errors() const { return exceptions; }
protected:
void error(const QV4::CompiledData::Binding *binding, const QString& description)
@@ -92,12 +55,12 @@ protected:
{ error(object->location, description); }
void error(const QV4::CompiledData::Location &location, const QString& description);
- int evaluateEnum(const QByteArray&, bool *ok) const;
+ int evaluateEnum(const QString &, bool *ok) const;
const QMetaObject *resolveType(const QString&) const;
private:
- QVector<QQmlJS::DiagnosticMessage> exceptions;
+ QVector<QQmlError> exceptions;
QQmlEnginePrivate *engine;
const QQmlPropertyValidator *validator;
Flags m_flags;
@@ -107,11 +70,6 @@ private:
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlCustomParser::Flags)
-#if 0
-#define QML_REGISTER_CUSTOM_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE, CUSTOMTYPE) \
- qmlRegisterCustomType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE, new CUSTOMTYPE)
-#endif
-
QT_END_NAMESPACE
#endif
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 299476f5c8..7055ca94e6 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDATA_P_H
#define QQMLDATA_P_H
@@ -57,6 +21,7 @@
#include <private/qv4value_p.h>
#include <private/qv4persistent_p.h>
#include <private/qqmlrefcount_p.h>
+#include <private/qqmlpropertycache_p.h>
#include <qqmlprivate.h>
#include <qjsengine.h>
#include <qvector.h>
@@ -74,6 +39,7 @@ class QQmlContextData;
class QQmlNotifier;
class QQmlDataExtended;
class QQmlNotifierEndpoint;
+class QQmlPropertyObserver;
namespace QV4 {
class ExecutableCompilationUnit;
@@ -82,42 +48,16 @@ struct Binding;
}
}
-// This is declared here because QQmlData below needs it and this file
-// in turn is included from qqmlcontext_p.h.
-class QQmlContextData;
-class Q_QML_PRIVATE_EXPORT QQmlContextDataRef
-{
-public:
- inline QQmlContextDataRef();
- inline QQmlContextDataRef(QQmlContextData *);
- inline QQmlContextDataRef(const QQmlContextDataRef &);
- inline ~QQmlContextDataRef();
-
- inline QQmlContextData *contextData() const;
- inline void setContextData(QQmlContextData *);
-
- inline bool isNull() const { return !m_contextData; }
-
- inline operator QQmlContextData*() const { return m_contextData; }
- inline QQmlContextData* operator->() const { return m_contextData; }
- inline QQmlContextDataRef &operator=(QQmlContextData *d);
- inline QQmlContextDataRef &operator=(const QQmlContextDataRef &other);
-
-private:
-
- inline void clear();
-
- QQmlContextData *m_contextData;
-};
-
// This class is structured in such a way, that simply zero'ing it is the
// default state for elemental object allocations. This is crucial in the
// workings of the QQmlInstruction::CreateSimpleObject instruction.
// Don't change anything here without first considering that case!
-class Q_QML_PRIVATE_EXPORT QQmlData : public QAbstractDeclarativeData
+class Q_QML_EXPORT QQmlData : public QAbstractDeclarativeData
{
public:
- QQmlData();
+ enum Ownership { DoesNotOwnMemory, OwnsMemory };
+
+ QQmlData(Ownership ownership);
~QQmlData();
static inline void init() {
@@ -125,7 +65,6 @@ public:
if (!initialized) {
initialized = true;
QAbstractDeclarativeData::destroyed = destroyed;
- QAbstractDeclarativeData::parentChanged = parentChanged;
QAbstractDeclarativeData::signalEmitted = signalEmitted;
QAbstractDeclarativeData::receivers = receivers;
QAbstractDeclarativeData::isSignalConnected = isSignalConnected;
@@ -133,33 +72,42 @@ public:
}
static void destroyed(QAbstractDeclarativeData *, QObject *);
- static void parentChanged(QAbstractDeclarativeData *, QObject *, QObject *);
static void signalEmitted(QAbstractDeclarativeData *, QObject *, int, void **);
static int receivers(QAbstractDeclarativeData *, const QObject *, int);
static bool isSignalConnected(QAbstractDeclarativeData *, const QObject *, int);
void destroyed(QObject *);
- void parentChanged(QObject *, QObject *);
void setImplicitDestructible() {
if (!explicitIndestructibleSet) indestructible = false;
}
- quint32 ownedByQml1:1; // This bit is shared with QML1's QDeclarativeData.
+ // If ownMemomry is true, the QQmlData was normally allocated. Otherwise it was allocated
+ // with placement new and QQmlData::destroyed is not allowed to free the memory
quint32 ownMemory:1;
+ // indestructible is set if and only if the object has CppOwnership
+ // This can be explicitly set with QJSEngine::setObjectOwnership
+ // Top level objects generally have CppOwnership (see QQmlcCmponentprivate::beginCreate),
+ // unless created by special methods like the QML component.createObject() function
quint32 indestructible:1;
+ // indestructible was explicitly set with setObjectOwnership
+ // or the object is a top-level object
quint32 explicitIndestructibleSet:1;
+ // set when one QObject has been wrapped into QObjectWrapper in multiple engines
+ // at the same time - a rather rare case
quint32 hasTaintedV4Object:1;
quint32 isQueuedForDeletion:1;
/*
* rootObjectInCreation should be true only when creating top level CPP and QML objects,
- * v8 GC will check this flag, only deletes the objects when rootObjectInCreation is false.
+ * v4 GC will check this flag, only deletes the objects when rootObjectInCreation is false.
*/
quint32 rootObjectInCreation:1;
+ // set when at least one of the object's properties is intercepted
quint32 hasInterceptorMetaObject:1;
quint32 hasVMEMetaObject:1;
- quint32 parentFrozen:1;
- quint32 dummy:6;
+ // If we have another wrapper for a const QObject * in the multiply wrapped QObjects.
+ quint32 hasConstWrapper: 1;
+ quint32 dummy:7;
// When bindingBitsSize < sizeof(ptr), we store the binding bit flags inside
// bindingBitsValue. When we need more than sizeof(ptr) bits, we allocated
@@ -176,37 +124,38 @@ public:
};
struct NotifyList {
- quint64 connectionMask;
-
- quint16 maximumTodoIndex;
- quint16 notifiesSize;
-
- QQmlNotifierEndpoint *todo;
- QQmlNotifierEndpoint**notifies;
+ QAtomicInteger<quint64> connectionMask;
+ QQmlNotifierEndpoint *todo = nullptr;
+ QQmlNotifierEndpoint**notifies = nullptr;
+ quint16 maximumTodoIndex = 0;
+ quint16 notifiesSize = 0;
void layout();
private:
void layout(QQmlNotifierEndpoint*);
};
- NotifyList *notifyList;
+ QAtomicPointer<NotifyList> notifyList;
- inline QQmlNotifierEndpoint *notify(int index);
+ inline QQmlNotifierEndpoint *notify(int index) const;
void addNotify(int index, QQmlNotifierEndpoint *);
int endpointCount(int index);
bool signalHasEndpoint(int index) const;
- void disconnectNotifiers();
- // The context that created the C++ object
+ enum class DeleteNotifyList { Yes, No };
+ void disconnectNotifiers(DeleteNotifyList doDelete);
+
+ // The context that created the C++ object; not refcounted to prevent cycles
QQmlContextData *context = nullptr;
- // The outermost context in which this object lives
+ // The outermost context in which this object lives; not refcounted to prevent cycles
QQmlContextData *outerContext = nullptr;
- QQmlContextDataRef ownContext;
+ QQmlRefPointer<QQmlContextData> ownContext;
- QQmlAbstractBinding *bindings;
- QQmlBoundSignal *signalHandlers;
+ QQmlAbstractBinding *bindings = nullptr;
+ QQmlBoundSignal *signalHandlers = nullptr;
+ std::vector<QQmlPropertyObserver> propertyObservers;
// Linked list for QQmlContext::contextObjects
- QQmlData *nextContextObject;
- QQmlData**prevContextObject;
+ QQmlData *nextContextObject = nullptr;
+ QQmlData**prevContextObject = nullptr;
inline bool hasBindingBit(int) const;
inline void setBindingBit(QObject *obj, int);
@@ -216,34 +165,38 @@ public:
inline void setPendingBindingBit(QObject *obj, int);
inline void clearPendingBindingBit(int);
- quint16 lineNumber;
- quint16 columnNumber;
+ quint16 lineNumber = 0;
+ quint16 columnNumber = 0;
- quint32 jsEngineId; // id of the engine that created the jsWrapper
+ quint32 jsEngineId = 0; // id of the engine that created the jsWrapper
struct DeferredData {
DeferredData();
~DeferredData();
unsigned int deferredIdx;
QMultiHash<int, const QV4::CompiledData::Binding *> bindings;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;//Not always the same as the other compilation unit
- QQmlContextData *context;//Could be either context or outerContext
+
+ // Not always the same as the other compilation unit
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
+
+ // Could be either context or outerContext
+ QQmlRefPointer<QQmlContextData> context;
Q_DISABLE_COPY(DeferredData);
};
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
QVector<DeferredData *> deferredData;
- void deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, QQmlContextData *);
+ void deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &,
+ const QQmlRefPointer<QQmlContextData> &);
void releaseDeferredData();
QV4::WeakValue jsWrapper;
- QQmlPropertyCache *propertyCache;
+ QQmlPropertyCache::ConstPtr propertyCache;
- QQmlGuardImpl *guards;
+ QQmlGuardImpl *guards = nullptr;
- static QQmlData *get(const QObject *object, bool create = false) {
- QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
+ static QQmlData *get(QObjectPrivate *priv, bool create) {
// If QObjectData::isDeletingChildren is set then access to QObjectPrivate::declarativeData has
// to be avoided because QObjectPrivate::currentChildBeingDeleted is in use.
if (priv->isDeletingChildren || priv->wasDeleted) {
@@ -258,6 +211,25 @@ public:
}
}
+ static QQmlData *get(const QObjectPrivate *priv) {
+ // If QObjectData::isDeletingChildren is set then access to QObjectPrivate::declarativeData has
+ // to be avoided because QObjectPrivate::currentChildBeingDeleted is in use.
+ if (priv->isDeletingChildren || priv->wasDeleted)
+ return nullptr;
+ if (priv->declarativeData)
+ return static_cast<QQmlData *>(priv->declarativeData);
+ return nullptr;
+ }
+
+ static QQmlData *get(QObject *object, bool create) {
+ return QQmlData::get(QObjectPrivate::get(object), create);
+ }
+
+ static QQmlData *get(const QObject *object) {
+ return QQmlData::get(QObjectPrivate::get(object));
+
+ }
+
static bool keepAliveDuringGarbageCollection(const QObject *object) {
QQmlData *ddata = get(object);
if (!ddata || ddata->indestructible || ddata->rootObjectInCreation)
@@ -269,19 +241,20 @@ public:
QHash<QQmlAttachedPropertiesFunc, QObject *> *attachedProperties() const;
static inline bool wasDeleted(const QObject *);
+ static inline bool wasDeleted(const QObjectPrivate *);
static void markAsDeleted(QObject *);
static void setQueuedForDeletion(QObject *);
- static inline void flushPendingBinding(QObject *, QQmlPropertyIndex propertyIndex);
+ static inline void flushPendingBinding(QObject *object, int coreIndex);
+ void flushPendingBinding(int coreIndex);
- static QQmlPropertyCache *ensurePropertyCache(QJSEngine *engine, QObject *object)
+ static QQmlPropertyCache::ConstPtr ensurePropertyCache(QObject *object)
{
- Q_ASSERT(engine);
QQmlData *ddata = QQmlData::get(object, /*create*/true);
if (Q_LIKELY(ddata->propertyCache))
return ddata->propertyCache;
- return createPropertyCache(engine, object);
+ return createPropertyCache(object);
}
Q_ALWAYS_INLINE static uint offsetForBit(int bit) { return static_cast<uint>(bit) / BitsPerType; }
@@ -289,12 +262,10 @@ public:
private:
// For attachedProperties
- mutable QQmlDataExtended *extendedData;
+ mutable QQmlDataExtended *extendedData = nullptr;
Q_NEVER_INLINE static QQmlData *createQQmlData(QObjectPrivate *priv);
- Q_NEVER_INLINE static QQmlPropertyCache *createPropertyCache(QJSEngine *engine, QObject *object);
-
- void flushPendingBindingImpl(QQmlPropertyIndex index);
+ Q_NEVER_INLINE static QQmlPropertyCache::ConstPtr createPropertyCache(QObject *object);
Q_ALWAYS_INLINE bool hasBitSet(int bit) const
{
@@ -326,39 +297,52 @@ private:
Q_NEVER_INLINE BindingBitsType *growBits(QObject *obj, int bit);
- Q_DISABLE_COPY(QQmlData);
+ Q_DISABLE_COPY_MOVE(QQmlData);
};
+bool QQmlData::wasDeleted(const QObjectPrivate *priv)
+{
+ if (!priv || priv->wasDeleted || priv->isDeletingChildren)
+ return true;
+
+ const QQmlData *ddata = QQmlData::get(priv);
+ return ddata && ddata->isQueuedForDeletion;
+}
+
bool QQmlData::wasDeleted(const QObject *object)
{
if (!object)
return true;
const QObjectPrivate *priv = QObjectPrivate::get(object);
- if (!priv || priv->wasDeleted)
- return true;
+ return QQmlData::wasDeleted(priv);
+}
- const QQmlData *ddata = QQmlData::get(object);
- return ddata && ddata->isQueuedForDeletion;
+inline bool isIndexInConnectionMask(quint64 connectionMask, int index)
+{
+ return connectionMask & (1ULL << quint64(index % 64));
}
-QQmlNotifierEndpoint *QQmlData::notify(int index)
+QQmlNotifierEndpoint *QQmlData::notify(int index) const
{
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
+
Q_ASSERT(index <= 0xFFFF);
- if (!notifyList || !(notifyList->connectionMask & (1ULL << quint64(index % 64)))) {
+ NotifyList *list = notifyList.loadRelaxed();
+ if (!list || !isIndexInConnectionMask(list->connectionMask.loadRelaxed(), index))
return nullptr;
- } else if (index < notifyList->notifiesSize) {
- return notifyList->notifies[index];
- } else if (index <= notifyList->maximumTodoIndex) {
- notifyList->layout();
- }
- if (index < notifyList->notifiesSize) {
- return notifyList->notifies[index];
- } else {
- return nullptr;
+ if (index < list->notifiesSize)
+ return list->notifies[index];
+
+ if (index <= list->maximumTodoIndex) {
+ list->layout();
+ if (index < list->notifiesSize)
+ return list->notifies[index];
}
+
+ return nullptr;
}
/*
@@ -367,7 +351,19 @@ QQmlNotifierEndpoint *QQmlData::notify(int index)
*/
inline bool QQmlData::signalHasEndpoint(int index) const
{
- return notifyList && (notifyList->connectionMask & (1ULL << quint64(index % 64)));
+ // This can be called from any thread.
+ // We still use relaxed semantics. If we're on a thread different from the "home" thread
+ // of the QQmlData, two interesting things might happen:
+ //
+ // 1. The list might go away while we hold it. In that case we are dealing with an object whose
+ // QObject dtor is being executed concurrently. This is UB already without the notify lists.
+ // Therefore, we don't need to consider it.
+ // 2. The connectionMask may be amended or zeroed while we are looking at it. In that case
+ // we "misreport" the endpoint. Since ordering of events across threads is inherently
+ // nondeterministic, either result is correct in that case. We can accept it.
+
+ NotifyList *list = notifyList.loadRelaxed();
+ return list && isIndexInConnectionMask(list->connectionMask.loadRelaxed(), index);
}
bool QQmlData::hasBindingBit(int coreIndex) const
@@ -414,11 +410,11 @@ void QQmlData::clearPendingBindingBit(int coreIndex)
clearBit(coreIndex * 2 + 1);
}
-void QQmlData::flushPendingBinding(QObject *o, QQmlPropertyIndex propertyIndex)
+void QQmlData::flushPendingBinding(QObject *object, int coreIndex)
{
- QQmlData *data = QQmlData::get(o, false);
- if (data && data->hasPendingBindingBit(propertyIndex.coreIndex()))
- data->flushPendingBindingImpl(propertyIndex);
+ QQmlData *data = QQmlData::get(object, false);
+ if (data && data->hasPendingBindingBit(coreIndex))
+ data->flushPendingBinding(coreIndex);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmldatablob.cpp b/src/qml/qml/qqmldatablob.cpp
index 750fc6de50..6b354c337f 100644
--- a/src/qml/qml/qqmldatablob.cpp
+++ b/src/qml/qml/qqmldatablob.cpp
@@ -1,50 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmldatablob_p.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmlprofiler_p.h>
#include <private/qqmltypeloader_p.h>
#include <private/qqmltypeloaderthread_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
#include <QtQml/qqmlengine.h>
+#include <qtqml_tracepoints_p.h>
+
#ifdef DATABLOB_DEBUG
#define ASSERT_CALLBACK() do { if (!m_typeLoader || !m_typeLoader->m_thread->isThisThread()) qFatal("QQmlDataBlob: An API call was made outside a callback"); } while (false)
#else
@@ -53,6 +20,8 @@
DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS);
+Q_DECLARE_LOGGING_CATEGORY(lcCycle)
+
QT_BEGIN_NAMESPACE
/*!
@@ -70,16 +39,14 @@ The QQmlTypeLoader invokes callbacks on the QQmlDataBlob as data becomes availab
This enum describes the status of the data blob.
-\list
-\li Null The blob has not yet been loaded by a QQmlTypeLoader
-\li Loading The blob is loading network data. The QQmlDataBlob::setData() callback has not yet been
- invoked or has not yet returned.
-\li WaitingForDependencies The blob is waiting for dependencies to be done before continuing.
- This status only occurs after the QQmlDataBlob::setData() callback has been made, and when the
- blob has outstanding dependencies.
-\li Complete The blob's data has been loaded and all dependencies are done.
-\li Error An error has been set on this blob.
-\endlist
+\value Null The blob has not yet been loaded by a QQmlTypeLoader
+\value Loading The blob is loading network data. The QQmlDataBlob::setData() callback has
+ not yet been invoked or has not yet returned.
+\value WaitingForDependencies The blob is waiting for dependencies to be done before continuing.
+ This status only occurs after the QQmlDataBlob::setData() callback has been made,
+ and when the blob has outstanding dependencies.
+\value Complete The blob's data has been loaded and all dependencies are done.
+\value Error An error has been set on this blob.
*/
/*!
@@ -87,11 +54,9 @@ This enum describes the status of the data blob.
This enum describes the type of the data blob.
-\list
-\li QmlFile This is a QQmlTypeData
-\li JavaScriptFile This is a QQmlScriptData
-\li QmldirFile This is a QQmlQmldirData
-\endlist
+\value QmlFile This is a QQmlTypeData
+\value JavaScriptFile This is a QQmlScriptData
+\value QmldirFile This is a QQmlQmldirData
*/
/*!
@@ -102,9 +67,8 @@ QQmlDataBlob::QQmlDataBlob(const QUrl &url, Type type, QQmlTypeLoader *manager)
m_inCallback(false), m_isDone(false)
{
//Set here because we need to get the engine from the manager
- if (m_typeLoader->engine() && m_typeLoader->engine()->urlInterceptor())
- m_url = m_typeLoader->engine()->urlInterceptor()->intercept(m_url,
- (QQmlAbstractUrlInterceptor::DataType)m_type);
+ if (const QQmlEngine *qmlEngine = m_typeLoader->engine())
+ m_url = qmlEngine->interceptUrl(m_url, (QQmlAbstractUrlInterceptor::DataType)m_type);
}
/*! \internal */
@@ -287,12 +251,23 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors)
Q_ASSERT(status() != Error);
Q_ASSERT(m_errors.isEmpty());
- m_errors = errors; // Must be set before the m_data fence
+ // m_errors must be set before the m_data fence
+ m_errors.reserve(errors.size());
+ for (const QQmlError &error : errors) {
+ if (error.url().isEmpty()) {
+ QQmlError mutableError = error;
+ mutableError.setUrl(url());
+ m_errors.append(mutableError);
+ } else {
+ m_errors.append(error);
+ }
+ }
+
m_data.setStatus(Error);
if (dumpErrors()) {
qWarning().nospace() << "Errors for " << urlString();
- for (int ii = 0; ii < errors.count(); ++ii)
+ for (int ii = 0; ii < errors.size(); ++ii)
qWarning().nospace() << " " << qPrintable(errors.at(ii).toString());
}
cancelAllWaitingFor();
@@ -304,28 +279,13 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors)
void QQmlDataBlob::setError(const QQmlJS::DiagnosticMessage &error)
{
QQmlError e;
- e.setColumn(error.column);
- e.setLine(error.line);
+ e.setColumn(qmlConvertSourceCoordinate<quint32, int>(error.loc.startColumn));
+ e.setLine(qmlConvertSourceCoordinate<quint32, int>(error.loc.startLine));
e.setDescription(error.message);
e.setUrl(url());
setError(e);
}
-void QQmlDataBlob::setError(const QVector<QQmlJS::DiagnosticMessage> &errors)
-{
- QList<QQmlError> finalErrors;
- finalErrors.reserve(errors.count());
- for (const auto &error : errors) {
- QQmlError e;
- e.setColumn(error.column);
- e.setLine(error.line);
- e.setDescription(error.message);
- e.setUrl(url());
- finalErrors << e;
- }
- setError(finalErrors);
-}
-
void QQmlDataBlob::setError(const QString &description)
{
QQmlError e;
@@ -351,7 +311,7 @@ void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
status() == Error || status() == Complete || m_isDone)
return;
- for (const auto &existingDep: qAsConst(m_waitingFor))
+ for (const auto &existingDep: std::as_const(m_waitingFor))
if (existingDep.data() == blob)
return;
@@ -359,6 +319,13 @@ void QQmlDataBlob::addDependency(QQmlDataBlob *blob)
m_waitingFor.append(blob);
blob->m_waitingOnMe.append(this);
+
+ // Check circular dependency
+ if (m_waitingOnMe.indexOf(blob) >= 0) {
+ qCWarning(lcCycle) << "Cyclic dependency detected between" << this->url().toString()
+ << "and" << blob->url().toString();
+ m_data.setStatus(Error);
+ }
}
/*!
@@ -535,7 +502,7 @@ void QQmlDataBlob::tryDone()
void QQmlDataBlob::cancelAllWaitingFor()
{
- while (m_waitingFor.count()) {
+ while (m_waitingFor.size()) {
QQmlRefPointer<QQmlDataBlob> blob = m_waitingFor.takeLast();
Q_ASSERT(blob->m_waitingOnMe.contains(this));
@@ -546,7 +513,7 @@ void QQmlDataBlob::cancelAllWaitingFor()
void QQmlDataBlob::notifyAllWaitingOnMe()
{
- while (m_waitingOnMe.count()) {
+ while (m_waitingOnMe.size()) {
QQmlDataBlob *blob = m_waitingOnMe.takeLast();
Q_ASSERT(std::any_of(blob->m_waitingFor.constBegin(), blob->m_waitingFor.constEnd(),
@@ -559,12 +526,13 @@ void QQmlDataBlob::notifyAllWaitingOnMe()
void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
{
Q_ASSERT(blob->status() == Error || blob->status() == Complete);
+ Q_TRACE_SCOPE(QQmlCompiling, blob->url());
QQmlCompilingProfiler prof(typeLoader()->profiler(), blob);
m_inCallback = true;
QQmlRefPointer<QQmlDataBlob> blobRef;
- for (int i = 0; i < m_waitingFor.count(); ++i) {
+ for (int i = 0; i < m_waitingFor.size(); ++i) {
if (m_waitingFor.at(i).data() == blob) {
blobRef = m_waitingFor.takeAt(i);
break;
@@ -607,7 +575,7 @@ QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const
}
QByteArray data(fileSize, Qt::Uninitialized);
- if (f.read(data.data(), data.length()) != data.length()) {
+ if (f.read(data.data(), data.size()) != data.size()) {
*error = f.errorString();
return QString();
}
diff --git a/src/qml/qml/qqmldatablob_p.h b/src/qml/qml/qqmldatablob_p.h
index 0450e94c02..87a7e8e2e8 100644
--- a/src/qml/qml/qqmldatablob_p.h
+++ b/src/qml/qml/qqmldatablob_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDATABLOB_P_H
#define QQMLDATABLOB_P_H
@@ -53,14 +17,15 @@
#include <private/qqmlrefcount_p.h>
#include <private/qqmljsdiagnosticmessage_p.h>
-#include <private/qv4compileddata_p.h>
#if QT_CONFIG(qml_network)
#include <QtNetwork/qnetworkreply.h>
#endif
+#include <QtQml/qqmlprivate.h>
#include <QtQml/qqmlerror.h>
#include <QtQml/qqmlabstracturlinterceptor.h>
+#include <QtQml/qqmlprivate.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qfileinfo.h>
@@ -69,9 +34,11 @@
QT_BEGIN_NAMESPACE
class QQmlTypeLoader;
-class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
+class Q_QML_EXPORT QQmlDataBlob : public QQmlRefCounted<QQmlDataBlob>
{
public:
+ using Ptr = QQmlRefPointer<QQmlDataBlob>;
+
enum Status {
Null, // Prior to QQmlTypeLoader::load()
Loading, // Prior to data being received and dataReceived() being called
@@ -88,7 +55,7 @@ public:
};
QQmlDataBlob(const QUrl &, Type, QQmlTypeLoader* manager);
- ~QQmlDataBlob() override;
+ virtual ~QQmlDataBlob();
void startLoading();
@@ -119,6 +86,11 @@ public:
QDateTime sourceTimeStamp() const;
bool exists() const;
bool isEmpty() const;
+ bool isValid() const
+ {
+ return hasInlineSourceCode || !fileInfo.filePath().isEmpty();
+ }
+
private:
friend class QQmlDataBlob;
friend class QQmlTypeLoader;
@@ -132,13 +104,12 @@ protected:
void setError(const QQmlError &);
void setError(const QList<QQmlError> &errors);
void setError(const QQmlJS::DiagnosticMessage &error);
- void setError(const QVector<QQmlJS::DiagnosticMessage> &errors);
void setError(const QString &description);
void addDependency(QQmlDataBlob *);
// Callbacks made in load thread
virtual void dataReceived(const SourceCodeData &) = 0;
- virtual void initializeFromCachedUnit(const QV4::CompiledData::Unit*) = 0;
+ virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) = 0;
virtual void done();
#if QT_CONFIG(qml_network)
virtual void networkError(QNetworkReply::NetworkError);
@@ -209,13 +180,14 @@ private:
}
}
- inline quint8 progress() const
+ inline qreal progress() const
{
- return quint8((_p.loadRelaxed() & ProgressMask) >> ProgressShift);
+ return quint8((_p.loadRelaxed() & ProgressMask) >> ProgressShift) / float(0xFF);
}
- inline void setProgress(quint8 v)
+ inline void setProgress(qreal progress)
{
+ quint8 v = 0xFF * progress;
while (true) {
int d = _p.loadRelaxed();
int nd = (d & ~ProgressMask) | ((v << ProgressShift) & ProgressMask);
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
index 02fde97b3d..efd8519a58 100644
--- a/src/qml/qml/qqmldelayedcallqueue.cpp
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmldelayedcallqueue_p.h"
#include <private/qqmlengine_p.h>
@@ -67,16 +31,16 @@ void QQmlDelayedCallQueue::DelayedFunctionCall::execute(QV4::ExecutionEngine *en
const QV4::FunctionObject *callback = m_function.as<QV4::FunctionObject>();
Q_ASSERT(callback);
const int argCount = array ? array->getLength() : 0;
- QV4::JSCallData jsCallData(scope, argCount);
- *jsCallData->thisObject = QV4::Encode::undefined();
+ QV4::JSCallArguments jsCallData(scope, argCount);
+ *jsCallData.thisObject = QV4::Encode::undefined();
for (int i = 0; i < argCount; i++) {
- jsCallData->args[i] = array->get(i);
+ jsCallData.args[i] = array->get(i);
}
callback->call(jsCallData);
- if (scope.engine->hasException) {
+ if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
error.setDescription(error.description() + QLatin1String(" (exception occurred during delayed function evaluation)"));
QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error);
@@ -106,25 +70,28 @@ void QQmlDelayedCallQueue::init(QV4::ExecutionEngine* engine)
m_tickedMethod = metaObject.method(methodIndex);
}
-QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *argv, int argc)
+QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::ExecutionEngine *engine, QQmlV4FunctionPtr args)
{
- QV4::Scope scope(b);
- if (argc == 0)
+ QQmlDelayedCallQueue *self = engine->delayedCallQueue();
+
+ QV4::Scope scope(engine);
+ if (args->length() == 0)
THROW_GENERIC_ERROR("Qt.callLater: no arguments given");
- const QV4::FunctionObject *func = argv[0].as<QV4::FunctionObject>();
+ QV4::ScopedValue firstArgument(scope, (*args)[0]);
+
+ const QV4::FunctionObject *func = firstArgument->as<QV4::FunctionObject>();
if (!func)
THROW_GENERIC_ERROR("Qt.callLater: first argument not a function or signal");
QPair<QObject *, int> functionData = QV4::QObjectMethod::extractQtMethod(func);
- QV4::ReturnedValue arg0 = argc ? argv[0].asReturnedValue() : QV4::Encode::undefined();
QVector<DelayedFunctionCall>::Iterator iter;
if (functionData.second != -1) {
// This is a QObject function wrapper
- iter = m_delayedFunctionCalls.begin();
- while (iter != m_delayedFunctionCalls.end()) {
+ iter = self->m_delayedFunctionCalls.begin();
+ while (iter != self->m_delayedFunctionCalls.end()) {
DelayedFunctionCall& dfc = *iter;
QPair<QObject *, int> storedFunctionData = QV4::QObjectMethod::extractQtMethod(dfc.m_function.as<QV4::FunctionObject>());
if (storedFunctionData == functionData) {
@@ -134,26 +101,26 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::F
}
} else {
// This is a JavaScript function (dynamic slot on VMEMO)
- iter = m_delayedFunctionCalls.begin();
- while (iter != m_delayedFunctionCalls.end()) {
+ iter = self->m_delayedFunctionCalls.begin();
+ while (iter != self->m_delayedFunctionCalls.end()) {
DelayedFunctionCall& dfc = *iter;
- if (arg0 == dfc.m_function.value()) {
+ if (firstArgument->asReturnedValue() == dfc.m_function.value()) {
break; // Already stored!
}
++iter;
}
}
- const bool functionAlreadyStored = (iter != m_delayedFunctionCalls.end());
+ const bool functionAlreadyStored = (iter != self->m_delayedFunctionCalls.end());
if (functionAlreadyStored) {
DelayedFunctionCall dfc = *iter;
- m_delayedFunctionCalls.erase(iter);
- m_delayedFunctionCalls.append(dfc);
+ self->m_delayedFunctionCalls.erase(iter);
+ self->m_delayedFunctionCalls.append(dfc);
} else {
- m_delayedFunctionCalls.append(QV4::PersistentValue(m_engine, arg0));
+ self->m_delayedFunctionCalls.append(QV4::PersistentValue(engine, firstArgument));
}
- DelayedFunctionCall& dfc = m_delayedFunctionCalls.last();
+ DelayedFunctionCall& dfc = self->m_delayedFunctionCalls.last();
if (dfc.m_objectGuard.isNull()) {
if (functionData.second != -1) {
// if it's a qobject function wrapper, guard against qobject deletion
@@ -166,18 +133,18 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::F
dfc.m_guarded = true;
}
}
- storeAnyArguments(dfc, argv, argc, 1, m_engine);
+ self->storeAnyArguments(dfc, args, 1, engine);
- if (!m_callbackOutstanding) {
- m_tickedMethod.invoke(this, Qt::QueuedConnection);
- m_callbackOutstanding = true;
+ if (!self->m_callbackOutstanding) {
+ self->m_tickedMethod.invoke(self, Qt::QueuedConnection);
+ self->m_callbackOutstanding = true;
}
return QV4::Encode::undefined();
}
-void QQmlDelayedCallQueue::storeAnyArguments(DelayedFunctionCall &dfc, const QV4::Value *argv, int argc, int offset, QV4::ExecutionEngine *engine)
+void QQmlDelayedCallQueue::storeAnyArguments(DelayedFunctionCall &dfc, QQmlV4FunctionPtr args, int offset, QV4::ExecutionEngine *engine)
{
- const int length = argc - offset;
+ const int length = args->length() - offset;
if (length == 0) {
dfc.m_args.clear();
return;
@@ -185,8 +152,8 @@ void QQmlDelayedCallQueue::storeAnyArguments(DelayedFunctionCall &dfc, const QV4
QV4::Scope scope(engine);
QV4::ScopedArrayObject array(scope, engine->newArrayObject(length));
uint i = 0;
- for (int j = offset, ej = argc; j < ej; ++i, ++j)
- array->put(i, argv[j]);
+ for (int j = offset, ej = args->length(); j < ej; ++i, ++j)
+ array->put(i, (*args)[j]);
dfc.m_args.set(engine, array);
}
diff --git a/src/qml/qml/qqmldelayedcallqueue_p.h b/src/qml/qml/qqmldelayedcallqueue_p.h
index 7962318561..88f0c4d118 100644
--- a/src/qml/qml/qqmldelayedcallqueue_p.h
+++ b/src/qml/qml/qqmldelayedcallqueue_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDELAYEDCALLQUEUE_P_H
#define QQMLDELAYEDCALLQUEUE_P_H
@@ -69,7 +33,8 @@ public:
void init(QV4::ExecutionEngine *);
- QV4::ReturnedValue addUniquelyAndExecuteLater(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue addUniquelyAndExecuteLater(QV4::ExecutionEngine *engine,
+ QQmlV4FunctionPtr args);
public Q_SLOTS:
void ticked();
@@ -89,7 +54,7 @@ private:
bool m_guarded;
};
- void storeAnyArguments(DelayedFunctionCall& dfc, const QV4::Value *argv, int argc, int offset, QV4::ExecutionEngine *engine);
+ void storeAnyArguments(DelayedFunctionCall& dfc, QQmlV4FunctionPtr args, int offset, QV4::ExecutionEngine *engine);
void executeAllExpired_Later();
QV4::ExecutionEngine *m_engine;
diff --git a/src/qml/qml/qqmldirdata.cpp b/src/qml/qml/qqmldirdata.cpp
index de74dfdf9b..8997146dba 100644
--- a/src/qml/qml/qqmldirdata.cpp
+++ b/src/qml/qml/qqmldirdata.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmldirdata_p.h>
@@ -51,30 +15,18 @@ const QString &QQmlQmldirData::content() const
return m_content;
}
-QQmlTypeLoader::Blob::PendingImportPtr QQmlQmldirData::import(QQmlTypeLoader::Blob *blob) const
+QV4::CompiledData::Location QQmlQmldirData::importLocation(QQmlTypeLoader::Blob *blob) const
{
- auto it = m_imports.find(blob);
- if (it == m_imports.end())
- return nullptr;
- return *it;
+ auto it = m_imports.constFind(blob);
+ if (it == m_imports.constEnd())
+ return QV4::CompiledData::Location();
+ return it->import->location;
}
-void QQmlQmldirData::setImport(QQmlTypeLoader::Blob *blob, QQmlTypeLoader::Blob::PendingImportPtr import)
+void QQmlQmldirData::setPriority(QQmlTypeLoader::Blob *blob,
+ QQmlTypeLoader::Blob::PendingImportPtr import, int priority)
{
- m_imports[blob] = std::move(import);
-}
-
-int QQmlQmldirData::priority(QQmlTypeLoader::Blob *blob) const
-{
- QHash<QQmlTypeLoader::Blob *, int>::const_iterator it = m_priorities.find(blob);
- if (it == m_priorities.end())
- return 0;
- return *it;
-}
-
-void QQmlQmldirData::setPriority(QQmlTypeLoader::Blob *blob, int priority)
-{
- m_priorities[blob] = priority;
+ m_imports.insert(blob, { std::move(import), priority });
}
void QQmlQmldirData::dataReceived(const SourceCodeData &data)
@@ -87,7 +39,7 @@ void QQmlQmldirData::dataReceived(const SourceCodeData &data)
}
}
-void QQmlQmldirData::initializeFromCachedUnit(const QV4::CompiledData::Unit *)
+void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *)
{
Q_UNIMPLEMENTED();
}
diff --git a/src/qml/qml/qqmldirdata_p.h b/src/qml/qml/qqmldirdata_p.h
index 34f1ff1678..777e3854eb 100644
--- a/src/qml/qml/qqmldirdata_p.h
+++ b/src/qml/qml/qqmldirdata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDIRDATA_P_H
#define QQMLDIRDATA_P_H
@@ -64,21 +28,39 @@ private:
public:
const QString &content() const;
+ QV4::CompiledData::Location importLocation(Blob *blob) const;
- PendingImportPtr import(QQmlTypeLoader::Blob *) const;
- void setImport(QQmlTypeLoader::Blob *, PendingImportPtr);
+ template<typename Callback>
+ bool processImports(Blob *blob, const Callback &callback) const
+ {
+ bool result = true;
+ const auto range = m_imports.equal_range(blob);
+ for (auto it = range.first; it != range.second; ++it) {
+ // Do we need to resolve this import?
+ if ((it->import->priority == 0) || (it->import->priority > it->priority)) {
+ // This is the (current) best resolution for this import
+ if (!callback(it->import))
+ result = false;
+ it->import->priority = it->priority;
+ }
+ }
+ return result;
+ }
- int priority(QQmlTypeLoader::Blob *) const;
- void setPriority(QQmlTypeLoader::Blob *, int);
+ void setPriority(Blob *, PendingImportPtr, int);
protected:
void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *) override;
+ void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) override;
private:
+ struct PrioritizedImport {
+ PendingImportPtr import;
+ int priority = 0;
+ };
+
QString m_content;
- QHash<QQmlTypeLoader::Blob *, QQmlTypeLoader::Blob::PendingImportPtr> m_imports;
- QHash<QQmlTypeLoader::Blob *, int> m_priorities;
+ QMultiHash<Blob *, PrioritizedImport> m_imports;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 6e1365ea9f..c7812059a1 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -1,67 +1,24 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlengine_p.h"
#include "qqmlengine.h"
-#include "qqmlcomponentattached_p.h"
#include "qqmlcontext_p.h"
#include "qqml.h"
#include "qqmlcontext.h"
-#include "qqmlexpression.h"
-#include "qqmlcomponent.h"
-#include "qqmlvme_p.h"
-#include "qqmlstringconverters_p.h"
#include "qqmlscriptstring.h"
#include "qqmlglobal_p.h"
-#include "qqmlcomponent_p.h"
-#include "qqmlextensioninterface.h"
-#include "qqmllist_p.h"
-#include "qqmltypenamecache_p.h"
#include "qqmlnotifier_p.h"
#include "qqmlincubator.h"
#include "qqmlabstracturlinterceptor.h"
+
#include <private/qqmldirparser_p.h>
#include <private/qqmlboundsignal_p.h>
#include <private/qqmljsdiagnosticmessage_p.h>
+#include <private/qqmltype_p_p.h>
+#include <private/qqmlpluginimporter_p.h>
#include <QtCore/qstandardpaths.h>
-#include <QtCore/qsettings.h>
#include <QtCore/qmetaobject.h>
#include <QDebug>
#include <QtCore/qcoreapplication.h>
@@ -70,11 +27,14 @@
#include <QtCore/qmutex.h>
#include <QtCore/qthread.h>
#include <private/qthread_p.h>
+#include <private/qqmlscriptdata_p.h>
+#include <QtQml/private/qqmlcomponentattached_p.h>
+#include <QtQml/private/qqmlsourcecoordinate_p.h>
+#include <QtQml/private/qqmlcomponent_p.h>
#if QT_CONFIG(qml_network)
#include "qqmlnetworkaccessmanagerfactory.h"
#include <QNetworkAccessManager>
-#include <QtNetwork/qnetworkconfigmanager.h>
#endif
#include <private/qobject_p.h>
@@ -89,54 +49,20 @@
#endif
#include <private/qqmlplatform_p.h>
#include <private/qqmlloggingcategory_p.h>
+#include <private/qv4sequenceobject_p.h>
#ifdef Q_OS_WIN // for %APPDATA%
# include <qt_windows.h>
-# ifndef Q_OS_WINRT
-# include <shlobj.h>
-# endif
+# include <shlobj.h>
# include <qlibrary.h>
# ifndef CSIDL_APPDATA
# define CSIDL_APPDATA 0x001a // <username>\Application Data
# endif
#endif // Q_OS_WIN
-Q_DECLARE_METATYPE(QQmlProperty)
-
QT_BEGIN_NAMESPACE
-// Declared in qqml.h
-int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
- const char *uri, int versionMajor,
- int versionMinor, const char *qmlName,
- const QString& reason)
-{
- QQmlPrivate::RegisterType type = {
- 0,
-
- 0,
- 0,
- 0,
- nullptr,
- reason,
-
- uri, versionMajor, versionMinor, qmlName, &staticMetaObject,
-
- QQmlAttachedPropertiesFunc(),
- nullptr,
-
- 0,
- 0,
- 0,
-
- nullptr, nullptr,
-
- nullptr,
- 0
- };
-
- return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
-}
+void qml_register_types_QML();
/*!
\qmltype QtObject
@@ -194,28 +120,9 @@ int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject,
\endcode
*/
-bool QQmlEnginePrivate::qml_debugging_enabled = false;
+Q_CONSTINIT std::atomic<bool> QQmlEnginePrivate::qml_debugging_enabled{false};
bool QQmlEnginePrivate::s_designerMode = false;
-void QQmlEnginePrivate::defineModule()
-{
- const char uri[] = "QtQml";
-
- qmlRegisterTypesAndRevisions<
- QObjectForeign,
-#if QT_CONFIG(qml_animation)
- QQmlTimer,
-#endif
-#if QT_CONFIG(qml_locale)
- QQmlLocale,
-#endif
- QQmlComponent,
- QQmlBind,
- QQmlConnections,
- QQmlLoggingCategory
- >(uri, 2);
-}
-
bool QQmlEnginePrivate::designerMode()
{
return s_designerMode;
@@ -290,440 +197,64 @@ QQmlImageProviderBase::~QQmlImageProviderBase()
{
}
-
-/*!
-\qmltype Qt
-\inqmlmodule QtQml
-\instantiates QQmlEnginePrivate
-\ingroup qml-utility-elements
-\keyword QmlGlobalQtObject
-\brief Provides a global object with useful enums and functions from Qt.
-
-The \c Qt object is a global object with utility functions, properties and enums.
-
-It is not instantiable; to use it, call the members of the global \c Qt object directly.
-For example:
-
-\qml
-import QtQuick 2.0
-
-Text {
- color: Qt.rgba(1, 0, 0, 1)
- text: Qt.md5("hello, world")
-}
-\endqml
-
-
-\section1 Enums
-
-The Qt object contains the enums available in the \l [QtCore]{Qt}{Qt Namespace}. For example, you can access
-the \l Qt::LeftButton and \l Qt::RightButton enumeration values as \c Qt.LeftButton and \c Qt.RightButton.
-
-
-\section1 Types
-
-The Qt object also contains helper functions for creating objects of specific
-data types. This is primarily useful when setting the properties of an item
-when the property has one of the following types:
-\list
-\li \c rect - use \l{Qt::rect()}{Qt.rect()}
-\li \c point - use \l{Qt::point()}{Qt.point()}
-\li \c size - use \l{Qt::size()}{Qt.size()}
-\endlist
-
-If the \c QtQuick module has been imported, the following helper functions for
-creating objects of specific data types are also available for clients to use:
-\list
-\li \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()}
-\li \c font - use \l{Qt::font()}{Qt.font()}
-\li \c vector2d - use \l{Qt::vector2d()}{Qt.vector2d()}
-\li \c vector3d - use \l{Qt::vector3d()}{Qt.vector3d()}
-\li \c vector4d - use \l{Qt::vector4d()}{Qt.vector4d()}
-\li \c quaternion - use \l{Qt::quaternion()}{Qt.quaternion()}
-\li \c matrix4x4 - use \l{Qt::matrix4x4()}{Qt.matrix4x4()}
-\endlist
-
-There are also string based constructors for these types. See \l{qtqml-typesystem-basictypes.html}{QML Basic Types} for more information.
-
-\section1 Date/Time Formatters
-
-The Qt object contains several functions for formatting QDateTime, QDate and QTime values.
-
-\list
- \li \l{Qt::formatDateTime}{string Qt.formatDateTime(datetime date, variant format)}
- \li \l{Qt::formatDate}{string Qt.formatDate(datetime date, variant format)}
- \li \l{Qt::formatTime}{string Qt.formatTime(datetime date, variant format)}
-\endlist
-
-The format specification is described at \l{Qt::formatDateTime}{Qt.formatDateTime}.
-
-
-\section1 Dynamic Object Creation
-The following functions on the global object allow you to dynamically create QML
-items from files or strings. See \l{Dynamic QML Object Creation from JavaScript} for an overview
-of their use.
-
-\list
- \li \l{Qt::createComponent()}{object Qt.createComponent(url)}
- \li \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)}
-\endlist
-
-
-\section1 Other Functions
-
-The following functions are also on the Qt object.
-
-\list
- \li \l{Qt::quit()}{Qt.quit()}
- \li \l{Qt::md5()}{Qt.md5(string)}
- \li \l{Qt::btoa()}{string Qt.btoa(string)}
- \li \l{Qt::atob()}{string Qt.atob(string)}
- \li \l{Qt::binding()}{object Qt.binding(function)}
- \li \l{Qt::locale()}{object Qt.locale()}
- \li \l{Qt::resolvedUrl()}{string Qt.resolvedUrl(string)}
- \li \l{Qt::openUrlExternally()}{Qt.openUrlExternally(string)}
- \li \l{Qt::fontFamilies()}{list<string> Qt.fontFamilies()}
-\endlist
-*/
-
-/*!
- \qmlproperty object Qt::platform
- \since 5.1
-
- The \c platform object provides info about the underlying platform.
-
- Its properties are:
-
- \table
- \row
- \li \c platform.os
- \li
-
- This read-only property contains the name of the operating system.
-
- Possible values are:
-
- \list
- \li \c "android" - Android
- \li \c "ios" - iOS
- \li \c "tvos" - tvOS
- \li \c "linux" - Linux
- \li \c "osx" - \macos
- \li \c "qnx" - QNX (since Qt 5.9.3)
- \li \c "unix" - Other Unix-based OS
- \li \c "windows" - Windows
- \li \c "winrt" - WinRT / UWP
- \endlist
-
- \row
- \li \c platform.pluginName
- \li This is the name of the platform set on the QGuiApplication instance
- as returned by \l QGuiApplication::platformName()
-
- \endtable
-*/
-
-/*!
- \qmlproperty object Qt::application
- \since 5.1
-
- The \c application object provides access to global application state
- properties shared by many QML components.
-
- Its properties are:
-
- \table
- \row
- \li \c application.active
- \li
- Deprecated, use Qt.application.state == Qt.ApplicationActive instead.
-
- \row
- \li \c application.state
- \li
- This read-only property indicates the current state of the application.
-
- Possible values are:
-
- \list
- \li Qt.ApplicationActive - The application is the top-most and focused application, and the
- user is able to interact with the application.
- \li Qt.ApplicationInactive - The application is visible or partially visible, but not selected
- to be in front, the user cannot interact with the application.
- On desktop platforms, this typically means that the user activated
- another application. On mobile platforms, it is more common to
- enter this state when the OS is interrupting the user with for
- example incoming calls, SMS-messages or dialogs. This is usually a
- transient state during which the application is paused. The user
- may return focus to your application, but most of the time it will
- be the first indication that the application is going to be suspended.
- While in this state, consider pausing or stopping any activity that
- should not continue when the user cannot interact with your
- application, such as a video, a game, animations, or sensors.
- You should also avoid performing CPU-intensive tasks which might
- slow down the application in front.
- \li Qt.ApplicationSuspended - The application is suspended and not visible to the user. On
- mobile platforms, the application typically enters this state when
- the user returns to the home screen or switches to another
- application. While in this state, the application should ensure
- that the user perceives it as always alive and does not lose his
- progress, saving any persistent data. The application should cease
- all activities and be prepared for code execution to stop. While
- suspended, the application can be killed at any time without
- further warnings (for example when low memory forces the OS to purge
- suspended applications).
- \li Qt.ApplicationHidden - The application is hidden and runs in the background. This is the
- normal state for applications that need to do background processing,
- like playing music, while the user interacts with other applications.
- The application should free up all graphical resources when entering
- this state. A Qt Quick application should not usually handle this state
- at the QML level. Instead, you should unload the entire UI and reload
- the QML files whenever the application becomes active again.
- \endlist
-
- \row
- \li \c application.layoutDirection
- \li
- This read-only property can be used to query the default layout direction of the
- application. On system start-up, the default layout direction depends on the
- application's language. The property has a value of \c Qt.RightToLeft in locales
- where text and graphic elements are read from right to left, and \c Qt.LeftToRight
- where the reading direction flows from left to right. You can bind to this
- property to customize your application layouts to support both layout directions.
-
- Possible values are:
-
- \list
- \li Qt.LeftToRight - Text and graphics elements should be positioned
- from left to right.
- \li Qt.RightToLeft - Text and graphics elements should be positioned
- from right to left.
- \endlist
- \row
- \li \c application.font
- \li This read-only property holds the default application font as
- returned by \l QGuiApplication::font().
- \row
- \li \c application.arguments
- \li This is a string list of the arguments the executable was invoked with.
- \row
- \li \c application.name
- \li This is the application name set on the QCoreApplication instance. This property can be written
- to in order to set the application name.
- \row
- \li \c application.displayName (since Qt 5.9)
- \li This is the application display name set on the QGuiApplication instance. This property can be written
- to in order to set the application display name.
- \row
- \li \c application.version
- \li This is the application version set on the QCoreApplication instance. This property can be written
- to in order to set the application version.
- \row
- \li \c application.organization
- \li This is the organization name set on the QCoreApplication instance. This property can be written
- to in order to set the organization name.
- \row
- \li \c application.domain
- \li This is the organization domain set on the QCoreApplication instance. This property can be written
- to in order to set the organization domain.
-
- \row
- \li \c application.supportsMultipleWindows
- \li This read-only property can be used to determine whether or not the
- platform supports multiple windows. Some embedded platforms do not support
- multiple windows, for example.
-
- \row
- \li \c application.screens
- \li An array containing the descriptions of all connected screens. The
- elements of the array are objects with the same properties as the
- \l{Screen} attached object. In practice the array corresponds to the screen
- list returned by QGuiApplication::screens(). In addition to examining
- properties like name, width, height, etc., the array elements can also be
- assigned to the screen property of Window items, thus serving as an
- alternative to the C++ side's QWindow::setScreen(). This property has been
- added in Qt 5.9.
-
- \endtable
-
- The object also has one signal, aboutToQuit(), which is the same as \l QCoreApplication::aboutToQuit().
-
- The following example uses the \c application object to indicate
- whether the application is currently active:
-
- \snippet qml/application.qml document
-
- Note that when using QML without a QGuiApplication, the following properties will be undefined:
- \list
- \li application.active
- \li application.state
- \li application.layoutDirection
- \li application.font
- \endlist
-
- \sa Screen, Window, {QtQuick.Window::Window::screen}{Window.screen}
-*/
-
-/*!
- \qmlproperty object Qt::inputMethod
- \since 5.0
-
- The \c inputMethod object allows access to application's QInputMethod object
- and all its properties and slots. See the QInputMethod documentation for
- further details.
-*/
-
-/*!
- \qmlproperty object Qt::styleHints
- \since 5.5
-
- The \c styleHints object provides platform-specific style hints and settings.
- See the QStyleHints documentation for further details.
-
- \note The \c styleHints object is only available when using the Qt Quick module.
-
- The following example uses the \c styleHints object to determine whether an
- item should gain focus on mouse press or touch release:
- \code
- import QtQuick 2.4
-
- MouseArea {
- id: button
-
- onPressed: {
- if (!Qt.styleHints.setFocusOnTouchRelease)
- button.forceActiveFocus()
- }
- onReleased: {
- if (Qt.styleHints.setFocusOnTouchRelease)
- button.forceActiveFocus()
- }
- }
- \endcode
-*/
-
-/*!
-\qmlmethod object Qt::include(string url, jsobject callback)
-\deprecated
-
-This method should not be used. Use ECMAScript modules instead and the native
-JavaScript \c import and \c export statements instead.
-
-Includes another JavaScript file. This method can only be used from within JavaScript files,
-and not regular QML files.
-
-This imports all functions from \a url into the current script's namespace.
-
-Qt.include() returns an object that describes the status of the operation. The object has
-a single property, \c {status}, that is set to one of the following values:
-
-\table
-\header \li Symbol \li Value \li Description
-\row \li result.OK \li 0 \li The include completed successfully.
-\row \li result.LOADING \li 1 \li Data is being loaded from the network.
-\row \li result.NETWORK_ERROR \li 2 \li A network error occurred while fetching the url.
-\row \li result.EXCEPTION \li 3 \li A JavaScript exception occurred while executing the included code.
-An additional \c exception property will be set in this case.
-\endtable
-
-The \c status property will be updated as the operation progresses.
-
-If provided, \a callback is invoked when the operation completes. The callback is passed
-the same object as is returned from the Qt.include() call.
-*/
-// Qt.include() is implemented in qv4include.cpp
-
-QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
-: propertyCapture(nullptr), rootContext(nullptr),
-#if QT_CONFIG(qml_debug)
- profiler(nullptr),
-#endif
- outputWarningsToMsgLog(true),
- cleanup(nullptr), erroredBindings(nullptr), inProgressCreations(0),
-#if QT_CONFIG(qml_worker_script)
- workerScriptEngine(nullptr),
-#endif
- activeObjectCreator(nullptr),
-#if QT_CONFIG(qml_network)
- networkAccessManager(nullptr), networkAccessManagerFactory(nullptr),
-#endif
- urlInterceptor(nullptr), scarceResourcesRefCount(0), importDatabase(e), typeLoader(e),
- uniqueId(1), incubatorCount(0), incubationController(nullptr)
-{
-}
-
QQmlEnginePrivate::~QQmlEnginePrivate()
{
if (inProgressCreations)
qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations);
- while (cleanup) {
- QQmlCleanup *c = cleanup;
- cleanup = c->next;
- if (cleanup) cleanup->prev = &cleanup;
- c->next = nullptr;
- c->prev = nullptr;
- c->clear();
- }
-
- doDeleteInEngineThread();
-
if (incubationController) incubationController->d = nullptr;
incubationController = nullptr;
QQmlMetaType::freeUnusedTypesAndCaches();
- for (auto iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) {
- iter.value()->isRegisteredWithEngine = false;
-
- // since unregisterInternalCompositeType() will not be called in this
- // case, we have to clean up the type registration manually
- QMetaType::unregisterType(iter.value()->metaTypeId);
- QMetaType::unregisterType(iter.value()->listMetaTypeId);
- }
#if QT_CONFIG(qml_debug)
delete profiler;
#endif
+ qDeleteAll(cachedValueTypeInstances);
}
void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
{
- if (QQmlData *d = QQmlData::get(o)) {
+ QObjectPrivate *p = QObjectPrivate::get(o);
+ if (QQmlData *d = QQmlData::get(p)) {
+ const auto invalidate = [](QQmlContextData *c) {c->invalidate();};
if (d->ownContext) {
- for (QQmlContextData *lc = d->ownContext->linkedContext; lc; lc = lc->linkedContext) {
- lc->invalidate();
- if (lc->contextObject == o)
- lc->contextObject = nullptr;
- }
- d->ownContext->invalidate();
- if (d->ownContext->contextObject == o)
- d->ownContext->contextObject = nullptr;
- d->ownContext = nullptr;
+ d->ownContext->deepClearContextObject(o, invalidate, invalidate);
+ d->ownContext.reset();
d->context = nullptr;
+ Q_ASSERT(!d->outerContext || d->outerContext->contextObject() != o);
+ } else if (d->outerContext && d->outerContext->contextObject() == o) {
+ d->outerContext->deepClearContextObject(o, invalidate, invalidate);
}
- if (d->outerContext && d->outerContext->contextObject == o)
- d->outerContext->contextObject = nullptr;
+ if (d->hasVMEMetaObject || d->hasInterceptorMetaObject) {
+ // This is somewhat dangerous because another thread might concurrently
+ // try to resolve the dynamic metaobject. In practice this will then
+ // lead to either the code path that still returns the interceptor
+ // metaobject or the code path that returns the string casted one. Both
+ // is fine if you cannot actually touch the object itself. Since the
+ // other thread is obviously not synchronized to this one, it can't.
+ //
+ // In particular we do this when delivering the frameSwapped() signal
+ // in QQuickWindow. The handler for frameSwapped() is written in a way
+ // that is thread safe as long as QQuickWindow's dtor hasn't finished.
+ // QQuickWindow's dtor does synchronize with the render thread, but it
+ // runs _after_ qdeclarativeelement_destructor.
+ static_cast<QQmlInterceptorMetaObject *>(p->metaObject)->invalidate();
+ d->hasVMEMetaObject = d->hasInterceptorMetaObject = false;
+ }
// Mark this object as in the process of deletion to
// prevent it resolving in bindings
QQmlData::markAsDeleted(o);
-
- // Disconnect the notifiers now - during object destruction this would be too late, since
- // the disconnect call wouldn't be able to call disconnectNotify(), as it isn't possible to
- // get the metaobject anymore.
- d->disconnectNotifiers();
}
}
-QQmlData::QQmlData()
- : ownedByQml1(false), ownMemory(true), indestructible(true), explicitIndestructibleSet(false),
+QQmlData::QQmlData(Ownership ownership)
+ : ownMemory(ownership == OwnsMemory), indestructible(true), explicitIndestructibleSet(false),
hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
- hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false),
- bindingBitsArraySize(InlineBindingArraySize), notifyList(nullptr),
- bindings(nullptr), signalHandlers(nullptr), nextContextObject(nullptr), prevContextObject(nullptr),
- lineNumber(0), columnNumber(0), jsEngineId(0),
- propertyCache(nullptr), guards(nullptr), extendedData(nullptr)
+ hasInterceptorMetaObject(false), hasVMEMetaObject(false), hasConstWrapper(false), dummy(0),
+ bindingBitsArraySize(InlineBindingArraySize)
{
memset(bindingBitsValue, 0, sizeof(bindingBitsValue));
init();
@@ -736,18 +267,9 @@ QQmlData::~QQmlData()
void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o)
{
QQmlData *ddata = static_cast<QQmlData *>(d);
- if (ddata->ownedByQml1)
- return;
ddata->destroyed(o);
}
-void QQmlData::parentChanged(QAbstractDeclarativeData *d, QObject *o, QObject *p)
-{
- QQmlData *ddata = static_cast<QQmlData *>(d);
- if (ddata->ownedByQml1)
- return;
- ddata->parentChanged(o, p);
-}
class QQmlThreadNotifierProxyObject : public QObject
{
@@ -775,7 +297,6 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
{
QQmlData *ddata = QQmlData::get(object, false);
if (!ddata) return; // Probably being deleted
- if (ddata->ownedByQml1) return;
// In general, QML only supports QObject's that live on the same thread as the QQmlEngine
// that they're exposed to. However, to make writing "worker objects" that calculate data
@@ -783,43 +304,48 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
// QQmlEngine to emit signals from a different thread. These signals are then automatically
// marshalled back onto the QObject's thread and handled by QML from there. This is tested
// by the qqmlecmascript::threadSignal() autotest.
- if (ddata->notifyList &&
- QThread::currentThreadId() != QObjectPrivate::get(object)->threadData->threadId.loadRelaxed()) {
- if (!QObjectPrivate::get(object)->threadData->thread.loadAcquire())
+ // Relaxed semantics here. If we're on a different thread we might schedule a useless event,
+ // but that should be rare.
+ if (!ddata->notifyList.loadRelaxed())
+ return;
+
+ auto objectThreadData = QObjectPrivate::get(object)->threadData.loadRelaxed();
+ if (QThread::currentThreadId() != objectThreadData->threadId.loadRelaxed()) {
+ if (!objectThreadData->thread.loadAcquire())
return;
QMetaMethod m = QMetaObjectPrivate::signal(object->metaObject(), index);
QList<QByteArray> parameterTypes = m.parameterTypes();
- QScopedPointer<QMetaCallEvent> ev(new QMetaCallEvent(m.methodIndex(), 0, nullptr,
- object, index,
- parameterTypes.count() + 1));
+ auto ev = std::make_unique<QMetaCallEvent>(m.methodIndex(), 0, nullptr,
+ object, index,
+ parameterTypes.size() + 1);
void **args = ev->args();
- int *types = ev->types();
+ QMetaType *types = ev->types();
- for (int ii = 0; ii < parameterTypes.count(); ++ii) {
+ for (int ii = 0; ii < parameterTypes.size(); ++ii) {
const QByteArray &typeName = parameterTypes.at(ii);
if (typeName.endsWith('*'))
- types[ii + 1] = QMetaType::VoidStar;
+ types[ii + 1] = QMetaType(QMetaType::VoidStar);
else
- types[ii + 1] = QMetaType::type(typeName);
+ types[ii + 1] = QMetaType::fromName(typeName);
- if (!types[ii + 1]) {
+ if (!types[ii + 1].isValid()) {
qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
"(Make sure '%s' is registered using qRegisterMetaType().)",
typeName.constData(), typeName.constData());
return;
}
- args[ii + 1] = QMetaType::create(types[ii + 1], a[ii + 1]);
+ args[ii + 1] = types[ii + 1].create(a[ii + 1]);
}
QQmlThreadNotifierProxyObject *mpo = new QQmlThreadNotifierProxyObject;
mpo->target = object;
- mpo->moveToThread(QObjectPrivate::get(object)->threadData->thread.loadAcquire());
- QCoreApplication::postEvent(mpo, ev.take());
+ mpo->moveToThread(objectThreadData->thread.loadAcquire());
+ QCoreApplication::postEvent(mpo, ev.release());
} else {
QQmlNotifierEndpoint *ep = ddata->notify(index);
@@ -830,16 +356,12 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
int QQmlData::receivers(QAbstractDeclarativeData *d, const QObject *, int index)
{
QQmlData *ddata = static_cast<QQmlData *>(d);
- if (ddata->ownedByQml1)
- return 0;
return ddata->endpointCount(index);
}
bool QQmlData::isSignalConnected(QAbstractDeclarativeData *d, const QObject *, int index)
{
QQmlData *ddata = static_cast<QQmlData *>(d);
- if (ddata->ownedByQml1)
- return false;
return ddata->signalHasEndpoint(index);
}
@@ -859,11 +381,15 @@ int QQmlData::endpointCount(int index)
void QQmlData::markAsDeleted(QObject *o)
{
- QQmlData::setQueuedForDeletion(o);
-
- QObjectPrivate *p = QObjectPrivate::get(o);
- for (QList<QObject *>::const_iterator it = p->children.constBegin(), end = p->children.constEnd(); it != end; ++it) {
- QQmlData::markAsDeleted(*it);
+ QVarLengthArray<QObject *> workStack;
+ workStack.push_back(o);
+ while (!workStack.isEmpty()) {
+ auto currentObject = workStack.last();
+ workStack.pop_back();
+ QQmlData::setQueuedForDeletion(currentObject);
+ auto currentObjectPriv = QObjectPrivate::get(currentObject);
+ for (QObject *child: std::as_const(currentObjectPriv->children))
+ workStack.push_back(child);
}
}
@@ -872,40 +398,70 @@ void QQmlData::setQueuedForDeletion(QObject *object)
if (object) {
if (QQmlData *ddata = QQmlData::get(object)) {
if (ddata->ownContext) {
- Q_ASSERT(ddata->ownContext == ddata->context);
- ddata->context->emitDestruction();
- if (ddata->ownContext->contextObject == object)
- ddata->ownContext->contextObject = nullptr;
- ddata->ownContext = nullptr;
+ Q_ASSERT(ddata->ownContext.data() == ddata->context);
+ ddata->ownContext->deepClearContextObject(object);
+ ddata->ownContext.reset();
ddata->context = nullptr;
}
ddata->isQueuedForDeletion = true;
+
+ // Disconnect the notifiers now - during object destruction this would be too late,
+ // since the disconnect call wouldn't be able to call disconnectNotify(), as it isn't
+ // possible to get the metaobject anymore.
+ // Also, there is no point in evaluating bindings in order to set properties on
+ // half-deleted objects.
+ ddata->disconnectNotifiers(DeleteNotifyList::No);
}
}
}
-void QQmlData::flushPendingBindingImpl(QQmlPropertyIndex index)
+void QQmlData::flushPendingBinding(int coreIndex)
{
- clearPendingBindingBit(index.coreIndex());
+ clearPendingBindingBit(coreIndex);
// Find the binding
QQmlAbstractBinding *b = bindings;
- while (b && (b->targetPropertyIndex().coreIndex() != index.coreIndex() ||
+ while (b && (b->targetPropertyIndex().coreIndex() != coreIndex ||
b->targetPropertyIndex().hasValueTypeIndex()))
b = b->nextBinding();
- if (b && b->targetPropertyIndex().coreIndex() == index.coreIndex() &&
+ if (b && b->targetPropertyIndex().coreIndex() == coreIndex &&
!b->targetPropertyIndex().hasValueTypeIndex())
b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
QQmlPropertyData::DontRemoveBinding);
}
-QQmlData::DeferredData::DeferredData()
-{
-}
+QQmlData::DeferredData::DeferredData() = default;
+QQmlData::DeferredData::~DeferredData() = default;
-QQmlData::DeferredData::~DeferredData()
+template<>
+int qmlRegisterType<void>(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
+ QQmlPrivate::RegisterType type = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QMetaType(),
+ QMetaType(),
+ 0, nullptr, nullptr,
+ QString(),
+ nullptr,
+ uri,
+ QTypeRevision::fromVersion(versionMajor, versionMinor),
+ qmlName,
+ nullptr,
+ nullptr,
+ nullptr,
+ -1,
+ -1,
+ -1,
+ nullptr,
+ nullptr,
+ nullptr,
+ QTypeRevision::zero(),
+ -1,
+ QQmlPrivate::ValueTypeCreationMethod::None,
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
}
bool QQmlEnginePrivate::baseModulesUninitialized = true;
@@ -914,23 +470,25 @@ void QQmlEnginePrivate::init()
Q_Q(QQmlEngine);
if (baseModulesUninitialized) {
+ // Register builtins
+ qml_register_types_QML();
+
+ // No need to specifically register those.
+ static_assert(std::is_same_v<QStringList, QList<QString>>);
+ static_assert(std::is_same_v<QVariantList, QList<QVariant>>);
- // required for the Compiler.
- qmlRegisterType<QObject>("QML", 1, 0, "QtObject");
- qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component");
+ qRegisterMetaType<QQmlScriptString>();
+ qRegisterMetaType<QQmlComponent::Status>();
+ qRegisterMetaType<QList<QObject*> >();
+ qRegisterMetaType<QQmlBinding*>();
+
+ // Protect the module: We don't want any URL interceptor to mess with the builtins.
+ qmlProtectModule("QML", 1);
QQmlData::init();
baseModulesUninitialized = false;
}
- qRegisterMetaType<QVariant>();
- qRegisterMetaType<QQmlScriptString>();
- qRegisterMetaType<QJSValue>();
- qRegisterMetaType<QQmlComponent::Status>();
- qRegisterMetaType<QList<QObject*> >();
- qRegisterMetaType<QList<int> >();
- qRegisterMetaType<QQmlBinding*>();
-
q->handle()->setQmlEngine(q);
rootContext = new QQmlContext(q,true);
@@ -942,29 +500,16 @@ void QQmlEnginePrivate::init()
\inmodule QtQml
\brief The QQmlEngine class provides an environment for instantiating QML components.
- Each QML component is instantiated in a QQmlContext.
- QQmlContext's are essential for passing data to QML
- components. In QML, contexts are arranged hierarchically and this
- hierarchy is managed by the QQmlEngine.
+ A QQmlEngine is used to manage \l{QQmlComponent}{components} and objects created from
+ them and execute their bindings and functions. QQmlEngine also inherits from
+ \l{QJSEngine} which allows seamless integration between your QML components and
+ JavaScript code.
- Prior to creating any QML components, an application must have
- created a QQmlEngine to gain access to a QML context. The
- following example shows how to create a simple Text item.
-
- \code
- QQmlEngine engine;
- QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
- QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
+ Each QML component is instantiated in a QQmlContext. In QML, contexts are arranged
+ hierarchically and this hierarchy is managed by the QQmlEngine. By default,
+ components are instantiated in the \l {QQmlEngine::rootContext()}{root context}.
- //add item to view, etc
- ...
- \endcode
-
- In this case, the Text item will be created in the engine's
- \l {QQmlEngine::rootContext()}{root context}.
-
- \sa QQmlComponent, QQmlContext, {QML Global Object}
+ \sa QQmlComponent, QQmlContext, {QML Global Object}, QQmlApplicationEngine
*/
/*!
@@ -995,30 +540,29 @@ QQmlEngine::QQmlEngine(QQmlEnginePrivate &dd, QObject *parent)
invalidated, but not destroyed (unless they are parented to the
QQmlEngine object).
- See QJSEngine docs for details on cleaning up the JS engine.
+ See ~QJSEngine() for details on cleaning up the JS engine.
*/
QQmlEngine::~QQmlEngine()
{
Q_D(QQmlEngine);
+ handle()->inShutdown = true;
QJSEnginePrivate::removeFromDebugServer(this);
- d->typeLoader.invalidate();
-
// Emit onDestruction signals for the root context before
// we destroy the contexts, engine, Singleton Types etc. that
// may be required to handle the destruction signal.
- QQmlContextData::get(rootContext())->emitDestruction();
+ QQmlContextPrivate::get(rootContext())->emitDestruction();
// clean up all singleton type instances which we own.
// we do this here and not in the private dtor since otherwise a crash can
// occur (if we are the QObject parent of the QObject singleton instance)
// XXX TODO: performance -- store list of singleton types separately?
- QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes();
- for (const QQmlType &currType : singletonTypes)
- d->destroySingletonInstance(currType);
+ d->singletonInstances.clear();
delete d->rootContext;
d->rootContext = nullptr;
+
+ d->typeLoader.invalidate();
}
/*! \fn void QQmlEngine::quit()
@@ -1055,14 +599,35 @@ QQmlEngine::~QQmlEngine()
Once the component cache has been cleared, components must be loaded before
any new objects can be created.
- \sa trimComponentCache()
+ \note Any existing objects created from QML components retain their types,
+ even if you clear the component cache. This includes singleton objects. If you
+ create more objects from the same QML code after clearing the cache, the new
+ objects will be of different types than the old ones. Assigning such a new
+ object to a property of its declared type belonging to an object created
+ before clearing the cache won't work.
+
+ As a general rule of thumb, make sure that no objects created from QML
+ components are alive when you clear the component cache.
+
+ \sa trimComponentCache(), clearSingletons()
*/
void QQmlEngine::clearComponentCache()
{
Q_D(QQmlEngine);
+
+ // Contexts can hold on to CUs but live on the JS heap.
+ // Use a non-incremental GC run to get rid of those.
+ QV4::MemoryManager *mm = handle()->memoryManager;
+ auto oldLimit = mm->gcStateMachine->timeLimit;
+ mm->setGCTimeLimit(-1);
+ mm->runGC();
+ mm->gcStateMachine->timeLimit = std::move(oldLimit);
+
+ handle()->clearCompilationUnits();
d->typeLoader.lock();
d->typeLoader.clearCache();
d->typeLoader.unlock();
+ QQmlMetaType::freeUnusedTypesAndCaches();
}
/*!
@@ -1080,10 +645,32 @@ void QQmlEngine::clearComponentCache()
void QQmlEngine::trimComponentCache()
{
Q_D(QQmlEngine);
+ handle()->trimCompilationUnits();
d->typeLoader.trimCache();
}
/*!
+ Clears all singletons the engine owns.
+
+ This function drops all singleton instances, deleting any QObjects owned by
+ the engine among them. This is useful to make sure that no QML-created objects
+ are left before calling clearComponentCache().
+
+ QML properties holding QObject-based singleton instances become null if the
+ engine owns the singleton or retain their value if the engine doesn't own it.
+ The singletons are not automatically re-created by accessing existing
+ QML-created objects. Only when new components are instantiated, the singletons
+ are re-created.
+
+ \sa clearComponentCache()
+ */
+void QQmlEngine::clearSingletons()
+{
+ Q_D(QQmlEngine);
+ d->singletonInstances.clear();
+}
+
+/*!
Returns the engine's root context.
The root context is automatically created by the QQmlEngine.
@@ -1100,48 +687,77 @@ QQmlContext *QQmlEngine::rootContext() const
return d->rootContext;
}
+#if QT_DEPRECATED_SINCE(6, 0)
/*!
\internal
+ \deprecated
This API is private for 5.1
- Sets the \a urlInterceptor to be used when resolving URLs in QML.
+ Returns the last QQmlAbstractUrlInterceptor. It must not be modified outside
+ the GUI thread.
+*/
+QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const
+{
+ Q_D(const QQmlEngine);
+ return d->urlInterceptors.last();
+}
+#endif
+
+/*!
+ Adds a \a urlInterceptor to be used when resolving URLs in QML.
This also applies to URLs used for loading script files and QML types.
- This should not be modifed while the engine is loading files, or URL
- selection may be inconsistent.
+ The URL interceptors should not be modifed while the engine is loading files,
+ or URL selection may be inconsistent. Multiple URL interceptors, when given,
+ will be called in the order they were added for each URL.
+
+ QQmlEngine does not take ownership of the interceptor and won't delete it.
*/
-void QQmlEngine::setUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
+void QQmlEngine::addUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
{
Q_D(QQmlEngine);
- d->urlInterceptor = urlInterceptor;
+ d->urlInterceptors.append(urlInterceptor);
}
/*!
- \internal
- This API is private for 5.1
+ Remove a \a urlInterceptor that was previously added using
+ \l addUrlInterceptor. The URL interceptors should not be modifed while the
+ engine is loading files, or URL selection may be inconsistent.
- Returns the current QQmlAbstractUrlInterceptor. It must not be modified outside
- the GUI thread.
+ This does not delete the interceptor, but merely removes it from the engine.
+ You can re-use it on the same or a different engine afterwards.
*/
-QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const
+void QQmlEngine::removeUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor)
+{
+ Q_D(QQmlEngine);
+ d->urlInterceptors.removeOne(urlInterceptor);
+}
+
+/*!
+ Run the current URL interceptors on the given \a url of the given \a type and
+ return the result.
+ */
+QUrl QQmlEngine::interceptUrl(const QUrl &url, QQmlAbstractUrlInterceptor::DataType type) const
{
Q_D(const QQmlEngine);
- return d->urlInterceptor;
+ QUrl result = url;
+ for (QQmlAbstractUrlInterceptor *interceptor : d->urlInterceptors)
+ result = interceptor->intercept(result, type);
+ return result;
}
-void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
+/*!
+ Returns the list of currently active URL interceptors.
+ */
+QList<QQmlAbstractUrlInterceptor *> QQmlEngine::urlInterceptors() const
{
- if (activeObjectCreator) {
- activeObjectCreator->finalizeCallbacks()->append(qMakePair(QPointer<QObject>(obj), index));
- } else {
- void *args[] = { nullptr };
- QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
- }
+ Q_D(const QQmlEngine);
+ return d->urlInterceptors;
}
QSharedPointer<QQmlImageProviderBase> QQmlEnginePrivate::imageProvider(const QString &providerId) const
{
const QString providerIdLower = providerId.toLower();
- QMutexLocker locker(&mutex);
+ QMutexLocker locker(&imageProviderMutex);
return imageProviders.value(providerIdLower);
}
@@ -1236,7 +852,7 @@ void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBa
Q_D(QQmlEngine);
QString providerIdLower = providerId.toLower();
QSharedPointer<QQmlImageProviderBase> sp(provider);
- QMutexLocker locker(&d->mutex);
+ QMutexLocker locker(&d->imageProviderMutex);
d->imageProviders.insert(std::move(providerIdLower), std::move(sp));
}
@@ -1249,7 +865,7 @@ QQmlImageProviderBase *QQmlEngine::imageProvider(const QString &providerId) cons
{
Q_D(const QQmlEngine);
const QString providerIdLower = providerId.toLower();
- QMutexLocker locker(&d->mutex);
+ QMutexLocker locker(&d->imageProviderMutex);
return d->imageProviders.value(providerIdLower).data();
}
@@ -1262,7 +878,7 @@ void QQmlEngine::removeImageProvider(const QString &providerId)
{
Q_D(QQmlEngine);
const QString providerIdLower = providerId.toLower();
- QMutexLocker locker(&d->mutex);
+ QMutexLocker locker(&d->imageProviderMutex);
d->imageProviders.take(providerIdLower);
}
@@ -1280,7 +896,9 @@ QUrl QQmlEngine::baseUrl() const
{
Q_D(const QQmlEngine);
if (d->baseUrl.isEmpty()) {
- return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator());
+ const QString currentPath = QDir::currentPath();
+ const QString rootPath = QDir::rootPath();
+ return QUrl::fromLocalFile((currentPath == rootPath) ? rootPath : (currentPath + QDir::separator()));
} else {
return d->baseUrl;
}
@@ -1325,6 +943,75 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
d->outputWarningsToMsgLog = enabled;
}
+
+/*!
+ \since 6.6
+ If this method is called inside of a function that is part of
+ a binding in QML, the binding will be treated as a translation binding.
+
+ \code
+ class I18nAwareClass : public QObject {
+
+ //...
+
+ QString text() const
+ {
+ if (auto engine = qmlEngine(this))
+ engine->markCurrentFunctionAsTranslationBinding();
+ return tr("Hello, world!");
+ }
+ };
+ \endcode
+
+ \note This function is mostly useful if you wish to provide your
+ own alternative to the qsTr function. To ensure that properties
+ exposed from C++ classes are updated on language changes, it is
+ instead recommended to react to \c LanguageChange events. That
+ is a more general mechanism which also works when the class is
+ used in a non-QML context, and has slightly less overhead. However,
+ using \c markCurrentFunctionAsTranslationBinding can be acceptable
+ when the class is already closely tied to the QML engine.
+ For more details, see \l {Prepare for Dynamic Language Changes}
+
+ \sa QQmlEngine::retranslate
+*/
+void QQmlEngine::markCurrentFunctionAsTranslationBinding()
+{
+ Q_D(QQmlEngine);
+ if (auto propertyCapture = d->propertyCapture)
+ propertyCapture->captureTranslation();
+}
+
+/*!
+ \internal
+
+ Capture the given property as part of a binding.
+ */
+void QQmlEngine::captureProperty(QObject *object, const QMetaProperty &property) const
+{
+ Q_D(const QQmlEngine);
+ if (d->propertyCapture && !property.isConstant()) {
+ d->propertyCapture->captureProperty(
+ object, property.propertyIndex(),
+ QMetaObjectPrivate::signalIndex(property.notifySignal()));
+ }
+}
+
+/*!
+ \qmlproperty string Qt::uiLanguage
+ \since 5.15
+
+ The uiLanguage holds the name of the language to be used for user interface
+ string translations. It is exposed in C++ as QQmlEngine::uiLanguage property.
+
+ You can set the value freely and use it in bindings. It is recommended to set it
+ after installing translators in your application. By convention, an empty string
+ means no translation from the language used in the source code is intended to occur.
+
+ If you're using QQmlApplicationEngine and the value changes, QQmlEngine::retranslate()
+ will be called.
+*/
+
/*!
\fn template<typename T> T QQmlEngine::singletonInstance(int qmlTypeId)
@@ -1336,43 +1023,30 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
type, either a default constructed QJSValue or a \c nullptr is returned.
QObject* example:
- \code
- class MySingleton : public QObject {
- Q_OBJECT
- static int typeId;
- // ...
- };
- // Register with QObject* callback
- MySingleton::typeId = qmlRegisterSingletonType<MySingleton>(...);
-
- // Retrieve as QObject*
- QQmlEngine engine;
- MySingleton* instance = engine.singletonInstance<MySingleton*>(MySingleton::typeId);
- \endcode
+ \snippet code/src_qml_qqmlengine.cpp 0
+ \codeline
+ \snippet code/src_qml_qqmlengine.cpp 1
+ \codeline
+ \snippet code/src_qml_qqmlengine.cpp 2
QJSValue example:
- \code
- // Register with QJSValue callback
- int typeId = qmlRegisterSingletonType(...);
- // Retrieve as QJSValue
- QQmlEngine engine;
- QJSValue instance = engine.singletonInstance<QJSValue>(typeId);
- \endcode
+ \snippet code/src_qml_qqmlengine.cpp 3
+ \codeline
+ \snippet code/src_qml_qqmlengine.cpp 4
- It is recommended to store the QML type id during registration, e.g. as a static member
- in the singleton class. Otherwise, a costly lookup via qmlTypeId() has to be performed
- at run-time.
+ It is recommended to store the QML type id, e.g. as a static member in the
+ singleton class. The lookup via qmlTypeId() is costly.
- \sa qmlRegisterSingletonType(), qmlTypeId()
+ \sa QML_SINGLETON, qmlRegisterSingletonType(), qmlTypeId()
\since 5.12
*/
template<>
QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
{
Q_D(QQmlEngine);
- QQmlType type = QQmlMetaType::qmlType(qmlTypeId, QQmlMetaType::TypeIdCategory::QmlType);
+ QQmlType type = QQmlMetaType::qmlTypeById(qmlTypeId);
if (!type.isValid() || !type.isSingleton())
return QJSValue();
@@ -1380,6 +1054,48 @@ QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
return d->singletonInstance<QJSValue>(type);
}
+
+/*!
+ \fn template<typename T> T QQmlEngine::singletonInstance(QAnyStringView uri, QAnyStringView typeName)
+
+ \overload
+ Returns the instance of a singleton type named \a typeName from the module specified by \a uri.
+
+ This method can be used as an alternative to calling qmlTypeId followed by the id based overload of
+ singletonInstance. This is convenient when one only needs to do a one time setup of a
+ singleton; if repeated access to the singleton is required, caching its typeId will allow
+ faster subsequent access via the
+ \l {QQmlEngine::singletonInstance(int qmlTypeId)}{type-id based overload}.
+
+ The template argument \e T may be either QJSValue or a pointer to a QObject-derived
+ type and depends on how the singleton was registered. If no instance of \e T has been
+ created yet, it is created now. If \a typeName does not represent a valid singleton
+ type, either a default constructed QJSValue or a \c nullptr is returned.
+
+ \snippet code/src_qml_qqmlengine.cpp 5
+
+ \sa QML_SINGLETON, qmlRegisterSingletonType(), qmlTypeId()
+ \since 6.5
+*/
+template<>
+QJSValue QQmlEngine::singletonInstance<QJSValue>(QAnyStringView uri, QAnyStringView typeName)
+{
+ Q_D(QQmlEngine);
+
+ auto loadHelper = QQml::makeRefPointer<LoadHelper>(&d->typeLoader, uri);
+
+ auto [moduleStatus, type] = loadHelper->resolveType(typeName);
+
+ if (moduleStatus == LoadHelper::ResolveTypeResult::NoSuchModule)
+ return {};
+ if (!type.isValid())
+ return {};
+ if (!type.isSingleton())
+ return {};
+
+ return d->singletonInstance<QJSValue>(type);
+}
+
/*!
Refreshes all binding expressions that use strings marked for translation.
@@ -1387,31 +1103,23 @@ QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
QCoreApplication::installTranslator, to ensure that your user-interface
shows up-to-date translations.
- \note Due to a limitation in the implementation, this function
- refreshes all the engine's bindings, not only those that use strings
- marked for translation.
- This may be optimized in a future release.
-
\since 5.10
*/
void QQmlEngine::retranslate()
{
Q_D(QQmlEngine);
- QQmlContextData *context = QQmlContextData::get(d->rootContext)->childContexts;
- while (context) {
- context->refreshExpressions();
- context = context->nextChild;
- }
+ d->translationLanguage.notify();
}
/*!
- Returns the QQmlContext for the \a object, or 0 if no
+ Returns the QQmlContext for the \a object, or nullptr if no
context has been set.
- When the QQmlEngine instantiates a QObject, the context is
- set automatically.
+ When the QQmlEngine instantiates a QObject, an internal context is assigned
+ to it automatically. Such internal contexts are read-only. You cannot set
+ context properties on them.
- \sa qmlContext(), qmlEngine()
+ \sa qmlContext(), qmlEngine(), QQmlContext::setContextProperty()
*/
QQmlContext *QQmlEngine::contextForObject(const QObject *object)
{
@@ -1444,78 +1152,10 @@ void QQmlEngine::setContextForObject(QObject *object, QQmlContext *context)
return;
}
- QQmlContextData *contextData = QQmlContextData::get(context);
+ QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(context);
Q_ASSERT(data->context == nullptr);
- data->context = contextData;
- contextData->addObject(data);
-}
-
-/*!
- \enum QQmlEngine::ObjectOwnership
-
- ObjectOwnership controls whether or not QML automatically destroys the
- QObject when the corresponding JavaScript object is garbage collected by the
- engine. The two ownership options are:
-
- \value CppOwnership The object is owned by C++ code and QML will never delete
- it. The JavaScript destroy() method cannot be used on these objects. This
- option is similar to QScriptEngine::QtOwnership.
-
- \value JavaScriptOwnership The object is owned by JavaScript. When the object
- is returned to QML as the return value of a method call, QML will track it
- and delete it if there are no remaining JavaScript references to it and
- it has no QObject::parent(). An object tracked by one QQmlEngine will be
- deleted during that QQmlEngine's destructor. Thus, JavaScript references
- between objects with JavaScriptOwnership from two different engines will
- not be valid if one of these engines is deleted. This option is similar to
- QScriptEngine::ScriptOwnership.
-
- Generally an application doesn't need to set an object's ownership
- explicitly. QML uses a heuristic to set the default ownership. By default, an
- object that is created by QML has JavaScriptOwnership. The exception to this
- are the root objects created by calling QQmlComponent::create() or
- QQmlComponent::beginCreate(), which have CppOwnership by default. The
- ownership of these root-level objects is considered to have been transferred
- to the C++ caller.
-
- Objects not-created by QML have CppOwnership by default. The exception to this
- are objects returned from C++ method calls; their ownership will be set to
- JavaScriptOwnership. This applies only to explicit invocations of Q_INVOKABLE
- methods or slots, but not to property getter invocations.
-
- Calling setObjectOwnership() overrides the default ownership heuristic used by
- QML.
-*/
-
-/*!
- Sets the \a ownership of \a object.
-*/
-void QQmlEngine::setObjectOwnership(QObject *object, ObjectOwnership ownership)
-{
- if (!object)
- return;
-
- QQmlData *ddata = QQmlData::get(object, true);
- if (!ddata)
- return;
-
- ddata->indestructible = (ownership == CppOwnership)?true:false;
- ddata->explicitIndestructibleSet = true;
-}
-
-/*!
- Returns the ownership of \a object.
-*/
-QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
-{
- if (!object)
- return CppOwnership;
-
- QQmlData *ddata = QQmlData::get(object, false);
- if (!ddata)
- return CppOwnership;
- else
- return ddata->indestructible?CppOwnership:JavaScriptOwnership;
+ data->context = contextData.data();
+ contextData->addOwnedObject(data);
}
/*!
@@ -1523,165 +1163,13 @@ QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object)
*/
bool QQmlEngine::event(QEvent *e)
{
- Q_D(QQmlEngine);
- if (e->type() == QEvent::User)
- d->doDeleteInEngineThread();
- else if (e->type() == QEvent::LanguageChange) {
+ if (e->type() == QEvent::LanguageChange) {
retranslate();
}
return QJSEngine::event(e);
}
-void QQmlEnginePrivate::doDeleteInEngineThread()
-{
- QFieldList<Deletable, &Deletable::next> list;
- mutex.lock();
- list.copyAndClear(toDeleteInEngineThread);
- mutex.unlock();
-
- while (Deletable *d = list.takeFirst())
- delete d;
-}
-
-namespace QtQml {
-
-void qmlExecuteDeferred(QObject *object)
-{
- QQmlData *data = QQmlData::get(object);
-
- if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object)) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
-
- QQmlComponentPrivate::DeferredState state;
- QQmlComponentPrivate::beginDeferred(ep, object, &state);
-
- // Release the reference for the deferral action (we still have one from construction)
- data->releaseDeferredData();
-
- QQmlComponentPrivate::completeDeferred(ep, &state);
- }
-}
-
-QQmlContext *qmlContext(const QObject *obj)
-{
- return QQmlEngine::contextForObject(obj);
-}
-
-QQmlEngine *qmlEngine(const QObject *obj)
-{
- QQmlData *data = QQmlData::get(obj, false);
- if (!data || !data->context)
- return nullptr;
- return data->context->engine;
-}
-
-static QObject *resolveAttachedProperties(QQmlAttachedPropertiesFunc pf, QQmlData *data,
- QObject *object, bool create)
-{
- if (!pf)
- return nullptr;
-
- QObject *rv = data->hasExtendedData() ? data->attachedProperties()->value(pf) : 0;
- if (rv || !create)
- return rv;
-
- rv = pf(object);
-
- if (rv)
- data->attachedProperties()->insert(pf, rv);
-
- return rv;
-}
-
-#if QT_DEPRECATED_SINCE(5, 14)
-QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
-{
- QQmlData *data = QQmlData::get(object, create);
-
- // Attached properties are only on objects created by QML,
- // unless explicitly requested (create==true)
- if (!data)
- return nullptr;
-
- QQmlEnginePrivate *engine = QQmlEnginePrivate::get(data->context);
- return resolveAttachedProperties(QQmlMetaType::attachedPropertiesFuncById(engine, id), data,
- const_cast<QObject *>(object), create);
-}
-
-QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
- const QMetaObject *attachedMetaObject, bool create)
-{
- if (*idCache == -1) {
- QQmlEngine *engine = object ? qmlEngine(object) : nullptr;
- *idCache = QQmlMetaType::attachedPropertiesFuncId(engine ? QQmlEnginePrivate::get(engine) : nullptr, attachedMetaObject);
- }
-
- if (*idCache == -1 || !object)
- return nullptr;
-
- return qmlAttachedPropertiesObjectById(*idCache, object, create);
-}
-#endif
-
-QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object,
- const QMetaObject *attachedMetaObject)
-{
- QQmlEngine *engine = object ? qmlEngine(object) : nullptr;
- return QQmlMetaType::attachedPropertiesFunc(engine ? QQmlEnginePrivate::get(engine) : nullptr,
- attachedMetaObject);
-}
-
-QObject *qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool create)
-{
- if (!object)
- return nullptr;
-
- QQmlData *data = QQmlData::get(object, create);
-
- // Attached properties are only on objects created by QML,
- // unless explicitly requested (create==true)
- if (!data)
- return nullptr;
-
- return resolveAttachedProperties(func, data, object, create);
-}
-
-} // namespace QtQml
-
-#if QT_DEPRECATED_SINCE(5, 1)
-
-// Also define symbols outside namespace to keep binary compatibility with Qt 5.0
-
-Q_QML_EXPORT void qmlExecuteDeferred(QObject *obj)
-{
- QtQml::qmlExecuteDeferred(obj);
-}
-
-Q_QML_EXPORT QQmlContext *qmlContext(const QObject *obj)
-{
- return QtQml::qmlContext(obj);
-}
-
-Q_QML_EXPORT QQmlEngine *qmlEngine(const QObject *obj)
-{
- return QtQml::qmlEngine(obj);
-}
-
-Q_QML_EXPORT QObject *qmlAttachedPropertiesObjectById(int id, const QObject *obj, bool create)
-{
- return QtQml::qmlAttachedPropertiesObjectById(id, obj, create);
-}
-
-Q_QML_EXPORT QObject *qmlAttachedPropertiesObject(int *idCache, const QObject *object,
- const QMetaObject *attachedMetaObject,
- bool create)
-{
- return QtQml::qmlAttachedPropertiesObject(idCache, object, attachedMetaObject, create);
-}
-
-#endif // QT_DEPRECATED_SINCE(5, 1)
-
class QQmlDataExtended {
public:
QQmlDataExtended();
@@ -1751,7 +1239,9 @@ void QQmlData::NotifyList::layout()
todo = nullptr;
}
-void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *context)
+void QQmlData::deferData(
+ int objectIndex, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlRefPointer<QQmlContextData> &context)
{
QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
deferData->deferredIdx = objectIndex;
@@ -1759,13 +1249,14 @@ void QQmlData::deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCo
deferData->context = context;
const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(objectIndex);
- const QV4::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(objectIndex);
+ const QV4::CompiledData::BindingPropertyData *propertyData
+ = compilationUnit->bindingPropertyDataPerObjectAt(objectIndex);
const QV4::CompiledData::Binding *binding = compiledObject->bindingTable();
for (quint32 i = 0; i < compiledObject->nBindings; ++i, ++binding) {
- const QQmlPropertyData *property = propertyData.at(i);
- if (property && binding->flags & QV4::CompiledData::Binding::IsDeferredBinding)
- deferData->bindings.insert(property->coreIndex(), binding);
+ const QQmlPropertyData *property = propertyData->at(i);
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding))
+ deferData->bindings.insert(property ? property->coreIndex() : -1, binding);
}
deferredData.append(deferData);
@@ -1787,49 +1278,73 @@ void QQmlData::releaseDeferredData()
void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
{
- if (!notifyList) {
- notifyList = (NotifyList *)malloc(sizeof(NotifyList));
- notifyList->connectionMask = 0;
- notifyList->maximumTodoIndex = 0;
- notifyList->notifiesSize = 0;
- notifyList->todo = nullptr;
- notifyList->notifies = nullptr;
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
+
+ NotifyList *list = notifyList.loadRelaxed();
+
+ if (!list) {
+ list = new NotifyList;
+ // We don't really care when this change takes effect on other threads. The notifyList can
+ // only become non-null once in the life time of a QQmlData. It becomes null again when the
+ // underlying QObject is deleted. At that point any interaction with the QQmlData is UB
+ // anyway. So, for all intents and purposese, the list becomes non-null once and then stays
+ // non-null "forever". We can apply relaxed semantics.
+ notifyList.storeRelaxed(list);
}
Q_ASSERT(!endpoint->isConnected());
index = qMin(index, 0xFFFF - 1);
- notifyList->connectionMask |= (1ULL << quint64(index % 64));
- if (index < notifyList->notifiesSize) {
+ // Likewise, we don't really care _when_ the change in the connectionMask is propagated to other
+ // threads. Cross-thread event ordering is inherently nondeterministic. Therefore, when querying
+ // the conenctionMask in the presence of concurrent modification, any result is correct.
+ list->connectionMask.storeRelaxed(
+ list->connectionMask.loadRelaxed() | (1ULL << quint64(index % 64)));
- endpoint->next = notifyList->notifies[index];
+ if (index < list->notifiesSize) {
+ endpoint->next = list->notifies[index];
if (endpoint->next) endpoint->next->prev = &endpoint->next;
- endpoint->prev = &notifyList->notifies[index];
- notifyList->notifies[index] = endpoint;
-
+ endpoint->prev = &list->notifies[index];
+ list->notifies[index] = endpoint;
} else {
- notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
+ list->maximumTodoIndex = qMax(int(list->maximumTodoIndex), index);
- endpoint->next = notifyList->todo;
+ endpoint->next = list->todo;
if (endpoint->next) endpoint->next->prev = &endpoint->next;
- endpoint->prev = &notifyList->todo;
- notifyList->todo = endpoint;
+ endpoint->prev = &list->todo;
+ list->todo = endpoint;
}
}
-void QQmlData::disconnectNotifiers()
+void QQmlData::disconnectNotifiers(QQmlData::DeleteNotifyList doDelete)
{
- if (notifyList) {
- while (notifyList->todo)
- notifyList->todo->disconnect();
- for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
- while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
+ if (NotifyList *list = notifyList.loadRelaxed()) {
+ while (QQmlNotifierEndpoint *todo = list->todo)
+ todo->disconnect();
+ for (int ii = 0; ii < list->notifiesSize; ++ii) {
+ while (QQmlNotifierEndpoint *ep = list->notifies[ii])
ep->disconnect();
}
- free(notifyList->notifies);
- free(notifyList);
- notifyList = nullptr;
+ free(list->notifies);
+
+ if (doDelete == DeleteNotifyList::Yes) {
+ // We can only get here from QQmlData::destroyed(), and that can only come from the
+ // the QObject dtor. If you're still sending signals at that point you have UB already
+ // without any threads. Therefore, it's enough to apply relaxed semantics.
+ notifyList.storeRelaxed(nullptr);
+ delete list;
+ } else {
+ // We can use relaxed semantics here. The worst thing that can happen is that some
+ // signal is falsely reported as connected. Signal connectedness across threads
+ // is not quite deterministic anyway.
+ list->connectionMask.storeRelaxed(0);
+ list->maximumTodoIndex = 0;
+ list->notifiesSize = 0;
+ list->notifies = nullptr;
+
+ }
}
}
@@ -1845,8 +1360,8 @@ void QQmlData::destroyed(QObject *object)
nextContextObject->prevContextObject = prevContextObject;
if (prevContextObject)
*prevContextObject = nextContextObject;
- else if (outerContext && outerContext->contextObjects == this)
- outerContext->contextObjects = nextContextObject;
+ else if (outerContext && outerContext->ownedObjects() == this)
+ outerContext->setOwnedObjects(nextContextObject);
QQmlAbstractBinding *binding = bindings;
while (binding) {
@@ -1856,7 +1371,7 @@ void QQmlData::destroyed(QObject *object)
if (bindings && !bindings->ref.deref())
delete bindings;
- compilationUnit = nullptr;
+ compilationUnit.reset();
qDeleteAll(deferredData);
deferredData.clear();
@@ -1903,17 +1418,18 @@ void QQmlData::destroyed(QObject *object)
free(bindingBits);
if (propertyCache)
- propertyCache->release();
+ propertyCache.reset();
- ownContext = nullptr;
+ ownContext.reset();
while (guards) {
- QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
- *guard = (QObject *)nullptr;
- guard->objectDestroyed(object);
+ auto *guard = guards;
+ guard->setObject(nullptr);
+ if (guard->objectDestroyed)
+ guard->objectDestroyed(guard);
}
- disconnectNotifiers();
+ disconnectNotifiers(DeleteNotifyList::Yes);
if (extendedData)
delete extendedData;
@@ -1927,25 +1443,6 @@ void QQmlData::destroyed(QObject *object)
this->~QQmlData();
}
-DEFINE_BOOL_CONFIG_OPTION(parentTest, QML_PARENT_TEST);
-
-void QQmlData::parentChanged(QObject *object, QObject *parent)
-{
- if (parentTest()) {
- if (parentFrozen && !QObjectPrivate::get(object)->wasDeleted) {
- QString on;
- QString pn;
-
- { QDebug dbg(&on); dbg << object; on = on.left(on.length() - 1); }
- { QDebug dbg(&pn); dbg << parent; pn = pn.left(pn.length() - 1); }
-
- qFatal("Object %s has had its parent frozen by QML and cannot be changed.\n"
- "User code is attempting to change it to %s.\n"
- "This behavior is NOT supported!", qPrintable(on), qPrintable(pn));
- }
- }
-}
-
QQmlData::BindingBitsType *QQmlData::growBits(QObject *obj, int bit)
{
BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
@@ -1973,16 +1470,14 @@ QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv)
{
Q_ASSERT(priv);
Q_ASSERT(!priv->isDeletingChildren);
- priv->declarativeData = new QQmlData;
+ priv->declarativeData = new QQmlData(OwnsMemory);
return static_cast<QQmlData *>(priv->declarativeData);
}
-QQmlPropertyCache *QQmlData::createPropertyCache(QJSEngine *engine, QObject *object)
+QQmlPropertyCache::ConstPtr QQmlData::createPropertyCache(QObject *object)
{
QQmlData *ddata = QQmlData::get(object, /*create*/true);
- ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object);
- if (ddata->propertyCache)
- ddata->propertyCache->addref();
+ ddata->propertyCache = QQmlMetaType::propertyCache(object, QTypeRevision {});
return ddata->propertyCache;
}
@@ -2008,38 +1503,38 @@ static void dumpwarning(const QQmlError &error)
switch (error.messageType()) {
case QtDebugMsg:
QMessageLogger(error.url().toString().toLatin1().constData(),
- error.line(), nullptr).debug().nospace()
- << qPrintable(error.toString());
+ error.line(), nullptr).debug().noquote().nospace()
+ << error.toString();
break;
case QtInfoMsg:
QMessageLogger(error.url().toString().toLatin1().constData(),
- error.line(), nullptr).info().nospace()
- << qPrintable(error.toString());
+ error.line(), nullptr).info().noquote().nospace()
+ << error.toString();
break;
case QtWarningMsg:
case QtFatalMsg: // fatal does not support streaming, and furthermore, is actually fatal. Probably not desirable for QML.
QMessageLogger(error.url().toString().toLatin1().constData(),
- error.line(), nullptr).warning().nospace()
- << qPrintable(error.toString());
+ error.line(), nullptr).warning().noquote().nospace()
+ << error.toString();
break;
case QtCriticalMsg:
QMessageLogger(error.url().toString().toLatin1().constData(),
- error.line(), nullptr).critical().nospace()
- << qPrintable(error.toString());
+ error.line(), nullptr).critical().noquote().nospace()
+ << error.toString();
break;
}
}
static void dumpwarning(const QList<QQmlError> &errors)
{
- for (int ii = 0; ii < errors.count(); ++ii)
+ for (int ii = 0; ii < errors.size(); ++ii)
dumpwarning(errors.at(ii));
}
void QQmlEnginePrivate::warning(const QQmlError &error)
{
Q_Q(QQmlEngine);
- q->warnings(QList<QQmlError>() << error);
+ emit q->warnings(QList<QQmlError>({error}));
if (outputWarningsToMsgLog)
dumpwarning(error);
}
@@ -2047,7 +1542,7 @@ void QQmlEnginePrivate::warning(const QQmlError &error)
void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
{
Q_Q(QQmlEngine);
- q->warnings(errors);
+ emit q->warnings(errors);
if (outputWarningsToMsgLog)
dumpwarning(errors);
}
@@ -2090,15 +1585,15 @@ QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(
QList<QQmlError> errors;
for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
if (m.isWarning()) {
- qWarning("%s:%d : %s", qPrintable(fileName), m.line, qPrintable(m.message));
+ qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message));
continue;
}
QQmlError error;
error.setUrl(QUrl(fileName));
error.setDescription(m.message);
- error.setLine(m.line);
- error.setColumn(m.column);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(m.loc.startLine));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(m.loc.startColumn));
errors << error;
}
return errors;
@@ -2130,7 +1625,8 @@ void QQmlEnginePrivate::cleanupScarceResources()
The newly added \a path will be first in the importPathList().
- \sa setImportPathList(), {QML Modules}
+ \b {See also} \l setImportPathList(), \l {QML Modules},
+ and \l [QtQml] {QML Import Path}
*/
void QQmlEngine::addImportPath(const QString& path)
{
@@ -2148,9 +1644,8 @@ void QQmlEngine::addImportPath(const QString& path)
provided by that module. A \c qmldir file is required for defining the
type version mapping and possibly QML extensions plugins.
- By default, the list contains the directory of the application executable,
- paths specified in the \c QML2_IMPORT_PATH environment variable,
- and the builtin \c Qml2ImportsPath from QLibraryInfo.
+ By default, this list contains the paths mentioned in
+ \l {QML Import Path}.
\sa addImportPath(), setImportPathList()
*/
@@ -2164,9 +1659,11 @@ QStringList QQmlEngine::importPathList() const
Sets \a paths as the list of directories where the engine searches for
installed modules in a URL-based directory structure.
- By default, the list contains the directory of the application executable,
- paths specified in the \c QML2_IMPORT_PATH environment variable,
- and the builtin \c Qml2ImportsPath from QLibraryInfo.
+ By default, this list contains the paths mentioned in
+ \l {QML Import Path}.
+
+ \warning Calling setImportPathList does not preserve the default
+ import paths.
\sa importPathList(), addImportPath()
*/
@@ -2194,7 +1691,6 @@ void QQmlEngine::addPluginPath(const QString& path)
d->importDatabase.addPluginPath(path);
}
-
/*!
Returns the list of directories where the engine searches for
native plugins for imported modules (referenced in the \c qmldir file).
@@ -2227,20 +1723,31 @@ void QQmlEngine::setPluginPathList(const QStringList &paths)
}
#if QT_CONFIG(library)
+#if QT_DEPRECATED_SINCE(6, 4)
/*!
+ \deprecated [6.4] Import the module from QML with an "import" statement instead.
+
Imports the plugin named \a filePath with the \a uri provided.
Returns true if the plugin was successfully imported; otherwise returns false.
On failure and if non-null, the \a errors list will have any errors which occurred prepended to it.
The plugin has to be a Qt plugin which implements the QQmlEngineExtensionPlugin interface.
+
+ \note Directly loading plugins like this can confuse the module import logic. In order to make
+ the import logic load plugins from a specific place, you can use \l addPluginPath(). Each
+ plugin should be part of a QML module that you can import using the "import" statement.
*/
bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
{
Q_D(QQmlEngine);
- return d->importDatabase.importDynamicPlugin(filePath, uri, QString(), -1, errors);
+ QQmlTypeLoaderQmldirContent qmldir;
+ QQmlPluginImporter importer(
+ uri, QTypeRevision(), &d->importDatabase, &qmldir, &d->typeLoader, errors);
+ return importer.importDynamicPlugin(filePath, uri, false).isValid();
}
#endif
+#endif
/*!
\property QQmlEngine::offlineStoragePath
@@ -2249,7 +1756,7 @@ bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList
Returns the directory where SQL and other offline
storage is placed.
- The SQL databases created with openDatabase() are stored here.
+ The SQL databases created with \c openDatabaseSync() are stored here.
The default is QML/OfflineStorage in the platform-standard
user application data directory.
@@ -2257,11 +1764,23 @@ bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList
Note that the path may not currently exist on the filesystem, so
callers wanting to \e create new files at this location should create
it first - see QDir::mkpath().
+
+ \sa {Qt Quick Local Storage QML Types}
*/
+
+/*!
+ \fn void QQmlEngine::offlineStoragePathChanged()
+ This signal is emitted when \l offlineStoragePath changes.
+ \since 6.5
+*/
+
void QQmlEngine::setOfflineStoragePath(const QString& dir)
{
Q_D(QQmlEngine);
+ if (dir == d->offlineStoragePath)
+ return;
d->offlineStoragePath = dir;
+ Q_EMIT offlineStoragePathChanged();
}
QString QQmlEngine::offlineStoragePath() const
@@ -2269,12 +1788,14 @@ QString QQmlEngine::offlineStoragePath() const
Q_D(const QQmlEngine);
if (d->offlineStoragePath.isEmpty()) {
- QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
+ QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QQmlEnginePrivate *e = const_cast<QQmlEnginePrivate *>(d);
- if (!dataLocation.isEmpty())
+ if (!dataLocation.isEmpty()) {
e->offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator())
+ QDir::separator() + QLatin1String("QML")
+ QDir::separator() + QLatin1String("OfflineStorage");
+ Q_EMIT e->q_func()->offlineStoragePathChanged();
+ }
}
return d->offlineStoragePath;
@@ -2295,144 +1816,24 @@ QString QQmlEngine::offlineStorageDatabaseFilePath(const QString &databaseName)
return d->offlineStorageDatabaseDirectory() + QLatin1String(md5.result().toHex());
}
-// #### Qt 6: Remove this function, it exists only for binary compatibility.
-/*!
- * \internal
- */
-bool QQmlEngine::addNamedBundle(const QString &name, const QString &fileName)
-{
- Q_UNUSED(name)
- Q_UNUSED(fileName)
- return false;
-}
-
QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const
{
Q_Q(const QQmlEngine);
return q->offlineStoragePath() + QDir::separator() + QLatin1String("Databases") + QDir::separator();
}
-bool QQmlEnginePrivate::isQObject(int t)
-{
- Locker locker(this);
- return m_compositeTypes.contains(t) || QQmlMetaType::isQObject(t);
-}
-
-QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const
-{
- Locker locker(this);
- int t = v.userType();
- if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) {
- if (ok) *ok = true;
- return *(QObject *const *)(v.constData());
- } else {
- return QQmlMetaType::toQObject(v, ok);
- }
-}
-
-QQmlMetaType::TypeCategory QQmlEnginePrivate::typeCategory(int t) const
-{
- Locker locker(this);
- if (m_compositeTypes.contains(t))
- return QQmlMetaType::Object;
- return QQmlMetaType::typeCategory(t);
-}
-
-bool QQmlEnginePrivate::isList(int t) const
-{
- return QQmlMetaType::isList(t);
-}
-
-int QQmlEnginePrivate::listType(int t) const
-{
- return QQmlMetaType::listType(t);
-}
-
-QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
-{
- Locker locker(this);
- auto iter = m_compositeTypes.constFind(t);
- if (iter != m_compositeTypes.cend()) {
- return QQmlMetaObject((*iter)->rootPropertyCache().data());
- } else {
- QQmlType type = QQmlMetaType::qmlType(t);
- return QQmlMetaObject(type.baseMetaObject());
- }
-}
-
-QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
-{
- Locker locker(this);
- auto iter = m_compositeTypes.constFind(t);
- if (iter != m_compositeTypes.cend()) {
- return QQmlMetaObject((*iter)->rootPropertyCache().data());
- } else {
- QQmlType type = QQmlMetaType::qmlType(t);
- return QQmlMetaObject(type.metaObject());
- }
-}
-
-QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
-{
- Locker locker(this);
- auto iter = m_compositeTypes.constFind(t);
- if (iter != m_compositeTypes.cend()) {
- return (*iter)->rootPropertyCache().data();
- } else {
- QQmlType type = QQmlMetaType::qmlType(t);
- locker.unlock();
- return type.isValid() ? cache(type.metaObject()) : nullptr;
- }
-}
-
-QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t, int minorVersion)
-{
- Locker locker(this);
- auto iter = m_compositeTypes.constFind(t);
- if (iter != m_compositeTypes.cend()) {
- return (*iter)->rootPropertyCache().data();
- } else {
- QQmlType type = QQmlMetaType::qmlType(t);
- locker.unlock();
-
- if (minorVersion >= 0)
- return type.isValid() ? cache(type, minorVersion) : nullptr;
- else
- return type.isValid() ? cache(type.baseMetaObject()) : nullptr;
- }
-}
-
-void QQmlEnginePrivate::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
-{
- compilationUnit->isRegisteredWithEngine = true;
-
- Locker locker(this);
- // The QQmlCompiledData is not referenced here, but it is removed from this
- // hash in the QQmlCompiledData destructor
- m_compositeTypes.insert(compilationUnit->metaTypeId, compilationUnit);
-}
-
-void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
-{
- compilationUnit->isRegisteredWithEngine = false;
-
- Locker locker(this);
- m_compositeTypes.remove(compilationUnit->metaTypeId);
-}
-
template<>
QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
{
Q_Q(QQmlEngine);
- QJSValue value = singletonInstances.value(type);
- if (!value.isUndefined()) {
- return value;
- }
-
- QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
+ QQmlType::SingletonInstanceInfo::ConstPtr siinfo = type.singletonInstanceInfo();
Q_ASSERT(siinfo != nullptr);
+ QJSValue value = singletonInstances.value(siinfo);
+ if (!value.isUndefined())
+ return value;
+
if (siinfo->scriptCallback) {
value = siinfo->scriptCallback(q, q);
if (value.isQObject()) {
@@ -2441,7 +1842,7 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
// should behave identically to QML singleton types.
q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
}
- singletonInstances.insert(type, value);
+ singletonInstances.convertAndInsert(v4engine(), siinfo, &value);
} else if (siinfo->qobjectCallback) {
QObject *o = siinfo->qobjectCallback(q, q);
@@ -2452,49 +1853,160 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
qPrintable(QString::fromUtf8(type.typeName()))));
warning(error);
} else {
+ type.createProxy(o);
+
// if this object can use a property cache, create it now
- QQmlData::ensurePropertyCache(q, o);
+ QQmlData::ensurePropertyCache(o);
+
+ // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
+ // should behave identically to QML singleton types. You can, however, manually
+ // assign a context; and clearSingletons() retains the contexts, in which case
+ // we don't want to see warnings about the object already having a context.
+ QQmlData *data = QQmlData::get(o, true);
+ if (!data->context) {
+ auto contextData = QQmlContextData::get(new QQmlContext(q->rootContext(), q));
+ data->context = contextData.data();
+ contextData->addOwnedObject(data);
+ }
}
- // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
- // should behave identically to QML singleton types.
- q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
+
value = q->newQObject(o);
- singletonInstances.insert(type, value);
+ singletonInstances.convertAndInsert(v4engine(), siinfo, &value);
} else if (!siinfo->url.isEmpty()) {
QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous);
+ if (component.isError()) {
+ warning(component.errors());
+ v4engine()->throwError(QLatin1String("Due to the preceding error(s), Singleton \"%1\" could not be loaded.").arg(QString::fromUtf8(type.typeName())));
+
+ return QJSValue(QJSValue::UndefinedValue);
+ }
QObject *o = component.beginCreate(q->rootContext());
value = q->newQObject(o);
- singletonInstances.insert(type, value);
+ singletonInstances.convertAndInsert(v4engine(), siinfo, &value);
component.completeCreate();
}
return value;
}
-void QQmlEnginePrivate::destroySingletonInstance(const QQmlType &type)
+bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
{
- Q_ASSERT(type.isSingleton() || type.isCompositeSingleton());
+ return typeLoader.isTypeLoaded(url);
+}
- QObject* o = singletonInstances.take(type).toQObject();
- if (o) {
- QQmlData *ddata = QQmlData::get(o, false);
- if (type.singletonInstanceInfo()->url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet)
- return;
- delete o;
+bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
+{
+ return typeLoader.isScriptLoaded(url);
+}
+
+void QQmlEnginePrivate::executeRuntimeFunction(const QUrl &url, qsizetype functionIndex,
+ QObject *thisObject, int argc, void **args,
+ QMetaType *types)
+{
+ const auto unit = compilationUnitFromUrl(url);
+ if (!unit)
+ return;
+ executeRuntimeFunction(unit, functionIndex, thisObject, argc, args, types);
+}
+
+void QQmlEnginePrivate::executeRuntimeFunction(const QV4::ExecutableCompilationUnit *unit,
+ qsizetype functionIndex, QObject *thisObject,
+ int argc, void **args, QMetaType *types)
+{
+ Q_ASSERT(unit);
+ Q_ASSERT((functionIndex >= 0) && (functionIndex < unit->runtimeFunctions.size()));
+ Q_ASSERT(thisObject);
+
+ QQmlData *ddata = QQmlData::get(thisObject);
+ Q_ASSERT(ddata && ddata->outerContext);
+
+ QV4::Function *function = unit->runtimeFunctions[functionIndex];
+ Q_ASSERT(function);
+ Q_ASSERT(function->compiledFunction);
+
+ QV4::ExecutionEngine *v4 = v4engine();
+
+ // NB: always use scriptContext() by default as this method ignores whether
+ // there's already a stack frame (except when dealing with closures). the
+ // method is called from C++ (through QQmlEngine::executeRuntimeFunction())
+ // and thus the caller must ensure correct setup
+ QV4::Scope scope(v4);
+ QV4::ExecutionContext *ctx = v4->scriptContext();
+ QV4::Scoped<QV4::ExecutionContext> callContext(scope,
+ QV4::QmlContext::create(ctx, ddata->outerContext, thisObject));
+
+ if (auto nested = function->nestedFunction()) {
+ // if a nested function is already known, call the closure directly
+ function = nested;
+ } else if (function->isClosureWrapper()) {
+ // if there is a nested function, but we don't know it, we need to call
+ // an outer function first and then the inner function. we fetch the
+ // return value of a function call (that is a closure) by calling a
+ // different version of ExecutionEngine::callInContext() that returns a
+ // QV4::ReturnedValue with no arguments since they are not needed by the
+ // outer function anyhow
+ QV4::ScopedFunctionObject result(scope,
+ v4->callInContext(function, thisObject, callContext, 0, nullptr));
+ Q_ASSERT(result->function());
+ Q_ASSERT(result->function()->compilationUnit == function->compilationUnit);
+
+ // overwrite the function and its context
+ function = result->function();
+ callContext = QV4::Scoped<QV4::ExecutionContext>(scope, result->scope());
}
+
+ v4->callInContext(function, thisObject, callContext, argc, args, types);
}
-bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
+QV4::ExecutableCompilationUnit *QQmlEnginePrivate::compilationUnitFromUrl(const QUrl &url)
{
- return typeLoader.isTypeLoaded(url);
+ QV4::ExecutionEngine *v4 = v4engine();
+ if (auto unit = v4->compilationUnitForUrl(url)) {
+ if (!unit->runtimeStrings)
+ unit->populate();
+ return unit.data();
+ }
+
+ auto unit = typeLoader.getType(url)->compilationUnit();
+ if (!unit)
+ return nullptr;
+
+ auto executable = v4->executableCompilationUnit(std::move(unit));
+ executable->populate();
+ return executable.data();
}
-bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
+QQmlRefPointer<QQmlContextData>
+QQmlEnginePrivate::createInternalContext(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QQmlRefPointer<QQmlContextData> &parentContext,
+ int subComponentIndex, bool isComponentRoot)
{
- return typeLoader.isScriptLoaded(url);
+ Q_ASSERT(unit);
+
+ QQmlRefPointer<QQmlContextData> context;
+ context = QQmlContextData::createRefCounted(parentContext);
+ context->setInternal(true);
+ context->setImports(unit->typeNameCache());
+ context->initFromTypeCompilationUnit(unit, subComponentIndex);
+
+ const auto *dependentScripts = unit->dependentScriptsPtr();
+ const qsizetype dependentScriptsSize = dependentScripts->size();
+ if (isComponentRoot && dependentScriptsSize) {
+ QV4::ExecutionEngine *v4 = v4engine();
+ Q_ASSERT(v4);
+ QV4::Scope scope(v4);
+
+ QV4::ScopedObject scripts(scope, v4->newArrayObject(dependentScriptsSize));
+ context->setImportedScripts(QV4::PersistentValue(v4, scripts.asReturnedValue()));
+ QV4::ScopedValue v(scope);
+ for (qsizetype i = 0; i < dependentScriptsSize; ++i)
+ scripts->put(i, (v = dependentScripts->at(i)->scriptValueForContext(context)));
+ }
+
+ return context;
}
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+#if defined(Q_OS_WIN)
// Normalize a file name using Shell API. As opposed to converting it
// to a short 8.3 name and back, this also works for drives where 8.3 notation
// is disabled (see 8dot3name options of fsutil.exe).
@@ -2526,7 +2038,7 @@ static inline QString shellNormalizeFileName(const QString &name)
canonicalName[0] = canonicalName.at(0).toUpper();
return QDir::cleanPath(canonicalName);
}
-#endif // Q_OS_WIN && !Q_OS_WINRT
+#endif // Q_OS_WIN
bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
{
@@ -2534,7 +2046,7 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
QFileInfo info(fileName);
const QString absolute = info.absoluteFilePath();
-#if defined(Q_OS_DARWIN) || defined(Q_OS_WINRT)
+#if defined(Q_OS_DARWIN)
const QString canonical = info.canonicalFilePath();
#elif defined(Q_OS_WIN)
// No difference if the path is qrc based
@@ -2571,8 +2083,8 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
return false;
}
#else
- Q_UNUSED(lengthIn)
- Q_UNUSED(fileName)
+ Q_UNUSED(lengthIn);
+ Q_UNUSED(fileName);
#endif
return true;
}
@@ -2601,6 +2113,53 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
\sa {QQmlEngine::contextForObject()}{contextForObject()}, qmlEngine()
*/
+void hasJsOwnershipIndicator(QQmlGuardImpl *) {};
+
+LoadHelper::LoadHelper(QQmlTypeLoader *loader, QAnyStringView uri)
+ : QQmlTypeLoader::Blob({}, QQmlDataBlob::QmlFile, loader)
+ , m_uri(uri.toString())
+
+{
+ auto import = std::make_shared<PendingImport>();
+ import->uri = m_uri;
+ QList<QQmlError> errorList;
+ if (!Blob::addImport(import, &errorList)) {
+ qCDebug(lcQmlImport) << "LoadHelper: Errors loading " << m_uri << errorList;
+ m_uri.clear(); // reset m_uri to remember the failure
+ }
+}
+
+LoadHelper::ResolveTypeResult LoadHelper::resolveType(QAnyStringView typeName)
+{
+ QQmlType type;
+ if (!couldFindModule())
+ return {ResolveTypeResult::NoSuchModule, type};
+ QQmlTypeModule *module = QQmlMetaType::typeModule(m_uri, QTypeRevision{});
+ if (module) {
+ type = module->type(typeName.toString(), {});
+ if (type.isValid())
+ return {ResolveTypeResult::ModuleFound, type};
+ }
+ // The module exists (see check above), but there is no QQmlTypeModule
+ // ==> pure QML module, attempt resolveType
+ QTypeRevision versionReturn;
+ QList<QQmlError> errors;
+ QQmlImportNamespace *ns_return = nullptr;
+ m_importCache->resolveType(
+ typeLoader(), typeName.toString(), &type, &versionReturn, &ns_return, &errors);
+ return {ResolveTypeResult::ModuleFound, type};
+}
+
+bool LoadHelper::couldFindModule() const
+{
+ if (m_uri.isEmpty())
+ return false;
+ for (const auto &import: std::as_const(m_unresolvedImports))
+ if (import->priority == 0) // compare QQmlTypeData::allDependenciesDone
+ return false;
+ return true;
+}
+
QT_END_NAMESPACE
#include "moc_qqmlengine.cpp"
diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h
index 31fe3a1849..9c20090613 100644
--- a/src/qml/qml/qqmlengine.h
+++ b/src/qml/qml/qqmlengine.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLENGINE_H
#define QQMLENGINE_H
@@ -46,21 +10,20 @@
#include <QtQml/qjsengine.h>
#include <QtQml/qqml.h>
#include <QtQml/qqmlerror.h>
+#include <QtQml/qqmlabstracturlinterceptor.h>
QT_BEGIN_NAMESPACE
-class QQmlAbstractUrlInterceptor;
-
-class Q_QML_EXPORT QQmlImageProviderBase
+class Q_QML_EXPORT QQmlImageProviderBase : public QObject
{
+ Q_OBJECT
public:
- enum ImageType {
+ enum ImageType : int {
+ Invalid = 0,
Image,
Pixmap,
Texture,
- Invalid,
- ImageResponse
- // ### Qt6: reorder these, and give Invalid a fixed large value
+ ImageResponse,
};
enum Flag {
@@ -81,7 +44,6 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlImageProviderBase::Flags)
class QQmlComponent;
class QQmlEnginePrivate;
-class QQmlImportsPrivate;
class QQmlExpression;
class QQmlContext;
class QQmlType;
@@ -93,7 +55,7 @@ class QQmlNetworkAccessManagerFactory;
class QQmlIncubationController;
class Q_QML_EXPORT QQmlEngine : public QJSEngine
{
- Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath)
+ Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath NOTIFY offlineStoragePathChanged)
Q_OBJECT
public:
explicit QQmlEngine(QObject *p = nullptr);
@@ -103,6 +65,7 @@ public:
void clearComponentCache();
void trimComponentCache();
+ void clearSingletons();
QStringList importPathList() const;
void setImportPathList(const QStringList &paths);
@@ -112,11 +75,16 @@ public:
void setPluginPathList(const QStringList &paths);
void addPluginPath(const QString& dir);
- bool addNamedBundle(const QString &name, const QString &fileName);
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED bool addNamedBundle(const QString &, const QString &) { return false; }
+#endif
#if QT_CONFIG(library)
+#if QT_DEPRECATED_SINCE(6, 4)
+ QT_DEPRECATED_VERSION_X_6_4("Import the module from QML instead")
bool importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors);
#endif
+#endif
#if QT_CONFIG(qml_network)
void setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *);
@@ -125,8 +93,18 @@ public:
QNetworkAccessManager *networkAccessManager() const;
#endif
- void setUrlInterceptor(QQmlAbstractUrlInterceptor* urlInterceptor);
- QQmlAbstractUrlInterceptor* urlInterceptor() const;
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED void setUrlInterceptor(QQmlAbstractUrlInterceptor* urlInterceptor)
+ {
+ addUrlInterceptor(urlInterceptor);
+ }
+ QT_DEPRECATED QQmlAbstractUrlInterceptor *urlInterceptor() const;
+#endif
+
+ void addUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor);
+ void removeUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor);
+ QList<QQmlAbstractUrlInterceptor *> urlInterceptors() const;
+ QUrl interceptUrl(const QUrl &url, QQmlAbstractUrlInterceptor::DataType type) const;
void addImageProvider(const QString &id, QQmlImageProviderBase *);
QQmlImageProviderBase *imageProvider(const QString &id) const;
@@ -145,19 +123,26 @@ public:
bool outputWarningsToStandardError() const;
void setOutputWarningsToStandardError(bool);
+ void markCurrentFunctionAsTranslationBinding();
+
template<typename T>
T singletonInstance(int qmlTypeId);
+ template<typename T>
+ T singletonInstance(QAnyStringView moduleName, QAnyStringView typeName);
+
+ void captureProperty(QObject *object, const QMetaProperty &property) const;
+
public Q_SLOTS:
void retranslate();
+Q_SIGNALS:
+ void offlineStoragePathChanged();
+
public:
static QQmlContext *contextForObject(const QObject *);
static void setContextForObject(QObject *, QQmlContext *);
- enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
- static void setObjectOwnership(QObject *, ObjectOwnership);
- static ObjectOwnership objectOwnership(QObject *);
protected:
QQmlEngine(QQmlEnginePrivate &dd, QObject *p);
bool event(QEvent *) override;
@@ -180,6 +165,15 @@ T QQmlEngine::singletonInstance(int qmlTypeId) {
return qobject_cast<T>(singletonInstance<QJSValue>(qmlTypeId).toQObject());
}
+template<>
+Q_QML_EXPORT QJSValue QQmlEngine::singletonInstance<QJSValue>(QAnyStringView uri, QAnyStringView typeName);
+
+template<typename T>
+T QQmlEngine::singletonInstance(QAnyStringView uri, QAnyStringView typeName)
+{
+ return qobject_cast<T>(singletonInstance<QJSValue>(uri, typeName).toQObject());
+}
+
QT_END_NAMESPACE
#endif // QQMLENGINE_H
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 98c7823921..7c820679ba 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLENGINE_P_H
#define QQMLENGINE_P_H
@@ -53,60 +17,46 @@
#include "qqmlengine.h"
-#include "qqmltypeloader_p.h"
-#include "qqmlimport_p.h"
-#include <private/qpodvector_p.h>
-#include "qqml.h"
-#include "qqmlvaluetype_p.h"
-#include "qqmlcontext.h"
-#include "qqmlcontext_p.h"
-#include "qqmlexpression.h"
-#include "qqmlproperty_p.h"
-#include "qqmlmetatype_p.h"
+#include <private/qfieldlist_p.h>
#include <private/qintrusivelist_p.h>
+#include <private/qjsengine_p.h>
+#include <private/qjsvalue_p.h>
+#include <private/qpodvector_p.h>
+#include <private/qqmldirparser_p.h>
+#include <private/qqmlimport_p.h>
+#include <private/qqmlmetatype_p.h>
+#include <private/qqmlnotifier_p.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmltypeloader_p.h>
+#include <private/qqmlvaluetype_p.h>
#include <private/qrecyclepool_p.h>
-#include <private/qfieldlist_p.h>
#include <private/qv4engine_p.h>
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlcontext.h>
+
#include <QtCore/qlist.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qmutex.h>
#include <QtCore/qpair.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qproperty.h>
#include <QtCore/qstack.h>
-#include <QtCore/qmutex.h>
#include <QtCore/qstring.h>
#include <QtCore/qthread.h>
-#include <private/qobject_p.h>
-
-#include <private/qjsengine_p.h>
-#include <private/qqmldirparser_p.h>
+#include <atomic>
QT_BEGIN_NAMESPACE
-class QQmlContext;
-class QQmlEngine;
-class QQmlContextPrivate;
-class QQmlExpression;
-class QQmlImportDatabase;
-class QNetworkReply;
class QNetworkAccessManager;
-class QQmlNetworkAccessManagerFactory;
-class QQmlTypeNameCache;
-class QQmlComponentAttached;
-class QQmlCleanup;
class QQmlDelayedError;
-class QQmlObjectCreator;
-class QDir;
class QQmlIncubator;
+class QQmlMetaObject;
+class QQmlNetworkAccessManagerFactory;
+class QQmlObjectCreator;
class QQmlProfiler;
class QQmlPropertyCapture;
-class QQmlMetaObject;
-
-struct QObjectForeign {
- Q_GADGET
- QML_FOREIGN(QObject)
- QML_NAMED_ELEMENT(QtObject)
- Q_CLASSINFO("QML.Root", "QML")
-};
// This needs to be declared here so that the pool for it can live in QQmlEnginePrivate.
// The inline method definitions are in qqmljavascriptexpression_p.h
@@ -123,11 +73,35 @@ public:
QQmlJavaScriptExpressionGuard *next;
};
-class Q_QML_PRIVATE_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
+struct QPropertyChangeTrigger : QPropertyObserver {
+ Q_DISABLE_COPY_MOVE(QPropertyChangeTrigger)
+
+ QPropertyChangeTrigger(QQmlJavaScriptExpression *expression)
+ : QPropertyObserver(&QPropertyChangeTrigger::trigger)
+ , m_expression(expression)
+ {
+ }
+
+ QPointer<QObject> target;
+ QQmlJavaScriptExpression *m_expression;
+ int propertyIndex = 0;
+ static void trigger(QPropertyObserver *, QUntypedPropertyData *);
+
+ QMetaProperty property() const;
+};
+
+struct TriggerList : QPropertyChangeTrigger {
+ TriggerList(QQmlJavaScriptExpression *expression)
+ : QPropertyChangeTrigger(expression)
+ {}
+ TriggerList *next = nullptr;
+};
+
+class Q_QML_EXPORT QQmlEnginePrivate : public QJSEnginePrivate
{
Q_DECLARE_PUBLIC(QQmlEngine)
public:
- QQmlEnginePrivate(QQmlEngine *);
+ explicit QQmlEnginePrivate(QQmlEngine *q) : importDatabase(q), typeLoader(q) {}
~QQmlEnginePrivate() override;
void init();
@@ -135,52 +109,48 @@ public:
// is just qmlClearTypeRegistrations (which can't be called while an engine exists)
static bool baseModulesUninitialized;
- QQmlPropertyCapture *propertyCapture;
+ QQmlPropertyCapture *propertyCapture = nullptr;
QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool;
+ QRecyclePool<TriggerList> qPropertyTriggerPool;
- QQmlContext *rootContext;
+ QQmlContext *rootContext = nullptr;
+ Q_OBJECT_BINDABLE_PROPERTY(QQmlEnginePrivate, QString, translationLanguage);
#if !QT_CONFIG(qml_debug)
static const quintptr profiler = 0;
#else
- QQmlProfiler *profiler;
+ QQmlProfiler *profiler = nullptr;
#endif
- bool outputWarningsToMsgLog;
-
- // Registered cleanup handlers
- QQmlCleanup *cleanup;
+ bool outputWarningsToMsgLog = true;
// Bindings that have had errors during startup
- QQmlDelayedError *erroredBindings;
- int inProgressCreations;
+ QQmlDelayedError *erroredBindings = nullptr;
+ int inProgressCreations = 0;
QV4::ExecutionEngine *v4engine() const { return q_func()->handle(); }
#if QT_CONFIG(qml_worker_script)
- QThread *workerScriptEngine;
+ QThread *workerScriptEngine = nullptr;
#endif
QUrl baseUrl;
- typedef QPair<QPointer<QObject>,int> FinalizeCallback;
- void registerFinalizeCallback(QObject *obj, int index);
-
- QQmlObjectCreator *activeObjectCreator;
+ QQmlObjectCreator *activeObjectCreator = nullptr;
#if QT_CONFIG(qml_network)
QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
QNetworkAccessManager *getNetworkAccessManager() const;
- mutable QNetworkAccessManager *networkAccessManager;
- mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory;
+ mutable QNetworkAccessManager *networkAccessManager = nullptr;
+ mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory = nullptr;
#endif
+ mutable QRecursiveMutex imageProviderMutex;
QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders;
QSharedPointer<QQmlImageProviderBase> imageProvider(const QString &providerId) const;
+ QList<QQmlAbstractUrlInterceptor *> urlInterceptors;
- QQmlAbstractUrlInterceptor* urlInterceptor;
-
- int scarceResourcesRefCount;
+ int scarceResourcesRefCount = 0;
void referenceScarceResources();
void dereferenceScarceResources();
@@ -189,55 +159,24 @@ public:
QString offlineStoragePath;
- mutable quint32 uniqueId;
- inline quint32 getUniqueId() const {
- return uniqueId++;
- }
-
// Unfortunate workaround to avoid a circular dependency between
// qqmlengine_p.h and qqmlincubator_p.h
- struct Incubator : public QSharedData {
+ struct Incubator {
QIntrusiveListNode next;
- // Unfortunate workaround for MSVC
- QIntrusiveListNode nextWaitingFor;
};
QIntrusiveList<Incubator, &Incubator::next> incubatorList;
- unsigned int incubatorCount;
- QQmlIncubationController *incubationController;
- void incubate(QQmlIncubator &, QQmlContextData *);
+ unsigned int incubatorCount = 0;
+ QQmlIncubationController *incubationController = nullptr;
+ void incubate(QQmlIncubator &, const QQmlRefPointer<QQmlContextData> &);
// These methods may be called from any thread
- inline bool isEngineThread() const;
- inline static bool isEngineThread(const QQmlEngine *);
- template<typename T>
- inline void deleteInEngineThread(T *);
- template<typename T>
- inline static void deleteInEngineThread(QQmlEnginePrivate *, T *);
QString offlineStorageDatabaseDirectory() const;
- // These methods may be called from the loader thread
- inline QQmlPropertyCache *cache(const QQmlType &, int);
- using QJSEnginePrivate::cache;
-
- // These methods may be called from the loader thread
- bool isQObject(int);
- QObject *toQObject(const QVariant &, bool *ok = nullptr) const;
- QQmlMetaType::TypeCategory typeCategory(int) const;
- bool isList(int) const;
- int listType(int) const;
- QQmlMetaObject rawMetaObjectForType(int) const;
- QQmlMetaObject metaObjectForType(int) const;
- QQmlPropertyCache *propertyCacheForType(int);
- QQmlPropertyCache *rawPropertyCacheForType(int, int minorVersion = -1);
- void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
- void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
-
bool isTypeLoaded(const QUrl &url) const;
bool isScriptLoaded(const QUrl &url) const;
template <typename T>
T singletonInstance(const QQmlType &type);
- void destroySingletonInstance(const QQmlType &type);
void sendQuit();
void sendExit(int retCode = 0);
@@ -252,33 +191,108 @@ public:
inline static QQmlEnginePrivate *get(QQmlEngine *e);
inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
inline static QQmlEnginePrivate *get(QQmlContext *c);
- inline static QQmlEnginePrivate *get(QQmlContextData *c);
+ inline static QQmlEnginePrivate *get(const QQmlRefPointer<QQmlContextData> &c);
inline static QQmlEngine *get(QQmlEnginePrivate *p);
inline static QQmlEnginePrivate *get(QV4::ExecutionEngine *e);
static QList<QQmlError> qmlErrorFromDiagnostics(const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages);
- static void defineModule();
-
static bool designerMode();
static void activateDesignerMode();
- static bool qml_debugging_enabled;
+ static std::atomic<bool> qml_debugging_enabled;
mutable QMutex networkAccessManagerMutex;
+ QQmlGadgetPtrWrapper *valueTypeInstance(QMetaType type)
+ {
+ int typeIndex = type.id();
+ auto it = cachedValueTypeInstances.constFind(typeIndex);
+ if (it != cachedValueTypeInstances.cend())
+ return *it;
+
+ if (QQmlValueType *valueType = QQmlMetaType::valueType(type)) {
+ QQmlGadgetPtrWrapper *instance = new QQmlGadgetPtrWrapper(valueType);
+ cachedValueTypeInstances.insert(typeIndex, instance);
+ return instance;
+ }
+
+ return nullptr;
+ }
+
+ void executeRuntimeFunction(const QUrl &url, qsizetype functionIndex, QObject *thisObject,
+ int argc = 0, void **args = nullptr, QMetaType *types = nullptr);
+ void executeRuntimeFunction(const QV4::ExecutableCompilationUnit *unit, qsizetype functionIndex,
+ QObject *thisObject, int argc = 0, void **args = nullptr,
+ QMetaType *types = nullptr);
+ QV4::ExecutableCompilationUnit *compilationUnitFromUrl(const QUrl &url);
+ QQmlRefPointer<QQmlContextData>
+ createInternalContext(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QQmlRefPointer<QQmlContextData> &parentContext,
+ int subComponentIndex, bool isComponentRoot);
+ static void setInternalContext(QObject *This, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlContextData::QmlObjectKind kind)
+ {
+ Q_ASSERT(This);
+ QQmlData *ddata = QQmlData::get(This, /*create*/ true);
+ // NB: copied from QQmlObjectCreator::createInstance()
+ //
+ // the if-statement logic to determine the kind is:
+ // if (static_cast<quint32>(index) == 0 || ddata->rootObjectInCreation || isInlineComponent)
+ // then QQmlContextData::DocumentRoot. here, we pass this through qmltc
+ context->installContext(ddata, kind);
+ Q_ASSERT(qmlEngine(This));
+ }
+
private:
- QHash<QQmlType, QJSValue> singletonInstances;
+ class SingletonInstances : private QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>
+ {
+ public:
+ void convertAndInsert(
+ QV4::ExecutionEngine *engine, const QQmlType::SingletonInstanceInfo::ConstPtr &type,
+ QJSValue *value)
+ {
+ QJSValuePrivate::manageStringOnV4Heap(engine, value);
+ insert(type, *value);
+ }
- // These members must be protected by a QQmlEnginePrivate::Locker as they are required by
- // the threaded loader. Only access them through their respective accessor methods.
- QHash<int, QV4::ExecutableCompilationUnit *> m_compositeTypes;
- static bool s_designerMode;
+ void clear()
+ {
+ const auto canDelete = [](QObject *instance, const auto &siinfo) -> bool {
+ if (!instance)
+ return false;
+
+ if (!siinfo->url.isEmpty())
+ return true;
+
+ const auto *ddata = QQmlData::get(instance, false);
+ return !(ddata && ddata->indestructible && ddata->explicitIndestructibleSet);
+ };
- // These members is protected by the full QQmlEnginePrivate::mutex mutex
- struct Deletable { Deletable():next(nullptr) {} virtual ~Deletable() {} Deletable *next; };
- QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread;
- void doDeleteInEngineThread();
+ for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
+ auto *instance = it.value().toQObject();
+ if (canDelete(instance, it.key()))
+ QQmlData::markAsDeleted(instance);
+ }
+
+ for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
+ QObject *instance = it.value().toQObject();
+
+ if (canDelete(instance, it.key()))
+ delete instance;
+ }
+
+ QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::clear();
+ }
+
+ using QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::value;
+ using QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::take;
+ };
+
+ SingletonInstances singletonInstances;
+ QHash<int, QQmlGadgetPtrWrapper *> cachedValueTypeInstances;
+
+ static bool s_designerMode;
void cleanupScarceResources();
};
@@ -313,83 +327,6 @@ inline void QQmlEnginePrivate::dereferenceScarceResources()
}
}
-/*!
-Returns true if the calling thread is the QQmlEngine thread.
-*/
-bool QQmlEnginePrivate::isEngineThread() const
-{
-
- return QThread::currentThread() == q_ptr->thread();
-}
-
-/*!
-Returns true if the calling thread is the QQmlEngine \a engine thread.
-*/
-bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine)
-{
- Q_ASSERT(engine);
- return QQmlEnginePrivate::get(engine)->isEngineThread();
-}
-
-/*!
-Delete \a value in the engine thread. If the calling thread is the engine
-thread, \a value will be deleted immediately.
-
-This method should be used for *any* type that has resources that need to
-be freed in the engine thread. This is generally types that use V8 handles.
-As there is some small overhead in checking the current thread, it is best
-practice to check if any V8 handles actually need to be freed and delete
-the instance directly if not.
-*/
-template<typename T>
-void QQmlEnginePrivate::deleteInEngineThread(T *value)
-{
- Q_ASSERT(value);
- if (isEngineThread()) {
- delete value;
- } else {
- struct I : public Deletable {
- I(T *value) : value(value) {}
- ~I() override { delete value; }
- T *value;
- };
- I *i = new I(value);
- mutex.lock();
- bool wasEmpty = toDeleteInEngineThread.isEmpty();
- toDeleteInEngineThread.append(i);
- mutex.unlock();
- if (wasEmpty)
- QCoreApplication::postEvent(q_ptr, new QEvent(QEvent::User));
- }
-}
-
-/*!
-Delete \a value in the \a engine thread. If the calling thread is the engine
-thread, \a value will be deleted immediately.
-*/
-template<typename T>
-void QQmlEnginePrivate::deleteInEngineThread(QQmlEnginePrivate *engine, T *value)
-{
- Q_ASSERT(engine);
- engine->deleteInEngineThread<T>(value);
-}
-
-/*!
-Returns a QQmlPropertyCache for \a type with \a minorVersion.
-
-The returned cache is not referenced, so if it is to be stored, call addref().
-*/
-QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, int minorVersion)
-{
- Q_ASSERT(type.isValid());
-
- if (minorVersion == -1 || !type.containsRevisionedAttributes())
- return cache(type.metaObject(), minorVersion);
-
- Locker locker(this);
- return QQmlMetaType::propertyCache(type, minorVersion);
-}
-
QV4::ExecutionEngine *QQmlEnginePrivate::getV4Engine(QQmlEngine *e)
{
Q_ASSERT(e);
@@ -411,14 +348,24 @@ const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e)
return e ? e->d_func() : nullptr;
}
+template<typename Context>
+QQmlEnginePrivate *contextEngine(const Context &context)
+{
+ if (!context)
+ return nullptr;
+ if (QQmlEngine *engine = context->engine())
+ return QQmlEnginePrivate::get(engine);
+ return nullptr;
+}
+
QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c)
{
- return (c && c->engine()) ? QQmlEnginePrivate::get(c->engine()) : nullptr;
+ return contextEngine(c);
}
-QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContextData *c)
+QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlRefPointer<QQmlContextData> &c)
{
- return (c && c->engine) ? QQmlEnginePrivate::get(c->engine) : nullptr;
+ return contextEngine(c);
}
QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
@@ -437,13 +384,35 @@ QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e)
}
template<>
-Q_QML_PRIVATE_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type);
+Q_QML_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type);
template<typename T>
T QQmlEnginePrivate::singletonInstance(const QQmlType &type) {
return qobject_cast<T>(singletonInstance<QJSValue>(type).toQObject());
}
+struct LoadHelper final : QQmlTypeLoader::Blob
+{
+ LoadHelper(QQmlTypeLoader *loader, QAnyStringView uri);
+
+ struct ResolveTypeResult
+ {
+ enum Status { NoSuchModule, ModuleFound } status;
+ QQmlType type;
+ };
+
+ ResolveTypeResult resolveType(QAnyStringView typeName);
+
+protected:
+ void dataReceived(const SourceCodeData &) final { Q_UNREACHABLE(); }
+ void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) final { Q_UNREACHABLE(); }
+
+private:
+ bool couldFindModule() const;
+ QString m_uri;
+};
+
+
QT_END_NAMESPACE
#endif // QQMLENGINE_P_H
diff --git a/src/qml/qml/qqmlenumdata_p.h b/src/qml/qml/qqmlenumdata_p.h
index df99c2c1bc..be734acbee 100644
--- a/src/qml/qml/qqmlenumdata_p.h
+++ b/src/qml/qml/qqmlenumdata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLENUMDATA_P_H
#define QQMLENUMDATA_P_H
diff --git a/src/qml/qml/qqmlenumvalue_p.h b/src/qml/qml/qqmlenumvalue_p.h
index ea0fc244cb..f5ea3c1a0e 100644
--- a/src/qml/qml/qqmlenumvalue_p.h
+++ b/src/qml/qml/qqmlenumvalue_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLENUMVALUE_P_H
#define QQMLENUMVALUE_P_H
@@ -52,6 +16,7 @@
//
#include <QtCore/qstring.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp
index 0b94ed3b49..415f8748f5 100644
--- a/src/qml/qml/qqmlerror.cpp
+++ b/src/qml/qml/qqmlerror.cpp
@@ -1,45 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlerror.h"
#include "qqmlfile.h"
-#include "qqmlsourcecoordinate_p.h"
#include <private/qqmljsdiagnosticmessage_p.h>
#include <QtCore/qdebug.h>
@@ -77,12 +40,21 @@ QT_BEGIN_NAMESPACE
\sa QQuickView::errors(), QQmlComponent::errors()
*/
-class QQmlErrorPrivate : public QQmlJS::DiagnosticMessage
+class QQmlErrorPrivate
{
public:
- QQmlErrorPrivate() { type = QtWarningMsg; }
QUrl url;
QPointer<QObject> object;
+ QString message;
+ QtMsgType type = QtWarningMsg;
+ int line = -1;
+ int column = -1;
+
+ friend bool operator==(const QQmlErrorPrivate &a, const QQmlErrorPrivate &b)
+ {
+ return a.url == b.url && a.object == b.object && a.message == b.message
+ && a.type == b.type && a.line == b.line && a.column == b.column;
+ }
};
/*!
@@ -185,7 +157,7 @@ void QQmlError::setDescription(const QString &description)
int QQmlError::line() const
{
if (d)
- return qmlConvertSourceCoordinate<quint32, int>(d->line);
+ return d->line;
return -1;
}
@@ -196,7 +168,7 @@ void QQmlError::setLine(int line)
{
if (!d)
d = new QQmlErrorPrivate;
- d->line = qmlConvertSourceCoordinate<int, quint32>(line);
+ d->line = line;
}
/*!
@@ -205,7 +177,7 @@ void QQmlError::setLine(int line)
int QQmlError::column() const
{
if (d)
- return qmlConvertSourceCoordinate<quint32, int>(d->column);
+ return d->column;
return -1;
}
@@ -216,7 +188,7 @@ void QQmlError::setColumn(int column)
{
if (!d)
d = new QQmlErrorPrivate;
- d->column = qmlConvertSourceCoordinate<int, quint32>(column);
+ d->column = column;
}
/*!
@@ -295,6 +267,11 @@ QString QQmlError::toString() const
return rv;
}
+bool operator==(const QQmlError &a, const QQmlError &b)
+{
+ return a.d == b.d || (a.d && b.d && *a.d == *b.d);
+}
+
/*!
\relates QQmlError
\fn QDebug operator<<(QDebug debug, const QQmlError &error)
@@ -314,19 +291,16 @@ QDebug operator<<(QDebug debug, const QQmlError &error)
if (f.open(QIODevice::ReadOnly)) {
QByteArray data = f.readAll();
QTextStream stream(data, QIODevice::ReadOnly);
-#if QT_CONFIG(textcodec)
- stream.setCodec("UTF-8");
-#endif
const QString code = stream.readAll();
- const auto lines = code.splitRef(QLatin1Char('\n'));
+ const auto lines = QStringView{code}.split(QLatin1Char('\n'));
- if (lines.count() >= error.line()) {
- const QStringRef &line = lines.at(error.line() - 1);
+ if (lines.size() >= error.line()) {
+ const QStringView &line = lines.at(error.line() - 1);
debug << "\n " << line.toLocal8Bit().constData();
if(error.column() > 0) {
int column = qMax(0, error.column() - 1);
- column = qMin(column, line.length());
+ column = qMin(column, line.size());
QByteArray ind;
ind.reserve(column);
diff --git a/src/qml/qml/qqmlerror.h b/src/qml/qml/qqmlerror.h
index 8ea493c11d..8ca57f1b99 100644
--- a/src/qml/qml/qqmlerror.h
+++ b/src/qml/qml/qqmlerror.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLERROR_H
#define QQMLERROR_H
@@ -47,7 +11,7 @@
QT_BEGIN_NAMESPACE
-// ### Qt 6: should this be called QQmlMessage, since it can have a message type?
+// ### Qt 7: should this be called QQmlMessage, since it can have a message type?
class QDebug;
class QQmlErrorPrivate;
class Q_QML_EXPORT QQmlError
@@ -55,9 +19,17 @@ class Q_QML_EXPORT QQmlError
public:
QQmlError();
QQmlError(const QQmlError &);
+ QQmlError(QQmlError &&other) noexcept
+ : d(std::exchange(other.d, nullptr))
+ {}
+
QQmlError &operator=(const QQmlError &);
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QQmlError)
~QQmlError();
+ void swap(QQmlError &other)
+ { qt_ptr_swap(d, other.d); }
+
bool isValid() const;
QUrl url() const;
@@ -76,13 +48,14 @@ public:
void setMessageType(QtMsgType messageType);
QString toString() const;
+ friend bool Q_QML_EXPORT operator==(const QQmlError &a, const QQmlError &b);
private:
QQmlErrorPrivate *d;
};
QDebug Q_QML_EXPORT operator<<(QDebug debug, const QQmlError &error);
-Q_DECLARE_TYPEINFO(QQmlError, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QQmlError, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index f6a5afb891..1cc734206e 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -1,48 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlexpression.h"
#include "qqmlexpression_p.h"
-#include "qqmlglobal_p.h"
#include "qqmlengine_p.h"
-#include "qqmlcontext_p.h"
#include "qqmlscriptstring_p.h"
#include "qqmlbinding_p.h"
#include <private/qqmlsourcecoordinate_p.h>
@@ -63,7 +25,8 @@ QQmlExpressionPrivate::~QQmlExpressionPrivate()
{
}
-void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QObject *me)
+void QQmlExpressionPrivate::init(const QQmlRefPointer<QQmlContextData> &ctxt, const QString &expr,
+ QObject *me)
{
expression = expr;
@@ -72,10 +35,11 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QOb
expressionFunctionValid = false;
}
-void QQmlExpressionPrivate::init(QQmlContextData *ctxt, QV4::Function *runtimeFunction, QObject *me)
+void QQmlExpressionPrivate::init(const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::Function *runtimeFunction, QObject *me)
{
expressionFunctionValid = true;
- QV4::ExecutionEngine *engine = ctxt->engine->handle();
+ QV4::ExecutionEngine *engine = ctxt->engine()->handle();
QV4::Scope scope(engine);
QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(engine->rootContext(), ctxt, me));
setupFunction(qmlContext, runtimeFunction);
@@ -141,23 +105,35 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt
return;
const QQmlScriptStringPrivate *scriptPrivate = script.d.data();
+ if (!scriptPrivate) {
+ // A null QQmlScriptStringPrivate is an empty expression without context.
+ // We may still want the explicitly passed context, though.
+ if (ctxt)
+ d->init(QQmlContextData::get(ctxt), QString(), scope);
+ return;
+ }
+
if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid()))
return;
- QQmlContextData *evalCtxtData = QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context);
+ QQmlRefPointer<QQmlContextData> evalCtxtData
+ = QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context);
QObject *scopeObject = scope ? scope : scriptPrivate->scope;
QV4::Function *runtimeFunction = nullptr;
if (scriptPrivate->context) {
- QQmlContextData *ctxtdata = QQmlContextData::get(scriptPrivate->context);
+ QQmlRefPointer<QQmlContextData> ctxtdata = QQmlContextData::get(scriptPrivate->context);
QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
- if (engine && ctxtdata && !ctxtdata->urlString().isEmpty() && ctxtdata->typeCompilationUnit) {
+ if (engine
+ && ctxtdata
+ && !ctxtdata->urlString().isEmpty()
+ && ctxtdata->typeCompilationUnit()) {
d->url = ctxtdata->urlString();
d->line = scriptPrivate->lineNumber;
d->column = scriptPrivate->columnNumber;
if (scriptPrivate->bindingId != QQmlBinding::Invalid)
- runtimeFunction = ctxtdata->typeCompilationUnit->runtimeFunctions.at(scriptPrivate->bindingId);
+ runtimeFunction = ctxtdata->typeCompilationUnit()->runtimeFunctions.at(scriptPrivate->bindingId);
}
}
@@ -175,10 +151,8 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt
If specified, the \a scope object's properties will also be in scope during
the expression's execution.
*/
-QQmlExpression::QQmlExpression(QQmlContext *ctxt,
- QObject *scope,
- const QString &expression,
- QObject *parent)
+QQmlExpression::QQmlExpression(QQmlContext *ctxt, QObject *scope, const QString &expression,
+ QObject *parent)
: QObject(*new QQmlExpressionPrivate, parent)
{
Q_D(QQmlExpression);
@@ -188,12 +162,10 @@ QQmlExpression::QQmlExpression(QQmlContext *ctxt,
/*!
\internal
*/
-QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
- const QString &expression)
-: QObject(*new QQmlExpressionPrivate, nullptr)
+QQmlExpression::QQmlExpression(QQmlExpressionPrivate &dd, QObject *parent) : QObject(dd, parent)
{
- Q_D(QQmlExpression);
- d->init(ctxt, expression, scope);
+// Q_D(QQmlExpression);
+// d->init(QQmlContextData::get(ctxt), expression, scope);
}
/*!
@@ -204,24 +176,23 @@ QQmlExpression::~QQmlExpression()
}
/*!
- Returns the QQmlEngine this expression is associated with, or 0 if there
+ Returns the QQmlEngine this expression is associated with, or \nullptr if there
is no association or the QQmlEngine has been destroyed.
*/
QQmlEngine *QQmlExpression::engine() const
{
Q_D(const QQmlExpression);
- return d->context()?d->context()->engine:nullptr;
+ return d->engine();
}
/*!
- Returns the QQmlContext this expression is associated with, or 0 if there
+ Returns the QQmlContext this expression is associated with, or \nullptr if there
is no association or the QQmlContext has been destroyed.
*/
QQmlContext *QQmlExpression::context() const
{
Q_D(const QQmlExpression);
- QQmlContextData *data = d->context();
- return data?data->asQQmlContext():nullptr;
+ return d->publicContext();
}
/*!
@@ -265,7 +236,7 @@ QVariant QQmlExpressionPrivate::value(bool *isUndefined)
{
Q_Q(QQmlExpression);
- if (!context() || !context()->isValid()) {
+ if (!hasValidContext()) {
qWarning("QQmlExpression: Attempted to evaluate an expression in an invalid context");
return QVariant();
}
@@ -280,7 +251,7 @@ QVariant QQmlExpressionPrivate::value(bool *isUndefined)
QV4::Scope scope(engine->handle());
QV4::ScopedValue result(scope, v4value(isUndefined));
if (!hasError())
- rv = scope.engine->toVariant(result, -1);
+ rv = QV4::ExecutionEngine::toVariant(result, QMetaType {});
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
diff --git a/src/qml/qml/qqmlexpression.h b/src/qml/qml/qqmlexpression.h
index 0eceeb12e1..c029c2069f 100644
--- a/src/qml/qml/qqmlexpression.h
+++ b/src/qml/qml/qqmlexpression.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLEXPRESSION_H
#define QQMLEXPRESSION_H
@@ -50,7 +14,6 @@ QT_BEGIN_NAMESPACE
class QString;
-class QQmlRefCount;
class QQmlEngine;
class QQmlContext;
class QQmlExpressionPrivate;
@@ -90,7 +53,7 @@ Q_SIGNALS:
void valueChanged();
private:
- QQmlExpression(QQmlContextData *, QObject *, const QString &);
+ QQmlExpression(QQmlExpressionPrivate &dd, QObject *parent);
Q_DISABLE_COPY(QQmlExpression)
Q_DECLARE_PRIVATE(QQmlExpression)
diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h
index da10b31b2c..740cb1b495 100644
--- a/src/qml/qml/qqmlexpression_p.h
+++ b/src/qml/qml/qqmlexpression_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLEXPRESSION_P_H
#define QQMLEXPRESSION_P_H
@@ -55,7 +19,6 @@
#include <private/qqmlengine_p.h>
#include <private/qfieldlist_p.h>
-#include <private/qflagpointer_p.h>
#include <private/qqmljavascriptexpression_p.h>
QT_BEGIN_NAMESPACE
@@ -70,12 +33,13 @@ public:
QQmlExpressionPrivate();
~QQmlExpressionPrivate() override;
- void init(QQmlContextData *, const QString &, QObject *);
- void init(QQmlContextData *, QV4::Function *runtimeFunction, QObject *);
+ void init(const QQmlRefPointer<QQmlContextData> &, const QString &, QObject *);
+ void init(const QQmlRefPointer<QQmlContextData> &, QV4::Function *runtimeFunction, QObject *);
QVariant value(bool *isUndefined = nullptr);
QV4::ReturnedValue v4value(bool *isUndefined = nullptr);
+ bool mustCaptureBindableProperty() const final {return true;}
static inline QQmlExpressionPrivate *get(QQmlExpression *expr);
static inline QQmlExpression *get(QQmlExpressionPrivate *expr);
diff --git a/src/qml/qml/qqmlextensioninterface.cpp b/src/qml/qml/qqmlextensioninterface.cpp
new file mode 100644
index 0000000000..6cefcd3217
--- /dev/null
+++ b/src/qml/qml/qqmlextensioninterface.cpp
@@ -0,0 +1,17 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtQml/qqmlextensioninterface.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlTypesExtensionInterface::~QQmlTypesExtensionInterface()
+ = default;
+
+QQmlExtensionInterface::~QQmlExtensionInterface()
+ = default;
+
+QQmlEngineExtensionInterface::~QQmlEngineExtensionInterface()
+ = default;
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlextensioninterface.h b/src/qml/qml/qqmlextensioninterface.h
index 1490bc512e..c7dfcae8bf 100644
--- a/src/qml/qml/qqmlextensioninterface.h
+++ b/src/qml/qml/qqmlextensioninterface.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLEXTENSIONINTERFACE_H
#define QQMLEXTENSIONINTERFACE_H
@@ -51,21 +15,21 @@ class QQmlEngine;
class Q_QML_EXPORT QQmlTypesExtensionInterface
{
public:
- virtual ~QQmlTypesExtensionInterface() = default;
+ virtual ~QQmlTypesExtensionInterface();
virtual void registerTypes(const char *uri) = 0;
};
class Q_QML_EXPORT QQmlExtensionInterface : public QQmlTypesExtensionInterface
{
public:
- ~QQmlExtensionInterface() override = default;
+ ~QQmlExtensionInterface() override;
virtual void initializeEngine(QQmlEngine *engine, const char *uri) = 0;
};
class Q_QML_EXPORT QQmlEngineExtensionInterface
{
public:
- virtual ~QQmlEngineExtensionInterface() = default;
+ virtual ~QQmlEngineExtensionInterface();
virtual void initializeEngine(QQmlEngine *engine, const char *uri) = 0;
};
diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
index 26364661a8..5af51769ab 100644
--- a/src/qml/qml/qqmlextensionplugin.cpp
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlextensionplugin.h"
#include "qqmlextensionplugin_p.h"
@@ -43,6 +7,21 @@
QT_BEGIN_NAMESPACE
/*!
+ \since 5.0
+ \inmodule QtQml
+ \class QQmlExtensionPlugin
+ \brief The QQmlExtensionPlugin class provides an abstract base for custom QML extension plugins
+ with custom type registration functions.
+
+ \ingroup plugins
+
+ \note If you need to write a plugin manually (which is rare) you should always use
+ \l{QQmlEngineExtensionPlugin}. QQmlExtensionPlugin only provides the registerTypes() and
+ unregisterTypes() functions in addition. You should not use them, but rather declare your
+ types with \l{QML_ELEMENT} and friends and have the build system take care of the registration.
+*/
+
+/*!
\since 5.14
\inmodule QtQml
\class QQmlEngineExtensionPlugin
@@ -61,11 +40,10 @@ QT_BEGIN_NAMESPACE
/*!
\fn void QQmlExtensionPlugin::registerTypes(const char *uri)
- \internal
Registers the QML types in the given \a uri. Subclasses should implement
- this to call qmlRegisterType() for all types which are provided by the extension
- plugin.
+ this to call \l {QQmlEngine::}{qmlRegisterType()} for all types which are
+ provided by the extension plugin.
The \a uri is an identifier for the plugin generated by the QML engine
based on the name and path of the extension's plugin library.
@@ -75,7 +53,11 @@ QT_BEGIN_NAMESPACE
\internal
*/
QQmlExtensionPlugin::QQmlExtensionPlugin(QObject *parent)
+#if QT_DEPRECATED_SINCE(6, 3)
: QObject(*(new QQmlExtensionPluginPrivate), parent)
+#else
+ : QObject(parent)
+#endif
{
}
@@ -102,24 +84,47 @@ QQmlExtensionPlugin::~QQmlExtensionPlugin() = default;
*/
QQmlEngineExtensionPlugin::~QQmlEngineExtensionPlugin() = default;
+#if QT_DEPRECATED_SINCE(6, 3)
/*!
\since 5.1
\internal
+ \deprecated [6.3] This is unnecessary and doesn't work for optional plugins
\brief Returns the URL of the directory from which the extension is loaded.
This is useful when the plugin also needs to load QML files or other
assets from the same directory.
+
+ \note You should not need this function. Other files that are part of the
+ module's public interface should be specified accordingly in the build
+ system and qmldir file. The build system makes sure that they end up
+ both in the final module directory, and in the resource file system.
+ You can use the copy from the resource file system in the plugin.
+ Non-QML/JS files private to the plugin can be added to the resource
+ file system manually. However, consider moving all such functionality
+ out of the plugin and making the plugin optional.
*/
QUrl QQmlExtensionPlugin::baseUrl() const
{
Q_D(const QQmlExtensionPlugin);
return d->baseUrl;
}
+#endif
/*!
- \internal
+ \since 6.0
+
+ Override this method to unregister types manually registered in registerTypes.
*/
+void QQmlExtensionPlugin::unregisterTypes()
+{
+}
+
+/*!
+ Initializes the extension from the \a uri using the \a engine. Here an application
+ plugin might, for example, expose some data or objects to QML,
+ as context properties on the engine's root context.
+ */
void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
{
Q_UNUSED(engine);
@@ -127,8 +132,6 @@ void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
}
/*!
- \fn void QQmlEngineExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
-
Initializes the extension from the \a uri using the \a engine. Here an application
plugin might, for example, expose some data or objects to QML,
as context properties on the engine's root context.
@@ -157,6 +160,30 @@ void QQmlEngineExtensionPlugin::initializeEngine(QQmlEngine *engine, const char
\inmodule QtQml
*/
+
+/*!
+ \macro Q_IMPORT_QML_PLUGIN(PluginName)
+ \since 6.2
+ \relates QQmlEngineExtensionPlugin
+
+ Ensures the plugin whose metadata-declaring plugin extension class is named
+ \a PluginName is linked into static builds. For the modules created using
+ \l qt_add_qml_module, the default plugin extension class name is computed
+ from the QML module URI by replacing dots with underscores, unless the
+ \c CLASS_NAME argument is specified.
+
+ For example:
+ \badcode
+ qt_add_qml_module(myplugin
+ # The plugin extension class name in this case is my_Company_QmlComponents.
+ URI my.Company.QmlComponents
+ ...
+ )
+ \endcode
+
+ \sa Q_IMPORT_PLUGIN
+*/
+
QT_END_NAMESPACE
#include "moc_qqmlextensionplugin.cpp"
diff --git a/src/qml/qml/qqmlextensionplugin.h b/src/qml/qml/qqmlextensionplugin.h
index ef7ff422cd..3d4494ba20 100644
--- a/src/qml/qml/qqmlextensionplugin.h
+++ b/src/qml/qml/qqmlextensionplugin.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLEXTENSIONPLUGIN_H
#define QQMLEXTENSIONPLUGIN_H
@@ -44,6 +8,15 @@
#include <QtCore/QUrl>
#include <QtQml/qqmlextensioninterface.h>
+#if defined(Q_CC_GHS)
+# define Q_GHS_KEEP_REFERENCE(S) QT_DO_PRAGMA(ghs reference S ##__Fv)
+#else
+# define Q_GHS_KEEP_REFERENCE(S)
+#endif
+
+#define Q_IMPORT_QML_PLUGIN(PLUGIN) \
+ Q_IMPORT_PLUGIN(PLUGIN)
+
QT_BEGIN_NAMESPACE
class QQmlEngine;
@@ -61,9 +34,13 @@ public:
explicit QQmlExtensionPlugin(QObject *parent = nullptr);
~QQmlExtensionPlugin() override;
+#if QT_DEPRECATED_SINCE(6, 3)
+ QT_DEPRECATED_VERSION_X_6_3("Provide a qmldir file to remove the need for calling baseUrl")
QUrl baseUrl() const;
+#endif
void registerTypes(const char *uri) override = 0;
+ virtual void unregisterTypes();
void initializeEngine(QQmlEngine *engine, const char *uri) override;
private:
diff --git a/src/qml/qml/qqmlextensionplugin_p.h b/src/qml/qml/qqmlextensionplugin_p.h
index 2abb5547aa..468fa9e8f4 100644
--- a/src/qml/qml/qqmlextensionplugin_p.h
+++ b/src/qml/qml/qqmlextensionplugin_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLEXTENSIONPLUGIN_P_H
#define QQMLEXTENSIONPLUGIN_P_H
@@ -56,6 +20,7 @@
QT_BEGIN_NAMESPACE
+#if QT_DEPRECATED_SINCE(6, 3)
class QQmlExtensionPluginPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQmlExtensionPlugin)
@@ -66,6 +31,7 @@ public:
QUrl baseUrl;
};
+#endif
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp
index 465a342129..bac70e69bb 100644
--- a/src/qml/qml/qqmlfile.cpp
+++ b/src/qml/qml/qqmlfile.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlfile.h"
@@ -46,18 +10,27 @@
#include <private/qqmlengine_p.h>
#include <private/qqmlglobal_p.h>
-/*!
-\class QQmlFile
-\brief The QQmlFile class gives access to local and remote files.
+QT_BEGIN_NAMESPACE
-\internal
+/*!
+ \class QQmlFile
+ \inmodule QtQml
+ \since 5.0
+ \brief The QQmlFile class provides static utility methods to categorize URLs.
-Supports file:// and qrc:/ uris and whatever QNetworkAccessManager supports.
+ QQmlFile provides some static utility methods to categorize URLs
+ and file names the way \l{QQmlEngine} does when loading content from them.
*/
-#define QQMLFILE_MAX_REDIRECT_RECURSION 16
+/*!
+ \internal
-QT_BEGIN_NAMESPACE
+ \enum QQmlFile::Status
+ \value Null
+ \value Ready
+ \value Error
+ \value Loading
+ */
static char qrc_string[] = "qrc";
static char file_string[] = "file";
@@ -65,6 +38,9 @@ static char file_string[] = "file";
#if defined(Q_OS_ANDROID)
static char assets_string[] = "assets";
static char content_string[] = "content";
+static char authority_externalstorage[] = "com.android.externalstorage.documents";
+static char authority_downloads_documents[] = "com.android.providers.downloads.documents";
+static char authority_media_documents[] = "com.android.providers.media.documents";
#endif
class QQmlFilePrivate;
@@ -97,7 +73,6 @@ private:
QQmlEngine *m_engine;
QQmlFilePrivate *m_p;
- int m_redirectCount;
QNetworkReply *m_reply;
};
#endif
@@ -132,7 +107,7 @@ int QQmlFileNetworkReply::replyFinishedIndex = -1;
int QQmlFileNetworkReply::replyDownloadProgressIndex = -1;
QQmlFileNetworkReply::QQmlFileNetworkReply(QQmlEngine *e, QQmlFilePrivate *p, const QUrl &url)
-: m_engine(e), m_p(p), m_redirectCount(0), m_reply(nullptr)
+: m_engine(e), m_p(p), m_reply(nullptr)
{
if (finishedIndex == -1) {
finishedIndex = QMetaMethod::fromSignal(&QQmlFileNetworkReply::finished).methodIndex();
@@ -166,27 +141,6 @@ QQmlFileNetworkReply::~QQmlFileNetworkReply()
void QQmlFileNetworkReply::networkFinished()
{
- ++m_redirectCount;
- if (m_redirectCount < QQMLFILE_MAX_REDIRECT_RECURSION) {
- QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
- if (redirect.isValid()) {
- QUrl url = m_reply->url().resolved(redirect.toUrl());
-
- QNetworkRequest req(url);
- req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
-
- m_reply->deleteLater();
- m_reply = m_engine->networkAccessManager()->get(req);
-
- QMetaObject::connect(m_reply, replyFinishedIndex,
- this, networkFinishedIndex);
- QMetaObject::connect(m_reply, replyDownloadProgressIndex,
- this, networkDownloadProgressIndex);
-
- return;
- }
- }
-
if (m_reply->error()) {
m_p->errorString = m_reply->errorString();
m_p->error = QQmlFilePrivate::Network;
@@ -216,22 +170,36 @@ QQmlFilePrivate::QQmlFilePrivate()
{
}
+/*!
+ \internal
+ */
QQmlFile::QQmlFile()
: d(new QQmlFilePrivate)
{
}
-QQmlFile::QQmlFile(QQmlEngine *e, const QUrl &url)
+/*!
+ \internal
+ Constructs a QQmlFile for content at \a url, using \a engine to retrieve it.
+ */
+QQmlFile::QQmlFile(QQmlEngine *engine, const QUrl &url)
: d(new QQmlFilePrivate)
{
- load(e, url);
+ load(engine, url);
}
-QQmlFile::QQmlFile(QQmlEngine *e, const QString &url)
- : QQmlFile(e, QUrl(url))
+/*!
+ \internal
+ Constructs a QQmlFile for content at \a url, using \a engine to retrieve it.
+ */
+QQmlFile::QQmlFile(QQmlEngine *engine, const QString &url)
+ : QQmlFile(engine, QUrl(url))
{
}
+/*!
+ \internal
+ */
QQmlFile::~QQmlFile()
{
#if QT_CONFIG(qml_network)
@@ -241,26 +209,41 @@ QQmlFile::~QQmlFile()
d = nullptr;
}
+/*!
+ \internal
+ */
bool QQmlFile::isNull() const
{
return status() == Null;
}
+/*!
+ \internal
+ */
bool QQmlFile::isReady() const
{
return status() == Ready;
}
+/*!
+ \internal
+ */
bool QQmlFile::isError() const
{
return status() == Error;
}
+/*!
+ \internal
+ */
bool QQmlFile::isLoading() const
{
return status() == Loading;
}
+/*!
+ \internal
+ */
QUrl QQmlFile::url() const
{
if (!d->urlString.isEmpty()) {
@@ -270,6 +253,9 @@ QUrl QQmlFile::url() const
return d->url;
}
+/*!
+ \internal
+ */
QQmlFile::Status QQmlFile::status() const
{
if (d->url.isEmpty() && d->urlString.isEmpty())
@@ -284,6 +270,9 @@ QQmlFile::Status QQmlFile::status() const
return Ready;
}
+/*!
+ \internal
+ */
QString QQmlFile::error() const
{
switch (d->error) {
@@ -297,21 +286,34 @@ QString QQmlFile::error() const
}
}
+/*!
+ \internal
+ */
qint64 QQmlFile::size() const
{
return d->data.size();
}
+/*!
+ \internal
+ */
const char *QQmlFile::data() const
{
return d->data.constData();
}
+/*!
+ \internal
+ */
QByteArray QQmlFile::dataByteArray() const
{
return d->data;
}
+/*!
+ \internal
+ Loads content at \a url using \a engine.
+ */
void QQmlFile::load(QQmlEngine *engine, const QUrl &url)
{
Q_ASSERT(engine);
@@ -342,6 +344,10 @@ void QQmlFile::load(QQmlEngine *engine, const QUrl &url)
}
}
+/*!
+ \internal
+ Loads content at \a url using \a engine.
+ */
void QQmlFile::load(QQmlEngine *engine, const QString &url)
{
Q_ASSERT(engine);
@@ -376,6 +382,9 @@ void QQmlFile::load(QQmlEngine *engine, const QString &url)
}
}
+/*!
+ \internal
+ */
void QQmlFile::clear()
{
d->url = QUrl();
@@ -384,12 +393,22 @@ void QQmlFile::clear()
d->error = QQmlFilePrivate::None;
}
-void QQmlFile::clear(QObject *)
+/*!
+ \internal
+ Redirects to the other clear() overload, ignoring \a object.
+ */
+void QQmlFile::clear(QObject *object)
{
+ Q_UNUSED(object);
clear();
}
#if QT_CONFIG(qml_network)
+
+/*!
+ \internal
+ Connects \a method of \a object to the internal \c{finished} signal.
+ */
bool QQmlFile::connectFinished(QObject *object, const char *method)
{
if (!d || !d->reply) {
@@ -397,10 +416,13 @@ bool QQmlFile::connectFinished(QObject *object, const char *method)
return false;
}
- return QObject::connect(d->reply, SIGNAL(finished()),
- object, method);
+ return QObject::connect(d->reply, SIGNAL(finished()), object, method);
}
+/*!
+ \internal
+ Connects \a method of \a object to the internal \c{finished} signal.
+ */
bool QQmlFile::connectFinished(QObject *object, int method)
{
if (!d || !d->reply) {
@@ -412,6 +434,10 @@ bool QQmlFile::connectFinished(QObject *object, int method)
object, method);
}
+/*!
+ \internal
+ Connects \a method of \a object to the internal \c{downloadProgress} signal.
+ */
bool QQmlFile::connectDownloadProgress(QObject *object, const char *method)
{
if (!d || !d->reply) {
@@ -423,6 +449,10 @@ bool QQmlFile::connectDownloadProgress(QObject *object, const char *method)
object, method);
}
+/*!
+ \internal
+ Connects \a method of \a object to the internal \c{downloadProgress} signal.
+ */
bool QQmlFile::connectDownloadProgress(QObject *object, int method)
{
if (!d || !d->reply) {
@@ -436,18 +466,21 @@ bool QQmlFile::connectDownloadProgress(QObject *object, int method)
#endif
/*!
-Returns true if QQmlFile will open \a url synchronously.
+ \internal
-Synchronous urls have a qrc:/ or file:// scheme.
+ Returns \c true if QQmlFile will open \a url synchronously.
+ Otherwise returns \c false. Synchronous urls have a \c{qrc:} or \c{file:}
+ scheme.
-\note On Android, urls with assets:/ scheme are also considered synchronous.
+ \note On Android, urls with \c{assets:} or \c{content:} scheme are also
+ considered synchronous.
*/
bool QQmlFile::isSynchronous(const QUrl &url)
{
QString scheme = url.scheme();
- if ((scheme.length() == 4 && 0 == scheme.compare(QLatin1String(file_string), Qt::CaseInsensitive)) ||
- (scheme.length() == 3 && 0 == scheme.compare(QLatin1String(qrc_string), Qt::CaseInsensitive))) {
+ if ((scheme.size() == 4 && 0 == scheme.compare(QLatin1String(file_string), Qt::CaseInsensitive)) ||
+ (scheme.size() == 3 && 0 == scheme.compare(QLatin1String(qrc_string), Qt::CaseInsensitive))) {
return true;
#if defined(Q_OS_ANDROID)
@@ -463,28 +496,31 @@ bool QQmlFile::isSynchronous(const QUrl &url)
}
/*!
-Returns true if QQmlFile will open \a url synchronously.
+ \internal
-Synchronous urls have a qrc:/ or file:// scheme.
+ Returns \c true if QQmlFile will open \a url synchronously.
+ Otherwise returns \c false. Synchronous urls have a \c{qrc:} or \c{file:}
+ scheme.
-\note On Android, urls with assets:/ scheme are also considered synchronous.
+ \note On Android, urls with \c{assets:} or \c{content:} scheme are also
+ considered synchronous.
*/
bool QQmlFile::isSynchronous(const QString &url)
{
- if (url.length() < 5 /* qrc:/ */)
+ if (url.size() < 5 /* qrc:/ */)
return false;
QChar f = url[0];
if (f == QLatin1Char('f') || f == QLatin1Char('F')) {
- return url.length() >= 7 /* file:// */ &&
+ return url.size() >= 7 /* file:// */ &&
url.startsWith(QLatin1String(file_string), Qt::CaseInsensitive) &&
url[4] == QLatin1Char(':') && url[5] == QLatin1Char('/') && url[6] == QLatin1Char('/');
} else if (f == QLatin1Char('q') || f == QLatin1Char('Q')) {
- return url.length() >= 5 /* qrc:/ */ &&
+ return url.size() >= 5 /* qrc:/ */ &&
url.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive) &&
url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/');
@@ -505,76 +541,149 @@ bool QQmlFile::isSynchronous(const QString &url)
return false;
}
-/*!
-Returns true if \a url is a local file that can be opened with QFile.
+#if defined(Q_OS_ANDROID)
+static bool hasLocalContentAuthority(const QUrl &url)
+{
+ const QString authority = url.authority();
+ return authority.isEmpty()
+ || authority == QLatin1String(authority_externalstorage)
+ || authority == QLatin1String(authority_downloads_documents)
+ || authority == QLatin1String(authority_media_documents);
+}
+#endif
-Local file urls have either a qrc:/ or file:// scheme.
+/*!
+ Returns \c true if \a url is a local file that can be opened with \l{QFile}.
+ Otherwise returns \c false. Local file urls have either a \c{qrc:} or
+ \c{file:} scheme.
-\note On Android, urls with assets:/ scheme are also considered local files.
+ \note On Android, urls with \c{assets:} or \c{content:} scheme are also
+ considered local files.
*/
bool QQmlFile::isLocalFile(const QUrl &url)
{
QString scheme = url.scheme();
- if ((scheme.length() == 4 && 0 == scheme.compare(QLatin1String(file_string), Qt::CaseInsensitive)) ||
- (scheme.length() == 3 && 0 == scheme.compare(QLatin1String(qrc_string), Qt::CaseInsensitive))) {
+ // file: URLs with two slashes following the scheme can be interpreted as local files
+ // where the slashes are part of the path. Therefore, disregard the authority.
+ // See QUrl::toLocalFile().
+ if (scheme.size() == 4 && scheme.startsWith(QLatin1String(file_string), Qt::CaseInsensitive))
return true;
+ if (scheme.size() == 3 && scheme.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive))
+ return url.authority().isEmpty();
+
#if defined(Q_OS_ANDROID)
- } else if (scheme.length() == 6 && 0 == scheme.compare(QLatin1String(assets_string), Qt::CaseInsensitive)) {
- return true;
+ if (scheme.length() == 6
+ && scheme.startsWith(QLatin1String(assets_string), Qt::CaseInsensitive))
+ return url.authority().isEmpty();
+ if (scheme.length() == 7
+ && scheme.startsWith(QLatin1String(content_string), Qt::CaseInsensitive))
+ return hasLocalContentAuthority(url);
#endif
- } else {
- return false;
- }
+ return false;
}
-/*!
-Returns true if \a url is a local file that can be opened with QFile.
-
-Local file urls have either a qrc:/ or file:// scheme.
-
-\note On Android, urls with assets:/ scheme are also considered local files.
-*/
-bool QQmlFile::isLocalFile(const QString &url)
+static bool hasScheme(const QString &url, const char *scheme, qsizetype schemeLength)
{
- if (url.length() < 5 /* qrc:/ */)
+ const qsizetype urlLength = url.size();
+
+ if (urlLength < schemeLength + 1)
return false;
- QChar f = url[0];
+ if (!url.startsWith(QLatin1String(scheme, scheme + schemeLength), Qt::CaseInsensitive))
+ return false;
- if (f == QLatin1Char('f') || f == QLatin1Char('F')) {
+ if (url[schemeLength] != QLatin1Char(':'))
+ return false;
- return url.length() >= 7 /* file:// */ &&
- url.startsWith(QLatin1String(file_string), Qt::CaseInsensitive) &&
- url[4] == QLatin1Char(':') && url[5] == QLatin1Char('/') && url[6] == QLatin1Char('/');
+ return true;
+}
- } else if (f == QLatin1Char('q') || f == QLatin1Char('Q')) {
+static qsizetype authorityOffset(const QString &url, qsizetype schemeLength)
+{
+ const qsizetype urlLength = url.size();
- return url.length() >= 5 /* qrc:/ */ &&
- url.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive) &&
- url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/');
+ if (urlLength < schemeLength + 3)
+ return -1;
+ const QLatin1Char slash('/');
+ if (url[schemeLength + 1] == slash && url[schemeLength + 2] == slash) {
+ // Exactly two slashes denote an authority.
+ if (urlLength < schemeLength + 4 || url[schemeLength + 3] != slash)
+ return schemeLength + 3;
}
+
+ return -1;
+}
+
#if defined(Q_OS_ANDROID)
- else if (f == QLatin1Char('a') || f == QLatin1Char('A')) {
- return url.length() >= 8 /* assets:/ */ &&
- url.startsWith(QLatin1String(assets_string), Qt::CaseInsensitive) &&
- url[6] == QLatin1Char(':') && url[7] == QLatin1Char('/');
- } else if (f == QLatin1Char('c') || f == QLatin1Char('C')) {
- return url.length() >= 9 /* content:/ */ &&
- url.startsWith(QLatin1String(content_string), Qt::CaseInsensitive) &&
- url[7] == QLatin1Char(':') && url[8] == QLatin1Char('/');
+static bool hasLocalContentAuthority(const QString &url, qsizetype schemeLength)
+{
+ const qsizetype offset = authorityOffset(url, schemeLength);
+ if (offset == -1)
+ return true; // no authority is a local authority.
+
+ const QString authorityAndPath = url.sliced(offset);
+ return authorityAndPath.startsWith(QLatin1String(authority_externalstorage))
+ || authorityAndPath.startsWith(QLatin1String(authority_downloads_documents))
+ || authorityAndPath.startsWith(QLatin1String(authority_media_documents));
+}
+
+#endif
+
+/*!
+ Returns \c true if \a url is a local file that can be opened with \l{QFile}.
+ Otherwise returns \c false. Local file urls have either a \c{qrc:} or
+ \c{file:} scheme.
+
+ \note On Android, urls with \c{assets:} or \c{content:} scheme are also considered
+ local files.
+*/
+bool QQmlFile::isLocalFile(const QString &url)
+{
+ if (url.size() < 4 /* qrc: */)
+ return false;
+
+ switch (url[0].toLatin1()) {
+ case 'f':
+ case 'F': {
+ // file: URLs with two slashes following the scheme can be interpreted as local files
+ // where the slashes are part of the path. Therefore, disregard the authority.
+ // See QUrl::toLocalFile().
+ const qsizetype fileLength = strlen(file_string);
+ return url.startsWith(QLatin1String(file_string, file_string + fileLength),
+ Qt::CaseInsensitive)
+ && url.size() > fileLength
+ && url[fileLength] == QLatin1Char(':');
}
+ case 'q':
+ case 'Q':
+ return hasScheme(url, qrc_string, strlen(qrc_string))
+ && authorityOffset(url, strlen(qrc_string)) == -1;
+#if defined(Q_OS_ANDROID)
+ case 'a':
+ case 'A':
+ return hasScheme(url, assets_string, strlen(assets_string))
+ && authorityOffset(url, strlen(assets_string)) == -1;
+ case 'c':
+ case 'C':
+ return hasScheme(url, content_string, strlen(content_string))
+ && hasLocalContentAuthority(url, strlen(content_string));
#endif
+ default:
+ break;
+ }
return false;
}
/*!
-If \a url is a local file returns a path suitable for passing to QFile. Otherwise returns an
-empty string.
+ If \a url is a local file returns a path suitable for passing to \l{QFile}.
+ Otherwise returns an empty string.
+
+ \sa isLocalFile
*/
QString QQmlFile::urlToLocalFileOrQrc(const QUrl& url)
{
@@ -585,15 +694,14 @@ QString QQmlFile::urlToLocalFileOrQrc(const QUrl& url)
}
#if defined(Q_OS_ANDROID)
- else if (url.scheme().compare(QLatin1String("assets"), Qt::CaseInsensitive) == 0) {
- if (url.authority().isEmpty())
+ if (url.scheme().compare(QLatin1String("assets"), Qt::CaseInsensitive) == 0)
+ return url.authority().isEmpty() ? url.toString() : QString();
+ if (url.scheme().compare(QLatin1String("content"), Qt::CaseInsensitive) == 0) {
+ if (hasLocalContentAuthority(url))
return url.toString();
return QString();
- } else if (url.scheme().compare(QLatin1String("content"), Qt::CaseInsensitive) == 0) {
- return url.toString();
}
#endif
-
return url.toLocalFile();
}
@@ -603,35 +711,59 @@ static QString toLocalFile(const QString &url)
if (!file.isLocalFile())
return QString();
- //XXX TODO: handle windows hostnames: "//servername/path/to/file.txt"
+ // QUrl::toLocalFile() interprets two slashes as part of the path.
+ // Therefore windows hostnames like "//servername/path/to/file.txt" are preserved.
return file.toLocalFile();
}
+static bool isDoubleSlashed(const QString &url, qsizetype offset)
+{
+ const qsizetype urlLength = url.size();
+ if (urlLength < offset + 2)
+ return false;
+
+ const QLatin1Char slash('/');
+ if (url[offset] != slash || url[offset + 1] != slash)
+ return false;
+
+ if (urlLength < offset + 3)
+ return true;
+
+ return url[offset + 2] != slash;
+}
+
/*!
-If \a url is a local file returns a path suitable for passing to QFile. Otherwise returns an
-empty string.
+ If \a url is a local file returns a path suitable for passing to \l{QFile}.
+ Otherwise returns an empty string.
+
+ \sa isLocalFile
*/
QString QQmlFile::urlToLocalFileOrQrc(const QString& url)
{
if (url.startsWith(QLatin1String("qrc://"), Qt::CaseInsensitive)) {
- if (url.length() > 6)
- return QLatin1Char(':') + url.midRef(6);
- return QString();
+ // Exactly two slashes are bad because that's a URL authority.
+ // One slash is fine and >= 3 slashes are file.
+ if (url.size() == 6 || url[6] != QLatin1Char('/')) {
+ Q_ASSERT(isDoubleSlashed(url, strlen("qrc:")));
+ return QString();
+ }
+ Q_ASSERT(!isDoubleSlashed(url, strlen("qrc:")));
+ return QLatin1Char(':') + QStringView{url}.mid(6);
}
if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) {
- if (url.length() > 4)
- return QLatin1Char(':') + url.midRef(4);
- return QString();
+ Q_ASSERT(!isDoubleSlashed(url, strlen("qrc:")));
+ if (url.size() > 4)
+ return QLatin1Char(':') + QStringView{url}.mid(4);
+ return QStringLiteral(":");
}
#if defined(Q_OS_ANDROID)
- else if (url.startsWith(QLatin1String("assets:"), Qt::CaseInsensitive)) {
- return url;
- } else if (url.startsWith(QLatin1String("content:"), Qt::CaseInsensitive)) {
- return url;
- }
+ if (url.startsWith(QLatin1String("assets:"), Qt::CaseInsensitive))
+ return isDoubleSlashed(url, strlen("assets:")) ? QString() : url;
+ if (hasScheme(url, content_string, strlen(content_string)))
+ return hasLocalContentAuthority(url, strlen(content_string)) ? url : QString();
#endif
return toLocalFile(url);
diff --git a/src/qml/qml/qqmlfile.h b/src/qml/qml/qqmlfile.h
index aec0981a95..af90e671a9 100644
--- a/src/qml/qml/qqmlfile.h
+++ b/src/qml/qml/qqmlfile.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLFILE_H
#define QQMLFILE_H
@@ -54,8 +18,8 @@ class Q_QML_EXPORT QQmlFile
{
public:
QQmlFile();
- QQmlFile(QQmlEngine *, const QUrl &);
- QQmlFile(QQmlEngine *, const QString &);
+ QQmlFile(QQmlEngine *engine, const QUrl &url);
+ QQmlFile(QQmlEngine *engine, const QString &url);
~QQmlFile();
enum Status { Null, Ready, Error, Loading };
@@ -78,7 +42,7 @@ public:
void load(QQmlEngine *, const QString &);
void clear();
- void clear(QObject *);
+ void clear(QObject *object);
#if QT_CONFIG(qml_network)
bool connectFinished(QObject *, const char *);
diff --git a/src/qml/qml/qqmlfileselector.cpp b/src/qml/qml/qqmlfileselector.cpp
index 32dce8b4bc..1704e2d994 100644
--- a/src/qml/qml/qqmlfileselector.cpp
+++ b/src/qml/qml/qqmlfileselector.cpp
@@ -1,53 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/QFileSelector>
#include <QtQml/QQmlAbstractUrlInterceptor>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtQml/private/qqmlapplicationengine_p.h>
#include <qobjectdefs.h>
#include "qqmlfileselector.h"
#include "qqmlfileselector_p.h"
+#include "qqmlengine_p.h"
#include <QDebug>
QT_BEGIN_NAMESPACE
-typedef QHash<QQmlAbstractUrlInterceptor*, QQmlFileSelector*> interceptorSelectorMap;
-Q_GLOBAL_STATIC(interceptorSelectorMap, interceptorInstances);
/*!
\class QQmlFileSelector
\since 5.2
@@ -89,8 +54,7 @@ Q_GLOBAL_STATIC(interceptorSelectorMap, interceptorInstances);
directories used for selection must start with a '+' character, so you will not accidentally
trigger this feature unless you have directories with such names inside your project.
- If a new QQmlFileSelector is set on the engine, the old one will be replaced. Use
- \l QQmlFileSelector::get() to query or use the existing instance.
+ If a new QQmlFileSelector is set on the engine, the old one will be replaced.
*/
/*!
@@ -104,8 +68,7 @@ QQmlFileSelector::QQmlFileSelector(QQmlEngine* engine, QObject* parent)
{
Q_D(QQmlFileSelector);
d->engine = engine;
- interceptorInstances()->insert(d->myInstance.data(), this);
- d->engine->setUrlInterceptor(d->myInstance.data());
+ d->engine->addUrlInterceptor(d->myInstance.data());
}
/*!
@@ -114,18 +77,17 @@ QQmlFileSelector::QQmlFileSelector(QQmlEngine* engine, QObject* parent)
QQmlFileSelector::~QQmlFileSelector()
{
Q_D(QQmlFileSelector);
- if (d->engine && QQmlFileSelector::get(d->engine) == this) {
- d->engine->setUrlInterceptor(nullptr);
+ if (d->engine) {
+ d->engine->removeUrlInterceptor(d->myInstance.data());
d->engine = nullptr;
}
- interceptorInstances()->remove(d->myInstance.data());
}
/*!
\since 5.7
Returns the QFileSelector instance used by the QQmlFileSelector.
*/
-QFileSelector *QQmlFileSelector::selector() const Q_DECL_NOTHROW
+QFileSelector *QQmlFileSelector::selector() const noexcept
{
Q_D(const QQmlFileSelector);
return d->selector;
@@ -148,7 +110,7 @@ QQmlFileSelectorPrivate::~QQmlFileSelectorPrivate()
/*!
Sets the QFileSelector instance for use by the QQmlFileSelector to \a selector.
QQmlFileSelector does not take ownership of the new QFileSelector. To reset QQmlFileSelector
- to use its internal QFileSelector instance, call setSelector(0).
+ to use its internal QFileSelector instance, call setSelector(\nullptr).
*/
void QQmlFileSelector::setSelector(QFileSelector *selector)
@@ -173,35 +135,49 @@ void QQmlFileSelector::setSelector(QFileSelector *selector)
Use this when extra selectors are all you need to avoid having to create your own
QFileSelector instance.
*/
-void QQmlFileSelector::setExtraSelectors(QStringList &strings)
-{
- Q_D(QQmlFileSelector);
- d->selector->setExtraSelectors(strings);
-}
-
-
-/*!
- Adds extra selectors contained in \a strings to the current QFileSelector being used.
- Use this when extra selectors are all you need to avoid having to create your own
- QFileSelector instance.
-*/
void QQmlFileSelector::setExtraSelectors(const QStringList &strings)
{
Q_D(QQmlFileSelector);
d->selector->setExtraSelectors(strings);
}
+#if QT_DEPRECATED_SINCE(6, 0)
/*!
+ \deprecated [6.0] The file selector should not be accessed after it
+ is set. It may be in use. See below for further details.
+
Gets the QQmlFileSelector currently active on the target \a engine.
+
+ This method is deprecated. You should not retrieve the files selector from an
+ engine after setting it. It may be in use.
+
+ If the \a engine passed here is a QQmlApplicationEngine that hasn't loaded any
+ QML files, yet, it will be initialized. Any later calls to
+ QQmlApplicationEngine::setExtraFileSelectors() will have no effect.
+
+ \sa QQmlApplicationEngine
*/
QQmlFileSelector* QQmlFileSelector::get(QQmlEngine* engine)
{
- //Since I think we still can't use dynamic_cast inside Qt...
- QQmlAbstractUrlInterceptor* current = engine->urlInterceptor();
- if (current && interceptorInstances()->contains(current))
- return interceptorInstances()->value(current);
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
+
+ if (qobject_cast<QQmlApplicationEngine *>(engine)) {
+ auto *appEnginePrivate = static_cast<QQmlApplicationEnginePrivate *>(enginePrivate);
+ appEnginePrivate->ensureInitialized();
+ }
+
+ const QUrl nonEmptyInvalid(QLatin1String(":"));
+ for (QQmlAbstractUrlInterceptor *interceptor : enginePrivate->urlInterceptors) {
+ const QUrl result = interceptor->intercept(
+ nonEmptyInvalid, QQmlAbstractUrlInterceptor::UrlString);
+ if (result.scheme() == QLatin1String("type")
+ && result.path() == QLatin1String("fileselector")) {
+ return static_cast<QQmlFileSelectorInterceptor *>(interceptor)->d->q_func();
+ }
+ }
return nullptr;
}
+#endif
/*!
\internal
@@ -216,9 +192,12 @@ QQmlFileSelectorInterceptor::QQmlFileSelectorInterceptor(QQmlFileSelectorPrivate
*/
QUrl QQmlFileSelectorInterceptor::intercept(const QUrl &path, DataType type)
{
- if ( type == QQmlAbstractUrlInterceptor::QmldirFile ) //Don't intercept qmldir files, to prevent double interception
- return path;
- return d->selector->select(path);
+ if (!path.isEmpty() && !path.isValid())
+ return QUrl(QLatin1String("type:fileselector"));
+
+ return type == QQmlAbstractUrlInterceptor::QmldirFile
+ ? path // Don't intercept qmldir files, to prevent double interception
+ : d->selector->select(path);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlfileselector.h b/src/qml/qml/qqmlfileselector.h
index 9b70e3936d..0509aa565a 100644
--- a/src/qml/qml/qqmlfileselector.h
+++ b/src/qml/qml/qqmlfileselector.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLFILESELECTOR_H
#define QQMLFILESELECTOR_H
@@ -56,11 +20,13 @@ class Q_QML_EXPORT QQmlFileSelector : public QObject
public:
explicit QQmlFileSelector(QQmlEngine *engine, QObject *parent = nullptr);
~QQmlFileSelector() override;
- QFileSelector *selector() const Q_DECL_NOTHROW;
+ QFileSelector *selector() const noexcept;
void setSelector(QFileSelector *selector);
- void setExtraSelectors(QStringList &strings); // TODO Qt6: remove
void setExtraSelectors(const QStringList &strings);
- static QQmlFileSelector* get(QQmlEngine*);
+
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED static QQmlFileSelector *get(QQmlEngine*);
+#endif
private:
Q_DISABLE_COPY(QQmlFileSelector)
diff --git a/src/qml/qml/qqmlfileselector_p.h b/src/qml/qml/qqmlfileselector_p.h
index a7360f83d9..58696acef7 100644
--- a/src/qml/qml/qqmlfileselector_p.h
+++ b/src/qml/qml/qqmlfileselector_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLFILESELECTOR_P_H
#define QQMLFILESELECTOR_P_H
@@ -57,11 +21,13 @@
#include <private/qobject_p.h>
#include <private/qtqmlglobal_p.h>
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
class QFileSelector;
class QQmlFileSelectorInterceptor;
-class Q_QML_PRIVATE_EXPORT QQmlFileSelectorPrivate : public QObjectPrivate
+class Q_QML_EXPORT QQmlFileSelectorPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQmlFileSelector)
public:
@@ -74,7 +40,7 @@ public:
QScopedPointer<QQmlFileSelectorInterceptor> myInstance;
};
-class Q_QML_PRIVATE_EXPORT QQmlFileSelectorInterceptor : public QQmlAbstractUrlInterceptor
+class Q_QML_EXPORT QQmlFileSelectorInterceptor : public QQmlAbstractUrlInterceptor
{
public:
QQmlFileSelectorInterceptor(QQmlFileSelectorPrivate* pd);
diff --git a/src/qml/qml/qqmlfinalizer.cpp b/src/qml/qml/qqmlfinalizer.cpp
new file mode 100644
index 0000000000..8b87b8955d
--- /dev/null
+++ b/src/qml/qml/qqmlfinalizer.cpp
@@ -0,0 +1,59 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qqmlfinalizer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlFinalizerHook::~QQmlFinalizerHook() = default;
+
+/*!
+ \class QQmlFinalizerHook
+ \internal
+
+ QQmlFinalizerHook is an internal interface to run code after the current toplevel
+ component has been completed.
+ At first, this might look like QQmlParserStaus' componentComplete functionality
+ by another name - however there is a difference. To understand it, consider the
+ following QML file:
+
+ \qml
+ import QtQuick
+ Item {
+ id: root
+ Rectangle {
+ id: rect
+ Rectangle { id: innerRect }
+ }
+ property Item it: Item {id: myItem }
+ }
+ \endqml
+
+ This file will instantiate 4 (sub-)components: One for each of root, rect, innerRect
+ and myItem. If the component gets loaded in a synchronous way, each of their
+ componentComplete (if existent) would run directly one after another (in a non-specified
+ order).
+
+ However, in the case of an asynchronous instantiation, e.g. via a loader, we might interrupt
+ the (sub-)component construction partway: There can be a delay between the various
+ componentComplete calls, and not all sub-components might have been constructed yet.
+ QQmlFinalizerHook::componentFinalized is instead called after all asynchronously instantiated
+ (sub-)components have been constructed. Notably, all bindings of those components have also
+ been set up.
+
+ \note While the engine does not use qobject_cast, tooling still relies on the interface
+ being marked as such. Thus you should always use the Q_INTERFACES macro in classes deriving
+ from QQmlFinalizerHook.
+*/
+
+/*!
+ \fn void QQmlFinalizerHook::componentFinalized()
+
+ The customization point provided by this interface. See the class description for
+ why it is useful and how it compares to componentComplete.
+
+ \sa QQmlParserStatus::componentComplete
+
+ */
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlfinalizer_p.h b/src/qml/qml/qqmlfinalizer_p.h
new file mode 100644
index 0000000000..66fd85ddad
--- /dev/null
+++ b/src/qml/qml/qqmlfinalizer_p.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLFINALIZER_P_H
+#define QQMLFINALIZER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/private/qtqmlglobal_p.h>
+#include <qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_EXPORT QQmlFinalizerHook
+{
+public:
+ virtual ~QQmlFinalizerHook();
+ virtual void componentFinalized() = 0;
+};
+#define QQmlFinalizerHook_iid "org.qt-project.Qt.QQmlFinalizerHook"
+Q_DECLARE_INTERFACE(QQmlFinalizerHook, QQmlFinalizerHook_iid)
+
+QT_END_NAMESPACE
+
+#endif // QQMLFINALIZER_P_H
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index acebb6bac3..1273067187 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -1,278 +1,746 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qqmlglobal_p.h>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include <QtQml/private/qjsvalue_p.h>
+#include <QtQml/private/qqmlglobal_p.h>
+#include <QtQml/private/qqmlmetatype_p.h>
#include <QtQml/qqmlengine.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qstringlist.h>
+
+#include <QtCore/private/qvariant_p.h>
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qdebug.h>
-#include <QtCore/QCoreApplication>
+#include <QtCore/qstringlist.h>
QT_BEGIN_NAMESPACE
-QQmlValueTypeProvider::QQmlValueTypeProvider()
- : next(nullptr)
-{
+// Pre-filter the metatype before poking QQmlMetaType::qmlType() and locking its mutex.
+static bool isConstructibleMetaType(const QMetaType metaType)
+{
+ switch (metaType.id()) {
+ // The builtins are not constructible this way.
+ case QMetaType::Void:
+ case QMetaType::Nullptr:
+ case QMetaType::QVariant:
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ case QMetaType::Float:
+ case QMetaType::Double:
+ case QMetaType::Long:
+ case QMetaType::ULong:
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ case QMetaType::Char:
+ case QMetaType::SChar:
+ case QMetaType::UChar:
+ case QMetaType::QChar:
+ case QMetaType::QString:
+ case QMetaType::Bool:
+ case QMetaType::QDateTime:
+ case QMetaType::QDate:
+ case QMetaType::QTime:
+ case QMetaType::QUrl:
+ case QMetaType::QRegularExpression:
+ case QMetaType::QByteArray:
+ case QMetaType::QLocale:
+ return false;
+ default:
+ break;
+ }
+
+ // QJSValue is also builtin
+ if (metaType == QMetaType::fromType<QJSValue>())
+ return false;
+
+ // We also don't want to construct pointers of any kind, or lists, or enums.
+ if (metaType.flags() &
+ (QMetaType::PointerToQObject
+ | QMetaType::IsEnumeration
+ | QMetaType::SharedPointerToQObject
+ | QMetaType::WeakPointerToQObject
+ | QMetaType::TrackingPointerToQObject
+ | QMetaType::IsUnsignedEnumeration
+ | QMetaType::PointerToGadget
+ | QMetaType::IsPointer
+ | QMetaType::IsQmlList)) {
+ return false;
+ }
+
+ return true;
}
-QQmlValueTypeProvider::~QQmlValueTypeProvider()
+static void *createVariantData(QMetaType type, QVariant *variant)
{
- QQml_removeValueTypeProvider(this);
+ const QtPrivate::QMetaTypeInterface *iface = type.iface();
+ QVariant::Private *d = &variant->data_ptr();
+ Q_ASSERT(d->is_null && !d->is_shared);
+ *d = QVariant::Private(iface);
+ if (QVariant::Private::canUseInternalSpace(iface))
+ return d->data.data;
+
+ // This is not exception safe.
+ // If your value type throws an exception from its ctor bad things will happen anyway.
+ d->data.shared = QVariant::PrivateShared::create(iface->size, iface->alignment);
+ d->is_shared = true;
+ return d->data.shared->data();
}
-const QMetaObject *QQmlValueTypeProvider::metaObjectForMetaType(int type)
+static void callConstructor(
+ const QMetaObject *targetMetaObject, int i, void *source, void *target)
{
- QQmlValueTypeProvider *p = this;
- do {
- if (const QMetaObject *mo = p->getMetaObjectForMetaType(type))
- return mo;
- } while ((p = p->next));
+ void *p[] = { target, source };
+ targetMetaObject->static_metacall(QMetaObject::ConstructInPlace, i, p);
+}
- return nullptr;
+template<typename Allocate>
+static void fromVerifiedType(
+ const QMetaObject *targetMetaObject, int ctorIndex, void *source, Allocate &&allocate)
+{
+ const QMetaMethod ctor = targetMetaObject->constructor(ctorIndex);
+ Q_ASSERT_X(ctor.parameterCount() == 1, "fromVerifiedType",
+ "Value type constructor must take exactly one argument");
+ callConstructor(targetMetaObject, ctorIndex, source, allocate());
}
-bool QQmlValueTypeProvider::initValueType(int type, QVariant& dst)
+
+template<typename Allocate, typename Retrieve>
+static bool fromMatchingType(
+ const QMetaObject *targetMetaObject, Allocate &&allocate, Retrieve &&retrieve)
{
- QQmlValueTypeProvider *p = this;
- do {
- if (p->init(type, dst))
+ for (int i = 0, end = targetMetaObject->constructorCount(); i < end; ++i) {
+ const QMetaMethod ctor = targetMetaObject->constructor(i);
+ if (ctor.parameterCount() != 1)
+ continue;
+
+ const QMetaType parameterType = ctor.parameterMetaType(0);
+
+ if (retrieve(parameterType, [&](QMetaType sourceMetaType, void *sourceData) {
+ if (sourceMetaType == parameterType) {
+ callConstructor(targetMetaObject, i, sourceData, allocate());
+ return true;
+ }
+
+ if (const QMetaObject *parameterMetaObject = parameterType.metaObject()) {
+ if (const QMetaObject *sourceMetaObject = sourceMetaType.metaObject();
+ sourceMetaObject && sourceMetaObject->inherits(parameterMetaObject)) {
+ // Allow construction from derived types.
+ callConstructor(targetMetaObject, i, sourceData, allocate());
+ return true;
+ }
+ }
+
+ // Do not recursively try to create parameters here. This may end up in infinite recursion.
+
+ // At this point, s should be a builtin type. For builtin types
+ // the QMetaType converters are good enough.
+ QVariant converted(parameterType);
+ if (QMetaType::convert(sourceMetaType, sourceData, parameterType, converted.data())) {
+ callConstructor(targetMetaObject, i, converted.data(), allocate());
+ return true;
+ }
+
+ return false;
+ })) {
return true;
- } while ((p = p->next));
+ }
+ }
return false;
}
-QVariant QQmlValueTypeProvider::createValueType(int type, int argc, const void *argv[])
+template<typename Allocate>
+static bool fromMatchingType(
+ const QMetaObject *targetMetaObject, const QV4::Value &source, Allocate &&allocate)
{
- QVariant v;
-
- QQmlValueTypeProvider *p = this;
- do {
- if (p->create(type, argc, argv, &v))
- return v;
- } while ((p = p->next));
+ return fromMatchingType(
+ targetMetaObject, std::forward<Allocate>(allocate),
+ [&](QMetaType parameterType, auto callback) {
+ QVariant variant = QV4::ExecutionEngine::toVariant(source, parameterType);
+ return callback(variant.metaType(), variant.data());
+ });
+}
- return QVariant();
+template<typename Allocate>
+static bool fromMatchingType(
+ const QMetaObject *targetMetaObject, QVariant source, Allocate &&allocate)
+{
+ return fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate),
+ [&](QMetaType, auto callback) {
+ return callback(source.metaType(), source.data());
+ });
}
-bool QQmlValueTypeProvider::createValueFromString(int type, const QString &s, void *data, size_t n)
+template<typename Allocate>
+static bool fromString(const QMetaObject *mo, QString s, Allocate &&allocate)
{
- Q_ASSERT(data);
+ for (int i = 0, end = mo->constructorCount(); i < end; ++i) {
+ const QMetaMethod ctor = mo->constructor(i);
+ if (ctor.parameterCount() != 1)
+ continue;
- QQmlValueTypeProvider *p = this;
- do {
- if (p->createFromString(type, s, data, n))
+ if (ctor.parameterMetaType(0) == QMetaType::fromType<QString>()) {
+ callConstructor(mo, i, &s, allocate());
return true;
- } while ((p = p->next));
+ }
+ }
return false;
}
-bool QQmlValueTypeProvider::createStringFromValue(int type, const void *data, QString *s)
+template<typename Get, typename Convert>
+static bool doWriteProperty(const QMetaProperty &metaProperty, void *target,
+ Get &&get, Convert &&convert)
{
- Q_ASSERT(data);
- Q_ASSERT(s);
+ const QMetaType propertyType = metaProperty.metaType();
+ QVariant property = get(propertyType);
+ if (property.metaType() == propertyType) {
+ metaProperty.writeOnGadget(target, std::move(property));
+ return true;
+ }
- QQmlValueTypeProvider *p = this;
- do {
- if (p->createStringFrom(type, data, s))
- return true;
- } while ((p = p->next));
+ QVariant converted = convert(propertyType);
+ if (converted.isValid()) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ return true;
+ }
+
+ converted = QVariant(propertyType);
+ if (QMetaType::convert(property.metaType(), property.constData(),
+ propertyType, converted.data())) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ return true;
+ }
return false;
}
-QVariant QQmlValueTypeProvider::createVariantFromString(const QString &s)
+static void doWriteProperties(
+ const QMetaObject *targetMetaObject, void *target, const QV4::Value &source)
{
- QVariant v;
+ const QV4::Object *o = static_cast<const QV4::Object *>(&source);
+ QV4::Scope scope(o->engine());
+ QV4::ScopedObject object(scope, o);
- QQmlValueTypeProvider *p = this;
- do {
- if (p->variantFromString(s, &v))
- return v;
- } while ((p = p->next));
+ for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
+ const QMetaProperty metaProperty = targetMetaObject->property(i);
+ const QString propertyName = QString::fromUtf8(metaProperty.name());
- // Return a variant containing the string itself
- return QVariant(s);
-}
+ QV4::ScopedString v4PropName(scope, scope.engine->newString(propertyName));
+ QV4::ScopedValue v4PropValue(scope, object->get(v4PropName));
-QVariant QQmlValueTypeProvider::createVariantFromString(int type, const QString &s, bool *ok)
-{
- QVariant v;
+ // We assume that data is freshly constructed.
+ // There is no point in reset()'ing properties of a freshly created object.
+ if (v4PropValue->isUndefined())
+ continue;
- QQmlValueTypeProvider *p = this;
- do {
- if (p->variantFromString(type, s, &v)) {
- if (ok) *ok = true;
- return v;
+ if (doWriteProperty(metaProperty, target, [&](const QMetaType &propertyType) {
+ return QV4::ExecutionEngine::toVariant(v4PropValue, propertyType);
+ }, [&](const QMetaType &propertyType) {
+ return QQmlValueTypeProvider::createValueType(v4PropValue, propertyType);
+ })) {
+ continue;
}
- } while ((p = p->next));
- if (ok) *ok = false;
- return QVariant();
+ const QMetaType propertyType = metaProperty.metaType();
+ QVariant property = QV4::ExecutionEngine::toVariant(v4PropValue, propertyType);
+ if (property.metaType() == propertyType) {
+ metaProperty.writeOnGadget(target, std::move(property));
+ continue;
+ }
+
+ QVariant converted = QQmlValueTypeProvider::createValueType(v4PropValue, propertyType);
+ if (converted.isValid()) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ continue;
+ }
+
+ converted = QVariant(propertyType);
+ if (QMetaType::convert(property.metaType(), property.constData(),
+ propertyType, converted.data())) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ continue;
+ }
+
+ qWarning().noquote()
+ << QLatin1String("Could not convert %1 to %2 for property %3")
+ .arg(v4PropValue->toQStringNoThrow(), QString::fromUtf8(propertyType.name()),
+ propertyName);
+ }
+}
+
+static QVariant byProperties(
+ const QMetaObject *targetMetaObject, QMetaType metaType, const QV4::Value &source)
+{
+ if (!source.isObject() || !targetMetaObject)
+ return QVariant();
+
+ QVariant result(metaType);
+ doWriteProperties(targetMetaObject, result.data(), source);
+ return result;
}
-QVariant QQmlValueTypeProvider::createVariantFromJsObject(int type, const QV4::Value &obj,
- QV4::ExecutionEngine *e, bool *ok)
+template<typename Read>
+static void doWriteProperties(
+ const QMetaObject *targetMetaObject, void *target,
+ const QMetaObject *sourceMetaObject, Read &&read)
{
- QVariant v;
+ for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
+ const QMetaProperty metaProperty = targetMetaObject->property(i);
+
+ const int sourceProperty = sourceMetaObject->indexOfProperty(metaProperty.name());
+
+ // We assume that data is freshly constructed.
+ // There is no point in reset()'ing properties of a freshly created object.
+ if (sourceProperty == -1)
+ continue;
- QQmlValueTypeProvider *p = this;
- do {
- if (p->variantFromJsObject(type, obj, e, &v)) {
- if (ok) *ok = true;
- return v;
+ const QMetaType propertyType = metaProperty.metaType();
+ QVariant property = read(sourceMetaObject, sourceProperty);
+ if (property.metaType() == propertyType) {
+ metaProperty.writeOnGadget(target, std::move(property));
+ continue;
}
- } while ((p = p->next));
- if (ok) *ok = false;
- return QVariant();
+ QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType);
+ if (converted.isValid()) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ continue;
+ }
+
+ converted = QVariant(propertyType);
+ if (QMetaType::convert(property.metaType(), property.constData(),
+ propertyType, converted.data())) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ continue;
+ }
+
+ qWarning().noquote()
+ << QLatin1String("Could not convert %1 to %2 for property %3")
+ .arg(property.toString(), QString::fromUtf8(propertyType.name()),
+ QString::fromUtf8(metaProperty.name()));
+ }
}
-bool QQmlValueTypeProvider::equalValueType(int type, const void *lhs, const QVariant& rhs)
+
+static void doWriteProperties(const QMetaObject *targetMeta, void *target, QObject *source)
{
- Q_ASSERT(lhs);
+ doWriteProperties(
+ targetMeta, target, source->metaObject(),
+ [source](const QMetaObject *sourceMetaObject, int sourceProperty) {
+ return sourceMetaObject->property(sourceProperty).read(source);
+ });
+}
- QQmlValueTypeProvider *p = this;
- do {
- if (p->equal(type, lhs, rhs))
- return true;
- } while ((p = p->next));
+static QVariant byProperties(
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType, QObject *source)
+{
+ if (!source || !targetMetaObject)
+ return QVariant();
- return false;
+ QVariant result(targetMetaType);
+ doWriteProperties(targetMetaObject, result.data(), source);
+ return result;
}
-bool QQmlValueTypeProvider::storeValueType(int type, const void *src, void *dst, size_t dstSize)
+static QVariant byProperties(
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType,
+ const QMetaObject *sourceMetaObject, const void *source)
{
- Q_ASSERT(src);
- Q_ASSERT(dst);
+ if (!source || !sourceMetaObject || !targetMetaObject)
+ return QVariant();
- QQmlValueTypeProvider *p = this;
- do {
- if (p->store(type, src, dst, dstSize))
- return true;
- } while ((p = p->next));
+ QVariant result(targetMetaType);
+ doWriteProperties(
+ targetMetaObject, result.data(), sourceMetaObject,
+ [source](const QMetaObject *sourceMetaObject, int sourceProperty) {
+ return sourceMetaObject->property(sourceProperty).readOnGadget(source);
+ });
+ return result;
+}
- return false;
+template<typename Map>
+void doWriteProperties(const QMetaObject *targetMetaObject, void *target, const Map &source)
+{
+ for (int i = 0; i < targetMetaObject->propertyCount(); ++i) {
+ const QMetaProperty metaProperty = targetMetaObject->property(i);
+
+ // We assume that data is freshly constructed.
+ // There is no point in reset()'ing properties of a freshly created object.
+ const auto it = source.constFind(QString::fromUtf8(metaProperty.name()));
+ if (it == source.constEnd())
+ continue;
+
+ const QMetaType propertyType = metaProperty.metaType();
+ QVariant property = *it;
+ if (property.metaType() == propertyType) {
+ metaProperty.writeOnGadget(target, std::move(property));
+ continue;
+ }
+
+ QVariant converted = QQmlValueTypeProvider::createValueType(property, propertyType);
+ if (converted.isValid()) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ continue;
+ }
+
+ converted = QVariant(propertyType);
+ if (QMetaType::convert(property.metaType(), property.constData(),
+ propertyType, converted.data())) {
+ metaProperty.writeOnGadget(target, std::move(converted));
+ continue;
+ }
+
+ qWarning().noquote()
+ << QLatin1String("Could not convert %1 to %2 for property %3")
+ .arg(property.toString(), QString::fromUtf8(propertyType.name()),
+ QString::fromUtf8(metaProperty.name()));
+ }
+}
+
+template<typename Map>
+QVariant byProperties(
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType, const Map &source)
+{
+ QVariant result(targetMetaType);
+ doWriteProperties(targetMetaObject, result.data(), source);
+ return result;
}
-bool QQmlValueTypeProvider::readValueType(const QVariant& src, void *dst, int dstType)
+static QVariant byProperties(
+ const QMetaObject *targetMetaObject, QMetaType targetMetaType, const QVariant &source)
{
- Q_ASSERT(dst);
+ if (!targetMetaObject)
+ return QVariant();
- QQmlValueTypeProvider *p = this;
- do {
- if (p->read(src, dst, dstType))
+ if (source.metaType() == QMetaType::fromType<QJSValue>()) {
+ QJSValue val = source.value<QJSValue>();
+ return byProperties(
+ targetMetaObject, targetMetaType, QV4::Value(QJSValuePrivate::asReturnedValue(&val)));
+ }
+
+ if (source.metaType() == QMetaType::fromType<QVariantMap>()) {
+ return byProperties(
+ targetMetaObject, targetMetaType,
+ *static_cast<const QVariantMap *>(source.constData()));
+ }
+
+ if (source.metaType() == QMetaType::fromType<QVariantHash>()) {
+ return byProperties(
+ targetMetaObject, targetMetaType,
+ *static_cast<const QVariantHash *>(source.constData()));
+ }
+
+ if (source.metaType().flags() & QMetaType::PointerToQObject)
+ return byProperties(targetMetaObject, targetMetaType, source.value<QObject *>());
+
+ if (const QMetaObject *sourceMeta = QQmlMetaType::metaObjectForValueType(source.metaType()))
+ return byProperties(targetMetaObject, targetMetaType, sourceMeta, source.constData());
+
+ return QVariant();
+}
+
+template<typename Allocate, typename DefaultConstruct>
+bool createOrConstructValueType(
+ const QQmlType &targetType, const QV4::Value &source,
+ Allocate &&allocate, DefaultConstruct &&defaultConstruct)
+{
+ const auto warn = [&](const QMetaObject *targetMetaObject) {
+ qWarning().noquote()
+ << "Could not find any constructor for value type"
+ << targetMetaObject->className() << "to call with value"
+ << source.toQStringNoThrow();
+ };
+
+ if (targetType.canPopulateValueType()) {
+ if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
+ if (source.isObject()) {
+ doWriteProperties(targetMetaObject, defaultConstruct(), source);
+ return true;
+ }
+ if (targetType.canConstructValueType()) {
+ if (fromMatchingType(targetMetaObject, source, allocate))
+ return true;
+ warn(targetMetaObject);
+ }
+ }
+ } else if (targetType.canConstructValueType()) {
+ if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
+ if (fromMatchingType(targetMetaObject, source, allocate))
+ return true;
+ warn(targetMetaObject);
+ }
+ }
+
+ if (const auto valueTypeFunction = targetType.createValueTypeFunction()) {
+ const QVariant result
+ = valueTypeFunction(QJSValuePrivate::fromReturnedValue(source.asReturnedValue()));
+ const QMetaType resultType = result.metaType();
+ if (resultType == targetType.typeId()) {
+ resultType.construct(allocate(), result.constData());
return true;
- } while ((p = p->next));
+ }
+ }
return false;
}
-bool QQmlValueTypeProvider::writeValueType(int type, const void *src, QVariant& dst)
-{
- Q_ASSERT(src);
+template<typename Allocate, typename DefaultConstruct>
+bool createOrConstructValueType(
+ const QQmlType &targetType, QMetaType sourceMetaType, void *source,
+ Allocate &&allocate, DefaultConstruct &&defaultConstruct)
+{
+
+ const auto warn = [&](const QMetaObject *targetMetaObject) {
+ qWarning().noquote()
+ << "Could not find any constructor for value type"
+ << targetMetaObject->className() << "to call with value" << source;
+ };
+
+ if (targetType.canPopulateValueType()) {
+ if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
+ if (const QMetaObject *sourceMetaObject
+ = QQmlMetaType::metaObjectForValueType(sourceMetaType)) {
+ doWriteProperties(
+ targetMetaObject, defaultConstruct(), sourceMetaObject,
+ [&source](const QMetaObject *sourceMetaObject, int sourceProperty) {
+ return sourceMetaObject->property(sourceProperty).readOnGadget(source);
+ });
+ return true;
+ }
+
+ if (sourceMetaType == QMetaType::fromType<QVariantMap>()) {
+ doWriteProperties(
+ targetMetaObject, defaultConstruct(),
+ *static_cast<const QVariantMap *>(source));
+ return true;
+ }
+
+ if (sourceMetaType == QMetaType::fromType<QVariantHash>()) {
+ doWriteProperties(
+ targetMetaObject, defaultConstruct(),
+ *static_cast<const QVariantHash *>(source));
+ return true;
+ }
+
+ if (sourceMetaType.flags() & QMetaType::PointerToQObject) {
+ doWriteProperties(
+ targetMetaObject, defaultConstruct(),
+ *static_cast<QObject *const *>(source));
+ return true;
+ }
+ }
+ }
- QQmlValueTypeProvider *p = this;
- do {
- if (p->write(type, src, dst))
- return true;
- } while ((p = p->next));
+ if (targetType.canConstructValueType()) {
+ if (const QMetaObject *targetMetaObject = targetType.metaObjectForValueType()) {
+ if (fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate),
+ [&](QMetaType, auto callback) {
+ return callback(sourceMetaType, source);
+ })) {
+ return true;
+ }
+ warn(targetMetaObject);
+ }
+ }
return false;
}
-const QMetaObject *QQmlValueTypeProvider::getMetaObjectForMetaType(int) { return nullptr; }
-bool QQmlValueTypeProvider::init(int, QVariant&) { return false; }
-bool QQmlValueTypeProvider::create(int, int, const void *[], QVariant *) { return false; }
-bool QQmlValueTypeProvider::createFromString(int, const QString &, void *, size_t) { return false; }
-bool QQmlValueTypeProvider::createStringFrom(int, const void *, QString *) { return false; }
-bool QQmlValueTypeProvider::variantFromString(const QString &, QVariant *) { return false; }
-bool QQmlValueTypeProvider::variantFromString(int, const QString &, QVariant *) { return false; }
-bool QQmlValueTypeProvider::variantFromJsObject(int, const QV4::Value &, QV4::ExecutionEngine *, QVariant *) { return false; }
-bool QQmlValueTypeProvider::equal(int, const void *, const QVariant&) { return false; }
-bool QQmlValueTypeProvider::store(int, const void *, void *, size_t) { return false; }
-bool QQmlValueTypeProvider::read(const QVariant&, void *, int) { return false; }
-bool QQmlValueTypeProvider::write(int, const void *, QVariant&) { return false; }
+/*!
+ * \internal
+ * Populate the value type in place at \a target, which is expected to be
+ * allocated and default-constructed, for example the result of a QVariant(QMetaType).
+ * This is efficient if we can do byProperties() since it can use the pre-constructed object.
+ * It also avoids the creation of a QVariant in most cases. It is not
+ * efficient if you're going to create a QVariant anyway.
+ */
+bool QQmlValueTypeProvider::populateValueType(
+ QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source)
+{
+ if (sourceMetaType == QMetaType::fromType<QJSValue>()) {
+ const QJSValue *val = static_cast<const QJSValue *>(source);
+ return populateValueType(
+ targetMetaType, target, QV4::Value(QJSValuePrivate::asReturnedValue(val)));
+ }
-struct ValueTypeProviderList {
- QQmlValueTypeProvider nullProvider;
- QQmlValueTypeProvider *head = &nullProvider;
-};
+ if (!isConstructibleMetaType(targetMetaType))
+ return false;
+
+ return createOrConstructValueType(
+ QQmlMetaType::qmlType(targetMetaType), sourceMetaType, source,
+ [targetMetaType, target]() {
+ targetMetaType.destruct(target);
+ return target;
+ }, [target]() {
+ return target;
+ });
+}
+
+/*!
+ * \internal
+ * Populate the value type in place at \a target, which is expected to be
+ * allocated and default-constructed, for example the result of a QVariant(QMetaType).
+ * This is efficient if we can do byProperties() since it can use the pre-constructed object.
+ * It also avoids the creation of a QVariant in most cases. It is not
+ * efficient if you're going to create a QVariant anyway.
+ */
+bool QQmlValueTypeProvider::populateValueType(
+ QMetaType targetMetaType, void *target, const QV4::Value &source)
+{
+ if (!isConstructibleMetaType(targetMetaType))
+ return false;
+
+ return createOrConstructValueType(
+ QQmlMetaType::qmlType(targetMetaType), source, [targetMetaType, target]() {
+ targetMetaType.destruct(target);
+ return target;
+ }, [target]() {
+ return target;
+ });
+}
+
+/*!
+ * \internal
+ * Specialization that constructs the value type on the heap using new and returns a pointer to it.
+ */
+void *QQmlValueTypeProvider::heapCreateValueType(
+ const QQmlType &targetType, const QV4::Value &source)
+{
+ void *target = nullptr;
+ if (createOrConstructValueType(
+ targetType, source, [&]() {
+ const QMetaType metaType = targetType.typeId();
+ const ushort align = metaType.alignOf();
+ target = align > __STDCPP_DEFAULT_NEW_ALIGNMENT__
+ ? operator new(metaType.sizeOf(), std::align_val_t(align))
+ : operator new(metaType.sizeOf());
+ return target;
+ }, [&]() {
+ target = targetType.typeId().create();
+ return target;
+ })) {
+ Q_ASSERT(target != nullptr);
+ }
+
+ return target;
+}
-Q_GLOBAL_STATIC(ValueTypeProviderList, valueTypeProviders)
+QVariant QQmlValueTypeProvider::constructValueType(
+ QMetaType targetMetaType, const QMetaObject *targetMetaObject,
+ int ctorIndex, void *ctorArg)
+{
+ QVariant result;
+ fromVerifiedType(targetMetaObject, ctorIndex, ctorArg,
+ [&]() { return createVariantData(targetMetaType, &result); });
+ return result;
+}
-Q_QML_PRIVATE_EXPORT void QQml_addValueTypeProvider(QQmlValueTypeProvider *newProvider)
+static QVariant fromJSValue(const QQmlType &type, const QJSValue &s, QMetaType metaType)
{
- if (ValueTypeProviderList *providers = valueTypeProviders()) {
- newProvider->next = providers->head;
- providers->head = newProvider;
+ if (const auto valueTypeFunction = type.createValueTypeFunction()) {
+ const QVariant result = valueTypeFunction(s);
+ if (result.metaType() == metaType)
+ return result;
}
+
+ return QVariant();
}
-Q_QML_PRIVATE_EXPORT void QQml_removeValueTypeProvider(QQmlValueTypeProvider *oldProvider)
+QVariant QQmlValueTypeProvider::createValueType(const QJSValue &s, QMetaType metaType)
{
- if (ValueTypeProviderList *providers = valueTypeProviders()) {
- QQmlValueTypeProvider *prev = providers->head;
- if (prev == oldProvider) {
- providers->head = oldProvider->next;
- return;
+ if (!isConstructibleMetaType(metaType))
+ return QVariant();
+ return fromJSValue(QQmlMetaType::qmlType(metaType), s, metaType);
+}
+
+QVariant QQmlValueTypeProvider::createValueType(const QString &s, QMetaType metaType)
+{
+ if (!isConstructibleMetaType(metaType))
+ return QVariant();
+ const QQmlType type = QQmlMetaType::qmlType(metaType);
+ if (type.canConstructValueType()) {
+ if (const QMetaObject *mo = type.metaObjectForValueType()) {
+ QVariant result;
+ if (fromString(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
}
+ }
- // singly-linked list removal
- for (; prev; prev = prev->next) {
- if (prev->next != oldProvider)
- continue; // this is not the provider you're looking for
- prev->next = oldProvider->next;
- return;
+ return fromJSValue(type, s, metaType);
+}
+
+QVariant QQmlValueTypeProvider::createValueType(const QV4::Value &s, QMetaType metaType)
+{
+ if (!isConstructibleMetaType(metaType))
+ return QVariant();
+ const QQmlType type = QQmlMetaType::qmlType(metaType);
+ const auto warn = [&](const QMetaObject *mo) {
+ qWarning().noquote()
+ << "Could not find any constructor for value type"
+ << mo->className() << "to call with value" << s.toQStringNoThrow();
+ };
+
+ if (type.canPopulateValueType()) {
+ if (const QMetaObject *mo = type.metaObject()) {
+ QVariant result = byProperties(mo, metaType, s);
+ if (result.isValid())
+ return result;
+ if (type.canConstructValueType()) {
+ if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
+ warn(mo);
+ }
}
+ } else if (type.canConstructValueType()) {
+ if (const QMetaObject *mo = type.metaObject()) {
+ QVariant result;
+ if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
+ warn(mo);
+ }
+ }
- qWarning("QQml_removeValueTypeProvider: was asked to remove provider %p but it was not found", oldProvider);
+ return fromJSValue(type, QJSValuePrivate::fromReturnedValue(s.asReturnedValue()), metaType);
+
+}
+
+/*!
+ * \internal
+ * This should only be called with either builtin types or wrapped QJSValues as source.
+ */
+QVariant QQmlValueTypeProvider::createValueType(const QVariant &s, QMetaType metaType)
+{
+ if (!isConstructibleMetaType(metaType))
+ return QVariant();
+ const QQmlType type = QQmlMetaType::qmlType(metaType);
+ const auto warn = [&](const QMetaObject *mo) {
+ qWarning().noquote()
+ << "Could not find any constructor for value type"
+ << mo->className() << "to call with value" << s;
+ };
+
+ if (type.canPopulateValueType()) {
+ if (const QMetaObject *mo = type.metaObjectForValueType()) {
+ QVariant result = byProperties(mo, metaType, s);
+ if (result.isValid())
+ return result;
+ if (type.canConstructValueType()) {
+ if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
+ warn(mo);
+ }
+ }
+ } else if (type.canConstructValueType()) {
+ if (const QMetaObject *mo = type.metaObjectForValueType()) {
+ QVariant result;
+ if (fromMatchingType(mo, s, [&]() { return createVariantData(metaType, &result); }))
+ return result;
+ warn(mo);
+ }
}
-}
-Q_AUTOTEST_EXPORT QQmlValueTypeProvider *QQml_valueTypeProvider()
-{
- if (ValueTypeProviderList *providers = valueTypeProviders())
- return providers->head;
- return nullptr;
+ return QVariant();
}
QQmlColorProvider::~QQmlColorProvider() {}
@@ -283,11 +751,15 @@ QVariant QQmlColorProvider::fromHslF(double, double, double, double) { return QV
QVariant QQmlColorProvider::fromHsvF(double, double, double, double) { return QVariant(); }
QVariant QQmlColorProvider::lighter(const QVariant &, qreal) { return QVariant(); }
QVariant QQmlColorProvider::darker(const QVariant &, qreal) { return QVariant(); }
+QVariant QQmlColorProvider::alpha(const QVariant &, qreal)
+{
+ return QVariant();
+}
QVariant QQmlColorProvider::tint(const QVariant &, const QVariant &) { return QVariant(); }
static QQmlColorProvider *colorProvider = nullptr;
-Q_QML_PRIVATE_EXPORT QQmlColorProvider *QQml_setColorProvider(QQmlColorProvider *newProvider)
+Q_QML_EXPORT QQmlColorProvider *QQml_setColorProvider(QQmlColorProvider *newProvider)
{
QQmlColorProvider *old = colorProvider;
colorProvider = newProvider;
@@ -313,9 +785,12 @@ Q_AUTOTEST_EXPORT QQmlColorProvider *QQml_colorProvider(void)
QQmlGuiProvider::~QQmlGuiProvider() {}
-QObject *QQmlGuiProvider::application(QObject *) { return new QQmlApplication(); }
+QQmlApplication *QQmlGuiProvider::application(QObject *parent)
+{
+ return new QQmlApplication(parent);
+}
QStringList QQmlGuiProvider::fontFamilies() { return QStringList(); }
-bool QQmlGuiProvider::openUrlExternally(QUrl &) { return false; }
+bool QQmlGuiProvider::openUrlExternally(const QUrl &) { return false; }
QObject *QQmlGuiProvider::inputMethod()
{
@@ -338,7 +813,7 @@ QString QQmlGuiProvider::pluginName() const { return QString(); }
static QQmlGuiProvider *guiProvider = nullptr;
-Q_QML_PRIVATE_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *newProvider)
+Q_QML_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *newProvider)
{
QQmlGuiProvider *old = guiProvider;
guiProvider = newProvider;
@@ -363,18 +838,8 @@ Q_AUTOTEST_EXPORT QQmlGuiProvider *QQml_guiProvider(void)
//Docs in qqmlengine.cpp
QQmlApplication::QQmlApplication(QObject *parent)
- : QObject(*(new QQmlApplicationPrivate),parent)
+ : QQmlApplication(*(new QQmlApplicationPrivate), parent)
{
- connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()),
- this, SIGNAL(aboutToQuit()));
- connect(QCoreApplication::instance(), SIGNAL(applicationNameChanged()),
- this, SIGNAL(nameChanged()));
- connect(QCoreApplication::instance(), SIGNAL(applicationVersionChanged()),
- this, SIGNAL(versionChanged()));
- connect(QCoreApplication::instance(), SIGNAL(organizationNameChanged()),
- this, SIGNAL(organizationChanged()));
- connect(QCoreApplication::instance(), SIGNAL(organizationDomainChanged()),
- this, SIGNAL(domainChanged()));
}
QQmlApplication::QQmlApplication(QQmlApplicationPrivate &dd, QObject *parent)
@@ -442,6 +907,62 @@ void QQmlApplication::setDomain(const QString &arg)
QCoreApplication::instance()->setOrganizationDomain(arg);
}
+static const QQmlData *ddata_for_cast(QObject *object)
+{
+ Q_ASSERT(object);
+ auto ddata = QQmlData::get(object, false);
+ return (ddata && ddata->propertyCache) ? ddata : nullptr;
+}
+
+bool qmlobject_can_cpp_cast(QObject *object, const QMetaObject *mo)
+{
+ Q_ASSERT(mo);
+ if (const QQmlData *ddata = ddata_for_cast(object))
+ return ddata->propertyCache->firstCppMetaObject()->inherits(mo);
+ return object->metaObject()->inherits(mo);
+}
+
+bool qmlobject_can_qml_cast(QObject *object, const QQmlType &type)
+{
+ Q_ASSERT(type.isValid());
+
+ // A non-composite type will always have a metaobject.
+ const QMetaObject *typeMetaObject = type.metaObject();
+ const QQmlPropertyCache::ConstPtr typePropertyCache = typeMetaObject
+ ? QQmlPropertyCache::ConstPtr()
+ : QQmlMetaType::findPropertyCacheInCompositeTypes(type.typeId());
+
+ if (const QQmlData *ddata = ddata_for_cast(object)) {
+ for (const QQmlPropertyCache *propertyCache = ddata->propertyCache.data(); propertyCache;
+ propertyCache = propertyCache->parent().data()) {
+
+ if (typeMetaObject) {
+ // Prefer the metaobject inheritance mechanism, since it is more accurate.
+ //
+ // Assume the object can be casted to the type. Then, if we have a type metaobject,
+ // the object's property cache inheritance has to contain it. Otherwise we would
+ // end up with diverging metaobject hierarchies if we created the object's
+ // metaobject. This would be a disaster.
+ if (const QMetaObject *objectMetaObject = propertyCache->metaObject())
+ return objectMetaObject->inherits(typeMetaObject);
+ } else {
+ // This is a best effort attempt. There are a number of ways for the
+ // property caches to be unrelated but the types still convertible.
+ // Multiple property caches can hold the same metaobject, for example for
+ // versions of non-composite types.
+ if (propertyCache == typePropertyCache.data())
+ return true;
+ }
+ }
+ }
+
+ // If nothing else works, we have to create the metaobjects.
+
+ return object->metaObject()->inherits(typeMetaObject
+ ? typeMetaObject
+ : (typePropertyCache ? typePropertyCache->createMetaObject() : nullptr));
+}
+
QT_END_NAMESPACE
#include "moc_qqmlglobal_p.cpp"
diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
index 3c540a6124..98fe2e6a79 100644
--- a/src/qml/qml/qqmlglobal_p.h
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLGLOBAL_H
#define QQMLGLOBAL_H
@@ -51,34 +15,41 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
-#include <QtCore/QObject>
-#include <private/qqmlmetaobject_p.h>
#include <private/qmetaobject_p.h>
+#include <private/qqmlmetaobject_p.h>
+#include <private/qqmltype_p.h>
+#include <private/qtqmlglobal_p.h>
+
+#include <QtQml/qqml.h>
+#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
+inline bool qmlConvertBoolConfigOption(const char *v)
+{
+ return v != nullptr && qstrcmp(v, "0") != 0 && qstrcmp(v, "false") != 0;
+}
+
+template<typename T, T(*Convert)(const char *)>
+T qmlGetConfigOption(const char *var)
+{
+ if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(var)))
+ return Convert(qgetenv(var));
+ return Convert(nullptr);
+}
#define DEFINE_BOOL_CONFIG_OPTION(name, var) \
static bool name() \
{ \
- static enum { Yes, No, Unknown } status = Unknown; \
- if (status == Unknown) { \
- status = No; \
- if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(#var))) { \
- const QByteArray v = qgetenv(#var); \
- if (v != "0" && v != "false") \
- status = Yes; \
- } \
- } \
- return status == Yes; \
+ static const bool result = qmlGetConfigOption<bool, qmlConvertBoolConfigOption>(#var); \
+ return result; \
}
/*!
Connect \a Signal of \a Sender to \a Method of \a Receiver. \a Signal must be
of type \a SenderType and \a Receiver of type \a ReceiverType.
- Unlike QObject::connect(), this method caches the lookup of the signal and method
+ Unlike QObject::connect(), this macro caches the lookup of the signal and method
indexes. It also does not require lazy QMetaObjects to be built so should be
preferred in all QML code that might interact with QML built objects.
@@ -117,7 +88,7 @@ do { \
Disconnect \a Signal of \a Sender from \a Method of \a Receiver. \a Signal must be
of type \a SenderType and \a Receiver of type \a ReceiverType.
- Unlike QObject::disconnect(), this method caches the lookup of the signal and method
+ Unlike QObject::disconnect(), this macro caches the lookup of the signal and method
indexes. It also does not require lazy QMetaObjects to be built so should be
preferred in all QML code that might interact with QML built objects.
@@ -152,6 +123,9 @@ do { \
QMetaObject::disconnect(sender, signalIdx, receiver, methodIdx); \
} while (0)
+Q_QML_EXPORT bool qmlobject_can_cpp_cast(QObject *object, const QMetaObject *mo);
+Q_QML_EXPORT bool qmlobject_can_qml_cast(QObject *object, const QQmlType &type);
+
/*!
This method is identical to qobject_cast<T>() except that it does not require lazy
QMetaObjects to be built, so should be preferred in all QML code that might interact
@@ -167,10 +141,23 @@ do { \
template<class T>
T qmlobject_cast(QObject *object)
{
- if (object && QQmlMetaObject::canConvert(object, &reinterpret_cast<T>(object)->staticMetaObject))
+ if (!object)
+ return nullptr;
+ if (qmlobject_can_cpp_cast(object, &(std::remove_pointer_t<T>::staticMetaObject)))
return static_cast<T>(object);
else
- return 0;
+ return nullptr;
+}
+
+class QQuickItem;
+template<>
+inline QQuickItem *qmlobject_cast<QQuickItem *>(QObject *object)
+{
+ if (!object || !object->isQuickItemType())
+ return nullptr;
+ // QQuickItem is incomplete here -> can't use static_cast
+ // but we don't need any pointer adjustment, so reinterpret is safe
+ return reinterpret_cast<QQuickItem *>(object);
}
#define IS_SIGNAL_CONNECTED(Sender, SenderType, Name, Arguments) \
@@ -216,57 +203,27 @@ inline void QQml_setParent_noEvent(QObject *object, QObject *parent)
d_ptr->sendChildEvents = sce;
}
-class Q_QML_PRIVATE_EXPORT QQmlValueTypeProvider
+class QQmlValueTypeProvider
{
public:
- QQmlValueTypeProvider();
- virtual ~QQmlValueTypeProvider();
-
- const QMetaObject *metaObjectForMetaType(int);
-
- bool initValueType(int, QVariant&);
-
- QVariant createValueType(int, int, const void *[]);
- bool createValueFromString(int, const QString &, void *, size_t);
- bool createStringFromValue(int, const void *, QString *);
-
- QVariant createVariantFromString(const QString &);
- QVariant createVariantFromString(int, const QString &, bool *);
- QVariant createVariantFromJsObject(int, const QV4::Value &, QV4::ExecutionEngine *, bool *);
-
- bool equalValueType(int, const void *, const QVariant&);
- bool storeValueType(int, const void *, void *, size_t);
- bool readValueType(const QVariant&, void *, int);
- bool writeValueType(int, const void *, QVariant&);
-
-private:
- virtual const QMetaObject *getMetaObjectForMetaType(int);
- virtual bool init(int, QVariant&);
-
- virtual bool create(int, int, const void *[], QVariant *);
- virtual bool createFromString(int, const QString &, void *, size_t);
- virtual bool createStringFrom(int, const void *, QString *);
-
- virtual bool variantFromString(const QString &, QVariant *);
- virtual bool variantFromString(int, const QString &, QVariant *);
- virtual bool variantFromJsObject(int, const QV4::Value &, QV4::ExecutionEngine *, QVariant *);
-
- virtual bool equal(int, const void *, const QVariant&);
- virtual bool store(int, const void *, void *, size_t);
- virtual bool read(const QVariant&, void *, int);
- virtual bool write(int, const void *, QVariant&);
-
- friend Q_QML_PRIVATE_EXPORT void QQml_addValueTypeProvider(QQmlValueTypeProvider *);
- friend Q_QML_PRIVATE_EXPORT void QQml_removeValueTypeProvider(QQmlValueTypeProvider *);
-
- QQmlValueTypeProvider *next;
+ static bool populateValueType(
+ QMetaType targetMetaType, void *target, const QV4::Value &source);
+ static bool populateValueType(
+ QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source);
+
+ static Q_QML_EXPORT void *heapCreateValueType(
+ const QQmlType &targetType, const QV4::Value &source);
+ static QVariant constructValueType(
+ QMetaType targetMetaType, const QMetaObject *targetMetaObject,
+ int ctorIndex, void *ctorArg);
+
+ static QVariant createValueType(const QJSValue &, QMetaType);
+ static QVariant createValueType(const QString &, QMetaType);
+ static QVariant createValueType(const QV4::Value &, QMetaType);
+ static QVariant createValueType(const QVariant &, QMetaType);
};
-Q_QML_PRIVATE_EXPORT void QQml_addValueTypeProvider(QQmlValueTypeProvider *);
-Q_AUTOTEST_EXPORT QQmlValueTypeProvider *QQml_valueTypeProvider();
-
-
-class Q_QML_PRIVATE_EXPORT QQmlColorProvider
+class Q_QML_EXPORT QQmlColorProvider
{
public:
virtual ~QQmlColorProvider();
@@ -278,31 +235,32 @@ public:
virtual QVariant fromHsvF(double, double, double, double);
virtual QVariant lighter(const QVariant &, qreal);
virtual QVariant darker(const QVariant &, qreal);
+ virtual QVariant alpha(const QVariant &, qreal);
virtual QVariant tint(const QVariant &, const QVariant &);
};
-Q_QML_PRIVATE_EXPORT QQmlColorProvider *QQml_setColorProvider(QQmlColorProvider *);
-Q_QML_PRIVATE_EXPORT QQmlColorProvider *QQml_colorProvider();
-
+Q_QML_EXPORT QQmlColorProvider *QQml_setColorProvider(QQmlColorProvider *);
+Q_QML_EXPORT QQmlColorProvider *QQml_colorProvider();
-class Q_QML_PRIVATE_EXPORT QQmlGuiProvider
+class QQmlApplication;
+class Q_QML_EXPORT QQmlGuiProvider
{
public:
virtual ~QQmlGuiProvider();
- virtual QObject *application(QObject *parent);
+ virtual QQmlApplication *application(QObject *parent);
virtual QObject *inputMethod();
virtual QObject *styleHints();
virtual QStringList fontFamilies();
- virtual bool openUrlExternally(QUrl &);
+ virtual bool openUrlExternally(const QUrl &);
virtual QString pluginName() const;
};
-Q_QML_PRIVATE_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *);
+Q_QML_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *);
Q_AUTOTEST_EXPORT QQmlGuiProvider *QQml_guiProvider();
class QQmlApplicationPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlApplication : public QObject
+class Q_QML_EXPORT QQmlApplication : public QObject
{
//Application level logic, subclassed by Qt Quick if available via QQmlGuiProvider
Q_OBJECT
@@ -311,6 +269,8 @@ class Q_QML_PRIVATE_EXPORT QQmlApplication : public QObject
Q_PROPERTY(QString version READ version WRITE setVersion NOTIFY versionChanged)
Q_PROPERTY(QString organization READ organization WRITE setOrganization NOTIFY organizationChanged)
Q_PROPERTY(QString domain READ domain WRITE setDomain NOTIFY domainChanged)
+ QML_ANONYMOUS
+ QML_ADDED_IN_VERSION(2, 0)
public:
QQmlApplication(QObject* parent=nullptr);
diff --git a/src/qml/qml/qqmlguard_p.h b/src/qml/qml/qqmlguard_p.h
index 3ac63926a0..685293868e 100644
--- a/src/qml/qml/qqmlguard_p.h
+++ b/src/qml/qml/qqmlguard_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLGUARD_P_H
#define QQMLGUARD_P_H
@@ -51,87 +15,106 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
-#include <QtCore/qvariant.h>
#include <private/qqmldata_p.h>
+#include <private/qqmlglobal_p.h>
QT_BEGIN_NAMESPACE
class QQmlGuardImpl
{
public:
+ using ObjectDestroyedFn = void(*)(QQmlGuardImpl *);
+
inline QQmlGuardImpl();
inline QQmlGuardImpl(QObject *);
inline QQmlGuardImpl(const QQmlGuardImpl &);
+protected:
inline ~QQmlGuardImpl();
+public: // ### make so it can be private
QObject *o = nullptr;
QQmlGuardImpl *next = nullptr;
QQmlGuardImpl **prev = nullptr;
+ ObjectDestroyedFn objectDestroyed = nullptr;
inline void addGuard();
inline void remGuard();
+
+ inline void setObject(QObject *g);
+ bool isNull() const noexcept { return !o; }
};
class QObject;
template<class T>
-class QQmlGuard : private QQmlGuardImpl
+class QQmlGuard : protected QQmlGuardImpl
{
friend class QQmlData;
public:
- inline QQmlGuard();
- inline QQmlGuard(T *);
- inline QQmlGuard(const QQmlGuard<T> &);
- inline virtual ~QQmlGuard();
+ Q_NODISCARD_CTOR inline QQmlGuard();
+ Q_NODISCARD_CTOR inline QQmlGuard(ObjectDestroyedFn objectDestroyed, T *);
+ Q_NODISCARD_CTOR inline QQmlGuard(T *);
+ Q_NODISCARD_CTOR inline QQmlGuard(const QQmlGuard<T> &);
inline QQmlGuard<T> &operator=(const QQmlGuard<T> &o);
inline QQmlGuard<T> &operator=(T *);
- inline T *object() const;
- inline void setObject(T *g);
+ T *object() const noexcept { return static_cast<T *>(o); }
+ void setObject(T *g) { QQmlGuardImpl::setObject(g); }
- inline bool isNull() const
- { return !o; }
+ using QQmlGuardImpl::isNull;
- inline T* operator->() const
- { return static_cast<T*>(const_cast<QObject*>(o)); }
- inline T& operator*() const
- { return *static_cast<T*>(const_cast<QObject*>(o)); }
- inline operator T*() const
- { return static_cast<T*>(const_cast<QObject*>(o)); }
- inline T* data() const
- { return static_cast<T*>(const_cast<QObject*>(o)); }
-
-protected:
- virtual void objectDestroyed(T *) {}
+ T *operator->() const noexcept { return object(); }
+ T &operator*() const { return *object(); }
+ operator T *() const noexcept { return object(); }
+ T *data() const noexcept { return object(); }
};
+/* used in QQmlStrongJSQObjectReference to indicate that the
+ * object has JS ownership
+ * We save it in objectDestroyFn to save space
+ * (implemented in qqmlengine.cpp)
+ */
+void Q_QML_EXPORT hasJsOwnershipIndicator(QQmlGuardImpl *);
+
template <typename T>
-class QQmlStrongJSQObjectReference : public QQmlGuard<T>
+class QQmlStrongJSQObjectReference final : protected QQmlGuardImpl
{
public:
- void setObject(T *o, QObject *parent) {
- T *old = this->object();
- if (o == old)
+ T *object() const noexcept { return static_cast<T *>(o); }
+
+ using QQmlGuardImpl::isNull;
+
+ T *operator->() const noexcept { return object(); }
+ T &operator*() const { return *object(); }
+ operator T *() const noexcept { return object(); }
+ T *data() const noexcept { return object(); }
+
+ void setObject(T *obj, QObject *parent) {
+ T *old = object();
+ if (obj == old)
return;
- if (m_jsOwnership && old && old->parent() == parent)
+ if (hasJsOwnership() && old && old->parent() == parent)
QQml_setParent_noEvent(old, nullptr);
- this->QQmlGuard<T>::operator=(o);
+ QQmlGuardImpl::setObject(obj);
- if (o && !o->parent() && !QQmlData::keepAliveDuringGarbageCollection(o)) {
- m_jsOwnership = true;
- QQml_setParent_noEvent(o, parent);
+ if (obj && !obj->parent() && !QQmlData::keepAliveDuringGarbageCollection(obj)) {
+ setJsOwnership(true);
+ QQml_setParent_noEvent(obj, parent);
} else {
- m_jsOwnership = false;
+ setJsOwnership(false);
}
}
private:
- using QQmlGuard<T>::setObject;
- using QQmlGuard<T>::operator=;
- bool m_jsOwnership = false;
+ bool hasJsOwnership() {
+ return objectDestroyed == hasJsOwnershipIndicator;
+ }
+
+ void setJsOwnership(bool itHasOwnership) {
+ objectDestroyed = itHasOwnership ? hasJsOwnershipIndicator : nullptr;
+ }
};
QT_END_NAMESPACE
@@ -150,8 +133,15 @@ QQmlGuardImpl::QQmlGuardImpl(QObject *g)
if (o) addGuard();
}
+/*
+ \internal
+ Copying a QQmlGuardImpl leaves the old one in the intrinsic linked list of guards.
+ The fresh copy does not contain the list pointer of the existing guard; instead
+ only the object and objectDestroyed pointers are copied, and if there is an object
+ we add the new guard to the object's list of guards.
+ */
QQmlGuardImpl::QQmlGuardImpl(const QQmlGuardImpl &g)
-: o(g.o)
+: o(g.o), objectDestroyed(g.objectDestroyed)
{
if (o) addGuard();
}
@@ -192,25 +182,28 @@ QQmlGuard<T>::QQmlGuard()
}
template<class T>
-QQmlGuard<T>::QQmlGuard(T *g)
-: QQmlGuardImpl(g)
+QQmlGuard<T>::QQmlGuard(ObjectDestroyedFn objDestroyed, T *obj)
+ : QQmlGuardImpl(obj)
{
+ objectDestroyed = objDestroyed;
}
template<class T>
-QQmlGuard<T>::QQmlGuard(const QQmlGuard<T> &g)
+QQmlGuard<T>::QQmlGuard(T *g)
: QQmlGuardImpl(g)
{
}
template<class T>
-QQmlGuard<T>::~QQmlGuard()
+QQmlGuard<T>::QQmlGuard(const QQmlGuard<T> &g)
+: QQmlGuardImpl(g)
{
}
template<class T>
QQmlGuard<T> &QQmlGuard<T>::operator=(const QQmlGuard<T> &g)
{
+ objectDestroyed = g.objectDestroyed;
setObject(g.object());
return *this;
}
@@ -218,18 +211,15 @@ QQmlGuard<T> &QQmlGuard<T>::operator=(const QQmlGuard<T> &g)
template<class T>
QQmlGuard<T> &QQmlGuard<T>::operator=(T *g)
{
+ /* this does not touch objectDestroyed, as operator= is only a convenience
+ * for setObject. All logic involving objectDestroyed is (sub-)class specific
+ * and remains unaffected.
+ */
setObject(g);
return *this;
}
-template<class T>
-T *QQmlGuard<T>::object() const
-{
- return static_cast<T *>(o);
-}
-
-template<class T>
-void QQmlGuard<T>::setObject(T *g)
+void QQmlGuardImpl::setObject(QObject *g)
{
if (g != o) {
if (prev) remGuard();
diff --git a/src/qml/qml/qqmlguardedcontextdata_p.h b/src/qml/qml/qqmlguardedcontextdata_p.h
new file mode 100644
index 0000000000..048f809f48
--- /dev/null
+++ b/src/qml/qml/qqmlguardedcontextdata_p.h
@@ -0,0 +1,95 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLGUARDEDCONTEXTDATA_P_H
+#define QQMLGUARDEDCONTEXTDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/private/qtqmlglobal_p.h>
+#include <QtQml/private/qqmlcontextdata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlGuardedContextData
+{
+ Q_DISABLE_COPY(QQmlGuardedContextData);
+public:
+ QQmlGuardedContextData() = default;
+ ~QQmlGuardedContextData() { unlink(); }
+
+ QQmlGuardedContextData(QQmlGuardedContextData &&) = default;
+ QQmlGuardedContextData &operator=(QQmlGuardedContextData &&) = default;
+
+ QQmlGuardedContextData(QQmlRefPointer<QQmlContextData> data)
+ {
+ setContextData(std::move(data));
+ }
+
+ QQmlGuardedContextData &operator=(QQmlRefPointer<QQmlContextData> d)
+ {
+ setContextData(std::move(d));
+ return *this;
+ }
+
+ QQmlRefPointer<QQmlContextData> contextData() const { return m_contextData; }
+ void setContextData(QQmlRefPointer<QQmlContextData> contextData)
+ {
+ if (m_contextData.data() == contextData.data())
+ return;
+ unlink();
+
+ if (contextData) {
+ m_contextData = std::move(contextData);
+ m_next = m_contextData->m_contextGuards;
+ if (m_next)
+ m_next->m_prev = &m_next;
+
+ m_contextData->m_contextGuards = this;
+ m_prev = &m_contextData->m_contextGuards;
+ }
+ }
+
+ bool isNull() const { return !m_contextData; }
+
+ operator const QQmlRefPointer<QQmlContextData> &() const { return m_contextData; }
+ QQmlContextData &operator*() const { return m_contextData.operator*(); }
+ QQmlContextData *operator->() const { return m_contextData.operator->(); }
+
+ QQmlGuardedContextData *next() const { return m_next; }
+
+private:
+ void reset()
+ {
+ m_contextData.reset();
+ m_next = nullptr;
+ m_prev = nullptr;
+ }
+
+ void unlink()
+ {
+ if (m_prev) {
+ *m_prev = m_next;
+ if (m_next)
+ m_next->m_prev = m_prev;
+ reset();
+ }
+ }
+
+ QQmlRefPointer<QQmlContextData> m_contextData;
+ QQmlGuardedContextData *m_next = nullptr;
+ QQmlGuardedContextData **m_prev = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLGUARDEDCONTEXTDATA_P_H
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index af6d067fbb..86380294ba 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Crimson AS <info@crimson.no>
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 Crimson AS <info@crimson.no>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlimport_p.h"
@@ -46,25 +10,62 @@
#include <QtCore/qfileinfo.h>
#include <QtCore/qpluginloader.h>
#include <QtCore/qlibraryinfo.h>
-#include <QtCore/qreadwritelock.h>
+#include <QtCore/qloggingcategory.h>
#include <QtQml/qqmlextensioninterface.h>
#include <QtQml/qqmlextensionplugin.h>
#include <private/qqmlextensionplugin_p.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmltypenamecache_p.h>
#include <private/qqmlengine_p.h>
-#include <private/qfieldlist_p.h>
#include <private/qqmltypemodule_p.h>
#include <private/qqmltypeloaderqmldircontent_p.h>
+#include <private/qqmlpluginimporter_p.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonarray.h>
+#include <QtQml/private/qqmltype_p_p.h>
+#include <QtQml/private/qqmlimportresolver_p.h>
+
+#ifdef Q_OS_MACOS
+#include "private/qcore_mac_p.h"
+#endif
#include <algorithm>
#include <functional>
+using namespace Qt::Literals::StringLiterals;
+
QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE)
+
+class QmlImportCategoryHolder
+{
+ Q_DISABLE_COPY_MOVE(QmlImportCategoryHolder);
+public:
+
+ QmlImportCategoryHolder() : m_category("qt.qml.import")
+ {
+ // We have to explicitly setEnabled() here because for categories that start with
+ // "qt." it won't accept QtDebugMsg as argument. Debug messages are off by default
+ // for all Qt logging categories.
+ if (qmlImportTrace())
+ m_category.setEnabled(QtDebugMsg, true);
+ }
+
+ ~QmlImportCategoryHolder() = default;
+
+ const QLoggingCategory &category() const { return m_category; }
+
+private:
+ QLoggingCategory m_category;
+};
+
+const QLoggingCategory &lcQmlImport()
+{
+ static const QmlImportCategoryHolder holder;
+ return holder.category();
+}
+
DEFINE_BOOL_CONFIG_OPTION(qmlCheckTypes, QML_CHECK_TYPES)
static const QLatin1Char Dot('.');
@@ -79,6 +80,28 @@ static bool designerSupportRequired = false;
namespace {
+QTypeRevision relevantVersion(const QString &uri, QTypeRevision version)
+{
+ return QQmlMetaType::latestModuleVersion(uri).isValid() ? version : QTypeRevision();
+}
+
+QQmlError moduleNotFoundError(const QString &uri, QTypeRevision version)
+{
+ QQmlError error;
+ if (version.hasMajorVersion()) {
+ error.setDescription(QQmlImportDatabase::tr(
+ "module \"%1\" version %2.%3 is not installed")
+ .arg(uri).arg(version.majorVersion())
+ .arg(version.hasMinorVersion()
+ ? QString::number(version.minorVersion())
+ : QLatin1String("x")));
+ } else {
+ error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed")
+ .arg(uri));
+ }
+ return error;
+}
+
QString resolveLocalUrl(const QString &url, const QString &relative)
{
if (relative.contains(Colon)) {
@@ -89,14 +112,14 @@ QString resolveLocalUrl(const QString &url, const QString &relative)
} else if (relative.at(0) == Slash || !url.contains(Slash)) {
return relative;
} else {
- const QStringRef baseRef = url.leftRef(url.lastIndexOf(Slash) + 1);
+ const QStringView baseRef = QStringView{url}.left(url.lastIndexOf(Slash) + 1);
if (relative == QLatin1String("."))
return baseRef.toString();
QString base = baseRef + relative;
// Remove any relative directory elements in the path
- int length = base.length();
+ int length = base.size();
int index = 0;
while ((index = base.indexOf(QLatin1String("/."), index)) != -1) {
if ((length > (index + 2)) && (base.at(index + 2) == Dot) &&
@@ -135,41 +158,6 @@ bool isPathAbsolute(const QString &path)
} // namespace
-struct RegisteredPlugin {
- QString uri;
- QPluginLoader* loader;
-};
-
-struct StringRegisteredPluginMap : public QMap<QString, RegisteredPlugin> {
- QMutex mutex;
-
- ~StringRegisteredPluginMap()
- {
- QMutexLocker lock(&mutex);
- for (const RegisteredPlugin &plugin : qAsConst(*this))
- delete plugin.loader;
- }
-};
-
-Q_GLOBAL_STATIC(StringRegisteredPluginMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri and the PluginLoaders
-
-void qmlClearEnginePlugins()
-{
- StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
- QMutexLocker lock(&plugins->mutex);
-#if QT_CONFIG(library)
- for (auto &plugin : qAsConst(*plugins)) {
- QPluginLoader* loader = plugin.loader;
- if (loader && !loader->unload())
- qWarning("Unloading %s failed: %s", qPrintable(plugin.uri), qPrintable(loader->errorString()));
- delete loader;
- }
-#endif
- plugins->clear();
-}
-
-typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair;
-
/*!
\internal
\class QQmlImportInstance
@@ -203,106 +191,16 @@ typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair;
import MyFoo 1.0 as Foo
*/
-class QQmlImportsPrivate
-{
-public:
- QQmlImportsPrivate(QQmlTypeLoader *loader);
- ~QQmlImportsPrivate();
-
- QQmlImportNamespace *importNamespace(const QString &prefix) const;
-
- bool addLibraryImport(const QString& uri, const QString &prefix,
- int vmaj, int vmin, const QString &qmldirIdentifier, const QString &qmldirUrl, bool incomplete,
- QQmlImportDatabase *database,
- QList<QQmlError> *errors);
-
- bool addFileImport(const QString &uri, const QString &prefix,
- int vmaj, int vmin,
- bool isImplicitImport, bool incomplete, QQmlImportDatabase *database,
- QList<QQmlError> *errors);
-
- bool updateQmldirContent(const QString &uri, const QString &prefix,
- const QString &qmldirIdentifier, const QString& qmldirUrl,
- QQmlImportDatabase *database,
- QList<QQmlError> *errors);
-
- bool resolveType(const QHashedStringRef &type, int *vmajor, int *vminor,
- QQmlType *type_return, QList<QQmlError> *errors,
- QQmlType::RegistrationType registrationType,
- QQmlImport::RecursionRestriction recursionRestriction
- = QQmlImport::PreventRecursion);
-
- QUrl baseUrl;
- QString base;
- int ref;
-
- // storage of data related to imports without a namespace
- mutable QQmlImportNamespace unqualifiedset;
-
- QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &) const;
-
- // storage of data related to imports with a namespace
- mutable QFieldList<QQmlImportNamespace, &QQmlImportNamespace::nextNamespace> qualifiedSets;
-
- QQmlTypeLoader *typeLoader;
-
- static bool locateQmldir(const QString &uri, int vmaj, int vmin,
- QQmlImportDatabase *database,
- QString *outQmldirFilePath, QString *outUrl);
-
- static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin,
- QList<QQmlError> *errors);
-
- bool importExtension(const QString &absoluteFilePath, const QString &uri,
- int vmaj, int vmin,
- QQmlImportDatabase *database,
- const QQmlTypeLoaderQmldirContent &qmldir,
- QList<QQmlError> *errors);
-
- bool getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors);
-
- QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
-
- QQmlImportInstance *addImportToNamespace(QQmlImportNamespace *nameSpace,
- const QString &uri, const QString &url,
- int vmaj, int vmin, QV4::CompiledData::Import::ImportType type,
- QList<QQmlError> *errors, bool lowPrecedence = false);
-
- bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris,
- const QString &qmldirPath, QList<QQmlError> *errors);
-};
-
/*!
\class QQmlImports
\brief The QQmlImports class encapsulates one QML document's import statements.
\internal
*/
-QQmlImports::QQmlImports(const QQmlImports &copy)
-: d(copy.d)
-{
- ++d->ref;
-}
-
-QQmlImports &
-QQmlImports::operator =(const QQmlImports &copy)
-{
- ++copy.d->ref;
- if (--d->ref == 0)
- delete d;
- d = copy.d;
- return *this;
-}
-
-QQmlImports::QQmlImports(QQmlTypeLoader *typeLoader)
- : d(new QQmlImportsPrivate(typeLoader))
-{
-}
-QQmlImports::~QQmlImports()
+QTypeRevision QQmlImports::validVersion(QTypeRevision version)
{
- if (--d->ref == 0)
- delete d;
+ // If the given version is invalid, return a valid but useless version to signal "It's OK".
+ return version.isValid() ? version : QTypeRevision::fromMinorVersion(0);
}
/*!
@@ -310,23 +208,20 @@ QQmlImports::~QQmlImports()
*/
void QQmlImports::setBaseUrl(const QUrl& url, const QString &urlString)
{
- d->baseUrl = url;
+ m_baseUrl = url;
- if (urlString.isEmpty()) {
- d->base = url.toString();
- } else {
- //Q_ASSERT(url.toString() == urlString);
- d->base = urlString;
- }
+ if (urlString.isEmpty())
+ m_base = url.toString();
+ else
+ m_base = urlString;
}
/*!
+ \fn QQmlImports::baseUrl()
+ \internal
+
Returns the base URL to be used for all relative file imports added.
*/
-QUrl QQmlImports::baseUrl() const
-{
- return d->baseUrl;
-}
/*
\internal
@@ -340,17 +235,17 @@ QUrl QQmlImports::baseUrl() const
*/
void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
{
- const QQmlImportNamespace &set = d->unqualifiedset;
+ const QQmlImportNamespace &set = m_unqualifiedset;
- for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ for (int ii = set.imports.size() - 1; ii >= 0; --ii) {
const QQmlImportInstance *import = set.imports.at(ii);
- QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion);
+ QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->version);
if (module) {
- cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, import->minversion));
+ cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, import->version));
}
}
- for (QQmlImportNamespace *ns = d->qualifiedSets.first(); ns; ns = d->qualifiedSets.next(ns)) {
+ for (QQmlImportNamespace *ns = m_qualifiedSets.first(); ns; ns = m_qualifiedSets.next(ns)) {
const QQmlImportNamespace &set = *ns;
@@ -358,12 +253,12 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
QQmlImportRef &typeimport = cache->m_namedImports[set.prefix];
typeimport.m_qualifier = set.prefix;
- for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ for (int ii = set.imports.size() - 1; ii >= 0; --ii) {
const QQmlImportInstance *import = set.imports.at(ii);
- QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion);
+ QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->version);
if (module) {
QQmlImportRef &typeimport = cache->m_namedImports[set.prefix];
- typeimport.modules.append(QQmlTypeModuleVersion(module, import->minversion));
+ typeimport.modules.append(QQmlTypeModuleVersion(module, import->version));
}
}
}
@@ -379,7 +274,7 @@ bool excludeBaseUrl(const QString &importUrl, const QString &fileName, const QSt
if (baseUrl.startsWith(importUrl))
{
- if (fileName == baseUrl.midRef(importUrl.size()))
+ if (fileName == QStringView{baseUrl}.mid(importUrl.size()))
return false;
}
@@ -390,41 +285,40 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::
{
typedef QQmlDirComponents::const_iterator ConstIterator;
- for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ for (int ii = set.imports.size() - 1; ii >= 0; --ii) {
const QQmlImportInstance *import = set.imports.at(ii);
const QQmlDirComponents &components = import->qmlDirComponents;
- const int importMajorVersion = import->majversion;
- const int importMinorVersion = import->minversion;
- auto shouldSkipSingleton = [importMajorVersion, importMinorVersion](int singletonMajorVersion, int singletonMinorVersion) -> bool {
- return importMajorVersion != -1 &&
- (singletonMajorVersion > importMajorVersion || (singletonMajorVersion == importMajorVersion && singletonMinorVersion > importMinorVersion));
+ const QTypeRevision importVersion = import->version;
+ auto shouldSkipSingleton = [importVersion](QTypeRevision singletonVersion) -> bool {
+ return importVersion.hasMajorVersion() &&
+ (singletonVersion.majorVersion() > importVersion.majorVersion()
+ || (singletonVersion.majorVersion() == importVersion.majorVersion()
+ && singletonVersion.minorVersion() > importVersion.minorVersion()));
};
ConstIterator cend = components.constEnd();
for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) {
if (cit->singleton && excludeBaseUrl(import->url, cit->fileName, baseUrl.toString())) {
- if (shouldSkipSingleton(cit->majorVersion, cit->minorVersion))
+ if (shouldSkipSingleton(cit->version))
continue;
QQmlImports::CompositeSingletonReference ref;
ref.typeName = cit->typeName;
ref.prefix = set.prefix;
- ref.majorVersion = cit->majorVersion;
- ref.minorVersion = cit->minorVersion;
+ ref.version = cit->version;
resultList.append(ref);
}
}
- if (QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion)) {
+ if (QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->version)) {
module->walkCompositeSingletons([&resultList, &set, &shouldSkipSingleton](const QQmlType &singleton) {
- if (shouldSkipSingleton(singleton.majorVersion(), singleton.minorVersion()))
+ if (shouldSkipSingleton(singleton.version()))
return;
QQmlImports::CompositeSingletonReference ref;
ref.typeName = singleton.elementName();
ref.prefix = set.prefix;
- ref.majorVersion = singleton.majorVersion();
- ref.minorVersion = singleton.minorVersion();
+ ref.version = singleton.version();
resultList.append(ref);
});
}
@@ -444,10 +338,10 @@ QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSi
{
QList<QQmlImports::CompositeSingletonReference> compositeSingletons;
- const QQmlImportNamespace &set = d->unqualifiedset;
+ const QQmlImportNamespace &set = m_unqualifiedset;
findCompositeSingletons(set, compositeSingletons, baseUrl());
- for (QQmlImportNamespace *ns = d->qualifiedSets.first(); ns; ns = d->qualifiedSets.next(ns)) {
+ for (QQmlImportNamespace *ns = m_qualifiedSets.first(); ns; ns = m_qualifiedSets.next(ns)) {
const QQmlImportNamespace &set = *ns;
findCompositeSingletons(set, compositeSingletons, baseUrl());
}
@@ -461,9 +355,9 @@ QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSi
if (lhs.typeName != rhs.typeName)
return lhs.typeName < rhs.typeName;
- return lhs.majorVersion != rhs.majorVersion
- ? lhs.majorVersion < rhs.majorVersion
- : lhs.minorVersion < rhs.minorVersion;
+ return lhs.version.majorVersion() != rhs.version.majorVersion()
+ ? lhs.version.majorVersion() < rhs.version.majorVersion()
+ : lhs.version.minorVersion() < rhs.version.minorVersion();
});
return compositeSingletons;
@@ -479,9 +373,9 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
{
QList<QQmlImports::ScriptReference> scripts;
- const QQmlImportNamespace &set = d->unqualifiedset;
+ const QQmlImportNamespace &set = m_unqualifiedset;
- for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ for (int ii = set.imports.size() - 1; ii >= 0; --ii) {
const QQmlImportInstance *import = set.imports.at(ii);
for (const QQmlDirParser::Script &script : import->qmlDirScripts) {
@@ -492,10 +386,10 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
}
}
- for (QQmlImportNamespace *ns = d->qualifiedSets.first(); ns; ns = d->qualifiedSets.next(ns)) {
+ for (QQmlImportNamespace *ns = m_qualifiedSets.first(); ns; ns = m_qualifiedSets.next(ns)) {
const QQmlImportNamespace &set = *ns;
- for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+ for (int ii = set.imports.size() - 1; ii >= 0; --ii) {
const QQmlImportInstance *import = set.imports.at(ii);
for (const QQmlDirParser::Script &script : import->qmlDirScripts) {
@@ -511,17 +405,6 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
return scripts;
}
-static QString joinStringRefs(const QVector<QStringRef> &refs, const QChar &sep)
-{
- QString str;
- for (auto it = refs.cbegin(); it != refs.cend(); ++it) {
- if (it != refs.cbegin())
- str += sep;
- str += *it;
- }
- return str;
-}
-
/*!
Forms complete paths to a qmldir file, from a base URL, a module URI and version specification.
@@ -532,47 +415,23 @@ static QString joinStringRefs(const QVector<QStringRef> &refs, const QChar &sep)
- base/QtQml.2/Models/qmldir
- base/QtQml/Models/qmldir
*/
-QStringList QQmlImports::completeQmldirPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin)
+QStringList QQmlImports::completeQmldirPaths(const QString &uri, const QStringList &basePaths,
+ QTypeRevision version)
{
- const QVector<QStringRef> parts = uri.splitRef(Dot, QString::SkipEmptyParts);
-
- QStringList qmlDirPathsPaths;
- // fully & partially versioned parts + 1 unversioned for each base path
- qmlDirPathsPaths.reserve(basePaths.count() * (2 * parts.count() + 1));
-
- for (int version = FullyVersioned; version <= Unversioned; ++version) {
- const QString ver = versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version));
-
- for (const QString &path : basePaths) {
- QString dir = path;
- if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
- dir += Slash;
-
- // append to the end
- qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver + Slash_qmldir;
-
- if (version != Unversioned) {
- // insert in the middle
- for (int index = parts.count() - 2; index >= 0; --index) {
- qmlDirPathsPaths += dir + joinStringRefs(parts.mid(0, index + 1), Slash)
- + ver + Slash
- + joinStringRefs(parts.mid(index + 1), Slash) + Slash_qmldir;
- }
- }
- }
- }
-
- return qmlDirPathsPaths;
+ QStringList paths = qQmlResolveImportPaths(uri, basePaths, version);
+ for (QString &path : paths)
+ path += Slash_qmldir;
+ return paths;
}
-QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version)
+QString QQmlImports::versionString(QTypeRevision version, ImportVersion versionMode)
{
- if (version == QQmlImports::FullyVersioned) {
+ if (versionMode == QQmlImports::FullyVersioned) {
// extension with fully encoded version number (eg. MyModule.3.2)
- return QString::asprintf(".%d.%d", vmaj, vmin);
- } else if (version == QQmlImports::PartiallyVersioned) {
+ return QString::asprintf(".%d.%d", version.majorVersion(), version.minorVersion());
+ } else if (versionMode == QQmlImports::PartiallyVersioned) {
// extension with encoded version major (eg. MyModule.3)
- return QString::asprintf(".%d", vmaj);
+ return QString::asprintf(".%d", version.majorVersion());
} // else extension without version number (eg. MyModule)
return QString();
}
@@ -590,30 +449,31 @@ QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version)
\sa addFileImport(), addLibraryImport
*/
-bool QQmlImports::resolveType(const QHashedStringRef &type,
- QQmlType *type_return, int *vmaj, int *vmin,
- QQmlImportNamespace** ns_return, QList<QQmlError> *errors,
- QQmlType::RegistrationType registrationType,
- QQmlImport::RecursionRestriction recursionRestriction) const
+bool QQmlImports::resolveType(
+ QQmlTypeLoader *typeLoader, const QHashedStringRef &type, QQmlType *type_return,
+ QTypeRevision *version_return, QQmlImportNamespace **ns_return, QList<QQmlError> *errors,
+ QQmlType::RegistrationType registrationType, bool *typeRecursionDetected) const
{
- QQmlImportNamespace* ns = d->findQualifiedNamespace(type);
+ QQmlImportNamespace *ns = findQualifiedNamespace(type);
if (ns) {
if (ns_return)
*ns_return = ns;
return true;
}
if (type_return) {
- if (d->resolveType(type, vmaj, vmin, type_return, errors, registrationType,
- recursionRestriction)) {
- if (qmlImportTrace()) {
-#define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \
- << ')' << "::resolveType: " << type.toString() << " => "
+ if (resolveType(typeLoader, type, version_return, type_return, errors, registrationType,
+ typeRecursionDetected)) {
+ if (lcQmlImport().isDebugEnabled()) {
+#define RESOLVE_TYPE_DEBUG qCDebug(lcQmlImport) \
+ << "resolveType:" << qPrintable(baseUrl().toString()) << type.toString() << " => "
if (type_return && type_return->isValid()) {
if (type_return->isCompositeSingleton())
RESOLVE_TYPE_DEBUG << type_return->typeName() << ' ' << type_return->sourceUrl() << " TYPE/URL-SINGLETON";
else if (type_return->isComposite())
RESOLVE_TYPE_DEBUG << type_return->typeName() << ' ' << type_return->sourceUrl() << " TYPE/URL";
+ else if (type_return->isInlineComponentType())
+ RESOLVE_TYPE_DEBUG << type_return->typeName() << ' ' << type_return->sourceUrl() << " TYPE(INLINECOMPONENT)";
else
RESOLVE_TYPE_DEBUG << type_return->typeName() << " TYPE";
}
@@ -625,11 +485,12 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
return false;
}
-bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent &qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
+bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl,
+ const QQmlTypeLoaderQmldirContent &qmldir,
+ QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
{
Q_ASSERT(resolvedUrl.endsWith(Slash));
url = resolvedUrl;
- localDirectoryPath = QQmlFile::urlToLocalFileOrQrc(url);
qmlDirComponents = qmldir.components();
@@ -640,30 +501,35 @@ bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQml
it != nameSpace->imports.constEnd(); ++it) {
if ((*it != this) && ((*it)->uri == uri)) {
QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("\"%1\" is ambiguous. Found in %2 and in %3").arg(uri).arg(url).arg((*it)->url));
+ error.setDescription(
+ QQmlImportDatabase::tr("\"%1\" is ambiguous. Found in %2 and in %3")
+ .arg(uri, url, (*it)->url));
errors->prepend(error);
return false;
}
}
- qmlDirScripts = getVersionedScripts(scripts, majversion, minversion);
+ qmlDirScripts = getVersionedScripts(scripts, version);
}
return true;
}
-QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin)
+QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qmldirscripts,
+ QTypeRevision version)
{
QMap<QString, QQmlDirParser::Script> versioned;
for (QList<QQmlDirParser::Script>::const_iterator sit = qmldirscripts.constBegin();
sit != qmldirscripts.constEnd(); ++sit) {
// Only include scripts that match our requested version
- if (((vmaj == -1) || (sit->majorVersion == vmaj)) &&
- ((vmin == -1) || (sit->minorVersion <= vmin))) {
+ if ((!version.hasMajorVersion() || (sit->version.majorVersion() == version.majorVersion()))
+ && (!version.hasMinorVersion()
+ || (sit->version.minorVersion() <= version.minorVersion()))) {
// Load the highest version that matches
- QMap<QString, QQmlDirParser::Script>::iterator vit = versioned.find(sit->nameSpace);
- if (vit == versioned.end() || (vit->minorVersion < sit->minorVersion)) {
+ const auto vit = versioned.constFind(sit->nameSpace);
+ if (vit == versioned.cend()
+ || (vit->version.minorVersion() < sit->version.minorVersion())) {
versioned.insert(sit->nameSpace, *sit);
}
}
@@ -673,6 +539,7 @@ QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qml
}
/*!
+ \fn QQmlImports::resolveType(QQmlImportNamespace *ns, const QHashedStringRef &type, QQmlType *type_return, QTypeRevision *version_return, QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType) const
\internal
Searching \e only in the namespace \a ns (previously returned in a call to
@@ -682,38 +549,37 @@ QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qml
If the return pointer is 0, the corresponding search is not done.
*/
-bool QQmlImports::resolveType(QQmlImportNamespace *ns, const QHashedStringRef &type,
- QQmlType *type_return, int *vmaj, int *vmin,
- QQmlType::RegistrationType registrationType) const
-{
- return ns->resolveType(d->typeLoader, type, vmaj, vmin, type_return, nullptr, nullptr, registrationType);
-}
bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
- int *vmajor, int *vminor, QQmlType *type_return, QString *base,
- bool *typeRecursionDetected,
+ QTypeRevision *version_return, QQmlType *type_return,
+ const QString *base, bool *typeRecursionDetected,
QQmlType::RegistrationType registrationType,
QQmlImport::RecursionRestriction recursionRestriction,
QList<QQmlError> *errors) const
{
- if (majversion >= 0 && minversion >= 0) {
- QQmlType t = QQmlMetaType::qmlType(type, uri, majversion, minversion);
- if (t.isValid()) {
- if (vmajor)
- *vmajor = majversion;
- if (vminor)
- *vminor = minversion;
- if (type_return)
- *type_return = t;
- return true;
- }
+ QQmlType t = QQmlMetaType::qmlType(type, uri, version);
+ if (t.isValid()) {
+ if (version_return)
+ *version_return = version;
+ if (type_return)
+ *type_return = t;
+ return true;
}
const QString typeStr = type.toString();
+ if (isInlineComponent) {
+ Q_ASSERT(type_return);
+ bool ret = uri == typeStr;
+ if (ret) {
+ Q_ASSERT(!type_return->isValid());
+ *type_return = QQmlMetaType::fetchOrCreateInlineComponentTypeForUrl(QUrl(url));
+ }
+ return ret;
+ }
QQmlDirComponents::ConstIterator it = qmlDirComponents.find(typeStr), end = qmlDirComponents.end();
if (it != end) {
QString componentUrl;
- bool isCompositeSingleton = false;
+ QQmlMetaType::CompositeTypeLookupMode lookupMode = QQmlMetaType::NonSingleton;
QQmlDirComponents::ConstIterator candidate = end;
for ( ; it != end && it.key() == typeStr; ++it) {
const QQmlDirParser::Component &c = *it;
@@ -730,30 +596,35 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
break;
}
- // importing version -1 means import ALL versions
- if ((majversion == -1) ||
- (implicitlyImported && c.internal) || // allow the implicit import of internal types
- (c.majorVersion == majversion && c.minorVersion <= minversion)) {
+ // importing invalid version means import ALL versions
+ if (!version.hasMajorVersion() || (implicitlyImported && c.internal)
+ // allow the implicit import of internal types
+ || (c.version.majorVersion() == version.majorVersion()
+ && c.version.minorVersion() <= version.minorVersion())) {
// Is this better than the previous candidate?
- if ((candidate == end) ||
- (c.majorVersion > candidate->majorVersion) ||
- ((c.majorVersion == candidate->majorVersion) && (c.minorVersion > candidate->minorVersion))) {
+ if ((candidate == end)
+ || (c.version.majorVersion() > candidate->version.majorVersion())
+ || ((c.version.majorVersion() == candidate->version.majorVersion())
+ && (c.version.minorVersion() > candidate->version.minorVersion()))) {
if (base) {
componentUrl = resolveLocalUrl(QString(url + c.typeName + dotqml_string), c.fileName);
if (c.internal) {
if (resolveLocalUrl(*base, c.fileName) != componentUrl)
continue; // failed attempt to access an internal type
}
- if (recursionRestriction == QQmlImport::PreventRecursion && *base == componentUrl) {
- if (typeRecursionDetected)
- *typeRecursionDetected = true;
+
+ const bool recursion = *base == componentUrl;
+ if (typeRecursionDetected)
+ *typeRecursionDetected = recursion;
+
+ if (recursionRestriction == QQmlImport::PreventRecursion && recursion) {
continue; // no recursion
}
}
// This is our best candidate so far
candidate = it;
- isCompositeSingleton = c.singleton;
+ lookupMode = c.singleton ? QQmlMetaType::Singleton : QQmlMetaType::NonSingleton;
}
}
}
@@ -761,18 +632,20 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
if (candidate != end) {
if (!base) // ensure we have a componentUrl
componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName);
- QQmlType returnType = QQmlMetaType::typeForUrl(componentUrl, type, isCompositeSingleton,
- nullptr, candidate->majorVersion,
- candidate->minorVersion);
- if (vmajor)
- *vmajor = candidate->majorVersion;
- if (vminor)
- *vminor = candidate->minorVersion;
+ QQmlType returnType = QQmlMetaType::typeForUrl(componentUrl, type, lookupMode,
+ nullptr, candidate->version);
+ if (version_return)
+ *version_return = candidate->version;
if (type_return)
*type_return = returnType;
return returnType.isValid();
}
- } else if (!isLibrary && !localDirectoryPath.isEmpty()) {
+ } else if (!isLibrary) {
+ // the base path of the import if it's a local file
+ const QString localDirectoryPath = QQmlFile::urlToLocalFileOrQrc(url);
+ if (localDirectoryPath.isEmpty())
+ return false;
+
QString qmlUrl;
bool exists = false;
@@ -803,12 +676,15 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
}
if (exists) {
- if (recursionRestriction == QQmlImport::PreventRecursion && base && (*base == qmlUrl)) { // no recursion
- if (typeRecursionDetected)
- *typeRecursionDetected = true;
- } else {
+ const bool recursion = base && *base == qmlUrl;
+ if (typeRecursionDetected)
+ *typeRecursionDetected = recursion;
+ if (recursionRestriction == QQmlImport::AllowRecursion || !recursion) {
QQmlType returnType = QQmlMetaType::typeForUrl(
- qmlUrl, type, registrationType == QQmlType::CompositeSingletonType, errors);
+ qmlUrl, type, registrationType == QQmlType::CompositeSingletonType
+ ? QQmlMetaType::Singleton
+ : QQmlMetaType::NonSingleton,
+ errors);
if (type_return)
*type_return = returnType;
return returnType.isValid();
@@ -819,52 +695,91 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
return false;
}
-bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, int *vminor,
- QQmlType *type_return, QList<QQmlError> *errors,
- QQmlType::RegistrationType registrationType,
- QQmlImport::RecursionRestriction recursionRestriction)
+bool QQmlImports::resolveType(
+ QQmlTypeLoader *typeLoader, const QHashedStringRef &type, QTypeRevision *version_return,
+ QQmlType *type_return, QList<QQmlError> *errors,
+ QQmlType::RegistrationType registrationType, bool *typeRecursionDetected) const
{
- QQmlImportNamespace *s = nullptr;
- int dot = type.indexOf(Dot);
- if (dot >= 0) {
- QHashedStringRef namespaceName(type.constData(), dot);
- s = findQualifiedNamespace(namespaceName);
- if (!s) {
- if (errors) {
- QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(namespaceName.toString()));
- errors->prepend(error);
- }
- return false;
- }
- int ndot = type.indexOf(Dot,dot+1);
- if (ndot > 0) {
- if (errors) {
- QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("- nested namespaces not allowed"));
- errors->prepend(error);
- }
- return false;
- }
- } else {
- s = &unqualifiedset;
- }
- QHashedStringRef unqualifiedtype = dot < 0 ? type : QHashedStringRef(type.constData()+dot+1, type.length()-dot-1);
- if (s) {
- if (s->resolveType(typeLoader, unqualifiedtype, vmajor, vminor, type_return, &base, errors,
- registrationType, recursionRestriction))
+ const QVector<QHashedStringRef> splitName = type.split(Dot);
+ auto resolveTypeInNamespace = [&](
+ QHashedStringRef unqualifiedtype, QQmlImportNamespace *nameSpace,
+ QList<QQmlError> *errors) -> bool {
+ if (nameSpace->resolveType(
+ typeLoader, unqualifiedtype, version_return, type_return, &m_base, errors,
+ registrationType, typeRecursionDetected))
return true;
- if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) {
+ if (nameSpace->imports.size() == 1
+ && !nameSpace->imports.at(0)->isLibrary
+ && type_return
+ && nameSpace != &m_unqualifiedset) {
// qualified, and only 1 url
*type_return = QQmlMetaType::typeForUrl(
- resolveLocalUrl(s->imports.at(0)->url,
+ resolveLocalUrl(nameSpace->imports.at(0)->url,
unqualifiedtype.toString() + QLatin1String(".qml")),
- type, false, errors);
+ type, QQmlMetaType::NonSingleton, errors);
return type_return->isValid();
}
+ return false;
+ };
+ switch (splitName.size()) {
+ case 1: {
+ // must be a simple type
+ return resolveTypeInNamespace(type, &m_unqualifiedset, errors);
}
-
- return false;
+ case 2: {
+ // either namespace + simple type OR simple type + inline component
+ QQmlImportNamespace *s = findQualifiedNamespace(splitName.at(0));
+ if (s) {
+ // namespace + simple type
+ return resolveTypeInNamespace(splitName.at(1), s, errors);
+ } else {
+ if (resolveTypeInNamespace(splitName.at(0), &m_unqualifiedset, nullptr)) {
+ // either simple type + inline component
+ *type_return = QQmlMetaType::inlineComponentType(
+ *type_return, splitName.at(1).toString());
+ return true;
+ } else {
+ // or a failure
+ if (errors) {
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("- %1 is neither a type nor a namespace").arg(splitName.at(0).toString()));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ }
+ }
+ case 3: {
+ // must be namespace + simple type + inline component
+ QQmlImportNamespace *s = findQualifiedNamespace(splitName.at(0));
+ QQmlError error;
+ if (!s) {
+ error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(splitName.at(0).toString()));
+ } else {
+ if (resolveTypeInNamespace(splitName.at(1), s, nullptr)) {
+ *type_return = QQmlMetaType::inlineComponentType(
+ *type_return, splitName.at(2).toString());
+ return true;
+ } else {
+ error.setDescription(QQmlImportDatabase::tr("- %1 is not a type").arg(splitName.at(1).toString()));
+ }
+ }
+ if (errors) {
+ errors->prepend(error);
+ }
+ return false;
+ }
+ default: {
+ // all other numbers suggest a user error
+ if (errors) {
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("- nested namespaces not allowed"));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ }
+ Q_UNREACHABLE();
}
QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const
@@ -877,37 +792,50 @@ QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const
}
bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
- int *vmajor, int *vminor, QQmlType *type_return,
- QString *base, QList<QQmlError> *errors,
+ QTypeRevision *version_return, QQmlType *type_return,
+ const QString *base, QList<QQmlError> *errors,
QQmlType::RegistrationType registrationType,
- QQmlImport::RecursionRestriction recursionRestriction)
+ bool *typeRecursionDetected)
{
- bool typeRecursionDetected = false;
- for (int i=0; i<imports.count(); ++i) {
+ QQmlImport::RecursionRestriction recursionRestriction =
+ typeRecursionDetected ? QQmlImport::AllowRecursion : QQmlImport::PreventRecursion;
+
+ bool localTypeRecursionDetected = false;
+ if (!typeRecursionDetected)
+ typeRecursionDetected = &localTypeRecursionDetected;
+
+ // TODO: move the sorting somewhere else and make resolveType() const.
+ if (needsSorting()) {
+ std::stable_partition(imports.begin(), imports.end(), [](QQmlImportInstance *import) {
+ return import->isInlineComponent;
+ });
+ setNeedsSorting(false);
+ }
+ for (int i=0; i<imports.size(); ++i) {
const QQmlImportInstance *import = imports.at(i);
- if (import->resolveType(typeLoader, type, vmajor, vminor, type_return, base,
- &typeRecursionDetected, registrationType, recursionRestriction, errors)) {
+ if (import->resolveType(typeLoader, type, version_return, type_return, base,
+ typeRecursionDetected, registrationType, recursionRestriction, errors)) {
if (qmlCheckTypes()) {
// check for type clashes
- for (int j = i+1; j<imports.count(); ++j) {
+ for (int j = i+1; j<imports.size(); ++j) {
const QQmlImportInstance *import2 = imports.at(j);
- if (import2->resolveType(typeLoader, type, vmajor, vminor, nullptr, base,
+ if (import2->resolveType(typeLoader, type, version_return, nullptr, base,
nullptr, registrationType)) {
if (errors) {
QString u1 = import->url;
QString u2 = import2->url;
if (base) {
- QStringRef b(base);
+ QStringView b(*base);
int dot = b.lastIndexOf(Dot);
if (dot >= 0) {
b = b.left(dot+1);
- QStringRef l = b.left(dot);
+ QStringView l = b.left(dot);
if (u1.startsWith(b))
- u1 = u1.mid(b.count());
+ u1 = u1.mid(b.size());
else if (u1 == l)
u1 = QQmlImportDatabase::tr("local directory");
if (u2.startsWith(b))
- u2 = u2.mid(b.count());
+ u2 = u2.mid(b.size());
else if (u2 == l)
u2 = QQmlImportDatabase::tr("local directory");
}
@@ -915,12 +843,20 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
QQmlError error;
if (u1 != u2) {
- error.setDescription(QQmlImportDatabase::tr("is ambiguous. Found in %1 and in %2").arg(u1).arg(u2));
+ error.setDescription(
+ QQmlImportDatabase::tr(
+ "is ambiguous. Found in %1 and in %2")
+ .arg(u1, u2));
} else {
- error.setDescription(QQmlImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
- .arg(u1)
- .arg(import->majversion).arg(import->minversion)
- .arg(import2->majversion).arg(import2->minversion));
+ error.setDescription(
+ QQmlImportDatabase::tr(
+ "is ambiguous. Found in %1 in version "
+ "%2.%3 and %4.%5")
+ .arg(u1)
+ .arg(import->version.majorVersion())
+ .arg(import->version.minorVersion())
+ .arg(import2->version.majorVersion())
+ .arg(import2->version.minorVersion()));
}
errors->prepend(error);
}
@@ -933,7 +869,7 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
}
if (errors) {
QQmlError error;
- if (typeRecursionDetected)
+ if (*typeRecursionDetected)
error.setDescription(QQmlImportDatabase::tr("is instantiated recursively"));
else
error.setDescription(QQmlImportDatabase::tr("is not a type"));
@@ -942,19 +878,9 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
return false;
}
-QQmlImportsPrivate::QQmlImportsPrivate(QQmlTypeLoader *loader)
-: ref(1), typeLoader(loader) {
-}
-
-QQmlImportsPrivate::~QQmlImportsPrivate()
-{
- while (QQmlImportNamespace *ns = qualifiedSets.takeFirst())
- delete ns;
-}
-
-QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStringRef &prefix) const
+QQmlImportNamespace *QQmlImports::findQualifiedNamespace(const QHashedStringRef &prefix) const
{
- for (QQmlImportNamespace *ns = qualifiedSets.first(); ns; ns = qualifiedSets.next(ns)) {
+ for (QQmlImportNamespace *ns = m_qualifiedSets.first(); ns; ns = m_qualifiedSets.next(ns)) {
if (prefix == ns->prefix)
return ns;
}
@@ -962,234 +888,75 @@ QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStr
}
/*
- Returns the list of possible versioned URI combinations. For example, if \a uri is
- QtQml.Models, \a vmaj is 2, and \a vmin is 0, this method returns the following:
- [QtQml.Models.2.0, QtQml.2.0.Models, QtQml.Models.2, QtQml.2.Models, QtQml.Models]
- */
-static QStringList versionUriList(const QString &uri, int vmaj, int vmin)
-{
- QStringList result;
- for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) {
- int index = uri.length();
- do {
- QString versionUri = uri;
- versionUri.insert(index, QQmlImports::versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version)));
- result += versionUri;
-
- index = uri.lastIndexOf(Dot, index - 1);
- } while (index > 0 && version != QQmlImports::Unversioned);
- }
- return result;
-}
-
-static QVector<QStaticPlugin> makePlugins()
-{
- QVector<QStaticPlugin> plugins;
- // To avoid traversing all static plugins for all imports, we cut down
- // the list the first time called to only contain QML plugins:
- const auto staticPlugins = QPluginLoader::staticPlugins();
- for (const QStaticPlugin &plugin : staticPlugins) {
- const QString iid = plugin.metaData().value(QLatin1String("IID")).toString();
- if (iid == QLatin1String(QQmlEngineExtensionInterface_iid)
- || iid == QLatin1String(QQmlExtensionInterface_iid)
- || iid == QLatin1String(QQmlExtensionInterface_iid_old)) {
- plugins.append(plugin);
- }
- }
- return plugins;
-}
-
-/*
- Get all static plugins that are QML plugins and has a meta data URI that matches with one of
- \a versionUris, which is a list of all possible versioned URI combinations - see versionUriList()
- above.
- */
-bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris,
- const QString &qmldirPath, QList<QQmlError> *errors)
-{
- static const QVector<QStaticPlugin> plugins = makePlugins();
- for (const QStaticPlugin &plugin : plugins) {
- // Since a module can list more than one plugin, we keep iterating even after we found a match.
- QObject *instance = plugin.instance();
- if (qobject_cast<QQmlEngineExtensionPlugin *>(instance)
- || qobject_cast<QQmlExtensionPlugin *>(instance)) {
- const QJsonArray metaTagsUriList = plugin.metaData().value(QLatin1String("uri")).toArray();
- if (metaTagsUriList.isEmpty()) {
- if (errors) {
- QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("static plugin for module \"%1\" with name \"%2\" has no metadata URI")
- .arg(uri).arg(QString::fromUtf8(instance->metaObject()->className())));
- error.setUrl(QUrl::fromLocalFile(qmldirPath));
- errors->prepend(error);
- }
- return false;
- }
- // A plugin can be set up to handle multiple URIs, so go through the list:
- for (const QJsonValue &metaTagUri : metaTagsUriList) {
- if (versionUris.contains(metaTagUri.toString())) {
- result.append(qMakePair(plugin, metaTagsUriList));
- break;
- }
- }
- }
- }
- return true;
-}
-
-/*
Import an extension defined by a qmldir file.
-
-\a qmldirFilePath is a raw file path.
*/
-bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
- const QString &uri,
- int vmaj, int vmin,
- QQmlImportDatabase *database,
- const QQmlTypeLoaderQmldirContent &qmldir,
- QList<QQmlError> *errors)
+QTypeRevision QQmlImports::importExtension(
+ QQmlTypeLoader *typeLoader, const QString &uri, QTypeRevision version,
+ const QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors)
{
- Q_ASSERT(qmldir.hasContent());
+ Q_ASSERT(qmldir->hasContent());
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(base) << ")::importExtension: "
- << "loaded " << qmldirFilePath;
+ qCDebug(lcQmlImport)
+ << "importExtension:" << qPrintable(m_base) << "loaded" << qmldir->qmldirLocation();
- if (designerSupportRequired && !qmldir.designerSupported()) {
+ if (designerSupportRequired && !qmldir->designerSupported()) {
if (errors) {
QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("module does not support the designer \"%1\"").arg(qmldir.typeNamespace()));
- error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
+ error.setDescription(
+ QQmlImportDatabase::tr("module does not support the designer \"%1\"")
+ .arg(qmldir->typeNamespace()));
+ error.setUrl(QUrl::fromLocalFile(qmldir->qmldirLocation()));
errors->prepend(error);
}
- return false;
+ return QTypeRevision();
}
- int qmldirPluginCount = qmldir.plugins().count();
- if (qmldirPluginCount == 0)
- return true;
+ if (qmldir->plugins().isEmpty()) {
+ // If the qmldir does not register a plugin, we might still have declaratively
+ // registered types (if we are dealing with an application instead of a library)
+ if (!QQmlMetaType::typeModule(uri, version))
+ QQmlMetaType::qmlRegisterModuleTypes(uri);
+ return validVersion(version);
+ }
- if (!database->qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(qmldirFilePath)) {
- // First search for listed qmldir plugins dynamically. If we cannot resolve them all, we continue
- // searching static plugins that has correct metadata uri. Note that since we only know the uri
- // for a static plugin, and not the filename, we cannot know which static plugin belongs to which
- // listed plugin inside qmldir. And for this reason, mixing dynamic and static plugins inside a
- // single module is not recommended.
-
- QString typeNamespace = qmldir.typeNamespace();
- QString qmldirPath = qmldirFilePath;
- int slash = qmldirPath.lastIndexOf(Slash);
- if (slash > 0)
- qmldirPath.truncate(slash);
-
- int dynamicPluginsFound = 0;
- int staticPluginsFound = 0;
-
-#if QT_CONFIG(library)
- const auto qmldirPlugins = qmldir.plugins();
- for (const QQmlDirParser::Plugin &plugin : qmldirPlugins) {
- QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name);
- if (!resolvedFilePath.isEmpty()) {
- dynamicPluginsFound++;
- if (!database->importDynamicPlugin(resolvedFilePath, uri, typeNamespace, vmaj, errors)) {
- if (errors) {
- // XXX TODO: should we leave the import plugin error alone?
- // Here, we pop it off the top and coalesce it into this error's message.
- // The reason is that the lower level may add url and line/column numbering information.
- QQmlError error;
- error.setDescription(
- QQmlImportDatabase::tr(
- "plugin cannot be loaded for module \"%1\": %2")
- .arg(uri, errors->takeFirst().description()));
- error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
- errors->prepend(error);
- }
- return false;
- }
- }
- }
-#endif // QT_CONFIG(library)
-
- if (dynamicPluginsFound < qmldirPluginCount) {
- // Check if the missing plugins can be resolved statically. We do this by looking at
- // the URIs embedded in a plugins meta data. Since those URIs can be anything from fully
- // versioned to unversioned, we need to compare with differnt version strings. If a module
- // has several plugins, they must all have the same version. Start by populating pluginPairs
- // with relevant plugins to cut the list short early on:
- const QStringList versionUris = versionUriList(uri, vmaj, vmin);
- QVector<StaticPluginPair> pluginPairs;
- if (!populatePluginPairVector(pluginPairs, uri, versionUris, qmldirFilePath, errors))
- return false;
+ QQmlPluginImporter importer(
+ uri, version, typeLoader->importDatabase(), qmldir, typeLoader, errors);
+ return importer.importPlugins();
+}
- const QString basePath = QFileInfo(qmldirPath).absoluteFilePath();
- for (const QString &versionUri : versionUris) {
- for (const StaticPluginPair &pair : qAsConst(pluginPairs)) {
- for (const QJsonValue &metaTagUri : pair.second) {
- if (versionUri == metaTagUri.toString()) {
- staticPluginsFound++;
- QObject *instance = pair.first.instance();
- if (!database->importStaticPlugin(instance, basePath, uri, typeNamespace, vmaj, errors)) {
- if (errors) {
- QQmlError poppedError = errors->takeFirst();
- QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("static plugin for module \"%1\" with name \"%2\" cannot be loaded: %3")
- .arg(uri).arg(QString::fromUtf8(instance->metaObject()->className())).arg(poppedError.description()));
- error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
- errors->prepend(error);
- }
- return false;
- }
- break;
- }
- }
- }
- if (staticPluginsFound > 0)
- break;
- }
- }
+QString QQmlImports::redirectQmldirContent(
+ QQmlTypeLoader *typeLoader, QQmlTypeLoaderQmldirContent *qmldir)
+{
+ const QString preferredPath = qmldir->preferredPath();
+ const QString url = preferredPath.startsWith(u':')
+ ? QStringLiteral("qrc") + preferredPath
+ : QUrl::fromLocalFile(preferredPath).toString();
- if ((dynamicPluginsFound + staticPluginsFound) < qmldirPluginCount) {
- if (errors) {
- QQmlError error;
- if (qmldirPluginCount > 1 && staticPluginsFound > 0)
- error.setDescription(QQmlImportDatabase::tr("could not resolve all plugins for module \"%1\"").arg(uri));
- else
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(qmldir.plugins()[dynamicPluginsFound].name));
- error.setUrl(QUrl::fromLocalFile(qmldirFilePath));
- errors->prepend(error);
- }
- return false;
- }
+ QQmlTypeLoaderQmldirContent redirected
+ = typeLoader->qmldirContent(url + QLatin1String("qmldir"));
- database->qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(qmldirFilePath);
- }
- return true;
+ // Ignore errors: If the qmldir doesn't exist, stick to the old one.
+ if (redirected.hasContent() && !redirected.hasError())
+ *qmldir = std::move(redirected);
+ return url;
}
-bool QQmlImportsPrivate::getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors)
+bool QQmlImports::getQmldirContent(
+ QQmlTypeLoader *typeLoader, const QString &qmldirIdentifier, const QString &uri,
+ QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors)
{
Q_ASSERT(errors);
Q_ASSERT(qmldir);
*qmldir = typeLoader->qmldirContent(qmldirIdentifier);
- if ((*qmldir).hasContent()) {
- // Ensure that parsing was successful
- if ((*qmldir).hasError()) {
- QUrl url = QUrl::fromLocalFile(qmldirIdentifier);
- const QList<QQmlError> qmldirErrors = (*qmldir).errors(uri);
- for (int i = 0; i < qmldirErrors.size(); ++i) {
- QQmlError error = qmldirErrors.at(i);
- error.setUrl(url);
- errors->append(error);
- }
- return false;
- }
- }
+ if (!qmldir->hasContent() || !qmldir->hasError())
+ return true;
- return true;
+ errors->append(qmldir->errors(uri, QUrl::fromLocalFile(qmldirIdentifier)));
+ return false;
}
-QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDatabase *database)
+QString QQmlImports::resolvedUri(const QString &dir_arg, QQmlImportDatabase *database)
{
QString dir = dir_arg;
if (dir.endsWith(Slash) || dir.endsWith(Backslash))
@@ -1200,9 +967,9 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
std::sort(paths.begin(), paths.end(), std::greater<QString>()); // Ensure subdirs preceed their parents.
QString stableRelativePath = dir;
- for (const QString &path : qAsConst(paths)) {
+ for (const QString &path : std::as_const(paths)) {
if (dir.startsWith(path)) {
- stableRelativePath = dir.mid(path.length()+1);
+ stableRelativePath = dir.mid(path.size()+1);
break;
}
}
@@ -1224,89 +991,48 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
return stableRelativePath;
}
-/*
-Locates the qmldir file for \a uri version \a vmaj.vmin. Returns true if found,
-and fills in outQmldirFilePath and outQmldirUrl appropriately. Otherwise returns
-false.
-*/
-bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQmlImportDatabase *database,
- QString *outQmldirFilePath, QString *outQmldirPathUrl)
-{
- Q_ASSERT(vmaj >= 0 && vmin >= 0); // Versions are always specified for libraries
-
- // Check cache first
-
- QQmlImportDatabase::QmldirCache *cacheHead = nullptr;
- {
- QQmlImportDatabase::QmldirCache **cachePtr = database->qmldirCache.value(uri);
- if (cachePtr) {
- cacheHead = *cachePtr;
- QQmlImportDatabase::QmldirCache *cache = cacheHead;
- while (cache) {
- if (cache->versionMajor == vmaj && cache->versionMinor == vmin) {
- *outQmldirFilePath = cache->qmldirFilePath;
- *outQmldirPathUrl = cache->qmldirPathUrl;
- return !cache->qmldirFilePath.isEmpty();
- }
- cache = cache->next;
- }
- }
- }
+/*!
+ \internal
- QQmlTypeLoader &typeLoader = QQmlEnginePrivate::get(database->engine)->typeLoader;
+ \fn template<typename Callback>
+ QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir(
+ const QString &uri, QTypeRevision version, const Callback &callback)
- // Interceptor might redirect remote files to local ones.
- QQmlAbstractUrlInterceptor *interceptor = typeLoader.engine()->urlInterceptor();
- QStringList localImportPaths = database->importPathList(
- interceptor ? QQmlImportDatabase::LocalOrRemote : QQmlImportDatabase::Local);
+ Locates the qmldir files for \a uri version \a version. For each one, calls
+ the \a callback. If the \a callback returns \c true, returns QmldirFound.
- // Search local import paths for a matching version
- const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(uri, localImportPaths, vmaj, vmin);
- for (QString qmldirPath : qmlDirPaths) {
- if (interceptor) {
- qmldirPath = QQmlFile::urlToLocalFileOrQrc(
- interceptor->intercept(QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
- QQmlAbstractUrlInterceptor::QmldirFile));
- }
+ If at least one callback invocation returned \c false and there are no qmldir
+ files left to check, returns QmldirRejected.
- QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath);
- if (!absoluteFilePath.isEmpty()) {
- QString url;
- const QStringRef absolutePath = absoluteFilePath.leftRef(absoluteFilePath.lastIndexOf(Slash) + 1);
- if (absolutePath.at(0) == Colon)
- url = QLatin1String("qrc") + absolutePath;
- else
- url = QUrl::fromLocalFile(absolutePath.toString()).toString();
-
- QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache;
- cache->versionMajor = vmaj;
- cache->versionMinor = vmin;
- cache->qmldirFilePath = absoluteFilePath;
- cache->qmldirPathUrl = url;
- cache->next = cacheHead;
- database->qmldirCache.insert(uri, cache);
-
- *outQmldirFilePath = absoluteFilePath;
- *outQmldirPathUrl = url;
+ Otherwise, if interception redirects a previously local qmldir URL to a remote
+ one, returns QmldirInterceptedToRemote. Otherwise, returns QmldirNotFound.
+*/
- return true;
+QTypeRevision QQmlImports::matchingQmldirVersion(
+ const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, QTypeRevision version,
+ QList<QQmlError> *errors)
+{
+ int bestMajorVersion = -1;
+ quint8 lowestMinorVersion = std::numeric_limits<quint8>::max();
+ quint8 highestMinorVersion = 0;
+
+ auto addVersion = [&](QTypeRevision newVersion) {
+ if (!newVersion.hasMajorVersion())
+ return;
+ if (!version.hasMajorVersion() || version.majorVersion() == newVersion.majorVersion()) {
+ if (newVersion.majorVersion() > bestMajorVersion) {
+ bestMajorVersion = newVersion.majorVersion();
+ if (newVersion.hasMinorVersion()) {
+ lowestMinorVersion = newVersion.minorVersion();
+ highestMinorVersion = newVersion.minorVersion();
+ }
+ } else if (newVersion.majorVersion() == bestMajorVersion
+ && newVersion.hasMinorVersion()) {
+ lowestMinorVersion = qMin(lowestMinorVersion, newVersion.minorVersion());
+ highestMinorVersion = qMax(highestMinorVersion, newVersion.minorVersion());
+ }
}
- }
-
- QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache;
- cache->versionMajor = vmaj;
- cache->versionMinor = vmin;
- cache->next = cacheHead;
- database->qmldirCache.insert(uri, cache);
-
- return false;
-}
-
-bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin,
- QList<QQmlError> *errors)
-{
- int lowest_min = INT_MAX;
- int highest_min = INT_MIN;
+ };
typedef QQmlDirComponents::const_iterator ConstIterator;
const QQmlDirComponents &components = qmldir.components();
@@ -1314,22 +1040,20 @@ bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent
ConstIterator cend = components.constEnd();
for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) {
for (ConstIterator cit2 = components.constBegin(); cit2 != cit; ++cit2) {
- if ((cit2->typeName == cit->typeName) &&
- (cit2->majorVersion == cit->majorVersion) &&
- (cit2->minorVersion == cit->minorVersion)) {
+ if (cit2->typeName == cit->typeName && cit2->version == cit->version) {
// This entry clashes with a predecessor
QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("\"%1\" version %2.%3 is defined more than once in module \"%4\"")
- .arg(cit->typeName).arg(cit->majorVersion).arg(cit->minorVersion).arg(uri));
+ error.setDescription(
+ QQmlImportDatabase::tr(
+ "\"%1\" version %2.%3 is defined more than once in module \"%4\"")
+ .arg(cit->typeName).arg(cit->version.majorVersion())
+ .arg(cit->version.minorVersion()).arg(uri));
errors->prepend(error);
- return false;
+ return QTypeRevision();
}
}
- if (cit->majorVersion == vmaj) {
- lowest_min = qMin(lowest_min, cit->minorVersion);
- highest_min = qMax(highest_min, cit->minorVersion);
- }
+ addVersion(cit->version);
}
typedef QList<QQmlDirParser::Script>::const_iterator SConstIterator;
@@ -1338,57 +1062,63 @@ bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent
SConstIterator send = scripts.constEnd();
for (SConstIterator sit = scripts.constBegin(); sit != send; ++sit) {
for (SConstIterator sit2 = scripts.constBegin(); sit2 != sit; ++sit2) {
- if ((sit2->nameSpace == sit->nameSpace) &&
- (sit2->majorVersion == sit->majorVersion) &&
- (sit2->minorVersion == sit->minorVersion)) {
+ if (sit2->nameSpace == sit->nameSpace && sit2->version == sit->version) {
// This entry clashes with a predecessor
QQmlError error;
error.setDescription(QQmlImportDatabase::tr("\"%1\" version %2.%3 is defined more than once in module \"%4\"")
- .arg(sit->nameSpace).arg(sit->majorVersion).arg(sit->minorVersion).arg(uri));
+ .arg(sit->nameSpace).arg(sit->version.majorVersion())
+ .arg(sit->version.minorVersion()).arg(uri));
errors->prepend(error);
- return false;
+ return QTypeRevision();
}
}
- if (sit->majorVersion == vmaj) {
- lowest_min = qMin(lowest_min, sit->minorVersion);
- highest_min = qMax(highest_min, sit->minorVersion);
- }
+ addVersion(sit->version);
}
- if (lowest_min > vmin || highest_min < vmin) {
- QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin));
- errors->prepend(error);
- return false;
+ // Failure to find a match is only an error if we were asking for a specific version ...
+ if (version.hasMajorVersion()
+ && (bestMajorVersion < 0
+ || (version.hasMinorVersion()
+ && (lowestMinorVersion > version.minorVersion()
+ || highestMinorVersion < version.minorVersion())))) {
+ errors->prepend(moduleNotFoundError(uri, version));
+ return QTypeRevision();
}
- return true;
+ // ... otherwise, anything is valid.
+ if (bestMajorVersion < 0)
+ return validVersion();
+
+ return QTypeRevision::fromVersion(
+ bestMajorVersion,
+ (version.hasMajorVersion() && version.hasMinorVersion())
+ ? version.minorVersion()
+ : highestMinorVersion);
}
-QQmlImportNamespace *QQmlImportsPrivate::importNamespace(const QString &prefix) const
+QQmlImportNamespace *QQmlImports::importNamespace(const QString &prefix)
{
QQmlImportNamespace *nameSpace = nullptr;
if (prefix.isEmpty()) {
- nameSpace = &unqualifiedset;
+ nameSpace = &m_unqualifiedset;
} else {
nameSpace = findQualifiedNamespace(prefix);
if (!nameSpace) {
nameSpace = new QQmlImportNamespace;
nameSpace->prefix = prefix;
- qualifiedSets.append(nameSpace);
+ m_qualifiedSets.append(nameSpace);
}
}
return nameSpace;
}
-QQmlImportInstance *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace *nameSpace,
- const QString &uri, const QString &url, int vmaj, int vmin,
- QV4::CompiledData::Import::ImportType type,
- QList<QQmlError> *errors, bool lowPrecedence)
+static QQmlImportInstance *addImportToNamespace(
+ QQmlImportNamespace *nameSpace, const QString &uri, const QString &url, QTypeRevision version,
+ QV4::CompiledData::Import::ImportType type, QList<QQmlError> *errors, quint16 precedence)
{
Q_ASSERT(nameSpace);
Q_ASSERT(errors);
@@ -1398,75 +1128,135 @@ QQmlImportInstance *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace
QQmlImportInstance *import = new QQmlImportInstance;
import->uri = uri;
import->url = url;
- import->localDirectoryPath = QQmlFile::urlToLocalFileOrQrc(url);
- import->majversion = vmaj;
- import->minversion = vmin;
+ import->version = version;
import->isLibrary = (type == QV4::CompiledData::Import::ImportLibrary);
+ import->precedence = precedence;
+ import->implicitlyImported = precedence >= QQmlImportInstance::Implicit;
- if (lowPrecedence)
- nameSpace->imports.append(import);
- else
- nameSpace->imports.prepend(import);
+ for (auto it = nameSpace->imports.cbegin(), end = nameSpace->imports.cend();
+ it != end; ++it) {
+ if ((*it)->precedence < precedence)
+ continue;
+ nameSpace->imports.insert(it, import);
+ return import;
+ }
+ nameSpace->imports.append(import);
return import;
}
-bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &prefix,
- int vmaj, int vmin, const QString &qmldirIdentifier, const QString &qmldirUrl, bool incomplete,
- QQmlImportDatabase *database,
- QList<QQmlError> *errors)
+QTypeRevision QQmlImports::addLibraryImport(
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ QTypeRevision version, const QString &qmldirIdentifier, const QString &qmldirUrl,
+ ImportFlags flags, quint16 precedence, QList<QQmlError> *errors)
{
- Q_ASSERT(database);
+ Q_ASSERT(typeLoader);
Q_ASSERT(errors);
+ qCDebug(lcQmlImport)
+ << "addLibraryImport:" << qPrintable(baseUrl().toString())
+ << uri << "version '" << version << "'" << "as" << prefix;
+
QQmlImportNamespace *nameSpace = importNamespace(prefix);
Q_ASSERT(nameSpace);
- QQmlImportInstance *inserted = addImportToNamespace(nameSpace, uri, qmldirUrl, vmaj, vmin, QV4::CompiledData::Import::ImportLibrary, errors);
+ QQmlImportInstance *inserted = addImportToNamespace(
+ nameSpace, uri, qmldirUrl, version,
+ QV4::CompiledData::Import::ImportLibrary, errors,
+ precedence);
Q_ASSERT(inserted);
- if (!incomplete) {
+ if (!(flags & QQmlImports::ImportIncomplete)) {
QQmlTypeLoaderQmldirContent qmldir;
if (!qmldirIdentifier.isEmpty()) {
- if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
- return false;
+ if (!getQmldirContent(typeLoader, qmldirIdentifier, uri, &qmldir, errors))
+ return QTypeRevision();
if (qmldir.hasContent()) {
- if (!importExtension(qmldir.pluginLocation(), uri, vmaj, vmin, database, qmldir, errors))
- return false;
+ version = importExtension(typeLoader, uri, version, &qmldir, errors);
+ if (!version.isValid())
+ return QTypeRevision();
- if (!inserted->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors))
- return false;
+ const QString resolvedUrl = qmldir.hasRedirection()
+ ? redirectQmldirContent(typeLoader, &qmldir)
+ : qmldirUrl;
+
+ if (!inserted->setQmldirContent(resolvedUrl, qmldir, nameSpace, errors))
+ return QTypeRevision();
}
}
// Ensure that we are actually providing something
- if ((vmaj < 0) || (vmin < 0) || !QQmlMetaType::isModule(uri, vmaj, vmin)) {
- if (inserted->qmlDirComponents.isEmpty() && inserted->qmlDirScripts.isEmpty()) {
- QQmlError error;
- if (QQmlMetaType::isAnyModule(uri))
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin));
- else
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri));
- errors->prepend(error);
- return false;
- } else if ((vmaj >= 0) && (vmin >= 0) && qmldir.hasContent()) {
- // Verify that the qmldir content is valid for this version
- if (!validateQmldirVersion(qmldir, uri, vmaj, vmin, errors))
- return false;
+ const QTypeRevision matchingVersion = QQmlMetaType::matchingModuleVersion(uri, version);
+ if (matchingVersion.isValid())
+ return matchingVersion;
+
+ if (inserted->qmlDirComponents.isEmpty() && inserted->qmlDirScripts.isEmpty()) {
+ if (qmldir.plugins().isEmpty()) {
+ if (!qmldir.imports().isEmpty())
+ return validVersion(); // This is a pure redirection
+ if (qmldir.hasTypeInfo())
+ return validVersion(); // A pure C++ module without plugin
}
+ errors->prepend(moduleNotFoundError(uri, relevantVersion(uri, version)));
+ return QTypeRevision();
+ } else if (qmldir.hasContent()) {
+ // Verify that the qmldir content is valid for this version
+ version = matchingQmldirVersion(qmldir, uri, version, errors);
+ if (!version.isValid())
+ return QTypeRevision();
}
}
- return true;
+ return validVersion(version);
}
-bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix,
- int vmaj, int vmin,
- bool isImplicitImport, bool incomplete, QQmlImportDatabase *database,
- QList<QQmlError> *errors)
+/*!
+ \internal
+
+ Adds information to \a database such that subsequent calls to resolveType()
+ will resolve types qualified by \a prefix by considering types found at the given \a uri.
+
+ The \a uri is either a directory (if importType is FileImport), or a URI resolved using paths
+ added via addImportPath() (if importType is LibraryImport).
+
+ The \a prefix may be empty, in which case the import location is considered for
+ unqualified types.
+
+ The base URL must already have been set with Import::setBaseUrl().
+
+ Optionally, the qmldir the import resolved to can be returned by providing the \a localQmldir
+ parameter. Not all imports will have a local qmldir. If there is none, the \a localQmldir
+ parameter won't be set.
+
+ Returns a valid QTypeRevision on success, and an invalid one on failure.
+ In case of failure, the \a errors array will filled appropriately.
+*/
+QTypeRevision QQmlImports::addFileImport(
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ QTypeRevision version, ImportFlags flags, quint16 precedence, QString *localQmldir,
+ QList<QQmlError> *errors)
{
+ Q_ASSERT(typeLoader);
+ Q_ASSERT(errors);
+
+ qCDebug(lcQmlImport)
+ << "addFileImport:" << qPrintable(baseUrl().toString())
+ << uri << version << "as" << prefix;
+
+ if (uri.startsWith(Slash) || uri.startsWith(Colon)) {
+ QQmlError error;
+ const QString fix = uri.startsWith(Slash) ? QLatin1String("file:") + uri
+ : QLatin1String("qrc") + uri;
+ error.setDescription(QQmlImportDatabase::tr(
+ "\"%1\" is not a valid import URL. "
+ "You can pass relative paths or URLs with schema, but not "
+ "absolute paths or resource paths. Try \"%2\".").arg(uri, fix));
+ errors->prepend(error);
+ return QTypeRevision();
+ }
+
Q_ASSERT(errors);
QQmlImportNamespace *nameSpace = importNamespace(prefix);
@@ -1475,13 +1265,11 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
// The uri for this import. For library imports this is the same as uri
// specified by the user, but it may be different in the case of file imports.
QString importUri = uri;
- QString qmldirUrl = resolveLocalUrl(base, importUri + (importUri.endsWith(Slash)
+ QString qmldirUrl = resolveLocalUrl(m_base, importUri + (importUri.endsWith(Slash)
? String_qmldir
: Slash_qmldir));
- if (QQmlAbstractUrlInterceptor *interceptor = typeLoader->engine()->urlInterceptor()) {
- qmldirUrl = interceptor->intercept(QUrl(qmldirUrl),
- QQmlAbstractUrlInterceptor::QmldirFile).toString();
- }
+ qmldirUrl = typeLoader->engine()->interceptUrl(
+ QUrl(qmldirUrl), QQmlAbstractUrlInterceptor::QmldirFile).toString();
QString qmldirIdentifier;
if (QQmlFile::isLocalFile(qmldirUrl)) {
@@ -1491,39 +1279,51 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
const QString dir = localFileOrQrc.left(localFileOrQrc.lastIndexOf(Slash) + 1);
if (!typeLoader->directoryExists(dir)) {
- if (!isImplicitImport) {
+ if (precedence < QQmlImportInstance::Implicit) {
QQmlError error;
error.setDescription(QQmlImportDatabase::tr("\"%1\": no such directory").arg(uri));
error.setUrl(QUrl(qmldirUrl));
errors->prepend(error);
}
- return false;
+ return QTypeRevision();
}
// Transforms the (possible relative) uri into our best guess relative to the
// import paths.
- importUri = resolvedUri(dir, database);
+ importUri = resolvedUri(dir, typeLoader->importDatabase());
if (importUri.endsWith(Slash))
importUri.chop(1);
- if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty())
- qmldirIdentifier = localFileOrQrc;
+ if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) {
+ qmldirIdentifier = std::move(localFileOrQrc);
+ if (localQmldir)
+ *localQmldir = qmldirIdentifier;
+ }
- } else if (nameSpace->prefix.isEmpty() && !incomplete) {
+ } else if (nameSpace->prefix.isEmpty() && !(flags & QQmlImports::ImportIncomplete)) {
- if (!isImplicitImport) {
+ if (precedence < QQmlImportInstance::Implicit) {
QQmlError error;
error.setDescription(QQmlImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(importUri));
error.setUrl(QUrl(qmldirUrl));
errors->prepend(error);
}
- return false;
+ return QTypeRevision();
}
// The url for the path containing files for this import
- QString url = resolveLocalUrl(base, uri);
+ QString url = resolveLocalUrl(m_base, uri);
+ if (url.isEmpty()) {
+ QQmlError error;
+ error.setDescription(
+ QQmlImportDatabase::tr("Cannot resolve URL for import \"%1\"").arg(uri));
+ error.setUrl(m_baseUrl);
+ errors->prepend(error);
+ return QTypeRevision();
+ }
+
if (!url.endsWith(Slash) && !url.endsWith(Backslash))
url += Slash;
@@ -1531,72 +1331,96 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
// if the implicit import has already been explicitly added, otherwise we can run into issues
// with duplicate imports. However remember that we attempted to add this as implicit import, to
// allow for the loading of internal types.
- if (isImplicitImport) {
+ if (precedence >= QQmlImportInstance::Implicit) {
for (QList<QQmlImportInstance *>::const_iterator it = nameSpace->imports.constBegin();
it != nameSpace->imports.constEnd(); ++it) {
if ((*it)->url == url) {
(*it)->implicitlyImported = true;
- return true;
+ return validVersion(version);
}
}
}
- QQmlImportInstance *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport);
- Q_ASSERT(inserted);
-
- if (!incomplete && !qmldirIdentifier.isEmpty()) {
+ if (!(flags & QQmlImports::ImportIncomplete) && !qmldirIdentifier.isEmpty()) {
QQmlTypeLoaderQmldirContent qmldir;
- if (!getQmldirContent(qmldirIdentifier, importUri, &qmldir, errors))
- return false;
+ if (!getQmldirContent(typeLoader, qmldirIdentifier, importUri, &qmldir, errors))
+ return QTypeRevision();
if (qmldir.hasContent()) {
- if (!importExtension(qmldir.pluginLocation(), importUri, vmaj, vmin, database, qmldir, errors))
- return false;
+ // Prefer the qmldir URI. Unless it doesn't exist.
+ const QString qmldirUri = qmldir.typeNamespace();
+ if (!qmldirUri.isEmpty())
+ importUri = qmldirUri;
+
+ QQmlImportInstance *inserted = addImportToNamespace(
+ nameSpace, importUri, url, version, QV4::CompiledData::Import::ImportFile,
+ errors, precedence);
+ Q_ASSERT(inserted);
+
+ version = importExtension(typeLoader, importUri, version, &qmldir, errors);
+ if (!version.isValid())
+ return QTypeRevision();
+
+ if (qmldir.hasRedirection())
+ url = redirectQmldirContent(typeLoader, &qmldir);
if (!inserted->setQmldirContent(url, qmldir, nameSpace, errors))
- return false;
+ return QTypeRevision();
+
+ return validVersion(version);
}
}
- return true;
+ QQmlImportInstance *inserted = addImportToNamespace(
+ nameSpace, importUri, url, version, QV4::CompiledData::Import::ImportFile,
+ errors, precedence);
+ Q_ASSERT(inserted);
+ return validVersion(version);
}
-bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString &prefix,
- const QString &qmldirIdentifier, const QString& qmldirUrl,
- QQmlImportDatabase *database, QList<QQmlError> *errors)
+QTypeRevision QQmlImports::updateQmldirContent(
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ const QString &qmldirIdentifier, const QString &qmldirUrl, QList<QQmlError> *errors)
{
+ Q_ASSERT(typeLoader);
+ Q_ASSERT(errors);
+
+ qDebug(lcQmlImport)
+ << "updateQmldirContent:" << qPrintable(baseUrl().toString())
+ << uri << "to" << qmldirUrl << "as" << prefix;
+
QQmlImportNamespace *nameSpace = importNamespace(prefix);
Q_ASSERT(nameSpace);
if (QQmlImportInstance *import = nameSpace->findImport(uri)) {
QQmlTypeLoaderQmldirContent qmldir;
- if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
- return false;
+ if (!getQmldirContent(typeLoader, qmldirIdentifier, uri, &qmldir, errors))
+ return QTypeRevision();
if (qmldir.hasContent()) {
- int vmaj = import->majversion;
- int vmin = import->minversion;
- if (!importExtension(qmldir.pluginLocation(), uri, vmaj, vmin, database, qmldir, errors))
- return false;
+ QTypeRevision version = importExtension(
+ typeLoader, uri, import->version, &qmldir, errors);
+ if (!version.isValid())
+ return QTypeRevision();
+
+ const QString resolvedUrl = qmldir.hasRedirection()
+ ? redirectQmldirContent(typeLoader, &qmldir)
+ : qmldirUrl;
- if (import->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors)) {
+ if (import->setQmldirContent(resolvedUrl, qmldir, nameSpace, errors)) {
if (import->qmlDirComponents.isEmpty() && import->qmlDirScripts.isEmpty()) {
// The implicit import qmldir can be empty, and plugins have no extra versions
- if (uri != QLatin1String(".") && !QQmlMetaType::isModule(uri, vmaj, vmin)) {
- QQmlError error;
- if (QQmlMetaType::isAnyModule(uri))
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin));
- else
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri));
- errors->prepend(error);
- return false;
+ if (uri != QLatin1String(".") && !QQmlMetaType::matchingModuleVersion(uri, version).isValid()) {
+ errors->prepend(moduleNotFoundError(uri, relevantVersion(uri, version)));
+ return QTypeRevision();
}
- } else if ((vmaj >= 0) && (vmin >= 0)) {
+ } else {
// Verify that the qmldir content is valid for this version
- if (!validateQmldirVersion(qmldir, uri, vmaj, vmin, errors))
- return false;
+ version = matchingQmldirVersion(qmldir, uri, version, errors);
+ if (!version.isValid())
+ return QTypeRevision();
}
- return true;
+ return validVersion(version);
}
}
}
@@ -1607,10 +1431,11 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString &
errors->prepend(error);
}
- return false;
+ return QTypeRevision();
}
/*!
+ \fn QQmlImports::addImplicitImport(QQmlTypeLoader *typeLoader, QString *localQmldir, QList<QQmlError> *errors)
\internal
Adds an implicit "." file import. This is equivalent to calling addFileImport(), but error
@@ -1618,96 +1443,20 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString &
Additionally, this will add the import with lowest instead of highest precedence.
*/
-bool QQmlImports::addImplicitImport(QQmlImportDatabase *importDb, QList<QQmlError> *errors)
-{
- Q_ASSERT(errors);
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString())
- << ")::addImplicitImport";
-
- bool incomplete = !isLocal(baseUrl());
- return d->addFileImport(QLatin1String("."), QString(), -1, -1, true, incomplete, importDb, errors);
-}
/*!
- \internal
-
- Adds information to \a imports such that subsequent calls to resolveType()
- will resolve types qualified by \a prefix by considering types found at the given \a uri.
-
- The uri is either a directory (if importType is FileImport), or a URI resolved using paths
- added via addImportPath() (if importType is LibraryImport).
-
- The \a prefix may be empty, in which case the import location is considered for
- unqualified types.
-
- The base URL must already have been set with Import::setBaseUrl().
-
- Optionally, the url the import resolved to can be returned by providing the url parameter.
- Not all imports will result in an output url being generated, in which case the url will
- be set to an empty string.
-
- Returns true on success, and false on failure. In case of failure, the errors array will
- filled appropriately.
-*/
-bool QQmlImports::addFileImport(QQmlImportDatabase *importDb,
- const QString& uri, const QString& prefix, int vmaj, int vmin,
- bool incomplete, QList<QQmlError> *errors)
-{
- Q_ASSERT(importDb);
- Q_ASSERT(errors);
-
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::addFileImport: "
- << uri << ' ' << vmaj << '.' << vmin << " as " << prefix;
-
- return d->addFileImport(uri, prefix, vmaj, vmin, false, incomplete, importDb, errors);
-}
-
-bool QQmlImports::addLibraryImport(QQmlImportDatabase *importDb,
- const QString &uri, const QString &prefix, int vmaj, int vmin,
- const QString &qmldirIdentifier, const QString& qmldirUrl, bool incomplete, QList<QQmlError> *errors)
-{
- Q_ASSERT(importDb);
- Q_ASSERT(errors);
-
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::addLibraryImport: "
- << uri << ' ' << vmaj << '.' << vmin << " as " << prefix;
-
- return d->addLibraryImport(uri, prefix, vmaj, vmin, qmldirIdentifier, qmldirUrl, incomplete, importDb, errors);
-}
-
-bool QQmlImports::updateQmldirContent(QQmlImportDatabase *importDb,
- const QString &uri, const QString &prefix,
- const QString &qmldirIdentifier, const QString& qmldirUrl, QList<QQmlError> *errors)
-{
- Q_ASSERT(importDb);
- Q_ASSERT(errors);
-
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::updateQmldirContent: "
- << uri << " to " << qmldirUrl << " as " << prefix;
-
- return d->updateQmldirContent(uri, prefix, qmldirIdentifier, qmldirUrl, importDb, errors);
-}
-
-bool QQmlImports::locateQmldir(QQmlImportDatabase *importDb,
- const QString& uri, int vmaj, int vmin,
- QString *qmldirFilePath, QString *url)
-{
- return d->locateQmldir(uri, vmaj, vmin, importDb, qmldirFilePath, url);
-}
-
-bool QQmlImports::isLocal(const QString &url)
-{
- return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
-}
-
-bool QQmlImports::isLocal(const QUrl &url)
-{
- return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
+ \internal
+ */
+bool QQmlImports::addInlineComponentImport(QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl)
+{
+ importInstance->url = importUrl.toString();
+ importInstance->uri = name;
+ importInstance->isInlineComponent = true;
+ importInstance->version = QTypeRevision::zero();
+ m_unqualifiedset.imports.push_back(importInstance);
+ m_unqualifiedset.setNeedsSorting(true);
+ return true;
}
QUrl QQmlImports::urlFromLocalFileOrQrcOrUrl(const QString &file)
@@ -1715,7 +1464,7 @@ QUrl QQmlImports::urlFromLocalFileOrQrcOrUrl(const QString &file)
QUrl url(QLatin1String(file.at(0) == Colon ? "qrc" : "") + file);
// We don't support single character schemes as those conflict with windows drive letters.
- if (url.scheme().length() < 2)
+ if (url.scheme().size() < 2)
return QUrl::fromLocalFile(file);
return url;
}
@@ -1725,6 +1474,29 @@ void QQmlImports::setDesignerSupportRequired(bool b)
designerSupportRequired = b;
}
+static QStringList parseEnvPath(const QString &envImportPath)
+{
+ if (QDir::listSeparator() == u':') {
+ // Double colons are interpreted as separator + resource path.
+ QStringList paths = envImportPath.split(u':');
+ bool wasEmpty = false;
+ for (auto it = paths.begin(); it != paths.end();) {
+ if (it->isEmpty()) {
+ wasEmpty = true;
+ it = paths.erase(it);
+ } else {
+ if (wasEmpty) {
+ it->prepend(u':');
+ wasEmpty = false;
+ }
+ ++it;
+ }
+ }
+ return paths;
+ } else {
+ return envImportPath.split(QDir::listSeparator(), Qt::SkipEmptyParts);
+ }
+}
/*!
\class QQmlImportDatabase
@@ -1735,169 +1507,64 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
: engine(e)
{
filePluginPath << QLatin1String(".");
- // Search order is applicationDirPath(), qrc:/qt-project.org/imports, $QML2_IMPORT_PATH, QLibraryInfo::Qml2ImportsPath
-
- QString installImportsPath = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath);
+ // Search order is:
+ // 1. android or macos specific bundle paths.
+ // 2. applicationDirPath()
+ // 3. qrc:/qt-project.org/imports
+ // 4. qrc:/qt/qml
+ // 5. $QML2_IMPORT_PATH
+ // 6. $QML_IMPORT_PATH
+ // 7. QLibraryInfo::QmlImportsPath
+
+ QString installImportsPath = QLibraryInfo::path(QLibraryInfo::QmlImportsPath);
addImportPath(installImportsPath);
+ auto addEnvImportPath = [this](const char *var) {
+ if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(var))) {
+ const QStringList paths = parseEnvPath(qEnvironmentVariable(var));
+ for (int ii = paths.size() - 1; ii >= 0; --ii)
+ addImportPath(paths.at(ii));
+ }
+ };
+
// env import paths
- if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QML2_IMPORT_PATH"))) {
- const QString envImportPath = qEnvironmentVariable("QML2_IMPORT_PATH");
-#if defined(Q_OS_WIN)
- QLatin1Char pathSep(';');
-#else
- QLatin1Char pathSep(':');
-#endif
- QStringList paths = envImportPath.split(pathSep, QString::SkipEmptyParts);
- for (int ii = paths.count() - 1; ii >= 0; --ii)
- addImportPath(paths.at(ii));
- }
+ addEnvImportPath("QML_IMPORT_PATH");
+ addEnvImportPath("QML2_IMPORT_PATH");
+ addImportPath(QStringLiteral("qrc:/qt/qml"));
addImportPath(QStringLiteral("qrc:/qt-project.org/imports"));
addImportPath(QCoreApplication::applicationDirPath());
-#if defined(Q_OS_ANDROID)
- addImportPath(QStringLiteral("qrc:/android_rcc_bundle/qml"));
- if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QT_BUNDLED_LIBS_PATH"))) {
- const QString envImportPath = qEnvironmentVariable("QT_BUNDLED_LIBS_PATH");
- QLatin1Char pathSep(':');
- QStringList paths = envImportPath.split(pathSep, QString::SkipEmptyParts);
- for (int ii = paths.count() - 1; ii >= 0; --ii)
- addPluginPath(paths.at(ii));
- }
-#endif
-}
-
-QQmlImportDatabase::~QQmlImportDatabase()
-{
- clearDirCache();
-}
-
-/*!
- \internal
-
- Returns the result of the merge of \a baseName with \a path, \a suffixes, and \a prefix.
- The \a prefix must contain the dot.
-
- \a qmldirPath is the location of the qmldir file.
- */
-QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
- const QString &qmldirPath,
- const QString &qmldirPluginPath,
- const QString &baseName, const QStringList &suffixes,
- const QString &prefix)
-{
- QStringList searchPaths = filePluginPath;
- bool qmldirPluginPathIsRelative = QDir::isRelativePath(qmldirPluginPath);
- if (!qmldirPluginPathIsRelative)
- searchPaths.prepend(qmldirPluginPath);
-
- for (const QString &pluginPath : qAsConst(searchPaths)) {
- QString resolvedPath;
- if (pluginPath == QLatin1String(".")) {
- if (qmldirPluginPathIsRelative && !qmldirPluginPath.isEmpty() && qmldirPluginPath != QLatin1String("."))
- resolvedPath = QDir::cleanPath(qmldirPath + Slash + qmldirPluginPath);
- else
- resolvedPath = qmldirPath;
- } else {
- if (QDir::isRelativePath(pluginPath))
- resolvedPath = QDir::cleanPath(qmldirPath + Slash + pluginPath);
- else
- resolvedPath = pluginPath;
- }
-
- // hack for resources, should probably go away
- if (resolvedPath.startsWith(Colon))
- resolvedPath = QCoreApplication::applicationDirPath();
-
- if (!resolvedPath.endsWith(Slash))
- resolvedPath += Slash;
-#if defined(Q_OS_ANDROID)
- if (qmldirPath.size() > 25 && qmldirPath.at(0) == QLatin1Char(':') && qmldirPath.at(1) == QLatin1Char('/') &&
- qmldirPath.startsWith(QStringLiteral(":/android_rcc_bundle/qml/"), Qt::CaseInsensitive)) {
- QString pluginName = qmldirPath.mid(21) + Slash + baseName;
- auto bundledPath = resolvedPath + QLatin1String("lib") + pluginName.replace(QLatin1Char('/'), QLatin1Char('_'));
- for (const QString &suffix : suffixes) {
- const QString absolutePath = typeLoader->absoluteFilePath(bundledPath + suffix);
- if (!absolutePath.isEmpty())
- return absolutePath;
- }
- }
-#endif
- resolvedPath += prefix + baseName;
- for (const QString &suffix : suffixes) {
- const QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + suffix);
- if (!absolutePath.isEmpty())
- return absolutePath;
+ auto addEnvPluginPath = [this](const char *var) {
+ if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(var))) {
+ const QStringList paths = parseEnvPath(qEnvironmentVariable(var));
+ for (int ii = paths.size() - 1; ii >= 0; --ii)
+ addPluginPath(paths.at(ii));
}
- }
-
- if (qmlImportTrace())
- qDebug() << "QQmlImportDatabase::resolvePlugin: Could not resolve plugin" << baseName
- << "in" << qmldirPath;
-
- return QString();
-}
-
-/*!
- \internal
-
- Returns the result of the merge of \a baseName with \a dir and the platform suffix.
-
- \table
- \header \li Platform \li Valid suffixes
- \row \li Windows \li \c .dll
- \row \li Unix/Linux \li \c .so
- \row \li \macos \li \c .dylib, \c .bundle, \c .so
- \endtable
-
- Version number on unix are ignored.
-*/
-QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
- const QString &qmldirPath, const QString &qmldirPluginPath,
- const QString &baseName)
-{
-#if defined(Q_OS_WIN)
- static const QString prefix;
- static const QStringList suffixes = {
-# ifdef QT_DEBUG
- QLatin1String("d.dll"), // try a qmake-style debug build first
-# endif
- QLatin1String(".dll")
- };
-#elif defined(Q_OS_DARWIN)
- static const QString prefix = QLatin1String("lib");
- static const QStringList suffixes = {
-# ifdef QT_DEBUG
- QLatin1String("_debug.dylib"), // try a qmake-style debug build first
- QLatin1String(".dylib"),
-# else
- QLatin1String(".dylib"),
- QLatin1String("_debug.dylib"), // try a qmake-style debug build after
-# endif
- QLatin1String(".so"),
- QLatin1String(".bundle")
- };
-#else // Unix
- static const QString prefix = QLatin1String("lib");
- static const QStringList suffixes = {
-# if defined(Q_OS_ANDROID)
- QStringLiteral(LIBS_SUFFIX),
-# endif
- QLatin1String(".so")
-
};
-#endif
-
- return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, suffixes, prefix);
-}
-/*!
- \internal
-*/
-QStringList QQmlImportDatabase::pluginPathList() const
-{
- return filePluginPath;
+ addEnvPluginPath("QML_PLUGIN_PATH");
+#if defined(Q_OS_ANDROID)
+ addImportPath(QStringLiteral("qrc:/android_rcc_bundle/qml"));
+ addEnvPluginPath("QT_BUNDLED_LIBS_PATH");
+#elif defined(Q_OS_MACOS)
+ // Add the main bundle's Resources/qml directory as an import path, so that QML modules are
+ // found successfully when running the app from its build dir.
+ // This is where macdeployqt and our CMake deployment logic puts Qt and user qmldir files.
+ if (CFBundleRef bundleRef = CFBundleGetMainBundle()) {
+ if (QCFType<CFURLRef> urlRef = CFBundleCopyResourceURL(
+ bundleRef,
+ QCFString(QLatin1String("qml")), 0, 0)) {
+ if (QCFType<CFURLRef> absoluteUrlRef = CFURLCopyAbsoluteURL(urlRef)) {
+ if (QCFString path = CFURLCopyFileSystemPath(absoluteUrlRef, kCFURLPOSIXPathStyle)) {
+ if (QFile::exists(path)) {
+ addImportPath(QDir(path).canonicalPath());
+ }
+ }
+ }
+ }
+ }
+#endif // Q_OS_DARWIN
}
/*!
@@ -1905,9 +1572,7 @@ QStringList QQmlImportDatabase::pluginPathList() const
*/
void QQmlImportDatabase::setPluginPathList(const QStringList &paths)
{
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImportDatabase::setPluginPathList: " << paths;
-
+ qCDebug(lcQmlImport) << "setPluginPathList:" << paths;
filePluginPath = paths;
}
@@ -1916,12 +1581,11 @@ void QQmlImportDatabase::setPluginPathList(const QStringList &paths)
*/
void QQmlImportDatabase::addPluginPath(const QString& path)
{
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImportDatabase::addPluginPath: " << path;
+ qCDebug(lcQmlImport) << "addPluginPath:" << path;
QUrl url = QUrl(path);
if (url.isRelative() || url.scheme() == QLatin1String("file")
- || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
+ || (url.scheme().size() == 1 && QFile::exists(path)) ) { // windows path
QDir dir = QDir(path);
filePluginPath.prepend(dir.canonicalPath());
} else {
@@ -1929,13 +1593,17 @@ void QQmlImportDatabase::addPluginPath(const QString& path)
}
}
+QString QQmlImportDatabase::absoluteFilePath(const QString &path) const
+{
+ return QQmlEnginePrivate::get(engine)->typeLoader.absoluteFilePath(path);
+}
+
/*!
\internal
*/
void QQmlImportDatabase::addImportPath(const QString& path)
{
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImportDatabase::addImportPath: " << path;
+ qCDebug(lcQmlImport) << "addImportPath:" << path;
if (path.isEmpty())
return;
@@ -1951,7 +1619,7 @@ void QQmlImportDatabase::addImportPath(const QString& path)
cPath = QLatin1String("qrc") + path;
cPath.replace(Backslash, Slash);
} else if (url.isRelative() ||
- (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path
+ (url.scheme().size() == 1 && QFile::exists(path)) ) { // windows path
QDir dir = QDir(path);
cPath = dir.canonicalPath();
} else {
@@ -1959,9 +1627,12 @@ void QQmlImportDatabase::addImportPath(const QString& path)
cPath.replace(Backslash, Slash);
}
- if (!cPath.isEmpty()
- && !fileImportPath.contains(cPath))
- fileImportPath.prepend(cPath);
+ if (!cPath.isEmpty()) {
+ if (fileImportPath.contains(cPath))
+ fileImportPath.move(fileImportPath.indexOf(cPath), 0);
+ else
+ fileImportPath.prepend(cPath);
+ }
}
/*!
@@ -1987,8 +1658,7 @@ QStringList QQmlImportDatabase::importPathList(PathType type) const
*/
void QQmlImportDatabase::setImportPathList(const QStringList &paths)
{
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImportDatabase::setImportPathList: " << paths;
+ qCDebug(lcQmlImport) << "setImportPathList:" << paths;
fileImportPath.clear();
for (auto it = paths.crbegin(); it != paths.crend(); ++it)
@@ -2001,181 +1671,37 @@ void QQmlImportDatabase::setImportPathList(const QStringList &paths)
/*!
\internal
*/
-static bool registerPluginTypes(QObject *instance, const QString &basePath, const QString &uri,
- const QString &typeNamespace, int vmaj, QList<QQmlError> *errors)
+QTypeRevision QQmlImportDatabase::lockModule(const QString &uri, const QString &typeNamespace,
+ QTypeRevision version, QList<QQmlError> *errors)
{
- if (qmlImportTrace())
- qDebug().nospace() << "QQmlImportDatabase::registerPluginTypes: " << uri << " from " << basePath;
-
- if (!QQmlMetaType::registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors))
- return false;
-
- if (vmaj >= 0 && !typeNamespace.isEmpty() && !QQmlMetaType::protectModule(uri, vmaj)) {
- QQmlError error;
- error.setDescription(
- QString::fromLatin1("Cannot protect module %1 %2 as it was never registered")
- .arg(uri).arg(vmaj));
- errors->append(error);
- return false;
+ if (!version.hasMajorVersion()) {
+ version = QQmlMetaType::latestModuleVersion(uri);
+ if (!version.isValid())
+ errors->prepend(moduleNotFoundError(uri, version));
}
-
- return true;
-}
-
-/*!
- \internal
-*/
-bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &basePath,
- const QString &uri, const QString &typeNamespace, int vmaj, QList<QQmlError> *errors)
-{
- // Dynamic plugins are differentiated by their filepath. For static plugins we
- // don't have that information so we use their address as key instead.
- const QString uniquePluginID = QString::asprintf("%p", instance);
- {
- StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
- QMutexLocker lock(&plugins->mutex);
-
- // Plugin types are global across all engines and should only be
- // registered once. But each engine still needs to be initialized.
- bool typesRegistered = plugins->contains(uniquePluginID);
-
- if (typesRegistered) {
- Q_ASSERT_X(plugins->value(uniquePluginID).uri == uri,
- "QQmlImportDatabase::importStaticPlugin",
- "Internal error: Static plugin imported previously with different uri");
- } else {
- RegisteredPlugin plugin;
- plugin.uri = uri;
- plugin.loader = nullptr;
- plugins->insert(uniquePluginID, plugin);
-
- if (!registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors))
- return false;
- }
-
- // Release the lock on plugins early as we're done with the global part. Releasing the lock
- // also allows other QML loader threads to acquire the lock while this thread is blocking
- // in the initializeEngine call to the gui thread (which in turn may be busy waiting for
- // other QML loader threads and thus not process the initializeEngine call).
- }
-
- if (!initializedPlugins.contains(uniquePluginID))
- finalizePlugin(instance, uniquePluginID, uri);
-
- return true;
-}
-
-#if QT_CONFIG(library)
-/*!
- \internal
-*/
-bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QString &uri,
- const QString &typeNamespace, int vmaj, QList<QQmlError> *errors)
-{
- QFileInfo fileInfo(filePath);
- const QString absoluteFilePath = fileInfo.absoluteFilePath();
-
- QObject *instance = nullptr;
- bool engineInitialized = initializedPlugins.contains(absoluteFilePath);
- {
- StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
- QMutexLocker lock(&plugins->mutex);
- bool typesRegistered = plugins->contains(absoluteFilePath);
-
- if (typesRegistered) {
- Q_ASSERT_X(plugins->value(absoluteFilePath).uri == uri,
- "QQmlImportDatabase::importDynamicPlugin",
- "Internal error: Plugin imported previously with different uri");
- }
-
- if (!engineInitialized || !typesRegistered) {
- if (!QQml_isFileCaseCorrect(absoluteFilePath)) {
- if (errors) {
- QQmlError error;
- error.setDescription(tr("File name case mismatch for \"%1\"").arg(absoluteFilePath));
- errors->prepend(error);
- }
- return false;
- }
-
- QPluginLoader* loader = nullptr;
- if (!typesRegistered) {
- loader = new QPluginLoader(absoluteFilePath);
-
- if (!loader->load()) {
- if (errors) {
- QQmlError error;
- error.setDescription(loader->errorString());
- errors->prepend(error);
- }
- delete loader;
- return false;
- }
- } else {
- loader = plugins->value(absoluteFilePath).loader;
- }
-
- instance = loader->instance();
-
- if (!typesRegistered) {
- RegisteredPlugin plugin;
- plugin.uri = uri;
- plugin.loader = loader;
- plugins->insert(absoluteFilePath, plugin);
-
- // Continue with shared code path for dynamic and static plugins:
- if (!registerPluginTypes(instance, fileInfo.absolutePath(), uri, typeNamespace, vmaj, errors))
- return false;
- }
- }
-
- // Release the lock on plugins early as we're done with the global part. Releasing the lock
- // also allows other QML loader threads to acquire the lock while this thread is blocking
- // in the initializeEngine call to the gui thread (which in turn may be busy waiting for
- // other QML loader threads and thus not process the initializeEngine call).
+ if (version.hasMajorVersion() && !typeNamespace.isEmpty()
+ && !QQmlMetaType::protectModule(uri, version, true)) {
+ // Not being able to protect the module means there are not types registered for it,
+ // means the plugin we loaded didn't provide any, means we didn't find the module.
+ // We output the generic error message as depending on the load order of imports we may
+ // hit this path or another one that only figures "plugin is already loaded but module
+ // unavailable" and doesn't try to protect it anymore.
+ errors->prepend(moduleNotFoundError(uri, version));
+ return QTypeRevision();
}
- if (!engineInitialized)
- finalizePlugin(instance, absoluteFilePath, uri);
-
- return true;
+ return version;
}
-bool QQmlImportDatabase::removeDynamicPlugin(const QString &filePath)
+bool QQmlImportDatabase::removeDynamicPlugin(const QString &pluginId)
{
- StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
- QMutexLocker lock(&plugins->mutex);
-
- auto it = plugins->find(QFileInfo(filePath).absoluteFilePath());
- if (it == plugins->end())
- return false;
-
- QPluginLoader *loader = it->loader;
- if (!loader)
- return false;
-
- if (!loader->unload()) {
- qWarning("Unloading %s failed: %s", qPrintable(it->uri),
- qPrintable(loader->errorString()));
- }
-
- delete loader;
- plugins->erase(it);
- return true;
+ return QQmlPluginImporter::removePlugin(pluginId);
}
QStringList QQmlImportDatabase::dynamicPlugins() const
{
- StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
- QMutexLocker lock(&plugins->mutex);
- QStringList results;
- for (auto it = plugins->constBegin(), end = plugins->constEnd(); it != end; ++it) {
- if (it->loader != nullptr)
- results.append(it.key());
- }
- return results;
+ return QQmlPluginImporter::plugins();
}
-#endif // QT_CONFIG(library)
void QQmlImportDatabase::clearDirCache()
{
@@ -2193,20 +1719,4 @@ void QQmlImportDatabase::clearDirCache()
qmldirCache.clear();
}
-void QQmlImportDatabase::finalizePlugin(QObject *instance, const QString &path, const QString &uri)
-{
- // The plugin's per-engine initialization does not need lock protection, as this function is
- // only called from the engine specific loader thread and importDynamicPlugin as well as
- // importStaticPlugin are the only places of access.
-
- initializedPlugins.insert(path);
- if (auto *extensionIface = qobject_cast<QQmlExtensionInterface *>(instance)) {
- QQmlEnginePrivate::get(engine)->typeLoader.initializeEngine(
- extensionIface, uri.toUtf8().constData());
- } else if (auto *engineIface = qobject_cast<QQmlEngineExtensionInterface *>(instance)) {
- QQmlEnginePrivate::get(engine)->typeLoader.initializeEngine(
- engineIface, uri.toUtf8().constData());
- }
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index 30d7c56a3e..ef9b4b3422 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -1,53 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLIMPORT_P_H
#define QQMLIMPORT_P_H
#include <QtCore/qurl.h>
#include <QtCore/qcoreapplication.h>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qset.h>
#include <QtCore/qstringlist.h>
+#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlerror.h>
+#include <QtQml/qqmlfile.h>
#include <private/qqmldirparser_p.h>
#include <private/qqmltype_p.h>
#include <private/qstringhash_p.h>
+#include <private/qfieldlist_p.h>
//
// W A R N I N G
@@ -66,10 +34,12 @@ class QQmlTypeNameCache;
class QQmlEngine;
class QDir;
class QQmlImportNamespace;
-class QQmlImportsPrivate;
class QQmlImportDatabase;
class QQmlTypeLoader;
class QQmlTypeLoaderQmldirContent;
+class QTypeRevision;
+
+const QLoggingCategory &lcQmlImport();
namespace QQmlImport {
enum RecursionRestriction { PreventRecursion, AllowRecursion };
@@ -77,24 +47,36 @@ namespace QQmlImport {
struct QQmlImportInstance
{
+ enum Precedence {
+ Lowest = std::numeric_limits<quint8>::max(),
+ Implicit = Lowest / 2,
+ Highest = 0,
+ };
+
QString uri; // e.g. QtQuick
QString url; // the base path of the import
- QString localDirectoryPath; // the base path of the import if it's a local file
- int majversion; // the major version imported
- int minversion; // the minor version imported
+ QTypeRevision version; // the version imported
+
bool isLibrary; // true means that this is not a file import
+
+ // not covered by precedence. You can set a component as implicitly imported after the fact.
bool implicitlyImported = false;
+ bool isInlineComponent = false;
+
+ quint8 precedence = 0;
+
QQmlDirComponents qmlDirComponents; // a copy of the components listed in the qmldir
QQmlDirScripts qmlDirScripts; // a copy of the scripts in the qmldir
bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent &qmldir,
QQmlImportNamespace *nameSpace, QList<QQmlError> *errors);
- static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin);
+ static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts,
+ QTypeRevision version);
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
- int *vmajor, int *vminor, QQmlType* type_return,
- QString *base = nullptr, bool *typeRecursionDetected = nullptr,
+ QTypeRevision *version_return, QQmlType* type_return,
+ const QString *base = nullptr, bool *typeRecursionDetected = nullptr,
QQmlType::RegistrationType = QQmlType::AnyRegistrationType,
QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion,
QList<QQmlError> *errors = nullptr) const;
@@ -111,62 +93,85 @@ public:
QQmlImportInstance *findImport(const QString &uri) const;
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
- int *vmajor, int *vminor, QQmlType* type_return,
- QString *base = nullptr, QList<QQmlError> *errors = nullptr,
+ QTypeRevision *version_return, QQmlType* type_return,
+ const QString *base = nullptr, QList<QQmlError> *errors = nullptr,
QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
- QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion);
+ bool *typeRecursionDeteced = nullptr);
// Prefix when used as a qualified import. Otherwise empty.
QHashedString prefix;
- // Used by QQmlImportsPrivate::qualifiedSets
- QQmlImportNamespace *nextNamespace;
+ // Used by QQmlImports::m_qualifiedSets
+ // set to this in unqualifiedSet to indicate that the lists of imports needs
+ // to be sorted when an inline component import was added
+ // We can't use flag pointer, as that does not work with QFieldList
+ QQmlImportNamespace *nextNamespace = nullptr;
+ bool needsSorting() const { return nextNamespace == this; }
+ void setNeedsSorting(bool needsSorting)
+ {
+ Q_ASSERT(nextNamespace == this || nextNamespace == nullptr);
+ nextNamespace = needsSorting ? this : nullptr;
+ }
};
-class Q_QML_PRIVATE_EXPORT QQmlImports
+class Q_QML_EXPORT QQmlImports final : public QQmlRefCounted<QQmlImports>
{
+ Q_DISABLE_COPY_MOVE(QQmlImports)
public:
enum ImportVersion { FullyVersioned, PartiallyVersioned, Unversioned };
- QQmlImports(QQmlTypeLoader *);
- QQmlImports(const QQmlImports &);
- ~QQmlImports();
- QQmlImports &operator=(const QQmlImports &);
+ enum ImportFlag : quint8 {
+ ImportNoFlag = 0x0,
+ ImportIncomplete = 0x1,
+ };
+ Q_DECLARE_FLAGS(ImportFlags, ImportFlag)
+
+ QQmlImports() = default;
+ ~QQmlImports()
+ {
+ while (QQmlImportNamespace *ns = m_qualifiedSets.takeFirst())
+ delete ns;
+ }
void setBaseUrl(const QUrl &url, const QString &urlString = QString());
- QUrl baseUrl() const;
+ QUrl baseUrl() const { return m_baseUrl; }
- bool resolveType(const QHashedStringRef &type,
- QQmlType *type_return,
- int *version_major, int *version_minor,
- QQmlImportNamespace **ns_return,
- QList<QQmlError> *errors = nullptr,
- QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
- QQmlImport::RecursionRestriction recursionRestriction
- = QQmlImport::PreventRecursion) const;
- bool resolveType(QQmlImportNamespace *,
- const QHashedStringRef& type,
- QQmlType *type_return, int *version_major, int *version_minor,
- QQmlType::RegistrationType registrationType
- = QQmlType::AnyRegistrationType) const;
+ bool resolveType(
+ QQmlTypeLoader *typeLoader, const QHashedStringRef &type, QQmlType *type_return,
+ QTypeRevision *version_return, QQmlImportNamespace **ns_return,
+ QList<QQmlError> *errors = nullptr,
+ QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
+ bool *typeRecursionDetected = nullptr) const;
+
+ QTypeRevision addImplicitImport(
+ QQmlTypeLoader *typeLoader, QString *localQmldir, QList<QQmlError> *errors)
+ {
+ Q_ASSERT(errors);
+ qCDebug(lcQmlImport) << "addImplicitImport:" << qPrintable(baseUrl().toString());
- bool addImplicitImport(QQmlImportDatabase *importDb, QList<QQmlError> *errors);
+ const ImportFlags flags =
+ ImportFlags(!isLocal(baseUrl()) ? ImportIncomplete : ImportNoFlag);
+ return addFileImport(
+ typeLoader, QLatin1String("."), QString(), QTypeRevision(), flags,
+ QQmlImportInstance::Implicit, localQmldir, errors);
+ }
- bool addFileImport(QQmlImportDatabase *,
- const QString& uri, const QString& prefix, int vmaj, int vmin, bool incomplete,
- QList<QQmlError> *errors);
+ bool addInlineComponentImport(
+ QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl);
- bool addLibraryImport(QQmlImportDatabase *importDb,
- const QString &uri, const QString &prefix, int vmaj, int vmin,
- const QString &qmldirIdentifier, const QString &qmldirUrl, bool incomplete, QList<QQmlError> *errors);
+ QTypeRevision addFileImport(
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ QTypeRevision version, ImportFlags flags, quint16 precedence, QString *localQmldir,
+ QList<QQmlError> *errors);
- bool updateQmldirContent(QQmlImportDatabase *importDb,
- const QString &uri, const QString &prefix,
- const QString &qmldirIdentifier, const QString &qmldirUrl, QList<QQmlError> *errors);
+ QTypeRevision addLibraryImport(
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ QTypeRevision version, const QString &qmldirIdentifier, const QString &qmldirUrl,
+ ImportFlags flags, quint16 precedence, QList<QQmlError> *errors);
- bool locateQmldir(QQmlImportDatabase *,
- const QString &uri, int vmaj, int vmin,
- QString *qmldirFilePath, QString *url);
+ QTypeRevision updateQmldirContent(
+ QQmlTypeLoader *typeLoader, const QString &uri, const QString &prefix,
+ const QString &qmldirIdentifier, const QString &qmldirUrl, QList<QQmlError> *errors);
void populateCache(QQmlTypeNameCache *cache) const;
@@ -183,83 +188,261 @@ public:
{
QString typeName;
QString prefix;
- int majorVersion;
- int minorVersion;
+ QTypeRevision version;
};
QList<CompositeSingletonReference> resolvedCompositeSingletons() const;
- static QStringList completeQmldirPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin);
- static QString versionString(int vmaj, int vmin, ImportVersion version);
+ static QStringList completeQmldirPaths(
+ const QString &uri, const QStringList &basePaths, QTypeRevision version);
+
+ static QString versionString(QTypeRevision version, ImportVersion importVersion);
+
+ static bool isLocal(const QString &url)
+ {
+ return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
+ }
+
+ static bool isLocal(const QUrl &url)
+ {
+ return !QQmlFile::urlToLocalFileOrQrc(url).isEmpty();
+ }
- static bool isLocal(const QString &url);
- static bool isLocal(const QUrl &url);
static QUrl urlFromLocalFileOrQrcOrUrl(const QString &);
static void setDesignerSupportRequired(bool b);
+ static QTypeRevision validVersion(QTypeRevision version = QTypeRevision());
+
private:
friend class QQmlImportDatabase;
- QQmlImportsPrivate *d;
+
+ QQmlImportNamespace *importNamespace(const QString &prefix);
+
+ bool resolveType(
+ QQmlTypeLoader *typeLoader, const QHashedStringRef &type, QTypeRevision *version_return,
+ QQmlType *type_return, QList<QQmlError> *errors,
+ QQmlType::RegistrationType registrationType,
+ bool *typeRecursionDetected = nullptr) const;
+
+ QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &) const;
+
+ static QTypeRevision matchingQmldirVersion(
+ const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri,
+ QTypeRevision version, QList<QQmlError> *errors);
+
+ QTypeRevision importExtension(
+ QQmlTypeLoader *typeLoader, const QString &uri, QTypeRevision version,
+ const QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors);
+
+ QString redirectQmldirContent(QQmlTypeLoader *typeLoader, QQmlTypeLoaderQmldirContent *qmldir);
+
+ bool getQmldirContent(
+ QQmlTypeLoader *typeLoader, const QString &qmldirIdentifier, const QString &uri,
+ QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors);
+
+ QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
+
+ QUrl m_baseUrl;
+ QString m_base;
+
+ // storage of data related to imports without a namespace
+ // TODO: This needs to be mutable because QQmlImportNamespace likes to sort itself on
+ // resolveType(). Therefore, QQmlImportNamespace::resolveType() is not const.
+ // There should be a better way to do this.
+ mutable QQmlImportNamespace m_unqualifiedset;
+
+ // storage of data related to imports with a namespace
+ QFieldList<QQmlImportNamespace, &QQmlImportNamespace::nextNamespace> m_qualifiedSets;
};
-class Q_QML_PRIVATE_EXPORT QQmlImportDatabase
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlImports::ImportFlags)
+
+class Q_QML_EXPORT QQmlImportDatabase
{
Q_DECLARE_TR_FUNCTIONS(QQmlImportDatabase)
public:
enum PathType { Local, Remote, LocalOrRemote };
+ enum LocalQmldirSearchLocation {
+ QmldirFileAndCache,
+ QmldirCacheOnly,
+ };
+
+ enum LocalQmldirResult {
+ QmldirFound,
+ QmldirNotFound,
+ QmldirInterceptedToRemote,
+ QmldirRejected
+ };
+
QQmlImportDatabase(QQmlEngine *);
- ~QQmlImportDatabase();
+ ~QQmlImportDatabase() { clearDirCache(); }
-#if QT_CONFIG(library)
- bool importDynamicPlugin(const QString &filePath, const QString &uri, const QString &importNamespace, int vmaj, QList<QQmlError> *errors);
- bool removeDynamicPlugin(const QString &filePath);
+ bool removeDynamicPlugin(const QString &pluginId);
QStringList dynamicPlugins() const;
-#endif
QStringList importPathList(PathType type = LocalOrRemote) const;
void setImportPathList(const QStringList &paths);
void addImportPath(const QString& dir);
- QStringList pluginPathList() const;
+ QStringList pluginPathList() const { return filePluginPath; }
void setPluginPathList(const QStringList &paths);
+
void addPluginPath(const QString& path);
+ template<typename Callback>
+ LocalQmldirResult locateLocalQmldir(
+ const QString &uri, QTypeRevision version, LocalQmldirSearchLocation location,
+ const Callback &callback);
+
+ static QTypeRevision lockModule(const QString &uri, const QString &typeNamespace,
+ QTypeRevision version, QList<QQmlError> *errors);
+
private:
- friend class QQmlImportsPrivate;
- QString resolvePlugin(QQmlTypeLoader *typeLoader,
- const QString &qmldirPath, const QString &qmldirPluginPath,
- const QString &baseName, const QStringList &suffixes,
- const QString &prefix = QString());
- QString resolvePlugin(QQmlTypeLoader *typeLoader,
- const QString &qmldirPath, const QString &qmldirPluginPath,
- const QString &baseName);
- bool importStaticPlugin(QObject *instance, const QString &basePath, const QString &uri,
- const QString &typeNamespace, int vmaj, QList<QQmlError> *errors);
+ friend class QQmlImports;
+ friend class QQmlPluginImporter;
+
+ QString absoluteFilePath(const QString &path) const;
void clearDirCache();
- void finalizePlugin(QObject *instance, const QString &path, const QString &uri);
struct QmldirCache {
- int versionMajor;
- int versionMinor;
+ QTypeRevision version;
QString qmldirFilePath;
QString qmldirPathUrl;
QmldirCache *next;
};
// Maps from an import to a linked list of qmldir info.
- // Used in QQmlImportsPrivate::locateQmldir()
+ // Used in QQmlImports::locateQmldir()
QStringHash<QmldirCache *> qmldirCache;
// XXX thread
QStringList filePluginPath;
QStringList fileImportPath;
- QSet<QString> qmlDirFilesForWhichPluginsHaveBeenLoaded;
+ QSet<QString> modulesForWhichPluginsHaveBeenLoaded;
QSet<QString> initializedPlugins;
QQmlEngine *engine;
};
+template<typename Callback>
+QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir(
+ const QString &uri, QTypeRevision version,
+ QQmlImportDatabase::LocalQmldirSearchLocation location, const Callback &callback)
+{
+ // Check cache first
+
+ LocalQmldirResult result = QmldirNotFound;
+ QmldirCache *cacheTail = nullptr;
+
+ QmldirCache **cachePtr = qmldirCache.value(uri);
+ QmldirCache *cacheHead = cachePtr ? *cachePtr : nullptr;
+ if (cacheHead) {
+ cacheTail = cacheHead;
+ do {
+ if (cacheTail->version == version) {
+ if (cacheTail->qmldirFilePath.isEmpty()) {
+ return cacheTail->qmldirPathUrl.isEmpty()
+ ? QmldirNotFound
+ : QmldirInterceptedToRemote;
+ }
+ if (callback(cacheTail->qmldirFilePath, cacheTail->qmldirPathUrl))
+ return QmldirFound;
+ result = QmldirRejected;
+ }
+ } while (cacheTail->next && (cacheTail = cacheTail->next));
+ }
+
+
+ // Do not try to construct the cache if it already had any entries for the URI.
+ // Otherwise we might duplicate cache entries.
+ if (location == QmldirCacheOnly || result != QmldirNotFound)
+ return result;
+
+ const bool hasInterceptors = !engine->urlInterceptors().isEmpty();
+
+ // Interceptor might redirect remote files to local ones.
+ QStringList localImportPaths = importPathList(hasInterceptors ? LocalOrRemote : Local);
+
+ // Search local import paths for a matching version
+ const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
+ uri, localImportPaths, version);
+
+ QString qmldirAbsoluteFilePath;
+ for (QString qmldirPath : qmlDirPaths) {
+ if (hasInterceptors) {
+ const QUrl intercepted = engine->interceptUrl(
+ QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
+ QQmlAbstractUrlInterceptor::QmldirFile);
+ qmldirPath = QQmlFile::urlToLocalFileOrQrc(intercepted);
+ if (result != QmldirInterceptedToRemote
+ && qmldirPath.isEmpty()
+ && !QQmlFile::isLocalFile(intercepted)) {
+ result = QmldirInterceptedToRemote;
+ }
+ }
+
+ qmldirAbsoluteFilePath = absoluteFilePath(qmldirPath);
+ if (!qmldirAbsoluteFilePath.isEmpty()) {
+ QString url;
+ const QString absolutePath = qmldirAbsoluteFilePath.left(
+ qmldirAbsoluteFilePath.lastIndexOf(u'/') + 1);
+ if (absolutePath.at(0) == u':') {
+ url = QStringLiteral("qrc") + absolutePath;
+ } else {
+ url = QUrl::fromLocalFile(absolutePath).toString();
+ // This handles the UNC path case as when the path is retrieved from the QUrl it
+ // will convert the host name from upper case to lower case. So the absoluteFilePath
+ // is changed at this point to make sure it will match later on in that case.
+ if (qmldirAbsoluteFilePath.startsWith(QStringLiteral("//"))) {
+ qmldirAbsoluteFilePath = QUrl::fromLocalFile(qmldirAbsoluteFilePath)
+ .toString(QUrl::RemoveScheme);
+ }
+ }
+
+ QmldirCache *cache = new QmldirCache;
+ cache->version = version;
+ cache->qmldirFilePath = qmldirAbsoluteFilePath;
+ cache->qmldirPathUrl = url;
+ cache->next = nullptr;
+ if (cacheTail)
+ cacheTail->next = cache;
+ else
+ qmldirCache.insert(uri, cache);
+ cacheTail = cache;
+
+ if (result != QmldirFound)
+ result = callback(qmldirAbsoluteFilePath, url) ? QmldirFound : QmldirRejected;
+
+ // Do not return here. Rather, construct the complete cache for this URI.
+ }
+ }
+
+ // Nothing found? Add an empty cache entry to signal that for further requests.
+ if (result == QmldirNotFound || result == QmldirInterceptedToRemote) {
+ QmldirCache *cache = new QmldirCache;
+ cache->version = version;
+ cache->next = cacheHead;
+ if (result == QmldirInterceptedToRemote) {
+ // The actual value doesn't matter as long as it's not empty.
+ // We only use it to discern QmldirInterceptedToRemote from QmldirNotFound above.
+ cache->qmldirPathUrl = QStringLiteral("intercepted");
+ }
+ qmldirCache.insert(uri, cache);
+
+ if (result == QmldirNotFound) {
+ qCDebug(lcQmlImport)
+ << "locateLocalQmldir:" << qPrintable(uri) << "module's qmldir file not found";
+ }
+ } else {
+ qCDebug(lcQmlImport)
+ << "locateLocalQmldir:" << qPrintable(uri) << "module's qmldir found at"
+ << qmldirAbsoluteFilePath;
+ }
+
+ return result;
+}
+
void qmlClearEnginePlugins();// For internal use by qmlClearRegisteredProperties
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index f0ef5360b0..5c18230450 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -1,51 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlincubator.h"
#include "qqmlcomponent.h"
#include "qqmlincubator_p.h"
-#include "qqmlexpression_p.h"
#include "qqmlobjectcreator_p.h"
#include <private/qqmlcomponent_p.h>
-void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
+void QQmlEnginePrivate::incubate(
+ QQmlIncubator &i, const QQmlRefPointer<QQmlContextData> &forContext)
{
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> p(i.d);
@@ -59,13 +23,13 @@ void QQmlEnginePrivate::incubate(QQmlIncubator &i, QQmlContextData *forContext)
// Need to find the first constructing context and see if it is asynchronous
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> parentIncubator;
- QQmlContextData *cctxt = forContext;
+ QQmlRefPointer<QQmlContextData> cctxt = forContext;
while (cctxt) {
- if (!cctxt->hasExtraObject && cctxt->incubator) {
- parentIncubator = cctxt->incubator;
+ if (QQmlIncubatorPrivate *incubator = cctxt->incubator()) {
+ parentIncubator = incubator;
break;
}
- cctxt = cctxt->parent;
+ cctxt = cctxt->parent();
}
if (parentIncubator && parentIncubator->isAsynchronous) {
@@ -139,7 +103,10 @@ QQmlIncubatorPrivate::~QQmlIncubatorPrivate()
void QQmlIncubatorPrivate::clear()
{
- compilationUnit = nullptr;
+ // reset the tagged pointer
+ if (requiredPropertiesFromComponent)
+ requiredPropertiesFromComponent = decltype(requiredPropertiesFromComponent){};
+ compilationUnit.reset();
if (next.isInList()) {
next.remove();
enginePriv->incubatorCount--;
@@ -149,9 +116,9 @@ void QQmlIncubatorPrivate::clear()
}
enginePriv = nullptr;
if (!rootContext.isNull()) {
- if (!rootContext->hasExtraObject)
- rootContext->incubator = nullptr;
- rootContext = nullptr;
+ if (rootContext->incubator())
+ rootContext->setIncubator(nullptr);
+ rootContext.setContextData({});
}
if (nextWaitingFor.isInList()) {
@@ -210,9 +177,15 @@ protected:
};
\endcode
-Although the previous example would work, it is not optimal. Real world incubation
-controllers should try and maximize the amount of idle time they consume - rather
-than a static amount like 5 milliseconds - while not disturbing the application.
+Although the example works, it is heavily simplified. Real world incubation controllers
+try and maximize the amount of idle time they consume while not disturbing the
+application. Using a static amount of 5 milliseconds like above may both leave idle
+time on the table in some frames and disturb the application in others.
+
+\l{QQuickWindow}, \l{QQuickView}, and \l{QQuickWidget} all pre-create an incubation
+controller that spaces out incubation over multiple frames using a more intelligent
+algorithm. You rarely have to write your own.
+
*/
/*!
@@ -262,12 +235,13 @@ void QQmlIncubatorPrivate::forceCompletion(QQmlInstantiationInterrupt &i)
{
while (QQmlIncubator::Loading == status) {
while (QQmlIncubator::Loading == status && !waitingFor.isEmpty())
- static_cast<QQmlIncubatorPrivate *>(waitingFor.first())->forceCompletion(i);
+ waitingFor.first()->forceCompletion(i);
if (QQmlIncubator::Loading == status)
incubate(i);
}
}
+
void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
{
if (!compilationUnit)
@@ -279,6 +253,20 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
// get a copy of the engine pointer as it might get reset;
QQmlEnginePrivate *enginePriv = this->enginePriv;
+ // Incubating objects takes quite a bit more stack space than our usual V4 function
+ enum { EstimatedSizeInV4Frames = 2 };
+ QV4::ExecutionEngineCallDepthRecorder<EstimatedSizeInV4Frames> callDepthRecorder(
+ compilationUnit->engine);
+ if (callDepthRecorder.hasOverflow()) {
+ QQmlError error;
+ error.setMessageType(QtCriticalMsg);
+ error.setUrl(compilationUnit->url());
+ error.setDescription(QQmlComponent::tr("Maximum call stack size exceeded."));
+ errors << error;
+ progress = QQmlIncubatorPrivate::Completed;
+ goto finishIncubate;
+ }
+
if (!vmeGuard.isOK()) {
QQmlError error;
error.setMessageType(QtInfoMsg);
@@ -299,11 +287,12 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
if (!tresult)
errors = creator->errors;
else {
- RequiredProperties& requiredProperties = creator->requiredProperties();
+ RequiredProperties* requiredProperties = creator->requiredProperties();
for (auto it = initialProperties.cbegin(); it != initialProperties.cend(); ++it) {
auto component = tresult;
auto name = it.key();
- QQmlProperty prop = QQmlComponentPrivate::removePropertyFromRequired(component, name, requiredProperties);
+ QQmlProperty prop = QQmlComponentPrivate::removePropertyFromRequired(
+ component, name, requiredProperties, QQmlEnginePrivate::get(enginePriv));
if (!prop.isValid() || !prop.write(it.value())) {
QQmlError error{};
error.setUrl(compilationUnit->url());
@@ -330,9 +319,9 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
ddata->rootObjectInCreation = false;
if (q) {
q->setInitialState(result);
- if (!creator->requiredProperties().empty()) {
- const auto& unsetRequiredProperties = creator->requiredProperties();
- for (const auto& unsetRequiredProperty: unsetRequiredProperties)
+ if (creator && !creator->requiredProperties()->empty()) {
+ const RequiredProperties *unsetRequiredProperties = creator->requiredProperties();
+ for (const auto& unsetRequiredProperty: *unsetRequiredProperties)
errors << QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
}
}
@@ -360,10 +349,8 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
if (watcher.hasRecursed())
return;
- QQmlContextData *ctxt = nullptr;
- ctxt = creator->finalize(i);
- if (ctxt) {
- rootContext = ctxt;
+ if (creator->finalize(i)) {
+ rootContext = creator->rootContext();
progress = QQmlIncubatorPrivate::Completed;
goto finishIncubate;
}
@@ -396,6 +383,37 @@ finishIncubate:
}
/*!
+ \internal
+ This is used to mimic the behavior of incubate when the
+ Component we want to incubate refers to a creatable
+ QQmlType (i.e., it is the result of loadFromModule).
+ */
+void QQmlIncubatorPrivate::incubateCppBasedComponent(QQmlComponent *component, QQmlContext *context)
+{
+ auto compPriv = QQmlComponentPrivate::get(component);
+ Q_ASSERT(compPriv->loadedType.isCreatable());
+ std::unique_ptr<QObject> object(component->beginCreate(context));
+ component->setInitialProperties(object.get(), initialProperties);
+ if (auto props = compPriv->state.requiredProperties()) {
+ requiredPropertiesFromComponent = props;
+ requiredPropertiesFromComponent.setTag(HadTopLevelRequired::Yes);
+ }
+ q->setInitialState(object.get());
+ if (requiredPropertiesFromComponent && !requiredPropertiesFromComponent->isEmpty()) {
+ for (const RequiredPropertyInfo &unsetRequiredProperty :
+ std::as_const(*requiredPropertiesFromComponent)) {
+ errors << QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(unsetRequiredProperty);
+ }
+ } else {
+ compPriv->completeCreate();
+ result = object.release();
+ progress = QQmlIncubatorPrivate::Completed;
+ }
+ changeStatus(calculateStatus());
+
+}
+
+/*!
Incubate objects for \a msecs, or until there are no more objects to incubate.
*/
void QQmlIncubationController::incubateFor(int msecs)
@@ -403,27 +421,31 @@ void QQmlIncubationController::incubateFor(int msecs)
if (!d || !d->incubatorCount)
return;
- QQmlInstantiationInterrupt i(msecs * 1000000);
- i.reset();
+ QDeadlineTimer deadline(msecs);
+ QQmlInstantiationInterrupt i(deadline);
do {
static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
} while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
}
/*!
-Incubate objects while the bool pointed to by \a flag is true, or until there are no
-more objects to incubate, or up to \a msecs if \a msecs is not zero.
+\since 5.15
+
+Incubate objects while the atomic bool pointed to by \a flag is true,
+or until there are no more objects to incubate, or up to \a msecs if \a
+msecs is not zero.
Generally this method is used in conjunction with a thread or a UNIX signal that sets
the bool pointed to by \a flag to false when it wants incubation to be interrupted.
+
+\note \a flag is read using acquire memory ordering.
*/
-void QQmlIncubationController::incubateWhile(volatile bool *flag, int msecs)
+void QQmlIncubationController::incubateWhile(std::atomic<bool> *flag, int msecs)
{
if (!d || !d->incubatorCount)
return;
- QQmlInstantiationInterrupt i(flag, msecs * 1000000);
- i.reset();
+ QQmlInstantiationInterrupt i(flag, msecs ? QDeadlineTimer(msecs) : QDeadlineTimer::Forever);
do {
static_cast<QQmlIncubatorPrivate*>(d->incubatorList.first())->incubate(i);
} while (d && d->incubatorCount != 0 && !i.shouldInterrupt());
@@ -441,25 +463,37 @@ synchronously which, depending on the complexity of the object, can cause notic
stutters in the application.
The use of QQmlIncubator gives more control over the creation of a QML object,
-including allowing it to be created asynchronously using application idle time. The following
+including allowing it to be created asynchronously using application idle time. The following
example shows a simple use of QQmlIncubator.
\code
+// Initialize the incubator
QQmlIncubator incubator;
component->create(incubator);
+\endcode
-while (!incubator.isReady()) {
- QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
-}
+Let the incubator run for a while (normally by returning control to the event loop),
+then poll it. There are a number of ways to get back to the incubator later. You may
+want to connect to one of the signals sent by \l{QQuickWindow}, or you may want to run
+a \l{QTimer} especially for that. You may also need the object for some specific
+purpose and poll the incubator when that purpose arises.
-QObject *object = incubator.object();
+\code
+// Poll the incubator
+if (incubator.isReady()) {
+ QObject *object = incubator.object();
+ // Use created object
+}
\endcode
-Asynchronous incubators are controlled by a QQmlIncubationController that is
-set on the QQmlEngine, which lets the engine know when the application is idle and
+Asynchronous incubators are controlled by a \l{QQmlIncubationController} that is
+set on the \l{QQmlEngine}, which lets the engine know when the application is idle and
incubating objects should be processed. If an incubation controller is not set on the
-QQmlEngine, QQmlIncubator creates objects synchronously regardless of the
-specified IncubationMode.
+\l{QQmlEngine}, \l{QQmlIncubator} creates objects synchronously regardless of the
+specified IncubationMode. By default, no incubation controller is set. However,
+\l{QQuickView}, \l{QQuickWindow} and \l{QQuickWidget} all set incubation controllers
+on their respective \l{QQmlEngine}s. These incubation controllers space out incubations
+across multiple frames while the view is being rendered.
QQmlIncubator supports three incubation modes:
\list
@@ -679,26 +713,33 @@ QObject *QQmlIncubator::object() const
}
/*!
-Return a list of properties which are required but haven't been set yet.
+Return a pointer to a list of properties which are required but haven't
+been set yet.
This list can be modified, so that subclasses which implement special logic
setInitialProperties can mark properties set there as no longer required.
\sa QQmlIncubator::setInitialProperties
\since 5.15
*/
-RequiredProperties &QQmlIncubatorPrivate::requiredProperties()
+RequiredProperties *QQmlIncubatorPrivate::requiredProperties()
{
- return creator->requiredProperties();
+ if (creator)
+ return creator->requiredProperties();
+ else
+ return requiredPropertiesFromComponent.data();
}
-bool QQmlIncubatorPrivate::hadRequiredProperties() const
+bool QQmlIncubatorPrivate::hadTopLevelRequiredProperties() const
{
- return creator->componentHadRequiredProperties();
+ if (creator)
+ return creator->componentHadTopLevelRequiredProperties();
+ else
+ return requiredPropertiesFromComponent.tag() == HadTopLevelRequired::Yes;
}
/*!
-Stores a mapping from property names to initial values with which the incubated
-component will be initialized
+Stores a mapping from property names to initial values, contained in
+\a initialProperties, with which the incubated component will be initialized.
\sa QQmlComponent::setInitialProperties
\since 5.15
@@ -719,13 +760,23 @@ void QQmlIncubator::statusChanged(Status status)
}
/*!
-Called after the \a object is first created, but before property bindings are
-evaluated and, if applicable, QQmlParserStatus::componentComplete() is
-called. This is equivalent to the point between QQmlComponent::beginCreate()
+Called after the \a object is first created, but before complex property
+bindings are evaluated and, if applicable, QQmlParserStatus::componentComplete()
+is called. This is equivalent to the point between QQmlComponent::beginCreate()
and QQmlComponent::completeCreate(), and can be used to assign initial values
to the object's properties.
The default implementation does nothing.
+
+\note Simple bindings such as numeric literals are evaluated before
+setInitialState() is called. The categorization of bindings into simple and
+complex ones is intentionally unspecified and may change between versions of
+Qt and depending on whether and how you are using \l{qmlcachegen}. You should
+not rely on any particular binding to be evaluated either before or after
+setInitialState() is called. For example, a constant expression like
+\e{MyType.EnumValue} may be recognized as such at compile time or deferred
+to be executed as binding. The same holds for constant expressions like
+\e{-(5)} or \e{"a" + " constant string"}.
*/
void QQmlIncubator::setInitialState(QObject *object)
{
diff --git a/src/qml/qml/qqmlincubator.h b/src/qml/qml/qqmlincubator.h
index f075407e73..c2389fc878 100644
--- a/src/qml/qml/qqmlincubator.h
+++ b/src/qml/qml/qqmlincubator.h
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLINCUBATOR_H
#define QQMLINCUBATOR_H
#include <QtQml/qtqmlglobal.h>
#include <QtQml/qqmlerror.h>
+#include <atomic>
QT_BEGIN_NAMESPACE
@@ -49,7 +14,6 @@ QT_BEGIN_NAMESPACE
class QQmlEngine;
class QQmlPropertyData;
class QVariant;
-using QVariantMap = QMap<QString, QVariant>;
class QQmlIncubatorPrivate;
class Q_QML_EXPORT QQmlIncubator
@@ -112,7 +76,7 @@ public:
int incubatingObjectCount() const;
void incubateFor(int msecs);
- void incubateWhile(volatile bool *flag, int msecs=0);
+ void incubateWhile(std::atomic<bool> *flag, int msecs = 0);
protected:
virtual void incubatingObjectCountChanged(int);
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index aadb147bd5..f35679a8a1 100644
--- a/src/qml/qml/qqmlincubator_p.h
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLINCUBATOR_P_H
#define QQMLINCUBATOR_P_H
@@ -46,7 +10,9 @@
#include <private/qqmlvme_p.h>
#include <private/qrecursionwatcher_p.h>
#include <private/qqmlengine_p.h>
-#include <private/qqmlcontext_p.h>
+#include <private/qqmlguardedcontextdata_p.h>
+
+#include <QtCore/qpointer.h>
//
// W A R N I N G
@@ -61,12 +27,10 @@
QT_BEGIN_NAMESPACE
-class QQmlPropertyData;
-struct RequiredPropertyInfo;
-using RequiredProperties = QHash<QQmlPropertyData*, RequiredPropertyInfo>;
+class RequiredProperties;
class QQmlIncubator;
-class Q_QML_PRIVATE_EXPORT QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator
+class Q_QML_EXPORT QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator, public QSharedData
{
public:
QQmlIncubatorPrivate(QQmlIncubator *q, QQmlIncubator::IncubationMode m);
@@ -74,6 +38,7 @@ public:
inline static QQmlIncubatorPrivate *get(QQmlIncubator *incubator) { return incubator->d; }
+ int subComponentToCreate;
QQmlIncubator *q;
QQmlIncubator::Status calculateStatus() const;
@@ -82,23 +47,31 @@ public:
QQmlIncubator::IncubationMode mode;
bool isAsynchronous;
+ enum Progress : char { Execute, Completing, Completed };
+ Progress progress;
QList<QQmlError> errors;
- enum Progress { Execute, Completing, Completed };
- Progress progress;
QPointer<QObject> result;
+ enum HadTopLevelRequired : bool {No = 0, Yes = 1};
+ /* TODO: unify with Creator pointer once QTBUG-108760 is implemented
+ though we don't acutally own the properties here; if we ever end up
+ with a use case for async incubation of C++ types, we however could
+ not rely on the component to still exist during incubation, and
+ would need to store a copy of the required properties instead
+ */
+ QTaggedPointer<RequiredProperties, HadTopLevelRequired> requiredPropertiesFromComponent;
QQmlGuardedContextData rootContext;
QQmlEnginePrivate *enginePriv;
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
QScopedPointer<QQmlObjectCreator> creator;
- int subComponentToCreate;
QQmlVMEGuard vmeGuard;
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> waitingOnMe;
typedef QQmlEnginePrivate::Incubator QIPBase;
- QIntrusiveList<QIPBase, &QIPBase::nextWaitingFor> waitingFor;
+ QIntrusiveListNode nextWaitingFor;
+ QIntrusiveList<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::nextWaitingFor> waitingFor;
QRecursionNode recursion;
QVariantMap initialProperties;
@@ -107,8 +80,9 @@ public:
void forceCompletion(QQmlInstantiationInterrupt &i);
void incubate(QQmlInstantiationInterrupt &i);
- RequiredProperties &requiredProperties();
- bool hadRequiredProperties() const;
+ void incubateCppBasedComponent(QQmlComponent *component, QQmlContext *context);
+ RequiredProperties *requiredProperties();
+ bool hadTopLevelRequiredProperties() const;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlinfo.cpp b/src/qml/qml/qqmlinfo.cpp
index 2bfd2d5bb4..159a519bdc 100644
--- a/src/qml/qml/qqmlinfo.cpp
+++ b/src/qml/qml/qqmlinfo.cpp
@@ -1,63 +1,33 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlinfo.h"
#include "qqmldata_p.h"
-#include "qqmlcontext.h"
-#include "qqmlcontext_p.h"
#include "qqmlmetatype_p.h"
#include "qqmlengine_p.h"
+#include "qqmlsourcecoordinate_p.h"
#include <QCoreApplication>
QT_BEGIN_NAMESPACE
/*!
- \namespace QtQml
+ \class QQmlInfo
\inmodule QtQml
- \brief Provides functions for producing logging messages for QML types.
+ \brief The QQmlInfo class allows logging of QML-related messages.
+
+ QQmlInfo is an opaque handle for QML-related diagnostic messages. You can
+ use the \c{<<} operator to add content to the message. When the QQmlInfo
+ object is destroyed, it prints the resulting message along with information
+ on the context.
+
+ \sa qmlDebug, qmlInfo, qmlWarning
*/
/*!
- \fn QQmlInfo QtQml::qmlDebug(const QObject *object)
- \relates QtQml
+ \fn QQmlInfo qmlDebug(const QObject *object)
+ \relates QQmlInfo
\since 5.9
Prints debug messages that include the file and line number for the
@@ -86,12 +56,12 @@ QT_BEGIN_NAMESPACE
QML MyCustomType (unknown location): Internal state: 42
\endcode
- \sa QtQml::qmlInfo, QtQml::qmlWarning
+ \sa qmlInfo, qmlWarning
*/
/*!
- \fn QQmlInfo QtQml::qmlInfo(const QObject *object)
- \relates QtQml
+ \fn QQmlInfo qmlInfo(const QObject *object)
+ \relates QQmlInfo
Prints informational messages that include the file and line number for the
specified QML \a object.
@@ -114,12 +84,12 @@ QT_BEGIN_NAMESPACE
QtMsgType. For Qt 5.9 and above, qmlInfo uses an info QtMsgType. To send
warnings, use qmlWarning.
- \sa QtQml::qmlDebug, QtQml::qmlWarning
+ \sa qmlDebug, qmlWarning
*/
/*!
- \fn QQmlInfo QtQml::qmlWarning(const QObject *object)
- \relates QtQml
+ \fn QQmlInfo qmlWarning(const QObject *object)
+ \relates QQmlInfo
\since 5.9
Prints warning messages that include the file and line number for the
@@ -139,36 +109,36 @@ QT_BEGIN_NAMESPACE
QML MyCustomType (unknown location): property cannot be set to 0
\endcode
- \sa QtQml::qmlDebug, QtQml::qmlInfo
+ \sa qmlDebug, qmlInfo
*/
/*!
- \fn QQmlInfo QtQml::qmlDebug(const QObject *object, const QQmlError &error)
+ \fn QQmlInfo qmlDebug(const QObject *object, const QQmlError &error)
\internal
*/
/*!
- \fn QQmlInfo QtQml::qmlDebug(const QObject *object, const QList<QQmlError> &errors)
+ \fn QQmlInfo qmlDebug(const QObject *object, const QList<QQmlError> &errors)
\internal
*/
/*!
- \fn QQmlInfo QtQml::qmlInfo(const QObject *object, const QQmlError &error)
+ \fn QQmlInfo qmlInfo(const QObject *object, const QQmlError &error)
\internal
*/
/*!
- \fn QQmlInfo QtQml::qmlInfo(const QObject *object, const QList<QQmlError> &errors)
+ \fn QQmlInfo qmlInfo(const QObject *object, const QList<QQmlError> &errors)
\internal
*/
/*!
- \fn QQmlInfo QtQml::qmlWarning(const QObject *object, const QQmlError &error)
+ \fn QQmlInfo qmlWarning(const QObject *object, const QQmlError &error)
\internal
*/
/*!
- \fn QQmlInfo QtQml::qmlWarning(const QObject *object, const QList<QQmlError> &errors)
+ \fn QQmlInfo qmlWarning(const QObject *object, const QList<QQmlError> &errors)
\internal
*/
@@ -214,15 +184,28 @@ QQmlInfo::~QQmlInfo()
QObject *object = const_cast<QObject *>(d->object);
if (object) {
- engine = qmlEngine(d->object);
+ // Some objects (e.g. like attached objects created in C++) won't have an associated engine,
+ // but we can still try to look for a parent object that does.
+ QObject *objectWithEngine = object;
+ while (objectWithEngine) {
+ engine = qmlEngine(objectWithEngine);
+ if (engine)
+ break;
+ objectWithEngine = objectWithEngine->parent();
+ }
- d->buffer.prepend(QLatin1String("QML ") + QQmlMetaType::prettyTypeName(object) + QLatin1String(": "));
+ if (!objectWithEngine || objectWithEngine == object) {
+ d->buffer.prepend(QLatin1String("QML ") + QQmlMetaType::prettyTypeName(object) + QLatin1String(": "));
+ } else {
+ d->buffer.prepend(QLatin1String("QML ") + QQmlMetaType::prettyTypeName(objectWithEngine)
+ + QLatin1String(" (parent or ancestor of ") + QQmlMetaType::prettyTypeName(object) + QLatin1String("): "));
+ }
- QQmlData *ddata = QQmlData::get(object, false);
+ QQmlData *ddata = QQmlData::get(objectWithEngine ? objectWithEngine : object, false);
if (ddata && ddata->outerContext) {
error.setUrl(ddata->outerContext->url());
- error.setLine(ddata->lineNumber);
- error.setColumn(ddata->columnNumber);
+ error.setLine(qmlConvertSourceCoordinate<quint16, int>(ddata->lineNumber));
+ error.setColumn(qmlConvertSourceCoordinate<quint16, int>(ddata->columnNumber));
}
}
@@ -237,8 +220,6 @@ QQmlInfo::~QQmlInfo()
}
}
-namespace QtQml {
-
#define MESSAGE_FUNCS(FuncName, MessageLevel) \
QQmlInfo FuncName(const QObject *me) \
{ \
@@ -265,28 +246,4 @@ MESSAGE_FUNCS(qmlDebug, QtMsgType::QtDebugMsg)
MESSAGE_FUNCS(qmlInfo, QtMsgType::QtInfoMsg)
MESSAGE_FUNCS(qmlWarning, QtMsgType::QtWarningMsg)
-
-} // namespace QtQml
-
-#if QT_DEPRECATED_SINCE(5, 1)
-
-// Also define symbols outside namespace to keep binary compatibility with Qt 5.0
-
-QQmlInfo qmlInfo(const QObject *me)
-{
- return QtQml::qmlInfo(me);
-}
-
-QQmlInfo qmlInfo(const QObject *me, const QQmlError &error)
-{
- return QtQml::qmlInfo(me, error);
-}
-
-QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors)
-{
- return QtQml::qmlInfo(me, errors);
-}
-
-#endif // QT_DEPRECATED_SINCE(5, 1)
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlinfo.h b/src/qml/qml/qqmlinfo.h
index faa112d4af..1fc0d4a2ae 100644
--- a/src/qml/qml/qqmlinfo.h
+++ b/src/qml/qml/qqmlinfo.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLINFO_H
#define QQMLINFO_H
@@ -49,25 +13,17 @@ QT_BEGIN_NAMESPACE
class QQmlInfo;
-// declared in namespace to avoid symbol conflicts with QtDeclarative
-namespace QtQml {
- Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me);
- Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QQmlError &error);
- Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QList<QQmlError> &errors);
+Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me);
+Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QQmlError &error);
+Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QList<QQmlError> &errors);
- Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me);
- Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QQmlError &error);
- Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors);
+Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me);
+Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QQmlError &error);
+Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors);
- Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me);
- Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QQmlError &error);
- Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QList<QQmlError> &errors);
-}
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_CLANG("-Wheader-hygiene")
-// This is necessary to allow for QtQuick1 and QtQuick2 scenes in a single application.
-using namespace QtQml;
-QT_WARNING_POP
+Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me);
+Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QQmlError &error);
+Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QList<QQmlError> &errors);
class QQmlInfoPrivate;
class Q_QML_EXPORT QQmlInfo : public QDebug
@@ -91,7 +47,7 @@ public:
inline QQmlInfo &operator<<(double t) { QDebug::operator<<(t); return *this; }
inline QQmlInfo &operator<<(const char* t) { QDebug::operator<<(t); return *this; }
inline QQmlInfo &operator<<(const QString & t) { QDebug::operator<<(t.toLocal8Bit().constData()); return *this; }
- inline QQmlInfo &operator<<(const QStringRef & t) { return operator<<(t.toString()); }
+ inline QQmlInfo &operator<<(QStringView t) { return operator<<(t.toString()); }
inline QQmlInfo &operator<<(const QLatin1String &t) { QDebug::operator<<(t.latin1()); return *this; }
inline QQmlInfo &operator<<(const QByteArray & t) { QDebug::operator<<(t); return *this; }
inline QQmlInfo &operator<<(const void * t) { QDebug::operator<<(t); return *this; }
@@ -102,15 +58,15 @@ public:
#endif
private:
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlDebug(const QObject *me);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlDebug(const QObject *me, const QQmlError &error);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlDebug(const QObject *me, const QList<QQmlError> &errors);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlInfo(const QObject *me);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlInfo(const QObject *me, const QQmlError &error);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlInfo(const QObject *me, const QList<QQmlError> &errors);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlWarning(const QObject *me);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlWarning(const QObject *me, const QQmlError &error);
- friend Q_QML_EXPORT QQmlInfo QtQml::qmlWarning(const QObject *me, const QList<QQmlError> &errors);
+ friend Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me);
+ friend Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QQmlError &error);
+ friend Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QList<QQmlError> &errors);
+ friend Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me);
+ friend Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QQmlError &error);
+ friend Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors);
+ friend Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me);
+ friend Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QQmlError &error);
+ friend Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QList<QQmlError> &errors);
QQmlInfo(QQmlInfoPrivate *);
QQmlInfoPrivate *d;
diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp
index 82cad8eba8..b29ce185ef 100644
--- a/src/qml/qml/qqmlirloader.cpp
+++ b/src/qml/qml/qqmlirloader.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlirloader_p.h"
#include <private/qqmlirbuilder_p.h>
@@ -58,12 +22,71 @@ void QQmlIRLoader::load()
for (quint32 i = 0; i < qmlUnit->nImports; ++i)
output->imports << qmlUnit->importAt(i);
- if (unit->flags & QV4::CompiledData::Unit::IsSingleton) {
- QmlIR::Pragma *p = New<QmlIR::Pragma>();
+ using QmlIR::Pragma;
+ const auto createPragma = [&](Pragma::PragmaType type) {
+ Pragma *p = New<Pragma>();
p->location = QV4::CompiledData::Location();
- p->type = QmlIR::Pragma::PragmaSingleton;
+ p->type = type;
output->pragmas << p;
- }
+ return p;
+ };
+
+ const auto createListPragma = [&](
+ Pragma::PragmaType type,
+ Pragma::ListPropertyAssignBehaviorValue value) {
+ createPragma(type)->listPropertyAssignBehavior = value;
+ };
+
+ const auto createComponentPragma = [&](
+ Pragma::PragmaType type,
+ Pragma::ComponentBehaviorValue value) {
+ createPragma(type)->componentBehavior = value;
+ };
+
+ const auto createFunctionSignaturePragma = [&](
+ Pragma::PragmaType type,
+ Pragma::FunctionSignatureBehaviorValue value) {
+ createPragma(type)->functionSignatureBehavior = value;
+ };
+
+ const auto createNativeMethodPragma = [&](
+ Pragma::PragmaType type,
+ Pragma::NativeMethodBehaviorValue value) {
+ createPragma(type)->nativeMethodBehavior = value;
+ };
+
+ const auto createValueTypePragma = [&](
+ Pragma::PragmaType type,
+ Pragma::ValueTypeBehaviorValues value) {
+ createPragma(type)->valueTypeBehavior = value;
+ };
+
+ if (unit->flags & QV4::CompiledData::Unit::IsSingleton)
+ createPragma(Pragma::Singleton);
+ if (unit->flags & QV4::CompiledData::Unit::IsStrict)
+ createPragma(Pragma::Strict);
+
+ if (unit->flags & QV4::CompiledData::Unit::ListPropertyAssignReplace)
+ createListPragma(Pragma::ListPropertyAssignBehavior, Pragma::Replace);
+ else if (unit->flags & QV4::CompiledData::Unit::ListPropertyAssignReplaceIfNotDefault)
+ createListPragma(Pragma::ListPropertyAssignBehavior, Pragma::ReplaceIfNotDefault);
+
+ if (unit->flags & QV4::CompiledData::Unit::ComponentsBound)
+ createComponentPragma(Pragma::ComponentBehavior, Pragma::Bound);
+
+ if (unit->flags & QV4::CompiledData::Unit::FunctionSignaturesIgnored)
+ createFunctionSignaturePragma(Pragma::FunctionSignatureBehavior, Pragma::Ignored);
+
+ if (unit->flags & QV4::CompiledData::Unit::NativeMethodsAcceptThisObject)
+ createNativeMethodPragma(Pragma::NativeMethodBehavior, Pragma::AcceptThisObject);
+
+ Pragma::ValueTypeBehaviorValues valueTypeBehavior = {};
+ if (unit->flags & QV4::CompiledData::Unit::ValueTypesCopied)
+ valueTypeBehavior |= Pragma::Copy;
+ if (unit->flags & QV4::CompiledData::Unit::ValueTypesAddressable)
+ valueTypeBehavior |= Pragma::Addressable;
+ if (valueTypeBehavior)
+ createValueTypePragma(Pragma::ValueTypeBehavior, valueTypeBehavior);
for (uint i = 0; i < qmlUnit->nObjects; ++i) {
const QV4::CompiledData::Object *serializedObject = qmlUnit->objectAt(i);
@@ -78,26 +101,26 @@ struct FakeExpression : public QQmlJS::AST::NullExpression
: location(start, length)
{}
- virtual QQmlJS::AST::SourceLocation firstSourceLocation() const
+ QQmlJS::SourceLocation firstSourceLocation() const override
{ return location; }
- virtual QQmlJS::AST::SourceLocation lastSourceLocation() const
+ QQmlJS::SourceLocation lastSourceLocation() const override
{ return location; }
private:
- QQmlJS::AST::SourceLocation location;
+ QQmlJS::SourceLocation location;
};
QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *serializedObject)
{
QmlIR::Object *object = pool->New<QmlIR::Object>();
- object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex);
+ object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex,
+ serializedObject->location);
object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
- object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
- object->flags = serializedObject->flags;
- object->id = serializedObject->id;
- object->location = serializedObject->location;
+ object->defaultPropertyIsAlias = serializedObject->hasAliasAsDefaultProperty();
+ object->flags = serializedObject->flags();
+ object->id = serializedObject->objectId();
object->locationOfIdProperty = serializedObject->locationOfIdProperty;
QVector<int> functionIndices;
@@ -107,9 +130,9 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
QmlIR::Binding *b = pool->New<QmlIR::Binding>();
*static_cast<QV4::CompiledData::Binding*>(b) = serializedObject->bindingTable()[i];
object->bindings->append(b);
- if (b->type == QV4::CompiledData::Binding::Type_Script) {
+ if (b->type() == QV4::CompiledData::Binding::Type_Script) {
functionIndices.append(b->value.compiledScriptIndex);
- b->value.compiledScriptIndex = functionIndices.count() - 1;
+ b->value.compiledScriptIndex = functionIndices.size() - 1;
QmlIR::CompiledFunctionOrExpression *foe = pool->New<QmlIR::CompiledFunctionOrExpression>();
foe->nameIndex = 0;
@@ -117,9 +140,9 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
QQmlJS::AST::ExpressionNode *expr;
if (b->stringIndex != quint32(0)) {
- const int start = output->code.length();
+ const int start = output->code.size();
const QString script = output->stringAt(b->stringIndex);
- const int length = script.length();
+ const int length = script.size();
output->code.append(script);
expr = new (pool) FakeExpression(start, length);
} else
@@ -129,7 +152,7 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
}
}
- Q_ASSERT(object->functionsAndExpressions->count == functionIndices.count());
+ Q_ASSERT(object->functionsAndExpressions->count == functionIndices.size());
for (uint i = 0; i < serializedObject->nSignals; ++i) {
const QV4::CompiledData::Signal *serializedSignal = serializedObject->signalAt(i);
@@ -185,7 +208,7 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
const QV4::CompiledData::Function *compiledFunction = unit->functionAt(*functionIdx);
functionIndices.append(*functionIdx);
- f->index = functionIndices.count() - 1;
+ f->index = functionIndices.size() - 1;
f->location = compiledFunction->location;
f->nameIndex = compiledFunction->nameIndex;
f->returnType = compiledFunction->returnType;
@@ -200,6 +223,20 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
object->runtimeFunctionIndices.allocate(pool, functionIndices);
+ const QV4::CompiledData::InlineComponent *serializedInlineComponent = serializedObject->inlineComponentTable();
+ for (uint i = 0; i < serializedObject->nInlineComponents; ++i, ++serializedInlineComponent) {
+ QmlIR::InlineComponent *ic = pool->New<QmlIR::InlineComponent>();
+ *static_cast<QV4::CompiledData::InlineComponent*>(ic) = *serializedInlineComponent;
+ object->inlineComponents->append(ic);
+ }
+
+ const QV4::CompiledData::RequiredPropertyExtraData *serializedRequiredPropertyExtraData = serializedObject->requiredPropertyExtraDataTable();
+ for (uint i = 0u; i < serializedObject->nRequiredPropertyExtraData; ++i, ++serializedRequiredPropertyExtraData) {
+ QmlIR::RequiredPropertyExtraData *extra = pool->New<QmlIR::RequiredPropertyExtraData>();
+ *static_cast<QV4::CompiledData::RequiredPropertyExtraData *>(extra) = *serializedRequiredPropertyExtraData;
+ object->requiredPropertyExtraDatas->append(extra);
+ }
+
return object;
}
diff --git a/src/qml/qml/qqmlirloader_p.h b/src/qml/qml/qqmlirloader_p.h
index 4812946ef0..8a14d6833e 100644
--- a/src/qml/qml/qqmlirloader_p.h
+++ b/src/qml/qml/qqmlirloader_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLIRLOADER_P_H
#define QQMLIRLOADER_P_H
@@ -62,7 +26,7 @@ struct Document;
struct Object;
}
-struct Q_QML_PRIVATE_EXPORT QQmlIRLoader {
+struct Q_QML_EXPORT QQmlIRLoader {
QQmlIRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output);
void load();
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 8661ebcc13..d7cf38984b 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -1,43 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmljavascriptexpression_p.h"
+#include "qqmljavascriptexpression_p.h"
#include <private/qqmlexpression_p.h>
#include <private/qv4context_p.h>
@@ -50,6 +15,10 @@
#include <private/qqmlglobal_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qqmlabstractbinding_p.h>
+#include <private/qqmlpropertybinding_p.h>
+#include <private/qproperty_p.h>
QT_BEGIN_NAMESPACE
@@ -72,8 +41,8 @@ bool QQmlDelayedError::addError(QQmlEnginePrivate *e)
void QQmlDelayedError::setErrorLocation(const QQmlSourceLocation &sourceLocation)
{
m_error.setUrl(QUrl(sourceLocation.sourceFile));
- m_error.setLine(sourceLocation.line);
- m_error.setColumn(sourceLocation.column);
+ m_error.setLine(qmlConvertSourceCoordinate<quint16, int>(sourceLocation.line));
+ m_error.setColumn(qmlConvertSourceCoordinate<quint16, int>(sourceLocation.column));
}
void QQmlDelayedError::setErrorDescription(const QString &description)
@@ -108,15 +77,33 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
m_nextExpression->m_prevExpression = m_prevExpression;
}
+ while (qpropertyChangeTriggers) {
+ auto current = qpropertyChangeTriggers;
+ qpropertyChangeTriggers = current->next;
+ QRecyclePool<TriggerList>::Delete(current);
+ }
+
clearActiveGuards();
clearError();
if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion.
m_scopeObject.asT2()->_s = nullptr;
}
+QString QQmlJavaScriptExpression::expressionIdentifier() const
+{
+ if (auto f = function()) {
+ QString url = f->sourceFile();
+ uint lineNumber = f->compiledFunction->location.line();
+ uint columnNumber = f->compiledFunction->location.column();
+ return url + QString::asprintf(":%u:%u", lineNumber, columnNumber);
+ }
+
+ return QStringLiteral("[native code]");
+}
+
void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v)
{
- activeGuards.setFlagValue(v);
+ activeGuards.setTag(v ? NotifyOnValueChanged : NoGuardTag);
if (!v)
clearActiveGuards();
}
@@ -133,7 +120,7 @@ QQmlSourceLocation QQmlJavaScriptExpression::sourceLocation() const
return QQmlSourceLocation();
}
-void QQmlJavaScriptExpression::setContext(QQmlContextData *context)
+void QQmlJavaScriptExpression::setContext(const QQmlRefPointer<QQmlContextData> &context)
{
if (m_prevExpression) {
*m_prevExpression = m_nextExpression;
@@ -143,20 +130,10 @@ void QQmlJavaScriptExpression::setContext(QQmlContextData *context)
m_nextExpression = nullptr;
}
- m_context = context;
-
- if (context) {
- m_nextExpression = context->expressions;
- if (m_nextExpression)
- m_nextExpression->m_prevExpression = &m_nextExpression;
- m_prevExpression = &context->expressions;
- context->expressions = this;
- }
-}
+ m_context = context.data();
-QV4::Function *QQmlJavaScriptExpression::function() const
-{
- return m_v4Function;
+ if (context)
+ context->addExpression(this);
}
void QQmlJavaScriptExpression::refresh()
@@ -165,87 +142,136 @@ void QQmlJavaScriptExpression::refresh()
QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(bool *isUndefined)
{
- QV4::ExecutionEngine *v4 = m_context->engine->handle();
- QV4::Scope scope(v4);
- QV4::JSCallData jsCall(scope);
+ QQmlEngine *qmlengine = engine();
+ if (!qmlengine) {
+ if (isUndefined)
+ *isUndefined = true;
+ return QV4::Encode::undefined();
+ }
+
+ QV4::Scope scope(qmlengine->handle());
+ QV4::JSCallArguments jsCall(scope);
- return evaluate(jsCall.callData(), isUndefined);
+ return evaluate(jsCall.callData(scope), isUndefined);
}
-QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined)
+class QQmlJavaScriptExpressionCapture
{
- Q_ASSERT(m_context && m_context->engine);
+ Q_DISABLE_COPY_MOVE(QQmlJavaScriptExpressionCapture)
+public:
+ QQmlJavaScriptExpressionCapture(QQmlJavaScriptExpression *expression, QQmlEngine *engine)
+ : watcher(expression)
+ , capture(engine, expression, &watcher)
+ , ep(QQmlEnginePrivate::get(engine))
+ {
+ Q_ASSERT(expression->notifyOnValueChanged() || expression->activeGuards.isEmpty());
+
+ lastPropertyCapture = ep->propertyCapture;
+ ep->propertyCapture = expression->notifyOnValueChanged() ? &capture : nullptr;
+
+ if (expression->notifyOnValueChanged())
+ capture.guards.copyAndClearPrepend(expression->activeGuards);
+ }
+
+ ~QQmlJavaScriptExpressionCapture()
+ {
+ if (capture.errorString) {
+ for (int ii = 0; ii < capture.errorString->size(); ++ii)
+ qWarning("%s", qPrintable(capture.errorString->at(ii)));
+ delete capture.errorString;
+ capture.errorString = nullptr;
+ }
+
+ while (QQmlJavaScriptExpressionGuard *g = capture.guards.takeFirst())
+ g->Delete();
+
+ ep->propertyCapture = lastPropertyCapture;
+ }
+
+ bool catchException(const QV4::Scope &scope) const
+ {
+ if (scope.hasException()) {
+ if (watcher.wasDeleted())
+ scope.engine->catchException(); // ignore exception
+ else
+ capture.expression->delayedError()->catchJavaScriptException(scope.engine);
+ return true;
+ }
+ if (!watcher.wasDeleted() && capture.expression->hasDelayedError())
+ capture.expression->delayedError()->clearError();
+ return false;
+ }
+
+private:
+ QQmlJavaScriptExpression::DeleteWatcher watcher;
+ QQmlPropertyCapture capture;
+ QQmlEnginePrivate *ep;
+ QQmlPropertyCapture *lastPropertyCapture;
+};
+
+QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined)
+{
+ QQmlEngine *qmlEngine = engine();
QV4::Function *v4Function = function();
- if (!v4Function) {
+ if (!v4Function || !qmlEngine) {
if (isUndefined)
*isUndefined = true;
return QV4::Encode::undefined();
}
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(m_context->engine);
-
// All code that follows must check with watcher before it accesses data members
// incase we have been deleted.
- DeleteWatcher watcher(this);
-
- Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty());
- QQmlPropertyCapture capture(m_context->engine, this, &watcher);
+ QQmlJavaScriptExpressionCapture capture(this, qmlEngine);
- QQmlPropertyCapture *lastPropertyCapture = ep->propertyCapture;
- ep->propertyCapture = notifyOnValueChanged() ? &capture : nullptr;
+ QV4::Scope scope(qmlEngine->handle());
-
- if (notifyOnValueChanged())
- capture.guards.copyAndClearPrepend(activeGuards);
-
- QV4::ExecutionEngine *v4 = m_context->engine->handle();
- callData->thisObject = v4->globalObject;
- if (scopeObject()) {
- QV4::ReturnedValue scope = QV4::QObjectWrapper::wrap(v4, scopeObject());
- if (QV4::Value::fromReturnedValue(scope).isObject())
- callData->thisObject = scope;
+ if (QObject *thisObject = scopeObject()) {
+ callData->thisObject = QV4::QObjectWrapper::wrap(scope.engine, thisObject);
+ if (callData->thisObject.isNullOrUndefined())
+ callData->thisObject = scope.engine->globalObject;
+ } else {
+ callData->thisObject = scope.engine->globalObject;
}
Q_ASSERT(m_qmlScope.valueRef());
- QV4::ReturnedValue res = v4Function->call(
+ QV4::ScopedValue result(scope, v4Function->call(
&(callData->thisObject.asValue<QV4::Value>()),
callData->argValues<QV4::Value>(), callData->argc(),
- static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef()));
- QV4::Scope scope(v4);
- QV4::ScopedValue result(scope, res);
+ static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef())));
- if (scope.hasException()) {
- if (watcher.wasDeleted())
- scope.engine->catchException(); // ignore exception
- else
- delayedError()->catchJavaScriptException(scope.engine);
+ if (capture.catchException(scope)) {
if (isUndefined)
*isUndefined = true;
- } else {
- if (isUndefined)
- *isUndefined = result->isUndefined();
-
- if (!watcher.wasDeleted() && hasDelayedError())
- delayedError()->clearError();
+ } else if (isUndefined) {
+ *isUndefined = result->isUndefined();
}
- if (capture.errorString) {
- for (int ii = 0; ii < capture.errorString->count(); ++ii)
- qWarning("%s", qPrintable(capture.errorString->at(ii)));
- delete capture.errorString;
- capture.errorString = nullptr;
- }
+ return result->asReturnedValue();
+}
- while (QQmlJavaScriptExpressionGuard *g = capture.guards.takeFirst())
- g->Delete();
+bool QQmlJavaScriptExpression::evaluate(void **a, const QMetaType *types, int argc)
+{
+ // All code that follows must check with watcher before it accesses data members
+ // incase we have been deleted.
+ QQmlEngine *qmlEngine = engine();
- if (!watcher.wasDeleted())
- setTranslationsCaptured(capture.translationCaptured);
+ // If there is no engine, we have no way to evaluate anything.
+ // This can happen on destruction.
+ if (!qmlEngine)
+ return false;
- ep->propertyCapture = lastPropertyCapture;
+ QQmlJavaScriptExpressionCapture capture(this, qmlEngine);
- return result->asReturnedValue();
+ QV4::Scope scope(qmlEngine->handle());
+
+ Q_ASSERT(m_qmlScope.valueRef());
+ Q_ASSERT(function());
+ const bool resultIsDefined = function()->call(
+ scopeObject(), a, types, argc,
+ static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef()));
+
+ return !capture.catchException(scope) && resultIsDefined;
}
void QQmlPropertyCapture::captureProperty(QQmlNotifier *n)
@@ -281,6 +307,99 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, bool doNotif
return;
Q_ASSERT(expression);
+
+ // If c < 0 we won't find any property. We better leave the metaobjects alone in that case.
+ // QQmlListModel expects us _not_ to trigger the creation of dynamic metaobjects from here.
+ if (c >= 0) {
+ const QQmlData *ddata = QQmlData::get(o, /*create=*/false);
+ const QMetaObject *metaObjectForBindable = nullptr;
+ if (auto const propCache = (ddata ? ddata->propertyCache.data() : nullptr)) {
+ Q_ASSERT(propCache->property(c));
+ if (propCache->property(c)->isBindable())
+ metaObjectForBindable = propCache->metaObject();
+ } else {
+ const QMetaObject *m = o->metaObject();
+ if (m->property(c).isBindable())
+ metaObjectForBindable = m;
+ }
+ if (metaObjectForBindable) {
+ captureBindableProperty(o, metaObjectForBindable, c);
+ return;
+ }
+ }
+
+ captureNonBindableProperty(o, n, c, doNotify);
+}
+
+void QQmlPropertyCapture::captureProperty(
+ QObject *o, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *propertyData,
+ bool doNotify)
+{
+ if (watcher->wasDeleted())
+ return;
+
+ Q_ASSERT(expression);
+
+ if (propertyData->isBindable()) {
+ if (const QMetaObject *metaObjectForBindable = propertyCache->metaObject()) {
+ captureBindableProperty(o, metaObjectForBindable, propertyData->coreIndex());
+ return;
+ }
+ }
+
+ captureNonBindableProperty(o, propertyData->notifyIndex(), propertyData->coreIndex(), doNotify);
+}
+
+bool QQmlJavaScriptExpression::needsPropertyChangeTrigger(QObject *target, int propertyIndex)
+{
+ TriggerList **prev = &qpropertyChangeTriggers;
+ TriggerList *current = qpropertyChangeTriggers;
+ while (current) {
+ if (!current->target) {
+ *prev = current->next;
+ QRecyclePool<TriggerList>::Delete(current);
+ current = *prev;
+ } else if (current->target == target && current->propertyIndex == propertyIndex) {
+ return false; // already installed
+ } else {
+ prev = &current->next;
+ current = current->next;
+ }
+ }
+
+ return true;
+}
+
+void QQmlPropertyCapture::captureTranslation()
+{
+ // use a unique invalid index to avoid needlessly querying the metaobject for
+ // the correct index of of the translationLanguage property
+ int const invalidIndex = -2;
+ if (expression->needsPropertyChangeTrigger(engine, invalidIndex)) {
+ auto trigger = expression->allocatePropertyChangeTrigger(engine, invalidIndex);
+ trigger->setSource(QQmlEnginePrivate::get(engine)->translationLanguage);
+ }
+}
+
+void QQmlPropertyCapture::captureBindableProperty(
+ QObject *o, const QMetaObject *metaObjectForBindable, int c)
+{
+ // if the property is a QPropery, and we're binding to a QProperty
+ // the automatic capturing process already takes care of everything
+ if (!expression->mustCaptureBindableProperty())
+ return;
+
+ if (expression->needsPropertyChangeTrigger(o, c)) {
+ auto trigger = expression->allocatePropertyChangeTrigger(o, c);
+ QUntypedBindable bindable;
+ void *argv[] = { &bindable };
+ metaObjectForBindable->metacall(o, QMetaObject::BindableProperty, c, argv);
+ bindable.observe(trigger);
+ }
+}
+
+void QQmlPropertyCapture::captureNonBindableProperty(QObject *o, int n, int c, bool doNotify)
+{
if (n == -1) {
if (!errorString) {
errorString = new QStringList;
@@ -290,11 +409,9 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, bool doNotif
errorString->append(preamble);
}
- const QMetaObject *metaObj = o->metaObject();
- QMetaProperty metaProp = metaObj->property(c);
-
+ const QMetaProperty metaProp = o->metaObject()->property(c);
QString error = QLatin1String(" ") +
- QString::fromUtf8(metaObj->className()) +
+ QString::fromUtf8(o->metaObject()->className()) +
QLatin1String("::") +
QString::fromUtf8(metaProp.name());
errorString->append(error);
@@ -336,10 +453,11 @@ QQmlDelayedError *QQmlJavaScriptExpression::delayedError()
}
QV4::ReturnedValue
-QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObject,
- const QString &code, const QString &filename, quint16 line)
+QQmlJavaScriptExpression::evalFunction(
+ const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scopeObject,
+ const QString &code, const QString &filename, quint16 line)
{
- QQmlEngine *engine = ctxt->engine;
+ QQmlEngine *engine = ctxt->engine();
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
QV4::ExecutionEngine *v4 = engine->handle();
@@ -366,10 +484,11 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObje
return result->asReturnedValue();
}
-void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject *qmlScope,
- const QString &code, const QString &filename, quint16 line)
+void QQmlJavaScriptExpression::createQmlBinding(
+ const QQmlRefPointer<QQmlContextData> &ctxt, QObject *qmlScope, const QString &code,
+ const QString &filename, quint16 line)
{
- QQmlEngine *engine = ctxt->engine;
+ QQmlEngine *engine = ctxt->engine();
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
QV4::ExecutionEngine *v4 = engine->handle();
@@ -395,7 +514,7 @@ void QQmlJavaScriptExpression::setupFunction(QV4::ExecutionContext *qmlContext,
return;
m_qmlScope.set(qmlContext->engine(), *qmlContext);
m_v4Function = f;
- setCompilationUnit(m_v4Function->executableCompilationUnit());
+ m_compilationUnit.reset(m_v4Function->executableCompilationUnit());
}
void QQmlJavaScriptExpression::setCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
@@ -403,6 +522,32 @@ void QQmlJavaScriptExpression::setCompilationUnit(const QQmlRefPointer<QV4::Exec
m_compilationUnit = compilationUnit;
}
+void QPropertyChangeTrigger::trigger(QPropertyObserver *observer, QUntypedPropertyData *) {
+ auto This = static_cast<QPropertyChangeTrigger *>(observer);
+ This->m_expression->expressionChanged();
+}
+
+QMetaProperty QPropertyChangeTrigger::property() const
+{
+ if (!target)
+ return {};
+ auto const mo = target->metaObject();
+ if (!mo)
+ return {};
+ return mo->property(propertyIndex);
+}
+
+QPropertyChangeTrigger *QQmlJavaScriptExpression::allocatePropertyChangeTrigger(QObject *target, int propertyIndex)
+{
+ auto trigger = QQmlEnginePrivate::get(engine())->qPropertyTriggerPool.New( this );
+ trigger->target = target;
+ trigger->propertyIndex = propertyIndex;
+ auto oldHead = qpropertyChangeTriggers;
+ trigger->next = oldHead;
+ qpropertyChangeTriggers = trigger;
+ return trigger;
+}
+
void QQmlJavaScriptExpression::clearActiveGuards()
{
while (QQmlJavaScriptExpressionGuard *g = activeGuards.takeFirst())
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index eecee08062..80e2033627 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLJAVASCRIPTEXPRESSION_P_H
#define QQMLJAVASCRIPTEXPRESSION_P_H
@@ -52,8 +16,10 @@
//
#include <QtCore/qglobal.h>
+#include <QtCore/qtaggedpointer.h>
#include <QtQml/qqmlerror.h>
#include <private/qqmlengine_p.h>
+#include <QtQml/private/qbipointer_p.h>
QT_BEGIN_NAMESPACE
@@ -96,17 +62,19 @@ private:
QQmlDelayedError **prevError;
};
-class Q_QML_PRIVATE_EXPORT QQmlJavaScriptExpression
+class Q_QML_EXPORT QQmlJavaScriptExpression
{
+ Q_DISABLE_COPY_MOVE(QQmlJavaScriptExpression)
public:
QQmlJavaScriptExpression();
virtual ~QQmlJavaScriptExpression();
- virtual QString expressionIdentifier() const = 0;
+ virtual QString expressionIdentifier() const;
virtual void expressionChanged() = 0;
QV4::ReturnedValue evaluate(bool *isUndefined);
QV4::ReturnedValue evaluate(QV4::CallData *callData, bool *isUndefined);
+ bool evaluate(void **a, const QMetaType *types, int argc);
inline bool notifyOnValueChanged() const;
@@ -118,12 +86,23 @@ public:
virtual QQmlSourceLocation sourceLocation() const;
- bool isValid() const { return context() != nullptr; }
+ bool hasContext() const { return m_context != nullptr; }
+ bool hasValidContext() const { return m_context && m_context->isValid(); }
+ QQmlContext *publicContext() const { return m_context ? m_context->asQQmlContext() : nullptr; }
- QQmlContextData *context() const { return m_context; }
- void setContext(QQmlContextData *context);
+ QQmlRefPointer<QQmlContextData> context() const { return m_context; }
+ void setContext(const QQmlRefPointer<QQmlContextData> &context);
- QV4::Function *function() const;
+ void insertIntoList(QQmlJavaScriptExpression **listHead)
+ {
+ m_nextExpression = *listHead;
+ if (m_nextExpression)
+ m_nextExpression->m_prevExpression = &m_nextExpression;
+ m_prevExpression = listHead;
+ *listHead = this;
+ }
+
+ QV4::Function *function() const { return m_v4Function; }
virtual void refresh();
@@ -145,12 +124,21 @@ public:
void clearError();
void clearActiveGuards();
QQmlDelayedError *delayedError();
+ virtual bool mustCaptureBindableProperty() const {return true;}
+
+ static QV4::ReturnedValue evalFunction(
+ const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope, const QString &code,
+ const QString &filename, quint16 line);
+
+ QQmlEngine *engine() const { return m_context ? m_context->engine() : nullptr; }
+ bool hasUnresolvedNames() const { return m_context && m_context->hasUnresolvedNames(); }
+
+ bool needsPropertyChangeTrigger(QObject *target, int propertyIndex);
+ QPropertyChangeTrigger *allocatePropertyChangeTrigger(QObject *target, int propertyIndex);
- static QV4::ReturnedValue evalFunction(QQmlContextData *ctxt, QObject *scope,
- const QString &code, const QString &filename,
- quint16 line);
protected:
- void createQmlBinding(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, quint16 line);
+ void createQmlBinding(const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope,
+ const QString &code, const QString &filename, quint16 line);
void setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f);
void setCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit);
@@ -159,30 +147,45 @@ protected:
// activeGuards:flag1 - notifyOnValueChanged
// activeGuards:flag2 - useSharedContext
QBiPointer<QObject, DeleteWatcher> m_scopeObject;
- QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards;
- void setTranslationsCaptured(bool captured) { m_error.setFlagValue(captured); }
- bool translationsCaptured() const { return m_error.flag(); }
+ enum GuardTag {
+ NoGuardTag,
+ NotifyOnValueChanged
+ };
+
+ QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next, GuardTag> activeGuards;
+
+ enum Tag {
+ NoTag,
+ InEvaluationLoop
+ };
+
+ QTaggedPointer<QQmlDelayedError, Tag> m_error;
private:
friend class QQmlContextData;
friend class QQmlPropertyCapture;
friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **);
- friend class QQmlTranslationBinding;
-
- // m_error:flag1 translationsCapturedDuringEvaluation
- QFlagPointer<QQmlDelayedError> m_error;
+ friend class QQmlTranslationBindingFromBinding;
+ friend class QQmlTranslationBindingFromTranslationInfo;
+ friend class QQmlJavaScriptExpressionCapture;
+ // Not refcounted as the context will clear the expressions when destructed.
QQmlContextData *m_context;
+
QQmlJavaScriptExpression **m_prevExpression;
QQmlJavaScriptExpression *m_nextExpression;
QV4::PersistentValue m_qmlScope;
QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compilationUnit;
+
QV4::Function *m_v4Function;
+
+protected:
+ TriggerList *qpropertyChangeTriggers = nullptr;
};
-class Q_QML_PRIVATE_EXPORT QQmlPropertyCapture
+class Q_QML_EXPORT QQmlPropertyCapture
{
public:
QQmlPropertyCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e, QQmlJavaScriptExpression::DeleteWatcher *w)
@@ -195,14 +198,18 @@ public:
void captureProperty(QQmlNotifier *);
void captureProperty(QObject *, int, int, bool doNotify = true);
- void captureTranslation() { translationCaptured = true; }
+ void captureProperty(QObject *, const QQmlPropertyCache *, const QQmlPropertyData *, bool doNotify = true);
+ void captureTranslation();
QQmlEngine *engine;
QQmlJavaScriptExpression *expression;
QQmlJavaScriptExpression::DeleteWatcher *watcher;
- QFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> guards;
+ QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> guards;
QStringList *errorString;
- bool translationCaptured = false;
+
+private:
+ void captureBindableProperty(QObject *o, const QMetaObject *metaObjectForBindable, int c);
+ void captureNonBindableProperty(QObject *o, int n, int c, bool doNotify);
};
QQmlJavaScriptExpression::DeleteWatcher::DeleteWatcher(QQmlJavaScriptExpression *e)
@@ -232,7 +239,7 @@ bool QQmlJavaScriptExpression::DeleteWatcher::wasDeleted() const
bool QQmlJavaScriptExpression::notifyOnValueChanged() const
{
- return activeGuards.flag();
+ return activeGuards.tag() == NotifyOnValueChanged;
}
QObject *QQmlJavaScriptExpression::scopeObject() const
diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp
index 5425bf498c..a166041070 100644
--- a/src/qml/qml/qqmllist.cpp
+++ b/src/qml/qml/qqmllist.cpp
@@ -1,68 +1,36 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmllist.h"
#include "qqmllist_p.h"
-#include "qqmlengine_p.h"
-#include "qqmlproperty_p.h"
+#include <QtQml/private/qqmlproperty_p.h>
QT_BEGIN_NAMESPACE
+static bool isObjectCompatible(QObject *object, QQmlListReferencePrivate *d)
+{
+ if (object) {
+ const QQmlMetaObject elementType = d->elementType();
+ if (elementType.isNull() || !QQmlMetaObject::canConvert(object, elementType))
+ return false;
+ }
+ return true;
+}
+
QQmlListReferencePrivate::QQmlListReferencePrivate()
-: propertyType(-1), refCount(1)
+: refCount(1)
{
}
-QQmlListReference QQmlListReferencePrivate::init(const QQmlListProperty<QObject> &prop, int propType, QQmlEngine *engine)
+QQmlListReference QQmlListReferencePrivate::init(
+ const QQmlListProperty<QObject> &prop, QMetaType propType)
{
QQmlListReference rv;
if (!prop.object) return rv;
- QQmlEnginePrivate *p = engine?QQmlEnginePrivate::get(engine):nullptr;
-
- int listType = p?p->listType(propType):QQmlMetaType::listType(propType);
- if (listType == -1) return rv;
-
rv.d = new QQmlListReferencePrivate;
rv.d->object = prop.object;
- rv.d->elementType = QQmlPropertyPrivate::rawMetaObjectForType(p, listType);
rv.d->property = prop;
rv.d->propertyType = propType;
@@ -119,34 +87,83 @@ QQmlListReference::QQmlListReference()
{
}
+#if QT_DEPRECATED_SINCE(6, 4)
/*!
+\since 6.1
+\obsolete [6.4] Use the constructors without QQmlEngine argument instead.
+
+Constructs a QQmlListReference from a QVariant \a variant containing a QQmlListProperty. If
+\a variant does not contain a list property, an invalid QQmlListReference is created. If the object
+owning the list property is destroyed after the reference is constructed, it will automatically
+become invalid. That is, it is safe to hold QQmlListReference instances even after the object is
+deleted.
+
+The \a engine is unused.
+*/
+QQmlListReference::QQmlListReference(const QVariant &variant, [[maybe_unused]] QQmlEngine *engine)
+ : QQmlListReference(variant)
+{}
+
+/*!
+\obsolete [6.4] Use the constructors without QQmlEngine argument instead.
+
Constructs a QQmlListReference for \a object's \a property. If \a property is not a list
property, an invalid QQmlListReference is created. If \a object is destroyed after
the reference is constructed, it will automatically become invalid. That is, it is safe to hold
QQmlListReference instances even after \a object is deleted.
-Passing \a engine is required to access some QML created list properties. If in doubt, and an engine
-is available, pass it.
+The \a engine is unused.
*/
-QQmlListReference::QQmlListReference(QObject *object, const char *property, QQmlEngine *engine)
-: d(nullptr)
+QQmlListReference::QQmlListReference(QObject *object, const char *property,
+ [[maybe_unused]] QQmlEngine *engine)
+ : QQmlListReference(object, property)
+{}
+#endif
+
+/*!
+\since 6.1
+
+Constructs a QQmlListReference from a QVariant \a variant containing a QQmlListProperty. If
+\a variant does not contain a list property, an invalid QQmlListReference is created. If the object
+owning the list property is destroyed after the reference is constructed, it will automatically
+become invalid. That is, it is safe to hold QQmlListReference instances even after the object is
+deleted.
+*/
+QQmlListReference::QQmlListReference(const QVariant &variant)
+ : d(nullptr)
+{
+ const QMetaType t = variant.metaType();
+ if (!(t.flags() & QMetaType::IsQmlList))
+ return;
+
+ d = new QQmlListReferencePrivate;
+ d->propertyType = t;
+
+ d->property.~QQmlListProperty();
+ t.construct(&d->property, variant.constData());
+
+ d->object = d->property.object;
+}
+
+/*!
+Constructs a QQmlListReference for \a object's \a property. If \a property is not a list
+property, an invalid QQmlListReference is created. If \a object is destroyed after
+the reference is constructed, it will automatically become invalid. That is, it is safe to hold
+QQmlListReference instances even after \a object is deleted.
+*/
+QQmlListReference::QQmlListReference(QObject *object, const char *property)
+ : d(nullptr)
{
if (!object || !property) return;
QQmlPropertyData local;
- QQmlPropertyData *data =
- QQmlPropertyCache::property(engine, object, QLatin1String(property), nullptr, local);
+ const QQmlPropertyData *data =
+ QQmlPropertyCache::property(object, QLatin1String(property), nullptr, &local);
if (!data || !data->isQList()) return;
- QQmlEnginePrivate *p = engine?QQmlEnginePrivate::get(engine):nullptr;
-
- int listType = p?p->listType(data->propType()):QQmlMetaType::listType(data->propType());
- if (listType == -1) return;
-
d = new QQmlListReferencePrivate;
d->object = object;
- d->elementType = p ? p->rawMetaObjectForType(listType) : QQmlMetaType::qmlType(listType).baseMetaObject();
d->propertyType = data->propType();
void *args[] = { &d->property, nullptr };
@@ -197,12 +214,11 @@ Returns the QMetaObject for the elements stored in the list property,
or \nullptr if the reference is invalid.
The QMetaObject can be used ahead of time to determine whether a given instance can be added
-to a list.
+to a list. If you didn't pass an engine on construction this may return nullptr.
*/
const QMetaObject *QQmlListReference::listElementType() const
{
- if (isValid()) return d->elementType.metaObject();
- else return nullptr;
+ return isValid() ? d->elementType() : nullptr;
}
/*!
@@ -250,10 +266,37 @@ bool QQmlListReference::canCount() const
}
/*!
- Return true if at(), count(), append() and clear() are implemented, so you can manipulate
- the list.
+Returns true if items in the list property can be replaced, otherwise false.
+Returns false if the reference is invalid.
-\sa isReadable(), at(), count(), append(), clear()
+\sa replace()
+*/
+bool QQmlListReference::canReplace() const
+{
+ return (isValid() && d->property.replace);
+}
+
+/*!
+Returns true if the last item can be removed from the list property, otherwise false.
+Returns false if the reference is invalid.
+
+\sa removeLast()
+*/
+bool QQmlListReference::canRemoveLast() const
+{
+ return (isValid() && d->property.removeLast);
+}
+
+/*!
+ Return true if at(), count(), append(), and either clear() or removeLast()
+ are implemented, so you can manipulate the list.
+
+ Mind that replace() and removeLast() can be emulated by stashing all
+ items and rebuilding the list using clear() and append(). Therefore,
+ they are not required for the list to be manipulable. Furthermore,
+ clear() can be emulated using removeLast().
+
+\sa isReadable(), at(), count(), append(), clear(), replace(), removeLast()
*/
bool QQmlListReference::isManipulable() const
{
@@ -284,7 +327,7 @@ bool QQmlListReference::append(QObject *object) const
{
if (!canAppend()) return false;
- if (object && !QQmlMetaObject::canConvert(object, d->elementType))
+ if (!isObjectCompatible(object, d))
return false;
d->property.append(&d->property, object);
@@ -297,7 +340,7 @@ Returns the list element at \a index, or 0 if the operation failed.
\sa canAt()
*/
-QObject *QQmlListReference::at(int index) const
+QObject *QQmlListReference::at(qsizetype index) const
{
if (!canAt()) return nullptr;
@@ -321,7 +364,7 @@ bool QQmlListReference::clear() const
/*!
Returns the number of objects in the list, or 0 if the operation failed.
*/
-int QQmlListReference::count() const
+qsizetype QQmlListReference::count() const
{
if (!canCount()) return 0;
@@ -329,6 +372,45 @@ int QQmlListReference::count() const
}
/*!
+\fn qsizetype QQmlListReference::size() const
+\since 6.2
+Returns the number of objects in the list, or 0 if the operation failed.
+*/
+
+/*!
+Replaces the item at \a index in the list with \a object.
+Returns true if the operation succeeded, otherwise false.
+
+\sa canReplace()
+*/
+bool QQmlListReference::replace(qsizetype index, QObject *object) const
+{
+ if (!canReplace())
+ return false;
+
+ if (!isObjectCompatible(object, d))
+ return false;
+
+ d->property.replace(&d->property, index, object);
+ return true;
+}
+
+/*!
+Removes the last item in the list.
+Returns true if the operation succeeded, otherwise false.
+
+\sa canRemoveLast()
+*/
+bool QQmlListReference::removeLast() const
+{
+ if (!canRemoveLast())
+ return false;
+
+ d->property.removeLast(&d->property);
+ return true;
+}
+
+/*!
\class QQmlListProperty
\since 5.0
\inmodule QtQml
@@ -365,7 +447,54 @@ Q_PROPERTY(QQmlListProperty<Fruit> fruit READ fruit)
QML list properties are type-safe - in this case \c {Fruit} is a QObject type that
\c {Apple}, \c {Orange} and \c {Banana} all derive from.
-\sa {Extending QML - Object and List Property Types Example}
+\sa {Chapter 5: Using List Property Types}
+*/
+
+/*!
+ \macro QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
+ \relates QQmlListProperty
+
+ This macro defines the behavior of the list properties of this class to Append.
+ When assigning the property in a derived type, the values are appended
+ to those of the base class. This is the default behavior.
+
+ \snippet code/src_qml_qqmllist.cpp 0
+
+ \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
+ \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
+ \sa {Defining Object Types through QML Documents}
+*/
+
+/*!
+ \macro QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
+ \relates QQmlListProperty
+
+ This macro defines the behavior of the list properties of this class to
+ ReplaceIfNotDefault.
+ When assigning the property in a derived type, the values replace those of
+ the base class unless it's the default property.
+ In the case of the default property, values are appended to those of the base class.
+
+ \snippet code/src_qml_qqmllist.cpp 1
+
+ \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
+ \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
+ \sa {Defining Object Types through QML Documents}
+*/
+
+/*!
+ \macro QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
+ \relates QQmlListProperty
+
+ This macro defines the behavior of the list properties of this class to Replace.
+ When assigning the property in a derived type, the values replace those
+ of the base class.
+
+ \snippet code/src_qml_qqmllist.cpp 2
+
+ \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
+ \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
+ \sa {Defining Object Types through QML Documents}
*/
/*!
@@ -375,14 +504,25 @@ QML list properties are type-safe - in this case \c {Fruit} is a QObject type th
/*!
\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, QList<T *> &list)
+\deprecated
Convenience constructor for making a QQmlListProperty value from an existing
QList \a list. The \a list reference must remain valid for as long as \a object
exists. \a object must be provided.
-Generally this constructor should not be used in production code, as a
-writable QList violates QML's memory management rules. However, this constructor
-can be very useful while prototyping.
+This constructor synthesizes the removeLast() and replace() methods
+introduced in Qt 5.15, using count(), at(), clear(), and append(). This is slow.
+If you intend to manipulate the list beyond clearing it, you should explicitly
+provide these methods.
+*/
+
+/*!
+\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, QList<T *> *list)
+\since 5.15
+
+Convenience constructor for making a QQmlListProperty value from an existing
+QList \a list. The \a list reference must remain valid for as long as \a object
+exists. \a object must be provided.
*/
/*!
@@ -408,6 +548,39 @@ remains valid while \a object exists.
Null pointers can be passed for any function. If any null pointers are passed in, the list
will be neither designable nor alterable by the debugger. It is recommended to provide valid
pointers for all functions.
+
+\note The resulting QQmlListProperty will synthesize the removeLast() and
+replace() methods using \a count, \a at, \a clear, and \a append if all of those
+are given. This is slow. If you intend to manipulate the list beyond clearing it,
+you should explicitly provide these methods.
+*/
+
+/*!
+\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(
+ QObject *object, void *data, AppendFunction append, CountFunction count,
+ AtFunction at, ClearFunction clear, ReplaceFunction replace,
+ RemoveLastFunction removeLast)
+
+Construct a QQmlListProperty from a set of operation functions \a append,
+\a count, \a at, \a clear, \a replace, and \removeLast. An opaque \a data handle
+may be passed which can be accessed from within the operation functions. The
+list property remains valid while \a object exists.
+
+Null pointers can be passed for any function, causing the respective function to
+be synthesized using the others, if possible. QQmlListProperty can synthesize
+\list
+ \li \a clear using \a count and \a removeLast
+ \li \a replace using \a count, \a at, \a clear, and \a append
+ \li \a replace using \a count, \a at, \a removeLast, and \a append
+ \li \a removeLast using \a count, \a at, \a clear, and \a append
+\endlist
+if those are given. This is slow, but if your list does not natively provide
+faster options for these primitives, you may want to use the synthesized ones.
+
+Furthermore, if either of \a count, \a at, \a append, and \a clear are neither
+given explicitly nor synthesized, the list will be neither designable nor
+alterable by the debugger. It is recommended to provide enough valid pointers
+to avoid this situation.
*/
/*!
@@ -421,7 +594,7 @@ Append the \a value to the list \a property.
/*!
\typedef QQmlListProperty::CountFunction
-Synonym for \c {int (*)(QQmlListProperty<T> *property)}.
+Synonym for \c {qsizetype (*)(QQmlListProperty<T> *property)}.
Return the number of elements in the list \a property.
*/
@@ -435,7 +608,7 @@ Returns true if this QQmlListProperty is equal to \a other, otherwise false.
/*!
\typedef QQmlListProperty::AtFunction
-Synonym for \c {T *(*)(QQmlListProperty<T> *property, int index)}.
+Synonym for \c {T *(*)(QQmlListProperty<T> *property, qsizetype index)}.
Return the element at position \a index in the list \a property.
*/
@@ -448,4 +621,31 @@ Synonym for \c {void (*)(QQmlListProperty<T> *property)}.
Clear the list \a property.
*/
+/*!
+\typedef QQmlListProperty::ReplaceFunction
+
+Synonym for \c {void (*)(QQmlListProperty<T> *property, qsizetype index, T *value)}.
+
+Replace the element at position \a index in the list \a property with \a value.
+*/
+
+/*!
+\typedef QQmlListProperty::RemoveLastFunction
+
+Synonym for \c {void (*)(QQmlListProperty<T> *property)}.
+
+Remove the last element from the list \a property.
+*/
+
+/*!
+\fn bool QQmlListReference::operator==(const QQmlListReference &other) const
+
+Compares this QQmlListReference to \a other, and returns \c true if they are
+equal. The two are only considered equal if one was created from the other
+via copy assignment or copy construction.
+
+\note Independently created references to the same object are not considered
+to be equal.
+*/
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllist.h b/src/qml/qml/qqmllist.h
index 90ec57c911..6f2c077764 100644
--- a/src/qml/qml/qqmllist.h
+++ b/src/qml/qml/qqmllist.h
@@ -1,76 +1,44 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLLIST_H
#define QQMLLIST_H
#include <QtQml/qtqmlglobal.h>
+
+#include <QtCore/qcontainerinfo.h>
#include <QtCore/qlist.h>
+#include <QtCore/qmetatype.h>
#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
-
class QObject;
struct QMetaObject;
-#ifndef QQMLLISTPROPERTY
-#define QQMLLISTPROPERTY
+#define QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND Q_CLASSINFO("QML.ListPropertyAssignBehavior", "Append")
+#define QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT Q_CLASSINFO("QML.ListPropertyAssignBehavior", "ReplaceIfNotDefault")
+#define QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE Q_CLASSINFO("QML.ListPropertyAssignBehavior", "Replace")
+
template<typename T>
class QQmlListProperty {
public:
- typedef void (*AppendFunction)(QQmlListProperty<T> *, T*);
- typedef int (*CountFunction)(QQmlListProperty<T> *);
- typedef T *(*AtFunction)(QQmlListProperty<T> *, int);
- typedef void (*ClearFunction)(QQmlListProperty<T> *);
-
- QQmlListProperty()
- : append(nullptr),
- count(nullptr),
- at(nullptr),
- clear(nullptr)
- {}
- QQmlListProperty(QObject *o, QList<T *> &list)
- : object(o), data(&list), append(qlist_append), count(qlist_count), at(qlist_at),
- clear(qlist_clear)
+ using value_type = T*;
+
+ using AppendFunction = void (*)(QQmlListProperty<T> *, T *);
+ using CountFunction = qsizetype (*)(QQmlListProperty<T> *);
+ using AtFunction = T *(*)(QQmlListProperty<T> *, qsizetype);
+ using ClearFunction = void (*)(QQmlListProperty<T> *);
+ using ReplaceFunction = void (*)(QQmlListProperty<T> *, qsizetype, T *);
+ using RemoveLastFunction = void (*)(QQmlListProperty<T> *);
+ QQmlListProperty() = default;
+
+ QQmlListProperty(QObject *o, QList<T *> *list)
+ : object(o), data(list), append(qlist_append), count(qlist_count), at(qlist_at),
+ clear(qlist_clear), replace(qlist_replace), removeLast(qlist_removeLast)
{}
+
QQmlListProperty(QObject *o, void *d, AppendFunction a, CountFunction c, AtFunction t,
ClearFunction r )
: object(o),
@@ -78,53 +46,136 @@ public:
append(a),
count(c),
at(t),
- clear(r)
-
+ clear(r),
+ replace((a && c && t && r) ? qslow_replace : nullptr),
+ removeLast((a && c && t && r) ? qslow_removeLast : nullptr)
{}
- QQmlListProperty(QObject *o, void *d, CountFunction c, AtFunction t)
+
+ QQmlListProperty(QObject *o, void *d, AppendFunction a, CountFunction c, AtFunction t,
+ ClearFunction r, ReplaceFunction s, RemoveLastFunction p)
: object(o),
data(d),
- append(nullptr),
- count(c), at(t),
- clear(nullptr)
+ append(a),
+ count(c),
+ at(t),
+ clear((!r && p && c) ? qslow_clear : r),
+ replace((!s && a && c && t && (r || p)) ? qslow_replace : s),
+ removeLast((!p && a && c && t && r) ? qslow_removeLast : p)
{}
+
+ QQmlListProperty(QObject *o, void *d, CountFunction c, AtFunction a)
+ : object(o), data(d), count(c), at(a)
+ {}
+
bool operator==(const QQmlListProperty &o) const {
return object == o.object &&
data == o.data &&
append == o.append &&
count == o.count &&
at == o.at &&
- clear == o.clear;
+ clear == o.clear &&
+ replace == o.replace &&
+ removeLast == o.removeLast;
}
QObject *object = nullptr;
void *data = nullptr;
- AppendFunction append;
+ AppendFunction append = nullptr;
+ CountFunction count = nullptr;
+ AtFunction at = nullptr;
+ ClearFunction clear = nullptr;
+ ReplaceFunction replace = nullptr;
+ RemoveLastFunction removeLast = nullptr;
+
+ template<typename List>
+ List toList()
+ {
+ if constexpr (std::is_same_v<List, QList<T *>>) {
+ if (append == qlist_append)
+ return *static_cast<QList<T *> *>(data);
+ }
- CountFunction count;
- AtFunction at;
+ const qsizetype size = count(this);
- ClearFunction clear;
+ List result;
+ if constexpr (QContainerInfo::has_reserve_v<List>)
+ result.reserve(size);
- void *dummy1 = nullptr;
- void *dummy2 = nullptr;
+ static_assert(QContainerInfo::has_push_back_v<List>);
+ for (qsizetype i = 0; i < size; ++i)
+ result.push_back(at(this, i));
+
+ return result;
+ }
private:
static void qlist_append(QQmlListProperty *p, T *v) {
- reinterpret_cast<QList<T *> *>(p->data)->append(v);
+ static_cast<QList<T *> *>(p->data)->append(v);
}
- static int qlist_count(QQmlListProperty *p) {
- return reinterpret_cast<QList<T *> *>(p->data)->count();
+ static qsizetype qlist_count(QQmlListProperty *p) {
+ return static_cast<QList<T *> *>(p->data)->size();
}
- static T *qlist_at(QQmlListProperty *p, int idx) {
- return reinterpret_cast<QList<T *> *>(p->data)->at(idx);
+ static T *qlist_at(QQmlListProperty *p, qsizetype idx) {
+ return static_cast<QList<T *> *>(p->data)->at(idx);
}
static void qlist_clear(QQmlListProperty *p) {
- return reinterpret_cast<QList<T *> *>(p->data)->clear();
+ return static_cast<QList<T *> *>(p->data)->clear();
+ }
+ static void qlist_replace(QQmlListProperty *p, qsizetype idx, T *v) {
+ return static_cast<QList<T *> *>(p->data)->replace(idx, v);
+ }
+ static void qlist_removeLast(QQmlListProperty *p) {
+ return static_cast<QList<T *> *>(p->data)->removeLast();
+ }
+
+ static void qslow_replace(QQmlListProperty<T> *list, qsizetype idx, T *v)
+ {
+ const qsizetype length = list->count(list);
+ if (idx < 0 || idx >= length)
+ return;
+
+ QVector<T *> stash;
+ if (list->clear != qslow_clear) {
+ stash.reserve(length);
+ for (qsizetype i = 0; i < length; ++i)
+ stash.append(i == idx ? v : list->at(list, i));
+ list->clear(list);
+ for (T *item : std::as_const(stash))
+ list->append(list, item);
+ } else {
+ stash.reserve(length - idx - 1);
+ for (qsizetype i = length - 1; i > idx; --i) {
+ stash.append(list->at(list, i));
+ list->removeLast(list);
+ }
+ list->removeLast(list);
+ list->append(list, v);
+ while (!stash.isEmpty())
+ list->append(list, stash.takeLast());
+ }
+ }
+
+ static void qslow_clear(QQmlListProperty<T> *list)
+ {
+ for (qsizetype i = 0, end = list->count(list); i < end; ++i)
+ list->removeLast(list);
+ }
+
+ static void qslow_removeLast(QQmlListProperty<T> *list)
+ {
+ const qsizetype length = list->count(list) - 1;
+ if (length < 0)
+ return;
+ QVector<T *> stash;
+ stash.reserve(length);
+ for (qsizetype i = 0; i < length; ++i)
+ stash.append(list->at(list, i));
+ list->clear(list);
+ for (T *item : std::as_const(stash))
+ list->append(list, item);
}
};
-#endif
class QQmlEngine;
class QQmlListReferencePrivate;
@@ -132,7 +183,17 @@ class Q_QML_EXPORT QQmlListReference
{
public:
QQmlListReference();
- QQmlListReference(QObject *, const char *property, QQmlEngine * = nullptr);
+
+#if QT_DEPRECATED_SINCE(6, 4)
+ QT_DEPRECATED_X("Drop the QQmlEngine* argument")
+ QQmlListReference(const QVariant &variant, [[maybe_unused]] QQmlEngine *engine);
+
+ QT_DEPRECATED_X("Drop the QQmlEngine* argument")
+ QQmlListReference(QObject *o, const char *property, [[maybe_unused]] QQmlEngine *engine);
+#endif
+
+ explicit QQmlListReference(const QVariant &variant);
+ QQmlListReference(QObject *o, const char *property);
QQmlListReference(const QQmlListReference &);
QQmlListReference &operator=(const QQmlListReference &);
~QQmlListReference();
@@ -146,20 +207,31 @@ public:
bool canAt() const;
bool canClear() const;
bool canCount() const;
+ bool canReplace() const;
+ bool canRemoveLast() const;
bool isManipulable() const;
bool isReadable() const;
bool append(QObject *) const;
- QObject *at(int) const;
+ QObject *at(qsizetype) const;
bool clear() const;
- int count() const;
+ qsizetype count() const;
+ qsizetype size() const { return count(); }
+ bool replace(qsizetype, QObject *) const;
+ bool removeLast() const;
+ bool operator==(const QQmlListReference &other) const {return d == other.d;}
private:
friend class QQmlListReferencePrivate;
QQmlListReferencePrivate* d;
};
+namespace QtPrivate {
+template<typename T>
+inline constexpr bool IsQmlListType<QQmlListProperty<T>> = true;
+}
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQmlListReference)
diff --git a/src/qml/qml/qqmllist_p.h b/src/qml/qml/qqmllist_p.h
index e182ced51d..642b3c3db1 100644
--- a/src/qml/qml/qqmllist_p.h
+++ b/src/qml/qml/qqmllist_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLLIST_P_H
#define QQMLLIST_P_H
@@ -53,6 +17,10 @@
#include "qqmllist.h"
#include "qqmlmetaobject_p.h"
+#include "qqmlmetatype_p.h"
+#include <QtQml/private/qbipointer_p.h>
+
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -61,12 +29,11 @@ class QQmlListReferencePrivate
public:
QQmlListReferencePrivate();
- static QQmlListReference init(const QQmlListProperty<QObject> &, int, QQmlEngine *);
+ static QQmlListReference init(const QQmlListProperty<QObject> &, QMetaType);
QPointer<QObject> object;
- QQmlMetaObject elementType;
QQmlListProperty<QObject> property;
- int propertyType;
+ QMetaType propertyType;
void addref();
void release();
@@ -75,8 +42,189 @@ public:
static inline QQmlListReferencePrivate *get(QQmlListReference *ref) {
return ref->d;
}
+
+ const QMetaObject *elementType()
+ {
+ if (!m_elementType) {
+ m_elementType = QQmlMetaType::rawMetaObjectForType(
+ QQmlMetaType::listValueType(propertyType)).metaObject();
+ }
+
+ return m_elementType;
+ }
+
+private:
+ const QMetaObject *m_elementType = nullptr;
+};
+
+template<typename T>
+class QQmlListIterator {
+public:
+ using difference_type = qsizetype;
+ using iterator_category = std::random_access_iterator_tag;
+ using value_type = T*;
+
+ class reference
+ {
+ public:
+ explicit reference(const QQmlListIterator *iter) : m_iter(iter) {}
+ reference(const reference &) = default;
+ reference(reference &&) = default;
+ ~reference() = default;
+
+ operator T *() const
+ {
+ if (m_iter == nullptr)
+ return nullptr;
+ return m_iter->m_list->at(m_iter->m_list, m_iter->m_i);
+ }
+
+ reference &operator=(T *value) {
+ m_iter->m_list->replace(m_iter->m_list, m_iter->m_i, value);
+ return *this;
+ }
+
+ reference &operator=(const reference &value) { return operator=((T *)(value)); }
+ reference &operator=(reference &&value) { return operator=((T *)(value)); }
+
+ friend void swap(reference a, reference b)
+ {
+ T *tmp = a;
+ a = b;
+ b = std::move(tmp);
+ }
+ private:
+ const QQmlListIterator *m_iter;
+ };
+
+ class pointer
+ {
+ public:
+ explicit pointer(const QQmlListIterator *iter) : m_iter(iter) {}
+ reference operator*() const { return reference(m_iter); }
+ QQmlListIterator operator->() const { return *m_iter; }
+
+ private:
+ const QQmlListIterator *m_iter;
+ };
+
+ QQmlListIterator() = default;
+ QQmlListIterator(QQmlListProperty<T> *list, qsizetype i) : m_list(list), m_i(i) {}
+
+ QQmlListIterator &operator++()
+ {
+ ++m_i;
+ return *this;
+ }
+
+ QQmlListIterator operator++(int)
+ {
+ QQmlListIterator result = *this;
+ ++m_i;
+ return result;
+ }
+
+ QQmlListIterator &operator--()
+ {
+ --m_i;
+ return *this;
+ }
+
+ QQmlListIterator operator--(int)
+ {
+ QQmlListIterator result = *this;
+ --m_i;
+ return result;
+ }
+
+ QQmlListIterator &operator+=(qsizetype j)
+ {
+ m_i += j;
+ return *this;
+ }
+
+ QQmlListIterator &operator-=(qsizetype j)
+ {
+ m_i -= j;
+ return *this;
+ }
+
+ QQmlListIterator operator+(qsizetype j)
+ {
+ return QQmlListIterator(m_list, m_i + j);
+ }
+
+ QQmlListIterator operator-(qsizetype j)
+ {
+ return QQmlListIterator(m_list, m_i - j);
+ }
+
+ reference operator*() const
+ {
+ return reference(this);
+ }
+
+ pointer operator->() const
+ {
+ return pointer(this);
+ }
+
+private:
+ friend inline bool operator==(const QQmlListIterator &a, const QQmlListIterator &b)
+ {
+ return a.m_list == b.m_list && a.m_i == b.m_i;
+ }
+
+ friend inline bool operator!=(const QQmlListIterator &a, const QQmlListIterator &b)
+ {
+ return a.m_list != b.m_list || a.m_i != b.m_i;
+ }
+
+ friend inline bool operator<(const QQmlListIterator &i, const QQmlListIterator &j)
+ {
+ return i - j < 0;
+ }
+
+ friend inline bool operator>=(const QQmlListIterator &i, const QQmlListIterator &j)
+ {
+ return !(i < j);
+ }
+
+ friend inline bool operator>(const QQmlListIterator &i, const QQmlListIterator &j)
+ {
+ return i - j > 0;
+ }
+
+ friend inline bool operator<=(const QQmlListIterator &i, const QQmlListIterator &j)
+ {
+ return !(i > j);
+ }
+
+ friend inline QQmlListIterator operator+(qsizetype i, const QQmlListIterator &j)
+ {
+ return j + i;
+ }
+
+ friend inline qsizetype operator-(const QQmlListIterator &i, const QQmlListIterator &j)
+ {
+ return i.m_i - j.m_i;
+ }
+
+ QQmlListProperty<T> *m_list = nullptr;
+ qsizetype m_i = 0;
};
+template<typename T>
+QQmlListIterator<T> begin(QQmlListProperty<T> &list)
+{
+ return QQmlListIterator<T>(&list, 0);
+}
+
+template<typename T>
+QQmlListIterator<T> end(QQmlListProperty<T> &list)
+{
+ return QQmlListIterator<T>(&list, list.count(&list));
+}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index 5349572921..8d5a585b62 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -1,105 +1,174 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmllistwrapper_p.h"
+
+#include <QtQml/qqmlinfo.h>
+
#include <private/qqmllist_p.h>
-#include <private/qv4objectproto_p.h>
-#include <qv4objectiterator_p.h>
+#include <private/qv4arrayiterator_p.h>
+#include <private/qv4arrayobject_p.h>
#include <private/qv4functionobject_p.h>
+#include <private/qv4objectiterator_p.h>
+#include <private/qv4objectproto_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4symbol_p.h>
QT_BEGIN_NAMESPACE
using namespace QV4;
+using namespace Qt::StringLiterals;
DEFINE_OBJECT_VTABLE(QmlListWrapper);
-void Heap::QmlListWrapper::init()
+static void setArrayData(Heap::QmlListWrapper *d)
+{
+ QV4::Scope scope(d->internalClass->engine);
+ QV4::ScopedObject o(scope, d);
+ o->arrayCreate();
+}
+
+struct ListWrapperObject
+{
+ QV4::Scope scope;
+ QV4::ScopedObject object;
+
+ ListWrapperObject(QQmlListProperty<QObject> *p)
+ : scope(static_cast<Heap::QmlListWrapper *>(p->data)->internalClass->engine)
+ , object(scope, static_cast<Heap::QmlListWrapper *>(p->data))
+ {
+ Q_ASSERT(object);
+ Q_ASSERT(object->arrayData());
+ }
+
+ Heap::ArrayData *arrayData() const
+ {
+ return object->arrayData();
+ }
+};
+
+static void appendWrapped(QQmlListProperty<QObject> *p, QObject *o)
+{
+ ListWrapperObject object(p);
+ Heap::ArrayData *arrayData = object.arrayData();
+
+ const uint length = arrayData->length();
+ if (Q_UNLIKELY(length == std::numeric_limits<uint>::max())) {
+ object.scope.engine->throwRangeError(QLatin1String("Too many elements."));
+ return;
+ }
+
+ ArrayData::realloc(object.object, Heap::ArrayData::Simple, length + 1, false);
+ arrayData->vtable()->put(
+ object.object, length, QV4::QObjectWrapper::wrap(object.scope.engine, o));
+}
+
+static qsizetype countWrapped(QQmlListProperty<QObject> *p)
+{
+ ListWrapperObject object(p);
+ return object.arrayData()->length();
+}
+
+static QObject *atWrapped(QQmlListProperty<QObject> *p, qsizetype i)
+{
+ ListWrapperObject object(p);
+ QV4::Scoped<QObjectWrapper> result(object.scope, object.arrayData()->get(i));
+ return result ? result->object() : nullptr;
+}
+
+static void clearWrapped(QQmlListProperty<QObject> *p)
+{
+ ListWrapperObject object(p);
+ object.arrayData()->vtable()->truncate(object.object, 0);
+}
+
+static void replaceWrapped(QQmlListProperty<QObject> *p, qsizetype i, QObject *o)
+{
+ ListWrapperObject object(p);
+ object.arrayData()->vtable()->put(
+ object.object, i, QV4::QObjectWrapper::wrap(object.scope.engine, o));
+}
+
+static void removeLastWrapped(QQmlListProperty<QObject> *p)
+{
+ ListWrapperObject object(p);
+ Heap::ArrayData *arrayData = object.arrayData();
+ const uint length = arrayData->length();
+ if (length > 0)
+ arrayData->vtable()->truncate(object.object, length - 1);
+}
+
+void Heap::QmlListWrapper::init(QMetaType propertyType)
+{
+ Object::init();
+ m_object.init();
+ m_propertyType = propertyType.iface();
+ setArrayData(this);
+ *property() = QQmlListProperty<QObject>(
+ nullptr, this,
+ appendWrapped, countWrapped, atWrapped,
+ clearWrapped, replaceWrapped, removeLastWrapped);
+}
+
+void Heap::QmlListWrapper::init(QObject *object, int propertyId, QMetaType propertyType)
+{
+ Object::init();
+ m_object.init(object);
+ m_propertyType = propertyType.iface();
+ void *args[] = { property(), nullptr };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyId, args);
+}
+
+void Heap::QmlListWrapper::init(
+ QObject *object, const QQmlListProperty<QObject> &list, QMetaType propertyType)
{
Object::init();
- object.init();
- QV4::Scope scope(internalClass->engine);
- QV4::ScopedObject o(scope, this);
- o->setArrayType(Heap::ArrayData::Custom);
+ m_object.init(object);
+ m_propertyType = propertyType.iface();
+ *property() = list;
}
void Heap::QmlListWrapper::destroy()
{
- object.destroy();
+ m_object.destroy();
Object::destroy();
}
-ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, QObject *object, int propId, int propType)
+ReturnedValue QmlListWrapper::create(
+ ExecutionEngine *engine, QObject *object, int propId, QMetaType propType)
{
if (!object || propId == -1)
return Encode::null();
-
- Scope scope(engine);
-
- Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocate<QmlListWrapper>());
- r->d()->object = object;
- r->d()->propertyType = propType;
- void *args[] = { &r->d()->property(), nullptr };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args);
- return r.asReturnedValue();
+ return engine->memoryManager->allocate<QmlListWrapper>(object, propId, propType)
+ ->asReturnedValue();
}
-ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, const QQmlListProperty<QObject> &prop, int propType)
+ReturnedValue QmlListWrapper::create(
+ ExecutionEngine *engine, const QQmlListProperty<QObject> &prop, QMetaType propType)
{
- Scope scope(engine);
+ return engine->memoryManager->allocate<QmlListWrapper>(prop.object, prop, propType)
+ ->asReturnedValue();
+}
- Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocate<QmlListWrapper>());
- r->d()->object = prop.object;
- r->d()->property() = prop;
- r->d()->propertyType = propType;
- return r.asReturnedValue();
+ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, QMetaType propType)
+{
+ return engine->memoryManager->allocate<QmlListWrapper>(propType)->asReturnedValue();
}
QVariant QmlListWrapper::toVariant() const
{
- if (!d()->object)
+ if (!d()->object())
return QVariant();
- return QVariant::fromValue(QQmlListReferencePrivate::init(d()->property(), d()->propertyType, engine()->qmlEngine()));
+ return QVariant::fromValue(toListReference());
}
+QQmlListReference QmlListWrapper::toListReference() const
+{
+ const Heap::QmlListWrapper *wrapper = d();
+ return QQmlListReferencePrivate::init(*wrapper->property(), wrapper->propertyType());
+}
ReturnedValue QmlListWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
{
@@ -108,35 +177,66 @@ ReturnedValue QmlListWrapper::virtualGet(const Managed *m, PropertyKey id, const
QV4::ExecutionEngine *v4 = w->engine();
if (id.isArrayIndex()) {
- uint index = id.asArrayIndex();
- quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
- if (index < count && w->d()->property().at) {
+ const uint index = id.asArrayIndex();
+ const quint32 count = w->d()->property()->count
+ ? w->d()->property()->count(w->d()->property())
+ : 0;
+ if (index < count && w->d()->property()->at) {
if (hasProperty)
*hasProperty = true;
- return QV4::QObjectWrapper::wrap(v4, w->d()->property().at(&w->d()->property(), index));
+ return QV4::QObjectWrapper::wrap(v4, w->d()->property()->at(w->d()->property(), index));
}
if (hasProperty)
*hasProperty = false;
return Value::undefinedValue().asReturnedValue();
- } else if (id.isString()) {
- if (id == v4->id_length()->propertyKey() && !w->d()->object.isNull()) {
- quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
- return Value::fromUInt32(count).asReturnedValue();
- }
}
return Object::virtualGet(m, id, receiver, hasProperty);
}
+qint64 QmlListWrapper::virtualGetLength(const Managed *m)
+{
+ Q_ASSERT(m->as<QmlListWrapper>());
+ QQmlListProperty<QObject> *property = static_cast<const QmlListWrapper *>(m)->d()->property();
+ Q_ASSERT(property);
+ return property->count ? property->count(property) : 0;
+}
+
bool QmlListWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
{
- // doesn't do anything. Should we throw?
- Q_UNUSED(m);
- Q_UNUSED(id);
- Q_UNUSED(value);
- Q_UNUSED(receiver);
- return false;
+ Q_ASSERT(m->as<QmlListWrapper>());
+
+ const auto *w = static_cast<const QmlListWrapper *>(m);
+ QV4::ExecutionEngine *v4 = w->engine();
+
+ QQmlListProperty<QObject> *prop = w->d()->property();
+
+ if (id.isArrayIndex()) {
+ if (!prop->count || !prop->replace)
+ return false;
+
+ const uint index = id.asArrayIndex();
+ const int count = prop->count(prop);
+ if (count < 0 || index >= uint(count))
+ return false;
+
+ if (value.isNull()) {
+ prop->replace(prop, index, nullptr);
+ return true;
+ }
+
+ QV4::Scope scope(v4);
+ QV4::ScopedObject so(scope, value.toObject(scope.engine));
+ if (auto *wrapper = so->as<QV4::QObjectWrapper>()) {
+ prop->replace(prop, index, wrapper->object());
+ return true;
+ }
+
+ return false;
+ }
+
+ return Object::virtualPut(m, id, value, receiver);
}
struct QmlListWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
@@ -150,18 +250,24 @@ PropertyKey QmlListWrapperOwnPropertyKeyIterator::next(const Object *o, Property
{
const QmlListWrapper *w = static_cast<const QmlListWrapper *>(o);
- quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
+ quint32 count = w->d()->property()->count ? w->d()->property()->count(w->d()->property()) : 0;
if (arrayIndex < count) {
uint index = arrayIndex;
++arrayIndex;
if (attrs)
*attrs = QV4::Attr_Data;
- if (pd)
- pd->value = QV4::QObjectWrapper::wrap(w->engine(), w->d()->property().at(&w->d()->property(), index));
+ if (pd) {
+ pd->value = QV4::QObjectWrapper::wrap(
+ w->engine(), w->d()->property()->at(w->d()->property(), index));
+ }
return PropertyKey::fromArrayIndex(index);
+ } else if (memberIndex == 0) {
+ ++memberIndex;
+ return o->engine()->id_length()->propertyKey();
}
- return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
+ // You cannot add any own properties via the regular JavaScript interfaces.
+ return PropertyKey::invalid();
}
OwnPropertyKeyIterator *QmlListWrapper::virtualOwnPropertyKeys(const Object *m, Value *target)
@@ -170,9 +276,48 @@ OwnPropertyKeyIterator *QmlListWrapper::virtualOwnPropertyKeys(const Object *m,
return new QmlListWrapperOwnPropertyKeyIterator;
}
-void PropertyListPrototype::init(ExecutionEngine *)
+void PropertyListPrototype::init()
{
+ defineDefaultProperty(QStringLiteral("pop"), method_pop, 0);
defineDefaultProperty(QStringLiteral("push"), method_push, 1);
+ defineDefaultProperty(QStringLiteral("shift"), method_shift, 0);
+ defineDefaultProperty(QStringLiteral("splice"), method_splice, 2);
+ defineDefaultProperty(QStringLiteral("unshift"), method_unshift, 1);
+ defineDefaultProperty(QStringLiteral("indexOf"), method_indexOf, 1);
+ defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1);
+ defineDefaultProperty(QStringLiteral("sort"), method_sort, 1);
+ defineAccessorProperty(QStringLiteral("length"), method_get_length, method_set_length);
+}
+
+ReturnedValue PropertyListPrototype::method_pop(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+ const qsizetype len = property->count(property);
+ if (!len)
+ RETURN_UNDEFINED();
+
+ if (!property->at)
+ return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
+ ScopedValue result(
+ scope, QV4::QObjectWrapper::wrap(scope.engine, property->at(property, len - 1)));
+
+ if (!property->removeLast)
+ return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
+ property->removeLast(property);
+
+ return result->asReturnedValue();
}
ReturnedValue PropertyListPrototype::method_push(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
@@ -184,17 +329,425 @@ ReturnedValue PropertyListPrototype::method_push(const FunctionObject *b, const
QmlListWrapper *w = instance->as<QmlListWrapper>();
if (!w)
RETURN_UNDEFINED();
- if (!w->d()->property().append)
- THROW_GENERIC_ERROR("List doesn't define an Append function");
- QV4::ScopedObject so(scope);
- for (int i = 0, ei = argc; i < ei; ++i)
- {
- so = argv[i].toObject(scope.engine);
- if (QV4::QObjectWrapper *wrapper = so->as<QV4::QObjectWrapper>())
- w->d()->property().append(&w->d()->property(), wrapper->object() );
+ QQmlListProperty<QObject> *property = w->d()->property();
+ if (!property->append)
+ return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+
+ for (int i = 0; i < argc; ++i) {
+ const Value &arg = argv[i];
+ if (!arg.isNull() && !arg.as<QObjectWrapper>())
+ THROW_TYPE_ERROR();
+ }
+
+ const qsizetype length = property->count(property);
+ if (!qIsAtMostUintLimit(length, std::numeric_limits<uint>::max() - argc))
+ return scope.engine->throwRangeError(QString::fromLatin1("List length out of range."));
+
+ for (int i = 0; i < argc; ++i) {
+ if (argv[i].isNull())
+ property->append(property, nullptr);
+ else
+ property->append(property, argv[i].as<QV4::QObjectWrapper>()->object());
}
- return Encode::undefined();
+
+ const auto actualLength = property->count(property);
+ if (actualLength != length + argc)
+ qmlWarning(property->object) << "List didn't append all objects";
+
+ return Encode(uint(actualLength));
+}
+
+ReturnedValue PropertyListPrototype::method_shift(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+ const qsizetype len = property->count(property);
+ if (!len)
+ RETURN_UNDEFINED();
+
+ if (!property->at)
+ return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
+ ScopedValue result(scope, QV4::QObjectWrapper::wrap(scope.engine, property->at(property, 0)));
+
+ if (!property->replace)
+ return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
+ if (!property->removeLast)
+ return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
+
+ for (qsizetype i = 1; i < len; ++i)
+ property->replace(property, i - 1, property->at(property, i));
+ property->removeLast(property);
+
+ return result->asReturnedValue();
+}
+
+ReturnedValue PropertyListPrototype::method_splice(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+ const qsizetype len = property->count(property);
+
+ const double rs = (argc ? argv[0] : Value::undefinedValue()).toInteger();
+ qsizetype start;
+ if (rs < 0)
+ start = static_cast<qsizetype>(qMax(0., len + rs));
+ else
+ start = static_cast<qsizetype>(qMin(rs, static_cast<double>(len)));
+
+ qsizetype deleteCount = 0;
+ qsizetype itemCount = 0;
+ if (argc == 1) {
+ deleteCount = len - start;
+ } else if (argc > 1){
+ itemCount = argc - 2;
+ double dc = argv[1].toInteger();
+ deleteCount = static_cast<qsizetype>(qMin(qMax(dc, 0.), double(len - start)));
+ }
+
+ if (itemCount > deleteCount
+ && len > std::numeric_limits<qsizetype>::max() - itemCount + deleteCount) {
+ return scope.engine->throwTypeError();
+ }
+
+ if (!qIsAtMostUintLimit(deleteCount, std::numeric_limits<uint>::max() - 1))
+ return scope.engine->throwRangeError(QString::fromLatin1("List length out of range."));
+
+ if (!property->at)
+ return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
+
+ for (qsizetype i = 0; i < itemCount; ++i) {
+ const auto arg = argv[i + 2];
+ if (!arg.isNull() && !arg.as<QObjectWrapper>())
+ THROW_TYPE_ERROR();
+ }
+
+ ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
+ newArray->arrayReserve(deleteCount);
+ ScopedValue v(scope);
+ for (qsizetype i = 0; i < deleteCount; ++i) {
+ newArray->arrayPut(
+ i, QObjectWrapper::wrap(scope.engine, property->at(property, start + i)));
+ }
+ newArray->setArrayLengthUnchecked(deleteCount);
+
+ if (!property->replace)
+ return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
+ if (!property->removeLast)
+ return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
+ if (!property->append)
+ return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
+
+ if (itemCount < deleteCount) {
+ for (qsizetype k = start; k < len - deleteCount; ++k)
+ property->replace(property, k + itemCount, property->at(property, k + deleteCount));
+ for (qsizetype k = len; k > len - deleteCount + itemCount; --k)
+ property->removeLast(property);
+ } else if (itemCount > deleteCount) {
+ for (qsizetype k = 0; k < itemCount - deleteCount; ++k)
+ property->append(property, nullptr);
+ for (qsizetype k = len - deleteCount; k > start; --k) {
+ property->replace(
+ property, k + itemCount - 1, property->at(property, k + deleteCount - 1));
+ }
+ }
+
+ for (qsizetype i = 0; i < itemCount; ++i) {
+ const auto arg = argv[i + 2];
+ if (arg.isNull())
+ property->replace(property, start + i, nullptr);
+ else
+ property->replace(property, start + i, arg.as<QObjectWrapper>()->object());
+ }
+
+ return newArray->asReturnedValue();
+}
+
+ReturnedValue PropertyListPrototype::method_unshift(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+ const qsizetype len = property->count(property);
+
+ if (std::numeric_limits<qsizetype>::max() - len < argc || !qIsAtMostUintLimit(len + argc))
+ return scope.engine->throwRangeError(QString::fromLatin1("List length out of range."));
+
+ if (!property->append)
+ return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
+ if (!property->replace)
+ return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
+
+ for (int i = 0; i < argc; ++i) {
+ const auto arg = argv[i];
+ if (!arg.isNull() && !arg.as<QObjectWrapper>())
+ THROW_TYPE_ERROR();
+ }
+
+ for (int i = 0; i < argc; ++i)
+ property->append(property, nullptr);
+ if (property->count(property) != argc + len)
+ return scope.engine->throwTypeError(u"List doesn't append null objects"_s);
+
+ for (qsizetype k = len; k > 0; --k)
+ property->replace(property, k + argc - 1, property->at(property, k - 1));
+
+ for (int i = 0; i < argc; ++i) {
+ const auto *wrapper = argv[i].as<QObjectWrapper>();
+ property->replace(property, i, wrapper ? wrapper->object() : nullptr);
+ }
+
+ return Encode(uint(len + argc));
+}
+
+template<typename Iterate>
+ReturnedValue firstOrLastIndexOf(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc, Iterate iterate)
+{
+ Scope scope(b);
+
+ // Undefined cannot be encoded as QObject*. In particular it's not nullptr.
+ if (argc == 0)
+ THROW_TYPE_ERROR();
+
+ QObject *searchValue;
+ if (argv[0].isNull()) {
+ searchValue = nullptr;
+ } else {
+ Scoped<QObjectWrapper> wrapper(scope, argv[0]);
+ if (wrapper)
+ searchValue = wrapper->object();
+ else
+ THROW_TYPE_ERROR();
+ }
+
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+ const qsizetype len = property->count(property);
+ if (!len)
+ return Encode(-1);
+
+
+ return iterate(scope.engine, property, len, searchValue);
+}
+
+ReturnedValue PropertyListPrototype::method_indexOf(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ return firstOrLastIndexOf(
+ b, thisObject, argv, argc,
+ [argc, argv](ExecutionEngine *engine, QQmlListProperty<QObject> *property,
+ qsizetype len, QObject *searchValue) -> ReturnedValue {
+ qsizetype fromIndex = 0;
+ if (argc >= 2) {
+ double f = argv[1].toInteger();
+ if (hasExceptionOrIsInterrupted(engine))
+ return Encode::undefined();
+ if (f >= len)
+ return Encode(-1);
+ if (f < 0)
+ f = qMax(len + f, 0.);
+ fromIndex = qsizetype(f);
+ }
+
+ for (qsizetype i = fromIndex; i < len; ++i) {
+ if (property->at(property, i) == searchValue) {
+ if (qIsAtMostUintLimit(i))
+ return Encode(uint(i));
+ return engine->throwRangeError(QString::fromLatin1("List length out of range."));
+ }
+ }
+
+ return Encode(-1);
+ });
+}
+
+ReturnedValue PropertyListPrototype::method_lastIndexOf(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ return firstOrLastIndexOf(
+ b, thisObject, argv, argc,
+ [argc, argv](ExecutionEngine *engine, QQmlListProperty<QObject> *property,
+ qsizetype len, QObject *searchValue) -> ReturnedValue {
+ qsizetype fromIndex = len - 1;
+ if (argc >= 2) {
+ double f = argv[1].toInteger();
+ if (hasExceptionOrIsInterrupted(engine))
+ return Encode::undefined();
+ if (f > 0)
+ f = qMin(f, (double)(len - 1));
+ else if (f < 0) {
+ f = len + f;
+ if (f < 0)
+ return Encode(-1);
+ }
+ fromIndex = qsizetype(f);
+ }
+
+ for (qsizetype i = fromIndex; i >= 0; --i) {
+ if (property->at(property, i) == searchValue) {
+ if (qIsAtMostUintLimit(i))
+ return Encode(uint(i));
+ return engine->throwRangeError(QString::fromLatin1("List length out of range."));
+ }
+ }
+
+ return Encode(-1);
+ });
+}
+
+ReturnedValue PropertyListPrototype::method_sort(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+ if (property->count(property) == 0)
+ return thisObject->asReturnedValue();
+ if (!property->at)
+ return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
+ if (!property->replace)
+ return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
+
+ ScopedValue comparefn(scope, argc ? argv[0] : Value::undefinedValue());
+ if (!comparefn->isUndefined() && !comparefn->isFunctionObject())
+ THROW_TYPE_ERROR();
+
+ const ArrayElementLessThan lessThan(scope.engine, comparefn);
+ sortHelper(begin(*property), end(*property), [&](QObject *a, QObject *b) {
+ Scoped<QObjectWrapper> o1(scope, QObjectWrapper::wrap(scope.engine, a));
+ Scoped<QObjectWrapper> o2(scope, QObjectWrapper::wrap(scope.engine, b));
+ return lessThan(o1, o2);
+ });
+
+ return thisObject->asReturnedValue();
+}
+
+ReturnedValue PropertyListPrototype::method_get_length(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ const QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+
+ qsizetype count = property->count(property);
+ if (qIsAtMostUintLimit(count))
+ return Encode(uint(count));
+
+ return scope.engine->throwRangeError(QString::fromLatin1("List length out of range."));
+}
+
+ReturnedValue PropertyListPrototype::method_set_length(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ QV4::Scope scope(b);
+ ScopedObject instance(scope, thisObject->toObject(scope.engine));
+ if (!instance)
+ RETURN_UNDEFINED();
+
+ const QmlListWrapper *w = instance->as<QmlListWrapper>();
+ if (!w)
+ RETURN_UNDEFINED();
+
+ QQmlListProperty<QObject> *property = w->d()->property();
+
+ bool ok = false;
+ const uint newLength = argc ? argv[0].asArrayLength(&ok) : 0;
+ if (!ok)
+ return scope.engine->throwRangeError(QString::fromLatin1("Invalid list length."));
+
+ if (newLength == 0 && property->clear) {
+ property->clear(property);
+ return true;
+ }
+
+ if (!property->count)
+ return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
+
+ qsizetype count = property->count(property);
+ if (!qIsAtMostUintLimit(count))
+ return scope.engine->throwRangeError(QString::fromLatin1("List length out of range."));
+
+ if (newLength < uint(count)) {
+ if (!property->removeLast)
+ return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
+
+ for (uint i = count; i > newLength; --i)
+ property->removeLast(property);
+
+ return true;
+ }
+
+ if (!property->append)
+ return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
+
+ for (uint i = count; i < newLength; ++i)
+ property->append(property, nullptr);
+
+ count = property->count(property);
+ if (!qIsAtMostUintLimit(count))
+ return scope.engine->throwRangeError(QString::fromLatin1("List length out of range."));
+
+ if (uint(count) != newLength)
+ return scope.engine->throwTypeError(u"List doesn't append null objects"_s);
+
+ return true;
+
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h
index c185122ad9..55100e9a07 100644
--- a/src/qml/qml/qqmllistwrapper_p.h
+++ b/src/qml/qml/qqmllistwrapper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLLISTWRAPPER_P_H
#define QQMLLISTWRAPPER_P_H
@@ -65,19 +29,33 @@ namespace QV4 {
namespace Heap {
-struct QmlListWrapper : Object {
- void init();
+struct QmlListWrapper : Object
+{
+ void init(QMetaType propertyType);
+ void init(QObject *object, int propertyId, QMetaType propertyType);
+ void init(QObject *object, const QQmlListProperty<QObject> &list, QMetaType propertyType);
void destroy();
- QQmlQPointer<QObject> object;
- QQmlListProperty<QObject> &property() {
- return *reinterpret_cast<QQmlListProperty<QObject>*>(propertyData);
+ QObject *object() const { return m_object.data(); }
+ QMetaType propertyType() const { return QMetaType(m_propertyType); }
+
+ const QQmlListProperty<QObject> *property() const
+ {
+ return reinterpret_cast<const QQmlListProperty<QObject>*>(m_propertyData);
}
- int propertyType;
+ QQmlListProperty<QObject> *property()
+ {
+ return reinterpret_cast<QQmlListProperty<QObject>*>(m_propertyData);
+ }
private:
- void *propertyData[sizeof(QQmlListProperty<QObject>)/sizeof(void*)];
+ void *m_propertyData[sizeof(QQmlListProperty<QObject>)/sizeof(void*)];
+
+ QV4QPointer<QObject> m_object;
+
+ // interface instead of QMetaType to keep class a POD
+ const QtPrivate::QMetaTypeInterface *m_propertyType;
};
}
@@ -87,22 +65,37 @@ struct Q_QML_EXPORT QmlListWrapper : Object
V4_OBJECT2(QmlListWrapper, Object)
V4_NEEDS_DESTROY
V4_PROTOTYPE(propertyListPrototype)
+ Q_MANAGED_TYPE(QmlListProperty)
- static ReturnedValue create(ExecutionEngine *engine, QObject *object, int propId, int propType);
- static ReturnedValue create(ExecutionEngine *engine, const QQmlListProperty<QObject> &prop, int propType);
+ static ReturnedValue create(ExecutionEngine *engine, QObject *object, int propId, QMetaType propType);
+ static ReturnedValue create(ExecutionEngine *engine, const QQmlListProperty<QObject> &prop, QMetaType propType);
+ static ReturnedValue create(ExecutionEngine *engine, QMetaType propType);
QVariant toVariant() const;
+ QQmlListReference toListReference() const;
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
+ static qint64 virtualGetLength(const Managed *m);
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
};
struct PropertyListPrototype : Object
{
- void init(ExecutionEngine *engine);
+ V4_PROTOTYPE(arrayPrototype)
+
+ void init();
+ static ReturnedValue method_pop(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_push(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_shift(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_splice(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_unshift(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_indexOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_lastIndexOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_sort(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_get_length(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_set_length(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
}
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index dca13ac8d4..3249f5a6eb 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -1,47 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmllocale_p.h"
-#include "qqmlengine_p.h"
#include <private/qqmlcontext_p.h>
#include <QtCore/qnumeric.h>
#include <QtCore/qdatetime.h>
+#include <QtCore/qtimezone.h>
#include <private/qlocale_p.h>
#include <private/qlocale_data_p.h>
@@ -49,13 +13,12 @@
#include <private/qv4dateobject_p.h>
#include <private/qv4numberobject_p.h>
#include <private/qv4stringobject_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
QT_BEGIN_NAMESPACE
using namespace QV4;
-DEFINE_OBJECT_VTABLE(QQmlLocaleData);
-
#define THROW_ERROR(string) \
do { \
return scope.engine->throwError(QString::fromUtf8(string)); \
@@ -63,13 +26,18 @@ DEFINE_OBJECT_VTABLE(QQmlLocaleData);
#define GET_LOCALE_DATA_RESOURCE(OBJECT) \
- QV4::Scoped<QQmlLocaleData> r(scope, OBJECT.as<QQmlLocaleData>()); \
+ QLocale *r = [&]() { \
+ QV4::Scoped<QQmlValueTypeWrapper> r(scope, OBJECT.as<QQmlValueTypeWrapper>()); \
+ return r ? r->cast<QLocale>() : nullptr; \
+ }(); \
if (!r) \
THROW_ERROR("Not a valid Locale object")
static bool isLocaleObject(const QV4::Value &val)
{
- return val.as<QQmlLocaleData>();
+ if (const QV4::QQmlValueTypeWrapper *wrapper = val.as<QQmlValueTypeWrapper>())
+ return wrapper->type() == QMetaType::fromType<QLocale>();
+ return false;
}
//--------------
@@ -114,16 +82,16 @@ ReturnedValue QQmlDateExtension::method_toLocaleString(const QV4::FunctionObject
if (argc == 2) {
if (String *s = argv[1].stringValue()) {
QString format = s->toQString();
- formattedDt = r->d()->locale->toString(dt, format);
+ formattedDt = r->toString(dt, format);
} else if (argv[1].isNumber()) {
quint32 intFormat = argv[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- formattedDt = r->d()->locale->toString(dt, format);
+ formattedDt = r->toString(dt, format);
} else {
THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format");
}
} else {
- formattedDt = r->d()->locale->toString(dt, enumFormat);
+ formattedDt = r->toString(dt, enumFormat);
}
RETURN_RESULT(scope.engine->newString(formattedDt));
@@ -158,16 +126,16 @@ ReturnedValue QQmlDateExtension::method_toLocaleTimeString(const QV4::FunctionOb
if (argc == 2) {
if (String *s = argv[1].stringValue()) {
QString format = s->toQString();
- formattedTime = r->d()->locale->toString(time, format);
+ formattedTime = r->toString(time, format);
} else if (argv[1].isNumber()) {
quint32 intFormat = argv[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- formattedTime = r->d()->locale->toString(time, format);
+ formattedTime = r->toString(time, format);
} else {
THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format");
}
} else {
- formattedTime = r->d()->locale->toString(time, enumFormat);
+ formattedTime = r->toString(time, enumFormat);
}
RETURN_RESULT(scope.engine->newString(formattedTime));
@@ -202,16 +170,16 @@ ReturnedValue QQmlDateExtension::method_toLocaleDateString(const QV4::FunctionOb
if (argc == 2) {
if (String *s = argv[1].stringValue()) {
QString format = s->toQString();
- formattedDate = r->d()->locale->toString(date, format);
+ formattedDate = r->toString(date, format);
} else if (argv[1].isNumber()) {
quint32 intFormat = argv[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- formattedDate = r->d()->locale->toString(date, format);
+ formattedDate = r->toString(date, format);
} else {
THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format");
}
} else {
- formattedDate = r->d()->locale->toString(date, enumFormat);
+ formattedDate = r->toString(date, enumFormat);
}
RETURN_RESULT(scope.engine->newString(formattedDate));
@@ -241,16 +209,16 @@ ReturnedValue QQmlDateExtension::method_fromLocaleString(const QV4::FunctionObje
if (argc == 3) {
if (String *s = argv[2].stringValue()) {
QString format = s->toQString();
- dt = r->d()->locale->toDateTime(dateString, format);
+ dt = r->toDateTime(dateString, format);
} else if (argv[2].isNumber()) {
quint32 intFormat = argv[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- dt = r->d()->locale->toDateTime(dateString, format);
+ dt = r->toDateTime(dateString, format);
} else {
THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format");
}
} else {
- dt = r->d()->locale->toDateTime(dateString, enumFormat);
+ dt = r->toDateTime(dateString, enumFormat);
}
RETURN_RESULT(engine->newDateObject(dt));
@@ -283,16 +251,16 @@ ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(const QV4::Function
if (argc == 3) {
if (String *s = argv[2].stringValue()) {
QString format = s->toQString();
- tm = r->d()->locale->toTime(dateString, format);
+ tm = r->toTime(dateString, format);
} else if (argv[2].isNumber()) {
quint32 intFormat = argv[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- tm = r->d()->locale->toTime(dateString, format);
+ tm = r->toTime(dateString, format);
} else {
THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format");
}
} else {
- tm = r->d()->locale->toTime(dateString, enumFormat);
+ tm = r->toTime(dateString, enumFormat);
}
QDateTime dt;
@@ -314,7 +282,7 @@ ReturnedValue QQmlDateExtension::method_fromLocaleDateString(const QV4::Function
QLocale locale;
QString dateString = s->toQString();
QDate date = locale.toDate(dateString);
- RETURN_RESULT(engine->newDateObject(QDateTime(date)));
+ RETURN_RESULT(engine->newDateObject(date.startOfDay(QTimeZone::UTC)));
}
}
@@ -329,19 +297,19 @@ ReturnedValue QQmlDateExtension::method_fromLocaleDateString(const QV4::Function
if (argc == 3) {
if (String *s = argv[2].stringValue()) {
QString format = s->toQString();
- dt = r->d()->locale->toDate(dateString, format);
+ dt = r->toDate(dateString, format);
} else if (argv[2].isNumber()) {
quint32 intFormat = argv[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
- dt = r->d()->locale->toDate(dateString, format);
+ dt = r->toDate(dateString, format);
} else {
THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format");
}
} else {
- dt = r->d()->locale->toDate(dateString, enumFormat);
+ dt = r->toDate(dateString, enumFormat);
}
- RETURN_RESULT(engine->newDateObject(QDateTime(dt)));
+ RETURN_RESULT(engine->newDateObject(dt.startOfDay(QTimeZone::UTC)));
}
ReturnedValue QQmlDateExtension::method_timeZoneUpdated(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *, int argc)
@@ -389,7 +357,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(const QV4::Functio
if (!argv[1].isString())
THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
QString fs = argv[1].toQString();
- if (fs.length())
+ if (fs.size())
format = fs.at(0).unicode();
}
int prec = 2;
@@ -399,7 +367,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(const QV4::Functio
prec = argv[2].toInt32();
}
- RETURN_RESULT(scope.engine->newString(r->d()->locale->toString(number, (char)format, prec)));
+ RETURN_RESULT(scope.engine->newString(r->toString(number, (char)format, prec)));
}
ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
@@ -428,7 +396,7 @@ ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(const QV4::Func
symbol = argv[1].toQStringNoThrow();
}
- RETURN_RESULT(scope.engine->newString(r->d()->locale->toCurrencyString(number, symbol)));
+ RETURN_RESULT(scope.engine->newString(r->toCurrencyString(number, symbol)));
}
ReturnedValue QQmlNumberExtension::method_fromLocaleString(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *argv, int argc)
@@ -445,13 +413,13 @@ ReturnedValue QQmlNumberExtension::method_fromLocaleString(const QV4::FunctionOb
THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
GET_LOCALE_DATA_RESOURCE(argv[0]);
- locale = *r->d()->locale;
+ locale = *r;
numberIdx = 1;
}
QString ns = argv[numberIdx].toQString();
- if (!ns.length())
+ if (!ns.size())
RETURN_RESULT(QV4::Encode(Q_QNAN));
bool ok = false;
@@ -466,254 +434,164 @@ ReturnedValue QQmlNumberExtension::method_fromLocaleString(const QV4::FunctionOb
//--------------
// Locale object
-ReturnedValue QQmlLocaleData::method_get_firstDayOfWeek(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
+void QQmlLocaleValueType::formattedDataSize(QQmlV4FunctionPtr args) const
{
- QV4::Scope scope(b);
- const QLocale *locale = getThisLocale(scope, thisObject);
- if (!locale)
- return Encode::undefined();
- int fdow = int(locale->firstDayOfWeek());
- if (fdow == 7)
- fdow = 0; // Qt::Sunday = 7, but Sunday is 0 in JS Date
- RETURN_RESULT(fdow);
-}
+ QV4::Scope scope(args->v4engine());
+ const auto doThrow = [&](const QString &message) {
+ args->setReturnValue(scope.engine->throwError(message));
+ };
+
+ const int argc = args->length();
+
+ if (argc < 1 || argc > 3) {
+ doThrow(QString::fromLatin1(
+ "Locale: formattedDataSize(): Expected 1-3 arguments, but received %1")
+ .arg(argc));
+ return;
+ }
-ReturnedValue QQmlLocaleData::method_get_measurementSystem(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(b);
- const QLocale *locale = getThisLocale(scope, thisObject);
- if (!locale)
- return Encode::undefined();
- return QV4::Encode(locale->measurementSystem());
-}
+ QV4::ScopedValue arg0(scope, (*args)[0]);
+ bool mismatched0 = false;
+ if (!arg0->isNumber()) {
+ // ### Qt7: Throw an exception here, so that we don't have to handle mismatched0 below.
+ qWarning() << "Locale: formattedDataSize(): Invalid argument ('bytes' should be a number)";
+ if (argc == 1) {
+ args->setReturnValue(
+ scope.engine->newString(locale.formattedDataSize(qint64(arg0->toInteger())))
+ ->asReturnedValue());
+ return;
+ }
-ReturnedValue QQmlLocaleData::method_get_textDirection(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(b);
- const QLocale *locale = getThisLocale(scope, thisObject);
- if (!locale)
- return Encode::undefined();
+ mismatched0 = true;
+ }
- return QV4::Encode(locale->textDirection());
-}
+ // Anything can be coerced to a number, for better or worse ...
+ Q_ASSERT(argc >= 2);
-ReturnedValue QQmlLocaleData::method_get_weekDays(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(b);
- const QLocale *locale = getThisLocale(scope, thisObject);
- if (!locale)
- return Encode::undefined();
-
- QList<Qt::DayOfWeek> days = locale->weekdays();
-
- QV4::ScopedArrayObject result(scope, scope.engine->newArrayObject());
- result->arrayReserve(days.size());
- for (int i = 0; i < days.size(); ++i) {
- int day = days.at(i);
- if (day == 7) // JS Date days in range 0(Sunday) to 6(Saturday)
- day = 0;
- result->arrayPut(i, QV4::Value::fromInt32(day));
+ QV4::ScopedValue arg1(scope, (*args)[1]);
+ if (!arg1->isInteger()) {
+ doThrow(QLatin1String(
+ "Locale: formattedDataSize(): Invalid argument ('precision' must be an int)"));
+ return;
+ }
+
+ if (mismatched0) {
+ if (argc == 2) {
+ const QString result = locale.formattedDataSize(
+ qint64(arg0->toInteger()), arg1->integerValue());
+ args->setReturnValue(scope.engine->newString(result)->asReturnedValue());
+ return;
+ }
+
+ QV4::ScopedValue arg2(scope, (*args)[2]);
+ if (arg2->isNumber()) {
+ const QString result = locale.formattedDataSize(
+ qint64(arg0->toInteger()), arg1->integerValue(),
+ QLocale::DataSizeFormats(arg2->integerValue()));
+ args->setReturnValue(scope.engine->newString(result)->asReturnedValue());
+ return;
+ }
}
- result->setArrayLengthUnchecked(days.size());
- return result.asReturnedValue();
+ Q_ASSERT(argc == 3);
+ Q_ASSERT(!QV4::ScopedValue(scope, (*args)[2])->isNumber());
+
+ doThrow(QLatin1String(
+ "Locale: formattedDataSize(): Invalid argument ('format' must be DataSizeFormat)"));
}
-ReturnedValue QQmlLocaleData::method_get_uiLanguages(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
+static QQmlLocale::DayOfWeek qtDayToQmlDay(Qt::DayOfWeek day)
{
- QV4::Scope scope(b);
- const QLocale *locale = getThisLocale(scope, thisObject);
- if (!locale)
- return Encode::undefined();
-
- QStringList langs = locale->uiLanguages();
- QV4::ScopedArrayObject result(scope, scope.engine->newArrayObject());
- result->arrayReserve(langs.size());
- QV4::ScopedValue v(scope);
- for (int i = 0; i < langs.size(); ++i)
- result->arrayPut(i, (v = scope.engine->newString(langs.at(i))));
+ return day == Qt::Sunday ? QQmlLocale::DayOfWeek::Sunday : QQmlLocale::DayOfWeek(day);
+}
- result->setArrayLengthUnchecked(langs.size());
+QQmlLocale::DayOfWeek QQmlLocaleValueType::firstDayOfWeek() const
+{
+ return qtDayToQmlDay(locale.firstDayOfWeek());
+}
- return result.asReturnedValue();
+QList<QQmlLocale::DayOfWeek> QQmlLocaleValueType::weekDays() const
+{
+ const QList<Qt::DayOfWeek> days = locale.weekdays();
+ QList<QQmlLocale::DayOfWeek> result;
+ result.reserve(days.size());
+ for (Qt::DayOfWeek day : days)
+ result.append(qtDayToQmlDay(day));
+ return result;
}
-ReturnedValue QQmlLocaleData::method_currencySymbol(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
+void QQmlLocaleValueType::toString(QQmlV4FunctionPtr args) const
{
- QV4::Scope scope(b);
- const QLocale *locale = getThisLocale(scope, thisObject);
- if (!locale)
- return Encode::undefined();
+ Scope scope(args->v4engine());
+ const auto doThrow = [&](const QString &message) {
+ args->setReturnValue(scope.engine->throwError(message));
+ };
- if (argc > 1)
- THROW_ERROR("Locale: currencySymbol(): Invalid arguments");
+ const int argc = args->length();
- QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol;
- if (argc == 1) {
- quint32 intFormat = argv[0].toNumber();
- format = QLocale::CurrencySymbolFormat(intFormat);
+ // toString()
+ Q_ASSERT(argc > 0);
+
+ if (argc > 3) {
+ doThrow(QString::fromLatin1("Locale: toString(): Expected 1-3 arguments, but received %1")
+ .arg(argc));
+ return;
}
- RETURN_RESULT(scope.engine->newString(locale->currencySymbol(format)));
-}
+ QV4::ScopedValue arg0(scope, (*args)[0]);
+ if (arg0->isNumber()) {
-#define LOCALE_FORMAT(FUNC) \
-ReturnedValue QQmlLocaleData::method_ ##FUNC (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) { \
- QV4::Scope scope(b); \
- const QLocale *locale = getThisLocale(scope, thisObject); \
- if (!locale) \
- return Encode::undefined(); \
- if (argc > 1) \
- THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \
- QLocale::FormatType format = QLocale::LongFormat;\
- if (argc == 1) { \
- quint32 intFormat = argv[0].toUInt32(); \
- format = QLocale::FormatType(intFormat); \
- } \
- RETURN_RESULT(scope.engine->newString(locale-> FUNC (format))); \
-}
+ // toString(int)
+ // toString(double)
+ Q_ASSERT(argc != 1);
-LOCALE_FORMAT(dateTimeFormat)
-LOCALE_FORMAT(timeFormat)
-LOCALE_FORMAT(dateFormat)
-
-// +1 added to idx because JS is 0-based, whereas QLocale months begin at 1.
-#define LOCALE_FORMATTED_MONTHNAME(VARIABLE) \
-ReturnedValue QQmlLocaleData::method_ ## VARIABLE (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) {\
- Scope scope(b); \
- const QLocale *locale = getThisLocale(scope, thisObject); \
- if (!locale) \
- return Encode::undefined(); \
- if (argc < 1 || argc > 2) \
- THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
- QLocale::FormatType enumFormat = QLocale::LongFormat; \
- int idx = argv[0].toInt32() + 1; \
- if (idx < 1 || idx > 12) \
- THROW_ERROR("Locale: Invalid month"); \
- QString name; \
- if (argc == 2) { \
- if (argv[1].isNumber()) { \
- quint32 intFormat = argv[1].toUInt32(); \
- QLocale::FormatType format = QLocale::FormatType(intFormat); \
- name = locale-> VARIABLE(idx, format); \
- } else { \
- THROW_ERROR("Locale: Invalid datetime format"); \
- } \
- } else { \
- name = locale-> VARIABLE(idx, enumFormat); \
- } \
- RETURN_RESULT(scope.engine->newString(name)); \
-}
+ QV4::ScopedValue arg1(scope, (*args)[1]);
+ if (!arg1->isString()) {
+ doThrow(QLatin1String("Locale: the second argument to the toString overload "
+ "whose first argument is a double should be a char"));
+ return;
+ }
-// 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date
-#define LOCALE_FORMATTED_DAYNAME(VARIABLE) \
-ReturnedValue QQmlLocaleData::method_ ## VARIABLE (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) {\
- Scope scope(b); \
- const QLocale *locale = getThisLocale(scope, thisObject); \
- if (!locale) \
- return Encode::undefined(); \
- if (argc < 1 || argc > 2) \
- THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
- QLocale::FormatType enumFormat = QLocale::LongFormat; \
- int idx = argv[0].toInt32(); \
- if (idx < 0 || idx > 7) \
- THROW_ERROR("Locale: Invalid day"); \
- if (idx == 0) idx = 7; \
- QString name; \
- if (argc == 2) { \
- if (argv[1].isNumber()) { \
- quint32 intFormat = argv[1].toUInt32(); \
- QLocale::FormatType format = QLocale::FormatType(intFormat); \
- name = locale-> VARIABLE(idx, format); \
- } else { \
- THROW_ERROR("Locale: Invalid datetime format"); \
- } \
- } else { \
- name = locale-> VARIABLE(idx, enumFormat); \
- } \
- RETURN_RESULT(scope.engine->newString(name)); \
-}
+ // toString(double, const QString &)
+ // toString(double, const QString &, int)
+ Q_ASSERT(argc == 3);
+ Q_ASSERT(!QV4::ScopedValue(scope, (*args)[2])->isInteger());
-LOCALE_FORMATTED_MONTHNAME(monthName)
-LOCALE_FORMATTED_MONTHNAME(standaloneMonthName)
-LOCALE_FORMATTED_DAYNAME(dayName)
-LOCALE_FORMATTED_DAYNAME(standaloneDayName)
-
-#define LOCALE_STRING_PROPERTY(VARIABLE) \
-ReturnedValue QQmlLocaleData::method_get_ ## VARIABLE (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) \
-{ \
- Scope scope(b); \
- const QLocale *locale = getThisLocale(scope, thisObject); \
- if (!locale) \
- return Encode::undefined(); \
- RETURN_RESULT(scope.engine->newString(locale-> VARIABLE()));\
-}
+ doThrow(QLatin1String("Locale: the third argument to the toString overload "
+ "whose first argument is a double should be an int"));
+ return;
+ }
-LOCALE_STRING_PROPERTY(name)
-LOCALE_STRING_PROPERTY(nativeLanguageName)
-LOCALE_STRING_PROPERTY(nativeCountryName)
-LOCALE_STRING_PROPERTY(decimalPoint)
-LOCALE_STRING_PROPERTY(groupSeparator)
-LOCALE_STRING_PROPERTY(percent)
-LOCALE_STRING_PROPERTY(zeroDigit)
-LOCALE_STRING_PROPERTY(negativeSign)
-LOCALE_STRING_PROPERTY(positiveSign)
-LOCALE_STRING_PROPERTY(exponential)
-LOCALE_STRING_PROPERTY(amText)
-LOCALE_STRING_PROPERTY(pmText)
-
-class QV4LocaleDataDeletable : public QV4::ExecutionEngine::Deletable
-{
-public:
- QV4LocaleDataDeletable(QV4::ExecutionEngine *engine);
- ~QV4LocaleDataDeletable();
+ if (arg0->as<DateObject>()) {
+ if (argc > 2) {
+ doThrow(QString::fromLatin1(
+ "Locale: the toString() overload that takes a Date as its first "
+ "argument expects 1 or 2 arguments, but received %1").arg(argc));
+ return;
+ }
- QV4::PersistentValue prototype;
-};
+ // toString(QDateTime)
+ Q_ASSERT(argc == 2);
+ QV4::ScopedValue arg1(scope, (*args)[1]);
-QV4LocaleDataDeletable::QV4LocaleDataDeletable(QV4::ExecutionEngine *engine)
-{
- QV4::Scope scope(engine);
- QV4::Scoped<QV4::Object> o(scope, engine->newObject());
-
- o->defineDefaultProperty(QStringLiteral("dateFormat"), QQmlLocaleData::method_dateFormat, 0);
- o->defineDefaultProperty(QStringLiteral("standaloneDayName"), QQmlLocaleData::method_standaloneDayName, 0);
- o->defineDefaultProperty(QStringLiteral("standaloneMonthName"), QQmlLocaleData::method_standaloneMonthName, 0);
- o->defineDefaultProperty(QStringLiteral("dayName"), QQmlLocaleData::method_dayName, 0);
- o->defineDefaultProperty(QStringLiteral("timeFormat"), QQmlLocaleData::method_timeFormat, 0);
- o->defineDefaultProperty(QStringLiteral("monthName"), QQmlLocaleData::method_monthName, 0);
- o->defineDefaultProperty(QStringLiteral("currencySymbol"), QQmlLocaleData::method_currencySymbol, 0);
- o->defineDefaultProperty(QStringLiteral("dateTimeFormat"), QQmlLocaleData::method_dateTimeFormat, 0);
- o->defineAccessorProperty(QStringLiteral("name"), QQmlLocaleData::method_get_name, nullptr);
- o->defineAccessorProperty(QStringLiteral("positiveSign"), QQmlLocaleData::method_get_positiveSign, nullptr);
- o->defineAccessorProperty(QStringLiteral("uiLanguages"), QQmlLocaleData::method_get_uiLanguages, nullptr);
- o->defineAccessorProperty(QStringLiteral("firstDayOfWeek"), QQmlLocaleData::method_get_firstDayOfWeek, nullptr);
- o->defineAccessorProperty(QStringLiteral("pmText"), QQmlLocaleData::method_get_pmText, nullptr);
- o->defineAccessorProperty(QStringLiteral("percent"), QQmlLocaleData::method_get_percent, nullptr);
- o->defineAccessorProperty(QStringLiteral("textDirection"), QQmlLocaleData::method_get_textDirection, nullptr);
- o->defineAccessorProperty(QStringLiteral("weekDays"), QQmlLocaleData::method_get_weekDays, nullptr);
- o->defineAccessorProperty(QStringLiteral("negativeSign"), QQmlLocaleData::method_get_negativeSign, nullptr);
- o->defineAccessorProperty(QStringLiteral("groupSeparator"), QQmlLocaleData::method_get_groupSeparator, nullptr);
- o->defineAccessorProperty(QStringLiteral("decimalPoint"), QQmlLocaleData::method_get_decimalPoint, nullptr);
- o->defineAccessorProperty(QStringLiteral("nativeLanguageName"), QQmlLocaleData::method_get_nativeLanguageName, nullptr);
- o->defineAccessorProperty(QStringLiteral("nativeCountryName"), QQmlLocaleData::method_get_nativeCountryName, nullptr);
- o->defineAccessorProperty(QStringLiteral("zeroDigit"), QQmlLocaleData::method_get_zeroDigit, nullptr);
- o->defineAccessorProperty(QStringLiteral("amText"), QQmlLocaleData::method_get_amText, nullptr);
- o->defineAccessorProperty(QStringLiteral("measurementSystem"), QQmlLocaleData::method_get_measurementSystem, nullptr);
- o->defineAccessorProperty(QStringLiteral("exponential"), QQmlLocaleData::method_get_exponential, nullptr);
-
- prototype.set(engine, o);
-}
+ // toString(QDateTime, QString)
+ Q_ASSERT(!arg1->isString());
-QV4LocaleDataDeletable::~QV4LocaleDataDeletable()
-{
-}
+ // toString(QDateTime, QLocale::FormatType)
+ Q_ASSERT(!arg1->isNumber());
+
+ doThrow(QLatin1String("Locale: the second argument to the toString overloads whose "
+ "first argument is a Date should be a string or FormatType"));
+ return;
+ }
-V4_DEFINE_EXTENSION(QV4LocaleDataDeletable, localeV4Data);
+ doThrow(QLatin1String("Locale: toString() expects either an int, double, "
+ "or Date as its first argument"));
+}
/*!
\qmltype Locale
- \instantiates QQmlLocale
+ //! \instantiates QQmlLocale
\inqmlmodule QtQml
\brief Provides locale specific properties and formatted data.
@@ -767,19 +645,17 @@ V4_DEFINE_EXTENSION(QV4LocaleDataDeletable, localeV4Data);
can use the following enumeration values to specify the formatting of
the string representation for a Date object.
- \list
- \li Locale.LongFormat The long version of day and month names; for
- example, returning "January" as a month name.
- \li Locale.ShortFormat The short version of day and month names; for
- example, returning "Jan" as a month name.
- \li Locale.NarrowFormat A special version of day and month names for
- use when space is limited; for example, returning "J" as a month
- name. Note that the narrow format might contain the same text for
- different months and days or it can even be an empty string if the
- locale doesn't support narrow names, so you should avoid using it
- for date formatting. Also, for the system locale this format is
- the same as ShortFormat.
- \endlist
+ \value Locale.LongFormat The long version of day and month names; for
+ example, returning "January" as a month name.
+ \value Locale.ShortFormat The short version of day and month names; for
+ example, returning "Jan" as a month name.
+ \value Locale.NarrowFormat A special version of day and month names for
+ use when space is limited; for example, returning "J" as a month
+ name. Note that the narrow format might contain the same text for
+ different months and days or it can even be an empty string if the
+ locale doesn't support narrow names, so you should avoid using it
+ for date formatting. Also, for the system locale this format is
+ the same as ShortFormat.
Additionally the double-to-string and string-to-double conversion functions are
@@ -805,31 +681,18 @@ V4_DEFINE_EXTENSION(QV4LocaleDataDeletable, localeV4Data);
\sa Date, Number
*/
-QQmlLocale::QQmlLocale()
-{
-}
-
-QQmlLocale::~QQmlLocale()
-{
-}
-
QV4::ReturnedValue QQmlLocale::locale(ExecutionEngine *engine, const QString &localeName)
{
- QLocale qlocale;
- if (!localeName.isEmpty())
- qlocale = localeName;
- return wrap(engine, qlocale);
-}
+ if (localeName.isEmpty()) {
+ return QQmlValueTypeWrapper::create(
+ engine, nullptr, &QQmlLocaleValueType::staticMetaObject,
+ QMetaType::fromType<QLocale>());
+ }
-QV4::ReturnedValue QQmlLocale::wrap(ExecutionEngine *v4, const QLocale &locale)
-{
- QV4::Scope scope(v4);
- QV4LocaleDataDeletable *d = localeV4Data(scope.engine);
- QV4::Scoped<QQmlLocaleData> wrapper(scope, v4->memoryManager->allocate<QQmlLocaleData>());
- *wrapper->d()->locale = locale;
- QV4::ScopedObject p(scope, d->prototype.value());
- wrapper->setPrototypeOf(p);
- return wrapper.asReturnedValue();
+ QLocale qlocale(localeName);
+ return QQmlValueTypeWrapper::create(
+ engine, &qlocale, &QQmlLocaleValueType::staticMetaObject,
+ QMetaType::fromType<QLocale>());
}
void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine)
@@ -854,10 +717,10 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
/*!
\qmlproperty string QtQml::Locale::name
- Holds the language and country of this locale as a
- string of the form "language_country", where
+ Holds the language and territory of this locale as a
+ string of the form "language_territory", where
language is a lowercase, two-letter ISO 639 language code,
- and country is an uppercase, two- or three-letter ISO 3166 country code.
+ and territory is an uppercase, two- or three-letter ISO 3166 territory code.
*/
/*!
@@ -873,6 +736,16 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
*/
/*!
+ \qmlproperty enumeration QtQml::Locale::numberOptions
+
+ Holds a set of options for number-to-string and
+ string-to-number conversions.
+
+ \sa Number::toLocaleString()
+ \sa Number::fromLocaleString()
+*/
+
+/*!
\qmlproperty string QtQml::Locale::percent
Holds the percent character of this locale.
@@ -931,6 +804,20 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
*/
/*!
+ \qmlmethod string QtQml::Locale::formattedDataSize(int bytes, int precision, DataSizeFormat format)
+ \since 6.2
+
+ Converts a size in \a bytes to a human-readable localized string, comprising a
+ number and a quantified unit.
+
+ The \a precision and \a format arguments are optional.
+
+ For more information, see \l QLocale::formattedDataSize().
+
+ \sa QLocale::DataSizeFormats
+*/
+
+/*!
\qmlmethod string QtQml::Locale::monthName(month, type)
Returns the localized name of \a month (0-11), in the optional
@@ -985,15 +872,13 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
Holds the first day of the week according to the current locale.
- \list
- \li Locale.Sunday = 0
- \li Locale.Monday = 1
- \li Locale.Tuesday = 2
- \li Locale.Wednesday = 3
- \li Locale.Thursday = 4
- \li Locale.Friday = 5
- \li Locale.Saturday = 6
- \endlist
+ \value Locale.Sunday 0
+ \value Locale.Monday 1
+ \value Locale.Tuesday 2
+ \value Locale.Wednesday 3
+ \value Locale.Thursday 4
+ \value Locale.Friday 5
+ \value Locale.Saturday 6
\note that these values match the JS Date API which is different
from the Qt C++ API where Qt::Sunday = 7.
@@ -1009,6 +894,51 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
*/
/*!
+ \qmlmethod string QtQml::Locale::toString(int i)
+ \since 6.5
+
+ Returns a localized string representation of \a i.
+
+ \sa QLocale::toString(int)
+*/
+
+/*!
+ \qmlmethod string QtQml::Locale::toString(double f, char format = 'g', int precision = 6)
+ \overload
+ \since 6.5
+
+ Returns a string representing the floating-point number \a f.
+
+ The form of the representation is controlled by the optional \a format and
+ \a precision parameters.
+
+ See \l {QLocale::toString(double, char, int)} for more information.
+*/
+
+/*!
+ \qmlmethod string QtQml::Locale::toString(Date date, string format)
+ \overload
+ \since 6.5
+
+ Returns a localized string representation of the given \a date in the
+ specified \a format. If \c format is an empty string, an empty string is
+ returned.
+
+ \sa QLocale::toString(QDate, QStringView)
+*/
+
+/*!
+ \qmlmethod string QtQml::Locale::toString(Date date, FormatType format = LongFormat)
+ \overload
+ \since 6.5
+
+ Returns a localized string representation of the given \a date in the
+ specified \a format. If \c format is omitted, \c Locale.LongFormat is used.
+
+ \sa QLocale::toString(QDate, QLocale::FormatType)
+*/
+
+/*!
\qmlproperty Array<string> QtQml::Locale::uiLanguages
Returns an ordered list of locale names for translation purposes in
@@ -1024,10 +954,9 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
\qmlproperty enumeration QtQml::Locale::textDirection
Holds the text direction of the language:
- \list
- \li Qt.LeftToRight
- \li Qt.RightToLeft
- \endlist
+
+ \value Qt.LeftToRight Text normally begins at the left side.
+ \value Qt.RightToLeft Text normally begins at the right side.
*/
/*!
@@ -1046,11 +975,11 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
\qmlmethod string QtQml::Locale::currencySymbol(format)
Returns the currency symbol for the specified \a format:
- \list
- \li Locale.CurrencyIsoCode a ISO-4217 code of the currency.
- \li Locale.CurrencySymbol a currency symbol.
- \li Locale.CurrencyDisplayName a user readable name of the currency.
- \endlist
+
+ \value Locale.CurrencyIsoCode a ISO-4217 code of the currency.
+ \value Locale.CurrencySymbol a currency symbol.
+ \value Locale.CurrencyDisplayName a user readable name of the currency.
+
\sa Number::toLocaleCurrencyString()
*/
@@ -1060,11 +989,12 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
Holds a native name of the language for the locale. For example
"Schwiizertüütsch" for Swiss-German locale.
- \sa nativeCountryName
+ \sa nativeTerritoryName
*/
/*!
\qmlproperty string QtQml::Locale::nativeCountryName
+ \deprecated [6.4] Use nativeTerritoryName instead.
Holds a native name of the country for the locale. For example
"España" for Spanish/Spain locale.
@@ -1073,20 +1003,26 @@ ReturnedValue QQmlLocale::method_localeCompare(const QV4::FunctionObject *b, con
*/
/*!
+ \qmlproperty string QtQml::Locale::nativeTerritoryName
+
+ Holds a native name of the territory for the locale. For example
+ "España" for Spanish/Spain locale.
+
+ \sa nativeLanguageName
+*/
+
+/*!
\qmlproperty enumeration QtQml::Locale::measurementSystem
This property defines which units are used for measurement.
- \list
- \li Locale.MetricSystem This value indicates metric units, such as meters,
- centimeters and millimeters.
- \li Locale.ImperialUSSystem This value indicates imperial units, such as
- inches and miles as they are used in the United States.
- \li Locale.ImperialUKSystem This value indicates imperial units, such as
- inches and miles as they are used in the United Kingdom.
- \li Locale.ImperialSystem Provided for compatibility. The same as
- Locale.ImperialUSSystem.
- \endlist
+ \value Locale.MetricSystem This value indicates metric units, such as meters,
+ centimeters and millimeters.
+ \value Locale.ImperialUSSystem This value indicates imperial units, such as
+ inches and miles as they are used in the United States.
+ \value Locale.ImperialUKSystem This value indicates imperial units, such as
+ inches and miles as they are used in the United Kingdom.
+ \value Locale.ImperialSystem Provided for compatibility. The same as Locale.ImperialUSSystem.
*/
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index 10e0dfcc38..5d26bf8a68 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLLOCALE_H
#define QQMLLOCALE_H
@@ -55,7 +19,7 @@
#include <QtCore/qlocale.h>
#include <QtCore/qobject.h>
-#include <private/qqmlglobal_p.h>
+#include <private/qtqmlglobal_p.h>
#include <private/qv4object_p.h>
QT_REQUIRE_CONFIG(qml_locale);
@@ -91,35 +55,13 @@ private:
};
-class Q_QML_PRIVATE_EXPORT QQmlLocale
+namespace QQmlLocale
{
- Q_GADGET
+ Q_NAMESPACE_EXPORT(Q_QML_EXPORT)
QML_NAMED_ELEMENT(Locale)
- QML_UNCREATABLE("Locale cannot be instantiated. Use Qt.locale().")
- QML_ADDED_IN_MINOR_VERSION(2)
-
-public:
- ~QQmlLocale();
+ QML_ADDED_IN_VERSION(2, 2)
+ QML_NAMESPACE_EXTENDED(QLocale)
- enum MeasurementSystem {
- MetricSystem = QLocale::MetricSystem,
- ImperialSystem = QLocale::ImperialSystem,
- ImperialUSSystem = QLocale::ImperialUSSystem,
- ImperialUKSystem = QLocale::ImperialUKSystem
- };
- Q_ENUM(MeasurementSystem)
- enum FormatType {
- LongFormat = QLocale::LongFormat,
- ShortFormat = QLocale::ShortFormat,
- NarrowFormat = QLocale::NarrowFormat
- };
- Q_ENUM(FormatType)
- enum CurrencySymbolFormat {
- CurrencyIsoCode = QLocale::CurrencyIsoCode,
- CurrencySymbol = QLocale::CurrencySymbol,
- CurrencyDisplayName = QLocale::CurrencyDisplayName
- };
- Q_ENUM(CurrencySymbolFormat)
// Qt defines Sunday as 7, but JS Date assigns Sunday 0
enum DayOfWeek {
Sunday = 0,
@@ -130,79 +72,174 @@ public:
Friday = Qt::Friday,
Saturday = Qt::Saturday
};
- Q_ENUM(DayOfWeek)
+ Q_ENUM_NS(DayOfWeek)
- static QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName);
- static QV4::ReturnedValue wrap(QV4::ExecutionEngine *engine, const QLocale &locale);
+ Q_QML_EXPORT QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName);
+ Q_QML_EXPORT void registerStringLocaleCompare(QV4::ExecutionEngine *engine);
+ Q_QML_EXPORT QV4::ReturnedValue method_localeCompare(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+};
- static void registerStringLocaleCompare(QV4::ExecutionEngine *engine);
+struct DayOfWeekList
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QList<QQmlLocale::DayOfWeek>)
+ QML_SEQUENTIAL_CONTAINER(QQmlLocale::DayOfWeek)
+};
-private:
- QQmlLocale();
+class QQmlLocaleValueType
+{
+ QLocale locale;
+
+ Q_PROPERTY(QQmlLocale::DayOfWeek firstDayOfWeek READ firstDayOfWeek CONSTANT)
+ Q_PROPERTY(QLocale::MeasurementSystem measurementSystem READ measurementSystem CONSTANT)
+ Q_PROPERTY(Qt::LayoutDirection textDirection READ textDirection CONSTANT)
+ Q_PROPERTY(QList<QQmlLocale::DayOfWeek> weekDays READ weekDays CONSTANT)
+ Q_PROPERTY(QStringList uiLanguages READ uiLanguages CONSTANT)
+
+ Q_PROPERTY(QString name READ name CONSTANT)
+ Q_PROPERTY(QString nativeLanguageName READ nativeLanguageName CONSTANT)
+#if QT_DEPRECATED_SINCE(6, 6)
+ Q_PROPERTY(QString nativeCountryName READ nativeCountryName CONSTANT)
+#endif
+ Q_PROPERTY(QString nativeTerritoryName READ nativeTerritoryName CONSTANT)
+ Q_PROPERTY(QString decimalPoint READ decimalPoint CONSTANT)
+ Q_PROPERTY(QString groupSeparator READ groupSeparator CONSTANT)
+ Q_PROPERTY(QString percent READ percent CONSTANT)
+ Q_PROPERTY(QString zeroDigit READ zeroDigit CONSTANT)
+ Q_PROPERTY(QString negativeSign READ negativeSign CONSTANT)
+ Q_PROPERTY(QString positiveSign READ positiveSign CONSTANT)
+ Q_PROPERTY(QString exponential READ exponential CONSTANT)
+ Q_PROPERTY(QString amText READ amText CONSTANT)
+ Q_PROPERTY(QString pmText READ pmText CONSTANT)
+
+ Q_PROPERTY(QLocale::NumberOptions numberOptions READ numberOptions WRITE setNumberOptions)
- static QV4::ReturnedValue method_localeCompare(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
-};
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QLocale)
+ QML_EXTENDED(QQmlLocaleValueType)
+ QML_CONSTRUCTIBLE_VALUE
-namespace QV4 {
+public:
+ Q_INVOKABLE QQmlLocaleValueType(const QString &name) : locale(name) {}
-namespace Heap {
+ Q_INVOKABLE QString currencySymbol(
+ QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol) const
+ {
+ return locale.currencySymbol(format);
+ }
-struct QQmlLocaleData : Object {
- inline void init() { locale = new QLocale; }
- void destroy() {
- delete locale;
- Object::destroy();
+ Q_INVOKABLE QString dateTimeFormat(QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ return locale.dateTimeFormat(format);
}
- QLocale *locale;
-};
-}
+ Q_INVOKABLE QString timeFormat(QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ return locale.timeFormat(format);
+ }
-struct QQmlLocaleData : public QV4::Object
-{
- V4_OBJECT2(QQmlLocaleData, Object)
- V4_NEEDS_DESTROY
-
- static QLocale *getThisLocale(QV4::Scope &scope, const QV4::Value *thisObject) {
- const QV4::Object *o = thisObject->as<Object>();
- const QQmlLocaleData *data = o ? o->as<QQmlLocaleData>() : nullptr;
- if (!data) {
- scope.engine->throwTypeError();
- return nullptr;
- }
- return data->d()->locale;
+ Q_INVOKABLE QString dateFormat(QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ return locale.dateFormat(format);
}
- static QV4::ReturnedValue method_currencySymbol(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_dateTimeFormat(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_timeFormat(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_dateFormat(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_monthName(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_standaloneMonthName(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_dayName(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_standaloneDayName(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
-
- static QV4::ReturnedValue method_get_firstDayOfWeek(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_measurementSystem(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_textDirection(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_weekDays(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_uiLanguages(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
-
- static QV4::ReturnedValue method_get_name(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_nativeLanguageName(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_nativeCountryName(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_decimalPoint(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_groupSeparator(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_percent(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_zeroDigit(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_negativeSign(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_positiveSign(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_exponential(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_amText(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue method_get_pmText(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
-};
+ Q_INVOKABLE QString monthName(int index, QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ // +1 added to idx because JS is 0-based, whereas QLocale months begin at 1.
+ return locale.monthName(index + 1, format);
+ }
+
+ Q_INVOKABLE QString standaloneMonthName(
+ int index, QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ // +1 added to idx because JS is 0-based, whereas QLocale months begin at 1.
+ return locale.standaloneMonthName(index + 1, format);
+ }
+
+ Q_INVOKABLE QString dayName(int index, QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ // 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date
+ return locale.dayName(index == 0 ? 7 : index, format);
+ }
+
+ Q_INVOKABLE QString standaloneDayName(
+ int index, QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ // 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date
+ return locale.standaloneDayName(index == 0 ? 7 : index, format);
+ }
+
+ Q_INVOKABLE void formattedDataSize(QQmlV4FunctionPtr args) const;
+ Q_INVOKABLE QString formattedDataSize(
+ double bytes, int precision = 2,
+ QLocale::DataSizeFormats format = QLocale::DataSizeIecFormat) const
+ {
+ return locale.formattedDataSize(
+ qint64(QV4::Value::toInteger(bytes)), precision, format);
+ }
+
+ Q_INVOKABLE void toString(QQmlV4FunctionPtr args) const;
-}
+ // As a special (undocumented) case, when called with no arguments,
+ // just forward to QDebug. This makes it consistent with other types
+ // in JS that can be converted to a string via toString().
+ Q_INVOKABLE QString toString() const { return QDebug::toString(locale); }
+
+ Q_INVOKABLE QString toString(int i) const { return locale.toString(i); }
+ Q_INVOKABLE QString toString(double f) const
+ {
+ return QJSNumberCoercion::isInteger(f) ? toString(int(f)) : locale.toString(f);
+ }
+ Q_INVOKABLE QString toString(double f, const QString &format, int precision = 6) const
+ {
+ // Lacking a char type, we have to use QString here
+ return format.length() < 1
+ ? QString()
+ : locale.toString(f, format.at(0).toLatin1(), precision);
+ }
+ Q_INVOKABLE QString toString(const QDateTime &dateTime, const QString &format) const
+ {
+ return locale.toString(dateTime, format);
+ }
+ Q_INVOKABLE QString toString(
+ const QDateTime &dateTime, QLocale::FormatType format = QLocale::LongFormat) const
+ {
+ return locale.toString(dateTime, format);
+ }
+
+ QQmlLocale::DayOfWeek firstDayOfWeek() const;
+ QLocale::MeasurementSystem measurementSystem() const { return locale.measurementSystem(); }
+ Qt::LayoutDirection textDirection() const { return locale.textDirection(); }
+ QList<QQmlLocale::DayOfWeek> weekDays() const;
+ QStringList uiLanguages() const { return locale.uiLanguages(); }
+
+ QString name() const { return locale.name(); }
+ QString nativeLanguageName() const { return locale.nativeLanguageName(); }
+#if QT_DEPRECATED_SINCE(6, 6)
+ QString nativeCountryName() const
+ {
+ QT_IGNORE_DEPRECATIONS(return locale.nativeCountryName();)
+ }
+#endif
+ QString nativeTerritoryName() const { return locale.nativeTerritoryName(); }
+ QString decimalPoint() const { return locale.decimalPoint(); }
+ QString groupSeparator() const { return locale.groupSeparator(); }
+ QString percent() const { return locale.percent(); }
+ QString zeroDigit() const { return locale.zeroDigit(); }
+ QString negativeSign() const { return locale.negativeSign(); }
+ QString positiveSign() const { return locale.positiveSign(); }
+ QString exponential() const { return locale.exponential(); }
+ QString amText() const { return locale.amText(); }
+ QString pmText() const { return locale.pmText(); }
+
+ QLocale::NumberOptions numberOptions() const { return locale.numberOptions(); }
+ void setNumberOptions(const QLocale::NumberOptions &numberOptions)
+ {
+ locale.setNumberOptions(numberOptions);
+ }
+};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/qml/qqmlloggingcategory.cpp
index b59a26e17e..8d7fd6c04d 100644
--- a/src/qml/qml/qqmlloggingcategory.cpp
+++ b/src/qml/qml/qqmlloggingcategory.cpp
@@ -1,46 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlloggingcategory_p.h"
#include <QtQml/qqmlinfo.h>
+#include <memory>
+
/*!
\qmltype LoggingCategory
\ingroup qml-utility-elements
@@ -49,11 +15,11 @@
\since 5.8
A logging category can be passed to console.log() and friends as the first argument.
- If supplied to to the logger the LoggingCategory's name will be used as Logging Category
- otherwise the default logging category will be used.
+ If supplied to the logger the LoggingCategory's name will be used as logging category.
+ Otherwise the default logging category will be used.
\qml
- import QtQuick 2.8
+ import QtQuick
Item {
LoggingCategory {
@@ -63,11 +29,18 @@
}
Component.onCompleted: {
- console.log(category, "message");
+ console.log(category, "log message");
+ console.warn(category, "warning message");
}
}
\endqml
+ By default this outputs only \c{com.qt.category: warning message}. The
+ \c{log message} is suppressed due to the \l{defaultLogLevel}. You can,
+ however, configure log levels for QML logging categories the same way
+ you can configure them for
+ \l{QLoggingCategory#configuring-categories}{QLoggingCategory}.
+
\note As the creation of objects is expensive, it is encouraged to put the needed
LoggingCategory definitions into a singleton and import this where needed.
@@ -92,8 +65,21 @@
Holds the default log level of the logging category. By default it is
created with the LoggingCategory.Debug log level.
+ The following enumeration values are available:
+ \list
+ \li LoggingCategory.Debug
+ \li LoggingCategory.Info
+ \li LoggingCategory.Warning
+ \li LoggingCategory.Critical
+ \li LoggingCategory.Fatal
+ \endlist
+
+ They mirror the values of the \l{QtMsgType} enumeration.
+
\note This property needs to be set when declaring the LoggingCategory
and cannot be changed later.
+
+ \sa QtMsgType
*/
QQmlLoggingCategory::QQmlLoggingCategory(QObject *parent)
@@ -118,7 +104,7 @@ QQmlLoggingCategory::DefaultLogLevel QQmlLoggingCategory::defaultLogLevel() cons
QLoggingCategory *QQmlLoggingCategory::category() const
{
- return m_category.data();
+ return m_category.get();
}
void QQmlLoggingCategory::classBegin()
@@ -129,32 +115,39 @@ void QQmlLoggingCategory::componentComplete()
{
m_initialized = true;
if (m_name.isNull()) {
- qmlWarning(this) << QLatin1String("Declaring the name of the LoggingCategory is mandatory and cannot be changed later !");
+ qmlWarning(this) << QLatin1String("Declaring the name of a LoggingCategory is mandatory and cannot be changed later");
} else {
- QScopedPointer<QLoggingCategory> category(new QLoggingCategory(m_name.constData(), QtMsgType(m_defaultLogLevel)));
+ auto category = std::make_unique<QLoggingCategory>(m_name.constData(), QtMsgType(m_defaultLogLevel));
m_category.swap(category);
}
}
void QQmlLoggingCategory::setDefaultLogLevel(DefaultLogLevel defaultLogLevel)
{
+ if (m_defaultLogLevel == defaultLogLevel)
+ return;
+
if (m_initialized) {
- qmlWarning(this) << QLatin1String("The defaultLogLevel of a LoggingCategory cannot be changed after the Item is created");
+ qmlWarning(this) << QLatin1String("The defaultLogLevel of a LoggingCategory cannot be changed after the component is completed");
return;
}
m_defaultLogLevel = defaultLogLevel;
}
-
void QQmlLoggingCategory::setName(const QString &name)
{
+ const QByteArray newName = name.toUtf8();
+
+ if (m_name == newName)
+ return;
+
if (m_initialized) {
- qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created");
+ qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the component is completed");
return;
}
- m_name = name.toUtf8();
+ m_name = newName;
}
#include "moc_qqmlloggingcategory_p.cpp"
diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/qml/qqmlloggingcategory_p.h
index c7377528b4..4a27e7e1d7 100644
--- a/src/qml/qml/qqmlloggingcategory_p.h
+++ b/src/qml/qml/qqmlloggingcategory_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLLOGGINGCATEGORY_P_H
#define QQMLLOGGINGCATEGORY_P_H
@@ -57,6 +21,9 @@
#include <QtQml/qqmlparserstatus.h>
#include <QtQml/qqml.h>
+#include <QtCore/private/qglobal_p.h>
+
+#include <memory>
QT_BEGIN_NAMESPACE
@@ -66,9 +33,9 @@ class QQmlLoggingCategory : public QObject, public QQmlParserStatus
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString name READ name WRITE setName)
- Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION 12)
+ Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION(2, 12))
QML_NAMED_ELEMENT(LoggingCategory)
- QML_ADDED_IN_MINOR_VERSION(8)
+ QML_ADDED_IN_VERSION(2, 8)
public:
enum DefaultLogLevel {
@@ -95,7 +62,7 @@ public:
private:
QByteArray m_name;
- QScopedPointer<QLoggingCategory> m_category;
+ std::unique_ptr<QLoggingCategory> m_category;
DefaultLogLevel m_defaultLogLevel = Debug;
bool m_initialized;
};
diff --git a/src/qml/qml/qqmlmetamoduleregistration.cpp b/src/qml/qml/qqmlmetamoduleregistration.cpp
new file mode 100644
index 0000000000..8e55b62b3a
--- /dev/null
+++ b/src/qml/qml/qqmlmetamoduleregistration.cpp
@@ -0,0 +1,26 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qtqmlglobal_p.h>
+#include <qqmlmoduleregistration.h>
+#include <qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+// Provide the type registration for QtQml here, in libQtQml.so.
+// This way we get a completely functional QtQml module and don't have to
+// rely on the plugin to be loaded.
+// In CMakeLists.txt we've specified NO_GENERATE_QMLTYPES to prevent
+// the generation of an extra type registration file.
+Q_QML_EXPORT void qml_register_types_QtQml()
+{
+ // ### Qt7: Handle version 6 like version 2.
+ qmlRegisterModule("QtQml", 2, 0);
+ qmlRegisterModule("QtQml", 2, 254);
+ qmlRegisterModule("QtQml", QT_VERSION_MAJOR, 0);
+ qmlRegisterModule("QtQml", QT_VERSION_MAJOR, QT_VERSION_MINOR);
+}
+
+static const QQmlModuleRegistration registration("QtQml", qml_register_types_QtQml);
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetaobject.cpp b/src/qml/qml/qqmlmetaobject.cpp
index a967f46b12..352db7bd69 100644
--- a/src/qml/qml/qqmlmetaobject.cpp
+++ b/src/qml/qml/qqmlmetaobject.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlmetaobject_p.h"
@@ -44,100 +8,6 @@
QT_BEGIN_NAMESPACE
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
-
-static bool isNamedEnumeratorInScope(const QMetaObject *resolvedMetaObject, const QByteArray &scope,
- const QByteArray &name)
-{
- for (int i = resolvedMetaObject->enumeratorCount() - 1; i >= 0; --i) {
- QMetaEnum m = resolvedMetaObject->enumerator(i);
- if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
- return true;
- }
- return false;
-}
-
-static bool isNamedEnumerator(const QMetaObject *metaObj, const QByteArray &scopedName)
-{
- QByteArray scope;
- QByteArray name;
- int scopeIdx = scopedName.lastIndexOf("::");
- if (scopeIdx != -1) {
- scope = scopedName.left(scopeIdx);
- name = scopedName.mid(scopeIdx + 2);
- } else {
- name = scopedName;
- }
-
- if (scope == "Qt")
- return isNamedEnumeratorInScope(StaticQtMetaObject::get(), scope, name);
-
- if (isNamedEnumeratorInScope(metaObj, scope, name))
- return true;
-
- if (metaObj->d.relatedMetaObjects && !scope.isEmpty()) {
- for (auto related = metaObj->d.relatedMetaObjects; *related; ++related) {
- if (isNamedEnumeratorInScope(*related, scope, name))
- return true;
- }
- }
-
- return false;
-}
-
-// Returns true if \a from is assignable to a property of type \a to
-bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
-{
- Q_ASSERT(!from.isNull() && !to.isNull());
-
- struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) {
- return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
- } };
-
- const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2();
- if (tom == &QObject::staticMetaObject) return true;
-
- if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache
- QQmlPropertyCache *fromp = from._m.asT1();
- QQmlPropertyCache *top = to._m.asT1();
-
- while (fromp) {
- if (fromp == top) return true;
- fromp = fromp->parent();
- }
- } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject
- QQmlPropertyCache *fromp = from._m.asT1();
-
- while (fromp) {
- const QMetaObject *fromm = fromp->metaObject();
- if (fromm && I::equal(fromm, tom)) return true;
- fromp = fromp->parent();
- }
- } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache
- const QMetaObject *fromm = from._m.asT2();
-
- if (!tom) return false;
-
- while (fromm) {
- if (I::equal(fromm, tom)) return true;
- fromm = fromm->superClass();
- }
- } else { // QMetaObject -> QMetaObject
- const QMetaObject *fromm = from._m.asT2();
-
- while (fromm) {
- if (I::equal(fromm, tom)) return true;
- fromm = fromm->superClass();
- }
- }
-
- return false;
-}
-
void QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index)
{
int offset;
@@ -146,11 +16,6 @@ void QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type,
case QMetaObject::ReadProperty:
case QMetaObject::WriteProperty:
case QMetaObject::ResetProperty:
- case QMetaObject::QueryPropertyDesignable:
- case QMetaObject::QueryPropertyEditable:
- case QMetaObject::QueryPropertyScriptable:
- case QMetaObject::QueryPropertyStored:
- case QMetaObject::QueryPropertyUser:
offset = (*metaObject)->propertyOffset();
while (*index < offset) {
*metaObject = (*metaObject)->superClass();
@@ -173,155 +38,22 @@ void QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type,
*index -= offset;
}
-QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
+QMetaType QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const
{
- if (_m.isNull()) return nullptr;
- if (_m.isT1()) return _m.asT1();
- else return e->cache(_m.asT2());
-}
-
-int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const
-{
- Q_ASSERT(!_m.isNull() && data.coreIndex() >= 0);
-
- int type = data.propType();
-
- const char *propTypeName = nullptr;
+ Q_ASSERT(_m && data.coreIndex() >= 0);
- if (type == QMetaType::UnknownType) {
+ QMetaType type = data.propType();
+ if (!type.isValid()) {
// Find the return type name from the method info
- QMetaMethod m;
-
- if (_m.isT1()) {
- QQmlPropertyCache *c = _m.asT1();
- Q_ASSERT(data.coreIndex() < c->methodIndexCacheStart + c->methodIndexCache.count());
-
- while (data.coreIndex() < c->methodIndexCacheStart)
- c = c->_parent;
-
- const QMetaObject *metaObject = c->createMetaObject();
- Q_ASSERT(metaObject);
- m = metaObject->method(data.coreIndex());
- } else {
- m = _m.asT2()->method(data.coreIndex());
- }
-
- type = m.returnType();
- propTypeName = m.typeName();
- }
-
- if (QMetaType::sizeOf(type) <= int(sizeof(int))) {
- if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration)
- return QMetaType::Int;
-
- if (isNamedEnumerator(metaObject(), propTypeName))
- return QMetaType::Int;
-
- if (type == QMetaType::UnknownType) {
- if (unknownTypeError)
- *unknownTypeError = propTypeName;
- }
- } // else we know that it's a known type, as sizeOf(UnknownType) == 0
-
- return type;
-}
-
-int *QQmlMetaObject::methodParameterTypes(int index, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const
-{
- Q_ASSERT(!_m.isNull() && index >= 0);
-
- if (_m.isT1()) {
- typedef QQmlPropertyCacheMethodArguments A;
-
- QQmlPropertyCache *c = _m.asT1();
- Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
-
- while (index < c->methodIndexCacheStart)
- c = c->_parent;
-
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
-
- if (rv->arguments() && static_cast<A *>(rv->arguments())->argumentsValid)
- return static_cast<A *>(rv->arguments())->arguments;
-
- const QMetaObject *metaObject = c->createMetaObject();
- Q_ASSERT(metaObject);
- QMetaMethod m = metaObject->method(index);
-
- int argc = m.parameterCount();
- if (!rv->arguments()) {
- A *args = c->createArgumentsObject(argc, m.parameterNames());
- rv->setArguments(args);
- }
- A *args = static_cast<A *>(rv->arguments());
-
- QList<QByteArray> argTypeNames; // Only loaded if needed
-
- for (int ii = 0; ii < argc; ++ii) {
- int type = m.parameterType(ii);
-
- if (QMetaType::sizeOf(type) > int(sizeof(int))) {
- // Cannot be passed as int
- // We know that it's a known type, as sizeOf(UnknownType) == 0
- } else if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration) {
- type = QMetaType::Int;
- } else {
- if (argTypeNames.isEmpty())
- argTypeNames = m.parameterTypes();
- if (isNamedEnumerator(metaObject, argTypeNames.at(ii))) {
- type = QMetaType::Int;
- } else if (type == QMetaType::UnknownType){
- if (unknownTypeError)
- *unknownTypeError = argTypeNames.at(ii);
- return nullptr;
- }
-
- }
- args->arguments[ii + 1] = type;
- }
- args->argumentsValid = true;
- return static_cast<A *>(rv->arguments())->arguments;
-
- } else {
- QMetaMethod m = _m.asT2()->method(index);
- return methodParameterTypes(m, argStorage, unknownTypeError);
-
- }
-}
-
-int *QQmlMetaObject::methodParameterTypes(const QMetaMethod &m, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const
-{
- Q_ASSERT(argStorage);
-
- int argc = m.parameterCount();
- argStorage->resize(argc + 1);
- argStorage->operator[](0) = argc;
- QList<QByteArray> argTypeNames; // Only loaded if needed
-
- for (int ii = 0; ii < argc; ++ii) {
- int type = m.parameterType(ii);
- if (QMetaType::sizeOf(type) > int(sizeof(int))) {
- // Cannot be passed as int
- // We know that it's a known type, as sizeOf(UnknownType) == 0
- } else if (QMetaType::typeFlags(type) & QMetaType::IsEnumeration) {
- type = QMetaType::Int;
- } else {
- if (argTypeNames.isEmpty())
- argTypeNames = m.parameterTypes();
- if (isNamedEnumerator(_m.asT2(), argTypeNames.at(ii))) {
- type = QMetaType::Int;
- } else if (type == QMetaType::UnknownType) {
- if (unknownTypeError)
- *unknownTypeError = argTypeNames.at(ii);
- return nullptr;
- }
- }
- argStorage->operator[](ii + 1) = type;
- }
-
- return argStorage->data();
+ type = _m->method(data.coreIndex()).returnMetaType();
+ }
+ if (type.flags().testFlag(QMetaType::IsEnumeration))
+ type = type.underlyingType();
+ if (type.isValid())
+ return type;
+ else if (unknownTypeError)
+ *unknownTypeError = _m->method(data.coreIndex()).typeName();
+ return QMetaType();
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetaobject_p.h b/src/qml/qml/qqmlmetaobject_p.h
index 65d6361b90..498c27884e 100644
--- a/src/qml/qml/qqmlmetaobject_p.h
+++ b/src/qml/qml/qqmlmetaobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLMETAOBJECT_P_H
#define QQMLMETAOBJECT_P_H
@@ -51,11 +15,9 @@
// We mean it.
//
-#include <QtQml/qtqmlglobal.h>
-
-#include <private/qflagpointer_p.h>
#include <private/qqmlpropertycache_p.h>
+#include <QtQml/qtqmlglobal.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qmetaobject.h>
@@ -72,12 +34,13 @@ class QQmlPropertyData;
class Q_QML_EXPORT QQmlMetaObject
{
public:
- typedef QVarLengthArray<int, 9> ArgTypeStorage;
+ template<qsizetype Prealloc>
+ using ArgTypeStorage = QVarLengthArray<QMetaType, Prealloc>;
- inline QQmlMetaObject();
- inline QQmlMetaObject(QObject *);
+ inline QQmlMetaObject() = default;
+ inline QQmlMetaObject(const QObject *);
inline QQmlMetaObject(const QMetaObject *);
- inline QQmlMetaObject(QQmlPropertyCache *);
+ inline QQmlMetaObject(const QQmlPropertyCache::ConstPtr &);
inline QQmlMetaObject(const QQmlMetaObject &);
inline QQmlMetaObject &operator=(const QQmlMetaObject &);
@@ -87,39 +50,131 @@ public:
inline const char *className() const;
inline int propertyCount() const;
- inline bool hasMetaObject() const;
inline const QMetaObject *metaObject() const;
- QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const;
+ QMetaType methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const;
+
+ /*!
+ \internal
+ Returns false if one of the types is unknown. Otherwise, fills \a argstorage with the
+ metatypes of the function.
+ */
+ template<typename ArgTypeStorage>
+ bool methodParameterTypes(
+ int index, ArgTypeStorage *argStorage, QByteArray *unknownTypeError) const
+ {
+ Q_ASSERT(_m && index >= 0);
+
+ QMetaMethod m = _m->method(index);
+ return methodParameterTypes(m, argStorage, unknownTypeError);
+ }
+
+ /*!
+ \internal
+ Returns false if one of the types is unknown. Otherwise, fills \a argstorage with the
+ metatypes of the function.
+ */
+ template<typename ArgTypeStorage>
+ bool constructorParameterTypes(
+ int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const
+ {
+ QMetaMethod m = _m->constructor(index);
+ return methodParameterTypes(m, dummy, unknownTypeError);
+ }
- int methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const;
- int *methodParameterTypes(int index, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const;
- static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
+ static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
+ {
+ Q_ASSERT(!from.isNull() && !to.isNull());
+ return from.metaObject()->inherits(to.metaObject());
+ }
// static_metacall (on Gadgets) doesn't call the base implementation and therefore
// we need a helper to find the correct meta object and property/method index.
- static void resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index);
+ static void resolveGadgetMethodOrPropertyIndex(
+ QMetaObject::Call type, const QMetaObject **metaObject, int *index);
+
+ template<typename ArgTypeStorage>
+ static bool methodParameterTypes(
+ const QMetaMethod &method, ArgTypeStorage *argStorage, QByteArray *unknownTypeError)
+ {
+ Q_ASSERT(argStorage);
+
+ const int argc = method.parameterCount();
+ argStorage->resize(argc);
+ for (int ii = 0; ii < argc; ++ii) {
+ if (!parameterType(method, ii, unknownTypeError, [argStorage](int ii, QMetaType &&type) {
+ argStorage->operator[](ii) = std::forward<QMetaType>(type);
+ })) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ template<typename ArgTypeStorage>
+ static bool methodReturnAndParameterTypes(
+ const QMetaMethod &method, ArgTypeStorage *argStorage, QByteArray *unknownTypeError)
+ {
+ Q_ASSERT(argStorage);
+
+ const int argc = method.parameterCount();
+ argStorage->resize(argc + 1);
+
+ QMetaType type = method.returnMetaType();
+ if (type.flags().testFlag(QMetaType::IsEnumeration))
+ type = type.underlyingType();
+
+ if (!type.isValid()) {
+ if (unknownTypeError)
+ *unknownTypeError = "return type";
+ return false;
+ }
+
+ argStorage->operator[](0) = type;
+
+ for (int ii = 0; ii < argc; ++ii) {
+ if (!parameterType(
+ method, ii, unknownTypeError, [argStorage](int ii, QMetaType &&type) {
+ argStorage->operator[](ii + 1) = std::forward<QMetaType>(type);
+ })) {
+ return false;
+ }
+ }
+
+ return true;
+ }
protected:
- QBiPointer<QQmlPropertyCache, const QMetaObject> _m;
- int *methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage,
- QByteArray *unknownTypeError) const;
+ template<typename Store>
+ static bool parameterType(
+ const QMetaMethod &method, int ii, QByteArray *unknownTypeError, const Store &store)
+ {
+ QMetaType type = method.parameterMetaType(ii);
+
+ // we treat enumerations as their underlying type
+ if (type.flags().testFlag(QMetaType::IsEnumeration))
+ type = type.underlyingType();
+
+ if (!type.isValid()) {
+ if (unknownTypeError)
+ *unknownTypeError = method.parameterTypeName(ii);
+ return false;
+ }
+
+ store(ii, std::move(type));
+ return true;
+ }
-};
-QQmlMetaObject::QQmlMetaObject()
-{
-}
+ const QMetaObject *_m = nullptr;
+
+};
-QQmlMetaObject::QQmlMetaObject(QObject *o)
+QQmlMetaObject::QQmlMetaObject(const QObject *o)
{
- if (o) {
- QQmlData *ddata = QQmlData::get(o, false);
- if (ddata && ddata->propertyCache) _m = ddata->propertyCache;
- else _m = o->metaObject();
- }
+ if (o)
+ _m = o->metaObject();
}
QQmlMetaObject::QQmlMetaObject(const QMetaObject *m)
@@ -127,9 +182,10 @@ QQmlMetaObject::QQmlMetaObject(const QMetaObject *m)
{
}
-QQmlMetaObject::QQmlMetaObject(QQmlPropertyCache *m)
- : _m(m)
+QQmlMetaObject::QQmlMetaObject(const QQmlPropertyCache::ConstPtr &m)
{
+ if (m)
+ _m = m->createMetaObject();
}
QQmlMetaObject::QQmlMetaObject(const QQmlMetaObject &o)
@@ -145,41 +201,26 @@ QQmlMetaObject &QQmlMetaObject::operator=(const QQmlMetaObject &o)
bool QQmlMetaObject::isNull() const
{
- return _m.isNull();
+ return !_m;
}
const char *QQmlMetaObject::className() const
{
- if (_m.isNull()) {
+ if (!_m)
return nullptr;
- } else if (_m.isT1()) {
- return _m.asT1()->className();
- } else {
- return _m.asT2()->className();
- }
+ return metaObject()->className();
}
int QQmlMetaObject::propertyCount() const
{
- if (_m.isNull()) {
+ if (!_m)
return 0;
- } else if (_m.isT1()) {
- return _m.asT1()->propertyCount();
- } else {
- return _m.asT2()->propertyCount();
- }
-}
-
-bool QQmlMetaObject::hasMetaObject() const
-{
- return _m.isT2() || (!_m.isNull() && _m.asT1()->metaObject());
+ return metaObject()->propertyCount();
}
const QMetaObject *QQmlMetaObject::metaObject() const
{
- if (_m.isNull()) return nullptr;
- if (_m.isT1()) return _m.asT1()->createMetaObject();
- else return _m.asT2();
+ return _m;
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index c21247bb95..1175bde3db 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -1,49 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlmetatype_p.h"
+#include <private/qqmlextensionplugin_p.h>
#include <private/qqmlmetatypedata_p.h>
-#include <private/qqmltypemodule_p_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
#include <private/qqmltype_p_p.h>
#include <private/qqmltypeloader_p.h>
-#include <private/qqmlextensionplugin_p.h>
+#include <private/qqmltypemodule_p.h>
+#include <private/qqmlvaluetype_p.h>
#include <private/qv4executablecompilationunit_p.h>
#include <QtCore/qcoreapplication.h>
@@ -51,6 +17,7 @@
#include <QtCore/qloggingcategory.h>
Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+Q_LOGGING_CATEGORY(lcTypeRegistration, "qt.qml.typeregistration")
QT_BEGIN_NAMESPACE
@@ -62,6 +29,12 @@ struct LockedData : private QQmlMetaTypeData
Q_GLOBAL_STATIC(LockedData, metaTypeData)
Q_GLOBAL_STATIC(QRecursiveMutex, metaTypeDataLock)
+struct ModuleUri : public QString
+{
+ ModuleUri(const QString &string) : QString(string) {}
+ ModuleUri(const std::unique_ptr<QQmlTypeModule> &module) : QString(module->module()) {}
+};
+
class QQmlMetaTypeDataPtr
{
Q_DISABLE_COPY_MOVE(QQmlMetaTypeDataPtr)
@@ -80,7 +53,7 @@ public:
bool isValid() const { return data != nullptr; }
private:
- QMutexLocker locker;
+ QMutexLocker<QRecursiveMutex> locker;
LockedData *data = nullptr;
};
@@ -88,45 +61,35 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data,
const QQmlPrivate::RegisterInterface &type)
{
auto *d = new QQmlTypePrivate(QQmlType::InterfaceType);
- d->iid = type.iid;
+ d->extraData.interfaceTypeData = type.iid;
d->typeId = type.typeId;
d->listId = type.listId;
- d->isSetup = true;
- d->version_maj = 0;
- d->version_min = 0;
+ d->module = QString::fromUtf8(type.uri);
+ d->version = type.version;
data->registerType(d);
return d;
}
-static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
- const QQmlPrivate::RegisterSingletonType &type)
+static QQmlTypePrivate *createQQmlType(
+ QQmlMetaTypeData *data, const QString &elementName,
+ const QQmlPrivate::RegisterSingletonType &type,
+ const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo)
{
auto *d = new QQmlTypePrivate(QQmlType::SingletonType);
data->registerType(d);
d->setName(QString::fromUtf8(type.uri), elementName);
- d->version_maj = type.versionMajor;
- d->version_min = type.versionMinor;
-
- if (type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi)) {
- if (type.version >= 1) // static metaobject added in version 1
- d->baseMetaObject = type.instanceMetaObject;
- if (type.version >= 2) // typeId added in version 2
- d->typeId = type.typeId;
- if (type.version >= 2) // revisions added in version 2
- d->revision = type.revision;
- }
+ d->version = type.version;
- d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
- d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi;
- if (type.version >= 3) {
- d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.generalizedQobjectApi;
- } else {
- d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi;
+ if (type.qObjectApi) {
+ d->baseMetaObject = type.instanceMetaObject;
+ d->typeId = type.typeId;
+ d->revision = type.revision;
}
- d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
- d->extraData.sd->singletonInstanceInfo->instanceMetaObject
- = ((type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi) ) && type.version >= 1) ? type.instanceMetaObject : nullptr;
+
+ d->extraData.singletonTypeData->singletonInstanceInfo = siinfo;
+ d->extraData.singletonTypeData->extFunc = type.extensionObjectCreate;
+ d->extraData.singletonTypeData->extMetaObject = type.extensionMetaObject;
return d;
}
@@ -138,72 +101,111 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
data->registerType(d);
d->setName(QString::fromUtf8(type.uri), elementName);
- d->version_maj = type.versionMajor;
- d->version_min = type.versionMinor;
- if (type.version >= 1) // revisions added in version 1
- d->revision = type.revision;
+ d->version = type.version;
+ d->revision = type.revision;
d->typeId = type.typeId;
d->listId = type.listId;
- d->extraData.cd->allocationSize = type.objectSize;
- d->extraData.cd->newFunc = type.create;
- d->extraData.cd->noCreationReason = type.noCreationReason;
+ d->extraData.cppTypeData->allocationSize = type.objectSize;
+ d->extraData.cppTypeData->userdata = type.userdata;
+ d->extraData.cppTypeData->newFunc = type.create;
+ d->extraData.cppTypeData->noCreationReason = type.noCreationReason;
+ d->extraData.cppTypeData->createValueTypeFunc = type.createValueType;
d->baseMetaObject = type.metaObject;
- d->extraData.cd->attachedPropertiesFunc = type.attachedPropertiesFunction;
- d->extraData.cd->attachedPropertiesType = type.attachedPropertiesMetaObject;
- d->extraData.cd->parserStatusCast = type.parserStatusCast;
- d->extraData.cd->propertyValueSourceCast = type.valueSourceCast;
- d->extraData.cd->propertyValueInterceptorCast = type.valueInterceptorCast;
- d->extraData.cd->extFunc = type.extensionObjectCreate;
- d->extraData.cd->customParser = reinterpret_cast<QQmlCustomParser *>(type.customParser);
- d->extraData.cd->registerEnumClassesUnscoped = true;
+ d->extraData.cppTypeData->attachedPropertiesFunc = type.attachedPropertiesFunction;
+ d->extraData.cppTypeData->attachedPropertiesType = type.attachedPropertiesMetaObject;
+ d->extraData.cppTypeData->parserStatusCast = type.parserStatusCast;
+ d->extraData.cppTypeData->propertyValueSourceCast = type.valueSourceCast;
+ d->extraData.cppTypeData->propertyValueInterceptorCast = type.valueInterceptorCast;
+ d->extraData.cppTypeData->finalizerCast = type.has(QQmlPrivate::RegisterType::FinalizerCast)
+ ? type.finalizerCast
+ : -1;
+ d->extraData.cppTypeData->extFunc = type.extensionObjectCreate;
+ d->extraData.cppTypeData->customParser = reinterpret_cast<QQmlCustomParser *>(type.customParser);
+ d->extraData.cppTypeData->registerEnumClassesUnscoped = true;
+ d->extraData.cppTypeData->registerEnumsFromRelatedTypes = true;
+ d->extraData.cppTypeData->constructValueType = type.has(QQmlPrivate::RegisterType::CreationMethod)
+ && type.creationMethod != QQmlPrivate::ValueTypeCreationMethod::None;
+ d->extraData.cppTypeData->populateValueType = type.has(QQmlPrivate::RegisterType::CreationMethod)
+ && type.creationMethod == QQmlPrivate::ValueTypeCreationMethod::Structured;
if (type.extensionMetaObject)
- d->extraData.cd->extMetaObject = type.extensionMetaObject;
+ d->extraData.cppTypeData->extMetaObject = type.extensionMetaObject;
// Check if the user wants only scoped enum classes
if (d->baseMetaObject) {
- auto indexOfClassInfo = d->baseMetaObject->indexOfClassInfo("RegisterEnumClassesUnscoped");
- if (indexOfClassInfo != -1 && QString::fromUtf8(d->baseMetaObject->classInfo(indexOfClassInfo).value()) == QLatin1String("false"))
- d->extraData.cd->registerEnumClassesUnscoped = false;
+ auto indexOfUnscoped = d->baseMetaObject->indexOfClassInfo("RegisterEnumClassesUnscoped");
+ if (indexOfUnscoped != -1
+ && qstrcmp(d->baseMetaObject->classInfo(indexOfUnscoped).value(), "false") == 0) {
+ d->extraData.cppTypeData->registerEnumClassesUnscoped = false;
+ }
+
+ auto indexOfRelated = d->baseMetaObject->indexOfClassInfo("RegisterEnumsFromRelatedTypes");
+ if (indexOfRelated != -1
+ && qstrcmp(d->baseMetaObject->classInfo(indexOfRelated).value(), "false") == 0) {
+ d->extraData.cppTypeData->registerEnumsFromRelatedTypes = false;
+ }
}
return d;
}
+static void addQQmlMetaTypeInterfaces(QQmlTypePrivate *priv, const QByteArray &className)
+{
+ Q_ASSERT(!className.isEmpty());
+ QByteArray ptr = className + '*';
+ QByteArray lst = "QQmlListProperty<" + className + '>';
+
+ QMetaType ptr_type(new QQmlMetaTypeInterface(ptr));
+ QMetaType lst_type(new QQmlListMetaTypeInterface(lst, ptr_type.iface()));
+
+ // Retrieve the IDs once, so that the types are added to QMetaType's custom type registry.
+ ptr_type.id();
+ lst_type.id();
+
+ priv->typeId = ptr_type;
+ priv->listId = lst_type;
+}
+
static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
const QQmlPrivate::RegisterCompositeType &type)
{
+ // This is a procedurally registered composite type. It's evil. It doesn't get any metatypes
+ // because we never want to find it in the compositeTypes. Otherwise we might mix it up with an
+ // actually compiled version of the same type.
+
auto *d = new QQmlTypePrivate(QQmlType::CompositeType);
data->registerType(d);
d->setName(QString::fromUtf8(type.uri), elementName);
- d->version_maj = type.versionMajor;
- d->version_min = type.versionMinor;
-
- d->extraData.fd->url = QQmlTypeLoader::normalize(type.url);
+ d->version = type.version;
+ d->extraData.compositeTypeData = QQmlTypeLoader::normalize(type.url);
return d;
}
-static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &elementName,
- const QQmlPrivate::RegisterCompositeSingletonType &type)
+static QQmlTypePrivate *createQQmlType(
+ QQmlMetaTypeData *data, const QString &elementName,
+ const QQmlPrivate::RegisterCompositeSingletonType &type,
+ const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo)
{
+ // This is a procedurally registered composite singleton. It's evil. It doesn't get any
+ // metatypes because we never want to find it in the compositeTypes. Otherwise we might mix it
+ // up with an actually compiled version of the same type.
+
auto *d = new QQmlTypePrivate(QQmlType::CompositeSingletonType);
data->registerType(d);
d->setName(QString::fromUtf8(type.uri), elementName);
- d->version_maj = type.versionMajor;
- d->version_min = type.versionMinor;
+ d->version = type.version;
- d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
- d->extraData.sd->singletonInstanceInfo->url = QQmlTypeLoader::normalize(type.url);
- d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
+ d->extraData.singletonTypeData->singletonInstanceInfo = siinfo;
return d;
}
void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
- const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
+ const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd,
+ QQmlMetaType::ClonePolicy policy)
{
// Set classname
- builder.setClassName(ignoreEnd->className());
+ builder.setClassName(mo->className());
// Clone Q_CLASSINFO
for (int ii = mo->classInfoOffset(); ii < mo->classInfoCount(); ++ii) {
@@ -217,44 +219,45 @@ void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
}
}
- // Clone Q_PROPERTY
- for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
- QMetaProperty property = mo->property(ii);
+ if (policy != QQmlMetaType::CloneEnumsOnly) {
+ // Clone Q_METHODS - do this first to avoid duplicating the notify signals.
+ for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
+ QMetaMethod method = mo->method(ii);
- int otherIndex = ignoreEnd->indexOfProperty(property.name());
- if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
- builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
- // Skip
- } else {
- builder.addProperty(property);
- }
- }
+ // More complex - need to search name
+ QByteArray name = method.name();
- // Clone Q_METHODS
- for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
- QMetaMethod method = mo->method(ii);
+ bool found = false;
- // More complex - need to search name
- QByteArray name = method.name();
+ for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
+ !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount(); ++ii) {
+ QMetaMethod other = ignoreEnd->method(ii);
- bool found = false;
+ found = name == other.name();
+ }
- for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
- !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
- ++ii) {
+ QMetaMethodBuilder m = builder.addMethod(method);
+ if (found) // SKIP
+ m.setAccess(QMetaMethod::Private);
+ }
- QMetaMethod other = ignoreEnd->method(ii);
+ // Clone Q_PROPERTY
+ for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
+ QMetaProperty property = mo->property(ii);
- found = name == other.name();
+ int otherIndex = ignoreEnd->indexOfProperty(property.name());
+ if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
+ builder.addProperty(QByteArray("__qml_ignore__") + property.name(),
+ QByteArray("void"));
+ // Skip
+ } else {
+ builder.addProperty(property);
+ }
}
-
- QMetaMethodBuilder m = builder.addMethod(method);
- if (found) // SKIP
- m.setAccess(QMetaMethod::Private);
}
- // Clone Q_ENUMS
+ // Clone enums registered with the metatype system
for (int ii = mo->enumeratorOffset(); ii < mo->enumeratorCount(); ++ii) {
QMetaEnum enumerator = mo->enumerator(ii);
@@ -267,21 +270,32 @@ void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
}
}
-void QQmlMetaType::qmlInsertModuleRegistration(const QString &uri, int majorVersion,
- void (*registerFunction)())
+void QQmlMetaType::qmlInsertModuleRegistration(const QString &uri, void (*registerFunction)())
{
- const QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
QQmlMetaTypeDataPtr data;
- if (data->moduleTypeRegistrationFunctions.contains(versionedUri))
- qFatal("Canot add multiple registrations for %s %d", qPrintable(uri), majorVersion);
+ if (data->moduleTypeRegistrationFunctions.contains(uri))
+ qFatal("Cannot add multiple registrations for %s", qPrintable(uri));
else
- data->moduleTypeRegistrationFunctions.insert(versionedUri, registerFunction);
+ data->moduleTypeRegistrationFunctions.insert(uri, registerFunction);
}
-void QQmlMetaType::qmlRegisterModuleTypes(const QString &uri, int majorVersion)
+void QQmlMetaType::qmlRemoveModuleRegistration(const QString &uri)
{
QQmlMetaTypeDataPtr data;
- data->registerModuleTypes(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
+
+ if (!data.isValid())
+ return; // shutdown/deletion race. Not a problem.
+
+ if (!data->moduleTypeRegistrationFunctions.contains(uri))
+ qFatal("Cannot remove multiple registrations for %s", qPrintable(uri));
+ else
+ data->moduleTypeRegistrationFunctions.remove(uri);
+}
+
+bool QQmlMetaType::qmlRegisterModuleTypes(const QString &uri)
+{
+ QQmlMetaTypeDataPtr data;
+ return data->registerModuleTypes(uri);
}
void QQmlMetaType::clearTypeRegistrations()
@@ -289,9 +303,7 @@ void QQmlMetaType::clearTypeRegistrations()
//Only cleans global static, assumed no running engine
QQmlMetaTypeDataPtr data;
- for (QQmlMetaTypeData::TypeModules::const_iterator i = data->uriToModule.constBegin(), cend = data->uriToModule.constEnd(); i != cend; ++i)
- delete *i;
-
+ data->uriToModule.clear();
data->types.clear();
data->idToType.clear();
data->nameToType.clear();
@@ -299,17 +311,33 @@ void QQmlMetaType::clearTypeRegistrations()
data->typePropertyCaches.clear();
data->urlToNonFileImportType.clear();
data->metaObjectToType.clear();
- data->uriToModule.clear();
data->undeletableTypes.clear();
+ data->propertyCaches.clear();
+ data->inlineComponentTypes.clear();
+
+ // Avoid deletion recursion (via QQmlTypePrivate dtor) by moving them out of the way first.
+ QQmlMetaTypeData::CompositeTypes emptyComposites;
+ emptyComposites.swap(data->compositeTypes);
+}
+
+void QQmlMetaType::registerTypeAlias(int typeIndex, const QString &name)
+{
+ QQmlMetaTypeDataPtr data;
+ const QQmlType type = data->types.value(typeIndex);
+ const QQmlTypePrivate *priv = type.priv();
+ data->nameToType.insert(name, priv);
}
-int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent)
+int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &function)
{
+ if (function.structVersion > 1)
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+
QQmlMetaTypeDataPtr data;
- data->parentFunctions.append(autoparent.function);
+ data->parentFunctions.append(function.function);
- return data->parentFunctions.count() - 1;
+ return data->parentFunctions.size() - 1;
}
void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function)
@@ -320,30 +348,23 @@ void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFun
QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type)
{
- if (type.version > 0)
+ if (type.structVersion > 1)
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
QQmlMetaTypeDataPtr data;
QQmlTypePrivate *priv = createQQmlType(data, type);
Q_ASSERT(priv);
- data->idToType.insert(priv->typeId, priv);
- data->idToType.insert(priv->listId, priv);
- // XXX No insertMulti, so no multi-version interfaces?
- if (!priv->elementName.isEmpty())
- data->nameToType.insert(priv->elementName, priv);
- if (data->interfaces.size() <= type.typeId)
- data->interfaces.resize(type.typeId + 16);
- if (data->lists.size() <= type.listId)
- data->lists.resize(type.listId + 16);
- data->interfaces.setBit(type.typeId, true);
- data->lists.setBit(type.listId, true);
+ data->idToType.insert(priv->typeId.id(), priv);
+ data->idToType.insert(priv->listId.id(), priv);
+
+ data->interfaces.insert(type.typeId.id());
return QQmlType(priv);
}
-QString registrationTypeString(QQmlType::RegistrationType typeType)
+static QString registrationTypeString(QQmlType::RegistrationType typeType)
{
QString typeStr;
if (typeType == QQmlType::CppType)
@@ -352,27 +373,43 @@ QString registrationTypeString(QQmlType::RegistrationType typeType)
typeStr = QStringLiteral("singleton type");
else if (typeType == QQmlType::CompositeSingletonType)
typeStr = QStringLiteral("composite singleton type");
+ else if (typeType == QQmlType::SequentialContainerType)
+ typeStr = QStringLiteral("sequential container type");
else
typeStr = QStringLiteral("type");
return typeStr;
}
// NOTE: caller must hold a QMutexLocker on "data"
-bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data,
- const char *uri, const QString &typeName, int majorVersion)
+static bool checkRegistration(
+ QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri,
+ const QString &typeName, QTypeRevision version, QMetaType::TypeFlags flags)
{
if (!typeName.isEmpty()) {
- if (typeName.at(0).isLower()) {
+ if (typeName.at(0).isLower() && (flags & QMetaType::PointerToQObject)) {
QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\"; type names must begin with an uppercase letter"));
- data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName));
+ data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType), typeName));
return false;
}
- int typeNameLen = typeName.length();
+ if (typeName.at(0).isUpper()
+ && (flags & (QMetaType::IsGadget | QMetaType::PointerToGadget))) {
+ qCWarning(lcTypeRegistration).noquote()
+ << QCoreApplication::translate(
+ "qmlRegisterType",
+ "Invalid QML %1 name \"%2\"; "
+ "value type names should begin with a lowercase letter")
+ .arg(registrationTypeString(typeType), typeName);
+ }
+
+ // There can also be types that aren't even gadgets, and there can be types for namespaces.
+ // We cannot check those, but namespaces should be uppercase.
+
+ int typeNameLen = typeName.size();
for (int ii = 0; ii < typeNameLen; ++ii) {
- if (!(typeName.at(ii).isLetterOrNumber() || typeName.at(ii) == '_')) {
+ if (!(typeName.at(ii).isLetterOrNumber() || typeName.at(ii) == u'_')) {
QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\""));
- data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName));
+ data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType), typeName));
return false;
}
}
@@ -380,16 +417,15 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
if (uri && !typeName.isEmpty()) {
QString nameSpace = QString::fromUtf8(uri);
- QQmlMetaTypeData::VersionedUri versionedUri;
- versionedUri.uri = nameSpace;
- versionedUri.majorVersion = majorVersion;
- if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)){
- if (qqtm->isLocked()){
- QString failure(QCoreApplication::translate("qmlRegisterType",
- "Cannot install %1 '%2' into protected module '%3' version '%4'"));
- data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace).arg(majorVersion));
- return false;
- }
+ QQmlTypeModule *qqtm = data->findTypeModule(nameSpace, version);
+ if (qqtm && qqtm->lockLevel() != QQmlTypeModule::LockLevel::Open) {
+ QString failure(QCoreApplication::translate(
+ "qmlRegisterType",
+ "Cannot install %1 '%2' into protected module '%3' version '%4'"));
+ data->recordTypeRegFailure(failure
+ .arg(registrationTypeString(typeType), typeName, nameSpace)
+ .arg(version.majorVersion()));
+ return false;
}
}
@@ -397,46 +433,40 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
}
// NOTE: caller must hold a QMutexLocker on "data"
-QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMetaTypeData *data)
+static QQmlTypeModule *getTypeModule(
+ const QHashedString &uri, QTypeRevision version, QQmlMetaTypeData *data)
{
- QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion);
- QQmlTypeModule *module = data->uriToModule.value(versionedUri);
- if (!module) {
- module = new QQmlTypeModule(versionedUri.uri, versionedUri.majorVersion);
- data->uriToModule.insert(versionedUri, module);
- }
- return module;
+ if (QQmlTypeModule *module = data->findTypeModule(uri, version))
+ return module;
+ return data->addTypeModule(std::make_unique<QQmlTypeModule>(uri, version.majorVersion()));
}
// NOTE: caller must hold a QMutexLocker on "data"
-void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
+static void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
{
Q_ASSERT(type);
if (!type->elementName.isEmpty())
- data->nameToType.insertMulti(type->elementName, type);
+ data->nameToType.insert(type->elementName, type);
if (type->baseMetaObject)
- data->metaObjectToType.insertMulti(type->baseMetaObject, type);
+ data->metaObjectToType.insert(type->baseMetaObject, type);
- if (type->typeId) {
- data->idToType.insert(type->typeId, type);
- if (data->objects.size() <= type->typeId)
- data->objects.resize(type->typeId + 16);
- data->objects.setBit(type->typeId, true);
- }
+ if (type->regType == QQmlType::SequentialContainerType) {
+ if (type->listId.isValid())
+ data->idToType.insert(type->listId.id(), type);
+ } else {
+ if (type->typeId.isValid())
+ data->idToType.insert(type->typeId.id(), type);
- if (type->listId) {
- if (data->lists.size() <= type->listId)
- data->lists.resize(type->listId + 16);
- data->lists.setBit(type->listId, true);
- data->idToType.insert(type->listId, type);
+ if (type->listId.flags().testFlag(QMetaType::IsQmlList))
+ data->idToType.insert(type->listId.id(), type);
}
if (!type->module.isEmpty()) {
const QHashedString &mod = type->module;
- QQmlTypeModule *module = getTypeModule(mod, type->version_maj, data);
+ QQmlTypeModule *module = getTypeModule(mod, type->version, data);
Q_ASSERT(module);
module->add(type);
}
@@ -444,38 +474,52 @@ void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data)
QQmlType QQmlMetaType::registerType(const QQmlPrivate::RegisterType &type)
{
+ if (type.structVersion > int(QQmlPrivate::RegisterType::CurrentVersion))
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+
QQmlMetaTypeDataPtr data;
QString elementName = QString::fromUtf8(type.elementName);
- if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.versionMajor))
+ if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.version,
+ QMetaType(type.typeId).flags())) {
return QQmlType();
+ }
QQmlTypePrivate *priv = createQQmlType(data, elementName, type);
-
addTypeToData(priv, data);
- if (!type.typeId)
- data->idToType.insert(priv->typeId, priv);
return QQmlType(priv);
}
-QQmlType QQmlMetaType::registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
+QQmlType QQmlMetaType::registerSingletonType(
+ const QQmlPrivate::RegisterSingletonType &type,
+ const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo)
{
+ if (type.structVersion > 1)
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+
QQmlMetaTypeDataPtr data;
QString typeName = QString::fromUtf8(type.typeName);
- if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.versionMajor))
+ if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.version,
+ QMetaType(type.typeId).flags())) {
return QQmlType();
+ }
- QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
+ QQmlTypePrivate *priv = createQQmlType(data, typeName, type, siinfo);
addTypeToData(priv, data);
return QQmlType(priv);
}
-QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type)
+QQmlType QQmlMetaType::registerCompositeSingletonType(
+ const QQmlPrivate::RegisterCompositeSingletonType &type,
+ const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo)
{
+ if (type.structVersion > 1)
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+
// Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
QQmlMetaTypeDataPtr data;
@@ -484,21 +528,24 @@ QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::Registe
if (*(type.uri) == '\0')
fileImport = true;
if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? nullptr : type.uri,
- typeName, type.versionMajor)) {
+ typeName, type.version, {})) {
return QQmlType();
}
- QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
+ QQmlTypePrivate *priv = createQQmlType(data, typeName, type, siinfo);
addTypeToData(priv, data);
QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
- files->insertMulti(QQmlTypeLoader::normalize(type.url), priv);
+ files->insert(siinfo->url, priv);
return QQmlType(priv);
}
QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
{
+ if (type.structVersion > 1)
+ qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
+
// Assumes URL is absolute and valid. Checking of user input should happen before the URL enters type.
QQmlMetaTypeDataPtr data;
@@ -506,61 +553,209 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit
bool fileImport = false;
if (*(type.uri) == '\0')
fileImport = true;
- if (!checkRegistration(QQmlType::CompositeType, data, fileImport?nullptr:type.uri, typeName, type.versionMajor))
+ if (!checkRegistration(QQmlType::CompositeType, data, fileImport?nullptr:type.uri, typeName,
+ type.version, {})) {
return QQmlType();
+ }
QQmlTypePrivate *priv = createQQmlType(data, typeName, type);
addTypeToData(priv, data);
QQmlMetaTypeData::Files *files = fileImport ? &(data->urlToType) : &(data->urlToNonFileImportType);
- files->insertMulti(QQmlTypeLoader::normalize(type.url), priv);
+ files->insert(QQmlTypeLoader::normalize(type.url), priv);
return QQmlType(priv);
}
-void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
+class QQmlMetaTypeRegistrationFailureRecorder
+{
+ Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder)
+public:
+ QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures)
+ : data(data)
+ {
+ data->setTypeRegistrationFailures(failures);
+ }
+
+ ~QQmlMetaTypeRegistrationFailureRecorder()
+ {
+ data->setTypeRegistrationFailures(nullptr);
+ }
+
+ QQmlMetaTypeData *data = nullptr;
+};
+
+
+static QQmlType createTypeForUrl(
+ QQmlMetaTypeData *data, const QUrl &url, const QHashedStringRef &qualifiedType,
+ QQmlMetaType::CompositeTypeLookupMode mode, QList<QQmlError> *errors, QTypeRevision version)
{
- QByteArray name = compilationUnit->rootPropertyCache()->className();
+ const int dot = qualifiedType.indexOf(QLatin1Char('.'));
+ const QString typeName = dot < 0
+ ? qualifiedType.toString()
+ : QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1);
+
+ QStringList failures;
+ QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
+
+ // Register the type. Note that the URI parameters here are empty; for
+ // file type imports, we do not place them in a URI as we don't
+ // necessarily have a good and unique one (picture a library import,
+ // which may be found in multiple plugin locations on disk), but there
+ // are other reasons for this too.
+ //
+ // By not putting them in a URI, we prevent the types from being
+ // registered on a QQmlTypeModule; this is important, as once types are
+ // placed on there, they cannot be easily removed, meaning if the
+ // developer subsequently loads a different import (meaning different
+ // types) with the same URI (using, say, a different plugin path), it is
+ // very undesirable that we continue to associate the types from the
+ // "old" URI with that new module.
+ //
+ // Not having URIs also means that the types cannot be found by name
+ // etc, the only way to look them up is through QQmlImports -- for
+ // better or worse.
+ const QQmlType::RegistrationType registrationType = mode == QQmlMetaType::Singleton
+ ? QQmlType::CompositeSingletonType
+ : QQmlType::CompositeType;
+ if (checkRegistration(registrationType, data, nullptr, typeName, version, {})) {
+
+ // TODO: Ideally we should defer most of this work using some lazy/atomic mechanism
+ // that creates the details on first use. We must not observably modify
+ // QQmlTypePrivate after it has been created since it is supposed to be immutable
+ // and shared across threads.
- QByteArray ptr = name + '*';
- QByteArray lst = "QQmlListProperty<" + name + '>';
+ auto *priv = new QQmlTypePrivate(registrationType);
+ addQQmlMetaTypeInterfaces(priv, QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(url));
+
+ priv->setName(QString(), typeName);
+ priv->version = version;
+
+ if (mode == QQmlMetaType::Singleton) {
+ QQmlType::SingletonInstanceInfo::Ptr siinfo = QQmlType::SingletonInstanceInfo::create();
+ siinfo->url = url;
+ siinfo->typeName = typeName.toUtf8();
+ priv->extraData.singletonTypeData->singletonInstanceInfo =
+ QQmlType::SingletonInstanceInfo::ConstPtr(
+ siinfo.take(), QQmlType::SingletonInstanceInfo::ConstPtr::Adopt);
+ } else {
+ priv->extraData.compositeTypeData = url;
+ }
- int ptr_type = QMetaType::registerNormalizedType(ptr,
- QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Destruct,
- QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Construct,
- sizeof(QObject*),
- static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags),
- nullptr);
- int lst_type = QMetaType::registerNormalizedType(lst,
- QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Destruct,
- QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Construct,
- sizeof(QQmlListProperty<QObject>),
- static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags),
- static_cast<QMetaObject*>(nullptr));
+ data->registerType(priv);
+ addTypeToData(priv, data);
+ return QQmlType(priv);
+ }
- compilationUnit->metaTypeId = ptr_type;
- compilationUnit->listMetaTypeId = lst_type;
+ // This means that the type couldn't be found by URL, but could not be
+ // registered either, meaning we most likely were passed some kind of bad
+ // data.
+ if (errors) {
+ QQmlError error;
+ error.setDescription(failures.join(u'\n'));
+ errors->prepend(error);
+ } else {
+ qWarning("%s", failures.join(u'\n').toLatin1().constData());
+ }
+ return QQmlType();
+}
+QQmlType QQmlMetaType::findCompositeType(
+ const QUrl &url, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit,
+ CompositeTypeLookupMode mode)
+{
+ const QUrl normalized = QQmlTypeLoader::normalize(url);
QQmlMetaTypeDataPtr data;
- data->qmlLists.insert(lst_type, ptr_type);
+
+ bool urlExists = true;
+ auto found = data->urlToType.constFind(normalized);
+ if (found == data->urlToType.cend()) {
+ found = data->urlToNonFileImportType.constFind(normalized);
+ if (found == data->urlToNonFileImportType.cend())
+ urlExists = false;
+ }
+
+ if (const QtPrivate::QMetaTypeInterface *iface = urlExists
+ ? found.value()->typeId.iface()
+ : nullptr) {
+ if (compilationUnit.isNull())
+ return QQmlType(*found);
+
+ const auto composite = data->compositeTypes.constFind(iface);
+ if (composite == data->compositeTypes.constEnd() || composite.value() == compilationUnit)
+ return QQmlType(*found);
+ }
+
+ const QQmlType type = createTypeForUrl(
+ data, normalized, QHashedStringRef(), mode, nullptr, QTypeRevision());
+
+ if (!urlExists && type.isValid())
+ data->urlToType.insert(normalized, type.priv());
+
+ return type;
}
-void QQmlMetaType::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
+static QQmlType doRegisterInlineComponentType(QQmlMetaTypeData *data, const QUrl &url)
{
- int ptr_type = compilationUnit->metaTypeId;
- int lst_type = compilationUnit->listMetaTypeId;
+ QQmlTypePrivate *priv = new QQmlTypePrivate(QQmlType::InlineComponentType);
+ priv->setName(QString(), url.fragment());
+
+ priv->extraData.inlineComponentTypeData = url;
+
+ const QByteArray className
+ = QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(url, url.fragment());
+
+ addQQmlMetaTypeInterfaces(priv, className);
+ const QQmlType result(priv);
+ priv->release();
+
+ data->inlineComponentTypes.insert(url, result);
+
+ return result;
+}
+QQmlType QQmlMetaType::findInlineComponentType(
+ const QUrl &url, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+{
QQmlMetaTypeDataPtr data;
- data->qmlLists.remove(lst_type);
- QMetaType::unregisterType(ptr_type);
- QMetaType::unregisterType(lst_type);
+ // If there is an "unclaimed" inline component type, we can "claim" it now. Otherwise
+ // we have to create a new one.
+ const auto it = data->inlineComponentTypes.constFind(url);
+ if (it != data->inlineComponentTypes.constEnd()) {
+ const auto jt = data->compositeTypes.constFind(it->typeId().iface());
+ if (jt == data->compositeTypes.constEnd() || *jt == compilationUnit)
+ return *it;
+ }
+
+ return doRegisterInlineComponentType(data, url);
+}
+
+void QQmlMetaType::unregisterInternalCompositeType(QMetaType metaType, QMetaType listMetaType)
+{
+ // This may be called from delayed dtors on shutdown when the data is already gone.
+ QQmlMetaTypeDataPtr data;
+ if (data.isValid()) {
+ if (QQmlValueType *vt = data->metaTypeToValueType.take(metaType.id()))
+ delete vt;
+ if (QQmlValueType *vt = data->metaTypeToValueType.take(listMetaType.id()))
+ delete vt;
+
+ auto it = data->compositeTypes.constFind(metaType.iface());
+ if (it != data->compositeTypes.constEnd())
+ data->compositeTypes.erase(it);
+ }
+
+ QMetaType::unregisterMetaType(metaType);
+ QMetaType::unregisterMetaType(listMetaType);
+ delete static_cast<const QQmlMetaTypeInterface *>(metaType.iface());
+ delete static_cast<const QQmlListMetaTypeInterface *>(listMetaType.iface());
}
int QQmlMetaType::registerUnitCacheHook(
const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration)
{
- if (hookRegistration.version > 0)
+ if (hookRegistration.structVersion > 1)
qFatal("qmlRegisterType(): Cannot mix incompatible QML versions.");
QQmlMetaTypeDataPtr data;
@@ -568,40 +763,135 @@ int QQmlMetaType::registerUnitCacheHook(
return 0;
}
-bool QQmlMetaType::protectModule(const QString &uri, int majVersion)
+QQmlType QQmlMetaType::registerSequentialContainer(
+ const QQmlPrivate::RegisterSequentialContainer &container)
{
+ if (container.structVersion > 1)
+ qFatal("qmlRegisterSequenceContainer(): Cannot mix incompatible QML versions.");
+
QQmlMetaTypeDataPtr data;
- QQmlMetaTypeData::VersionedUri versionedUri;
- versionedUri.uri = uri;
- versionedUri.majorVersion = majVersion;
+ if (!checkRegistration(QQmlType::SequentialContainerType, data, container.uri, QString(),
+ container.version, {})) {
+ return QQmlType();
+ }
+
+ QQmlTypePrivate *priv = new QQmlTypePrivate(QQmlType::SequentialContainerType);
- if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)) {
- qqtm->lock();
- return true;
+ data->registerType(priv);
+ priv->setName(QString::fromUtf8(container.uri), QString());
+ priv->version = container.version;
+ priv->revision = container.revision;
+ priv->typeId = container.metaSequence.valueMetaType();
+ priv->listId = container.typeId;
+ priv->extraData.sequentialContainerTypeData = container.metaSequence;
+
+ addTypeToData(priv, data);
+
+ return QQmlType(priv);
+}
+
+void QQmlMetaType::unregisterSequentialContainer(int id)
+{
+ unregisterType(id);
+}
+
+bool QQmlMetaType::protectModule(const QString &uri, QTypeRevision version,
+ bool weakProtectAllVersions)
+{
+ QQmlMetaTypeDataPtr data;
+ if (version.hasMajorVersion()) {
+ if (QQmlTypeModule *module = data->findTypeModule(uri, version)) {
+ if (!weakProtectAllVersions) {
+ module->setLockLevel(QQmlTypeModule::LockLevel::Strong);
+ return true;
+ }
+ } else {
+ return false;
+ }
}
- return false;
+
+ const auto range = std::equal_range(
+ data->uriToModule.begin(), data->uriToModule.end(), uri,
+ std::less<ModuleUri>());
+
+ for (auto it = range.first; it != range.second; ++it)
+ (*it)->setLockLevel(QQmlTypeModule::LockLevel::Weak);
+
+ return range.first != range.second;
+}
+
+void QQmlMetaType::registerModuleImport(const QString &uri, QTypeRevision moduleVersion,
+ const QQmlDirParser::Import &import)
+{
+ QQmlMetaTypeDataPtr data;
+
+ data->moduleImports.insert(QQmlMetaTypeData::VersionedUri(uri, moduleVersion), import);
}
-void QQmlMetaType::registerModule(const char *uri, int versionMajor, int versionMinor)
+void QQmlMetaType::unregisterModuleImport(const QString &uri, QTypeRevision moduleVersion,
+ const QQmlDirParser::Import &import)
{
QQmlMetaTypeDataPtr data;
+ data->moduleImports.remove(QQmlMetaTypeData::VersionedUri(uri, moduleVersion), import);
+}
- QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data);
+QList<QQmlDirParser::Import> QQmlMetaType::moduleImports(
+ const QString &uri, QTypeRevision version)
+{
+ QQmlMetaTypeDataPtr data;
+ QList<QQmlDirParser::Import> result;
+
+ const auto unrevisioned = data->moduleImports.equal_range(
+ QQmlMetaTypeData::VersionedUri(uri, QTypeRevision()));
+ for (auto it = unrevisioned.second; it != unrevisioned.first;)
+ result.append(*(--it));
+
+ if (version.hasMajorVersion()) {
+ const auto revisioned = data->moduleImports.equal_range(
+ QQmlMetaTypeData::VersionedUri(uri, version));
+ for (auto it = revisioned.second; it != revisioned.first;)
+ result.append(*(--it));
+ return result;
+ }
+
+ // Use latest module available with that URI.
+ const auto begin = data->moduleImports.begin();
+ auto it = unrevisioned.first;
+ if (it == begin)
+ return result;
+
+ const QQmlMetaTypeData::VersionedUri latestVersion = (--it).key();
+ if (latestVersion.uri != uri)
+ return result;
+
+ do {
+ result += *it;
+ } while (it != begin && (--it).key() == latestVersion);
+
+ return result;
+}
+
+void QQmlMetaType::registerModule(const char *uri, QTypeRevision version)
+{
+ QQmlMetaTypeDataPtr data;
+
+ QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), version, data);
Q_ASSERT(module);
- module->addMinorVersion(versionMinor);
+ if (version.hasMinorVersion())
+ module->addMinorVersion(version.minorVersion());
}
-int QQmlMetaType::typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+int QQmlMetaType::typeId(const char *uri, QTypeRevision version, const char *qmlName)
{
QQmlMetaTypeDataPtr data;
- QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data);
+ QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), version, data);
if (!module)
return -1;
- QQmlType type = module->type(QHashedStringRef(QString::fromUtf8(qmlName)), versionMinor);
+ QQmlType type = module->type(QHashedStringRef(QString::fromUtf8(qmlName)), version);
if (!type.isValid())
return -1;
@@ -615,40 +905,21 @@ void QQmlMetaType::registerUndeletableType(const QQmlType &dtype)
}
static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const QString &uri,
- int majorVersion)
+ QTypeRevision version)
{
// Has any type previously been installed to this namespace?
QHashedString nameSpace(uri);
for (const QQmlType &type : data->types) {
- if (type.module() == nameSpace && type.majorVersion() == majorVersion)
+ if (type.module() == nameSpace && type.version().majorVersion() == version.majorVersion())
return true;
}
return false;
}
-class QQmlMetaTypeRegistrationFailureRecorder
-{
- Q_DISABLE_COPY_MOVE(QQmlMetaTypeRegistrationFailureRecorder)
-public:
- QQmlMetaTypeRegistrationFailureRecorder(QQmlMetaTypeData *data, QStringList *failures)
- : data(data)
- {
- data->setTypeRegistrationFailures(failures);
- }
-
- ~QQmlMetaTypeRegistrationFailureRecorder()
- {
- data->setTypeRegistrationFailures(nullptr);
- }
-
- QQmlMetaTypeData *data = nullptr;
-};
-
-
-bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePath,
- const QString &uri, const QString &typeNamespace, int vmaj,
- QList<QQmlError> *errors)
+QQmlMetaType::RegistrationResult QQmlMetaType::registerPluginTypes(
+ QObject *instance, const QString &basePath, const QString &uri,
+ const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors)
{
if (!typeNamespace.isEmpty() && typeNamespace != uri) {
// This is an 'identified' module
@@ -657,10 +928,10 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
QQmlError error;
error.setDescription(
QStringLiteral("Module namespace '%1' does not match import URI '%2'")
- .arg(typeNamespace).arg(uri));
+ .arg(typeNamespace, uri));
errors->prepend(error);
}
- return false;
+ return RegistrationResult::Failure;
}
QStringList failures;
@@ -669,7 +940,7 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
if (!typeNamespace.isEmpty()) {
// This is an 'identified' module
- if (namespaceContainsRegistrations(data, typeNamespace, vmaj)) {
+ if (namespaceContainsRegistrations(data, typeNamespace, version)) {
// Other modules have already installed to this namespace
if (errors) {
QQmlError error;
@@ -678,7 +949,7 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
.arg(typeNamespace));
errors->prepend(error);
}
- return false;
+ return RegistrationResult::Failure;
}
} else {
// This is not an identified module - provide a warning
@@ -687,7 +958,7 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
"it cannot be protected from external registrations.").arg(uri));
}
- if (!qobject_cast<QQmlEngineExtensionInterface *>(instance)) {
+ if (instance && !qobject_cast<QQmlEngineExtensionInterface *>(instance)) {
QQmlTypesExtensionInterface *iface = qobject_cast<QQmlTypesExtensionInterface *>(instance);
if (!iface) {
if (errors) {
@@ -697,35 +968,40 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
"QQmlEngineExtensionInterface").arg(typeNamespace));
errors->prepend(error);
}
- return false;
+ return RegistrationResult::Failure;
}
+#if QT_DEPRECATED_SINCE(6, 3)
if (auto *plugin = qobject_cast<QQmlExtensionPlugin *>(instance)) {
// basepath should point to the directory of the module, not the plugin file itself:
QQmlExtensionPluginPrivate::get(plugin)->baseUrl
= QQmlImports::urlFromLocalFileOrQrcOrUrl(basePath);
}
+#else
+ Q_UNUSED(basePath)
+#endif
const QByteArray bytes = uri.toUtf8();
const char *moduleId = bytes.constData();
iface->registerTypes(moduleId);
}
- data->registerModuleTypes(QQmlMetaTypeData::VersionedUri(uri, vmaj));
+ if (failures.isEmpty() && !data->registerModuleTypes(uri))
+ return RegistrationResult::NoRegistrationFunction;
if (!failures.isEmpty()) {
if (errors) {
- for (const QString &failure : qAsConst(failures)) {
+ for (const QString &failure : std::as_const(failures)) {
QQmlError error;
error.setDescription(failure);
errors->prepend(error);
}
}
- return false;
+ return RegistrationResult::Failure;
}
}
- return true;
+ return RegistrationResult::Success;
}
/*
@@ -741,8 +1017,8 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat
*/
QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
const QHashedStringRef &qualifiedType,
- bool isCompositeSingleton, QList<QQmlError> *errors,
- int majorVersion, int minorVersion)
+ CompositeTypeLookupMode mode, QList<QQmlError> *errors,
+ QTypeRevision version)
{
// ### unfortunate (costly) conversion
const QUrl url = QQmlTypeLoader::normalize(QUrl(urlString));
@@ -759,128 +1035,80 @@ QQmlType QQmlMetaType::typeForUrl(const QString &urlString,
return ret;
}
- const int dot = qualifiedType.indexOf(QLatin1Char('.'));
- const QString typeName = dot < 0
- ? qualifiedType.toString()
- : QString(qualifiedType.constData() + dot + 1, qualifiedType.length() - dot - 1);
-
- QStringList failures;
- QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures);
-
- // Register the type. Note that the URI parameters here are empty; for
- // file type imports, we do not place them in a URI as we don't
- // necessarily have a good and unique one (picture a library import,
- // which may be found in multiple plugin locations on disk), but there
- // are other reasons for this too.
- //
- // By not putting them in a URI, we prevent the types from being
- // registered on a QQmlTypeModule; this is important, as once types are
- // placed on there, they cannot be easily removed, meaning if the
- // developer subsequently loads a different import (meaning different
- // types) with the same URI (using, say, a different plugin path), it is
- // very undesirable that we continue to associate the types from the
- // "old" URI with that new module.
- //
- // Not having URIs also means that the types cannot be found by name
- // etc, the only way to look them up is through QQmlImports -- for
- // better or worse.
- const QQmlType::RegistrationType registrationType = isCompositeSingleton
- ? QQmlType::CompositeSingletonType
- : QQmlType::CompositeType;
- if (checkRegistration(registrationType, data, nullptr, typeName, majorVersion)) {
- auto *priv = new QQmlTypePrivate(registrationType);
- priv->setName(QString(), typeName);
- priv->version_maj = majorVersion;
- priv->version_min = minorVersion;
-
- if (isCompositeSingleton) {
- priv->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo;
- priv->extraData.sd->singletonInstanceInfo->url = url;
- priv->extraData.sd->singletonInstanceInfo->typeName = typeName;
- } else {
- priv->extraData.fd->url = url;
- }
-
- data->registerType(priv);
- addTypeToData(priv, data);
- data->urlToType.insertMulti(url, priv);
- return QQmlType(priv);
- }
-
- // This means that the type couldn't be found by URL, but could not be
- // registered either, meaning we most likely were passed some kind of bad
- // data.
- if (errors) {
- QQmlError error;
- error.setDescription(failures.join('\n'));
- errors->prepend(error);
- } else {
- qWarning("%s", failures.join('\n').toLatin1().constData());
- }
- return QQmlType();
-}
-
-QRecursiveMutex *QQmlMetaType::typeRegistrationLock()
-{
- return metaTypeDataLock();
+ const QQmlType type = createTypeForUrl(
+ data, url, qualifiedType, mode, errors, version);
+ data->urlToType.insert(url, type.priv());
+ return type;
}
/*
- Returns true if a module \a uri of any version is installed.
+ Returns the latest version of \a uri installed, or an in valid QTypeRevision().
*/
-bool QQmlMetaType::isAnyModule(const QString &uri)
+QTypeRevision QQmlMetaType::latestModuleVersion(const QString &uri)
{
QQmlMetaTypeDataPtr data;
+ auto upper = std::upper_bound(data->uriToModule.begin(), data->uriToModule.end(), uri,
+ std::less<ModuleUri>());
+ if (upper == data->uriToModule.begin())
+ return QTypeRevision();
- for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.cbegin();
- iter != data->uriToModule.cend(); ++iter) {
- if ((*iter)->module() == uri)
- return true;
- }
-
- return false;
+ const auto module = (--upper)->get();
+ return (module->module() == uri)
+ ? QTypeRevision::fromVersion(module->majorVersion(), module->maximumMinorVersion())
+ : QTypeRevision();
}
/*
Returns true if a module \a uri of this version is installed and locked;
*/
-bool QQmlMetaType::isLockedModule(const QString &uri, int majVersion)
+bool QQmlMetaType::isStronglyLockedModule(const QString &uri, QTypeRevision version)
{
QQmlMetaTypeDataPtr data;
- QQmlMetaTypeData::VersionedUri versionedUri;
- versionedUri.uri = uri;
- versionedUri.majorVersion = majVersion;
- if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0))
- return qqtm->isLocked();
+ if (QQmlTypeModule* qqtm = data->findTypeModule(uri, version))
+ return qqtm->lockLevel() == QQmlTypeModule::LockLevel::Strong;
return false;
}
/*
- Returns true if any type or API has been registered for the given \a module with at least
- versionMajor.versionMinor, or if types have been registered for \a module with at most
- versionMajor.versionMinor.
-
- So if only 4.7 and 4.9 have been registered, 4.7,4.8, and 4.9 are valid, but not 4.6 nor 4.10.
+ Returns the best matching registered version for the given \a module. If \a version is
+ the does not have a major version, returns the latest registered version. Otherwise
+ chooses the same major version and checks if the minor version is within the range
+ of registered minor versions. If so, retuens the original version, otherwise returns
+ an invalid version. If \a version does not have a minor version, chooses the latest one.
*/
-bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor)
+QTypeRevision QQmlMetaType::matchingModuleVersion(const QString &module, QTypeRevision version)
{
- Q_ASSERT(versionMajor >= 0 && versionMinor >= 0);
+ if (!version.hasMajorVersion())
+ return latestModuleVersion(module);
+
QQmlMetaTypeDataPtr data;
// first, check Types
- QQmlTypeModule *tm =
- data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor));
- if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
- return true;
+ if (QQmlTypeModule *tm = data->findTypeModule(module, version)) {
+ if (!version.hasMinorVersion())
+ return QTypeRevision::fromVersion(version.majorVersion(), tm->maximumMinorVersion());
- return false;
+ if (tm->minimumMinorVersion() <= version.minorVersion()
+ && tm->maximumMinorVersion() >= version.minorVersion()) {
+ return version;
+ }
+ }
+
+ return QTypeRevision();
}
-QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion)
+QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, QTypeRevision version)
{
QQmlMetaTypeDataPtr data;
- return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion));
+
+ if (version.hasMajorVersion())
+ return data->findTypeModule(uri, version);
+
+ auto range = std::equal_range(data->uriToModule.begin(), data->uriToModule.end(),
+ uri, std::less<ModuleUri>());
+
+ return range.first == range.second ? nullptr : (--range.second)->get();
}
QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
@@ -891,7 +1119,7 @@ QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
{
- if (!isQObject(v.userType())) {
+ if (!v.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
if (ok) *ok = false;
return nullptr;
}
@@ -901,54 +1129,28 @@ QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
return *(QObject *const *)v.constData();
}
-bool QQmlMetaType::isQObject(int userType)
-{
- if (userType == QMetaType::QObjectStar)
- return true;
-
- QQmlMetaTypeDataPtr data;
- return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType);
-}
-
/*
Returns the item type for a list of type \a id.
*/
-int QQmlMetaType::listType(int id)
-{
- QQmlMetaTypeDataPtr data;
- QHash<int, int>::ConstIterator iter = data->qmlLists.constFind(id);
- if (iter != data->qmlLists.cend())
- return *iter;
- QQmlTypePrivate *type = data->idToType.value(id);
- if (type && type->listId == id)
- return type->typeId;
- else
- return 0;
-}
-
-#if QT_DEPRECATED_SINCE(5, 14)
-int QQmlMetaType::attachedPropertiesFuncId(QQmlEnginePrivate *engine, const QMetaObject *mo)
-{
- QQmlMetaTypeDataPtr data;
-
- for (auto it = data->metaObjectToType.constFind(mo), end = data->metaObjectToType.constEnd();
- it != end && it.key() == mo; ++it) {
- const QQmlType type(it.value());
- if (type.attachedPropertiesFunction(engine))
- return type.attachedPropertiesId(engine);
+QMetaType QQmlMetaType::listValueType(QMetaType metaType)
+{
+ if (isList(metaType)) {
+ const auto iface = metaType.iface();
+ if (iface && iface->metaObjectFn == &dynamicQmlListMarker)
+ return QMetaType(static_cast<const QQmlListMetaTypeInterface *>(iface)->valueType);
+ } else if (metaType.flags() & QMetaType::PointerToQObject) {
+ return QMetaType();
}
- return -1;
-}
-
-QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFuncById(QQmlEnginePrivate *engine, int id)
-{
- if (id < 0)
- return nullptr;
QQmlMetaTypeDataPtr data;
- return data->types.at(id).attachedPropertiesFunction(engine);
+ Q_ASSERT(data);
+ QQmlTypePrivate *type = data->idToType.value(metaType.id());
+
+ if (type && type->listId == metaType)
+ return type->typeId;
+ else
+ return QMetaType {};
}
-#endif
QQmlAttachedPropertiesFunc QQmlMetaType::attachedPropertiesFunc(QQmlEnginePrivate *engine,
const QMetaObject *mo)
@@ -1011,120 +1213,64 @@ QMetaMethod QQmlMetaType::defaultMethod(QObject *obj)
return defaultMethod(metaObject);
}
-QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType)
-{
- if (userType < 0)
- return Unknown;
- if (userType == QMetaType::QObjectStar)
- return Object;
-
- QQmlMetaTypeDataPtr data;
- if (data->qmlLists.contains(userType))
- return List;
- else if (userType < data->objects.size() && data->objects.testBit(userType))
- return Object;
- else if (userType < data->lists.size() && data->lists.testBit(userType))
- return List;
- else
- return Unknown;
-}
-
/*!
See qmlRegisterInterface() for information about when this will return true.
*/
-bool QQmlMetaType::isInterface(int userType)
+bool QQmlMetaType::isInterface(QMetaType type)
{
const QQmlMetaTypeDataPtr data;
- return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType);
+ return data->interfaces.contains(type.id());
}
-const char *QQmlMetaType::interfaceIId(int userType)
-{
-
- QQmlTypePrivate *typePrivate = nullptr;
- {
- QQmlMetaTypeDataPtr data;
- typePrivate = data->idToType.value(userType);
- }
-
- QQmlType type(typePrivate);
- if (type.isInterface() && type.typeId() == userType)
- return type.interfaceIId();
- else
- return nullptr;
-}
-
-bool QQmlMetaType::isList(int userType)
+const char *QQmlMetaType::interfaceIId(QMetaType metaType)
{
const QQmlMetaTypeDataPtr data;
- if (data->qmlLists.contains(userType))
- return true;
- return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType);
-}
-
-/*!
- A custom string convertor allows you to specify a function pointer that
- returns a variant of \a type. For example, if you have written your own icon
- class that you want to support as an object property assignable in QML:
-
- \code
- int type = qRegisterMetaType<SuperIcon>("SuperIcon");
- QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString);
- \endcode
-
- The function pointer must be of the form:
- \code
- QVariant (*StringConverter)(const QString &);
- \endcode
- */
-void QQmlMetaType::registerCustomStringConverter(int type, StringConverter converter)
-{
- QQmlMetaTypeDataPtr data;
- if (data->stringConverters.contains(type))
- return;
- data->stringConverters.insert(type, converter);
+ const QQmlType type(data->idToType.value(metaType.id()));
+ return (type.isInterface() && type.typeId() == metaType) ? type.interfaceIId() : nullptr;
}
-/*!
- Return the custom string converter for \a type, previously installed through
- registerCustomStringConverter()
- */
-QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type)
+bool QQmlMetaType::isList(QMetaType type)
{
- const QQmlMetaTypeDataPtr data;
- return data->stringConverters.value(type);
+ if (type.flags().testFlag(QMetaType::IsQmlList))
+ return true;
+ else
+ return false;
}
/*!
Returns the type (if any) of URI-qualified named \a qualifiedName and version specified
by \a version_major and \a version_minor.
*/
-QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor)
+QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, QTypeRevision version)
{
int slash = qualifiedName.indexOf(QLatin1Char('/'));
if (slash <= 0)
return QQmlType();
QHashedStringRef module(qualifiedName.constData(), slash);
- QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1);
+ QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.size() - slash - 1);
- return qmlType(name, module, version_major, version_minor);
+ return qmlType(name, module, version);
}
/*!
- Returns the type (if any) of \a name in \a module and version specified
- by \a version_major and \a version_minor.
+ \internal
+ Returns the type (if any) of \a name in \a module and the specified \a version.
+
+ If \a version has no major version, accept any version.
+ If \a version has no minor version, accept any minor version.
+ If \a module is empty, search in all modules and accept any version.
*/
-QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor)
+QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module,
+ QTypeRevision version)
{
- Q_ASSERT(version_major >= 0 && version_minor >= 0);
const QQmlMetaTypeDataPtr data;
- QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name);
+ const QHashedString key(QString::fromRawData(name.constData(), name.length()), name.hash());
+ QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(key);
while (it != data->nameToType.cend() && it.key() == name) {
QQmlType t(*it);
- // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty
- if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor))
+ if (module.isEmpty() || t.availableInVersion(module, version))
return t;
++it;
}
@@ -1133,8 +1279,8 @@ QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedString
}
/*!
- Returns the type (if any) that corresponds to the \a metaObject. Returns null if no
- type is registered.
+ Returns the type (if any) that corresponds to the \a metaObject. Returns an invalid type if no
+ such type is registered.
*/
QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject)
{
@@ -1147,44 +1293,53 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject)
by \a version_major and \a version_minor in module specified by \a uri. Returns null if no
type is registered.
*/
-QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor)
+QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module,
+ QTypeRevision version)
{
- Q_ASSERT(version_major >= 0 && version_minor >= 0);
const QQmlMetaTypeDataPtr data;
- QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject);
- while (it != data->metaObjectToType.cend() && it.key() == metaObject) {
+ const auto range = data->metaObjectToType.equal_range(metaObject);
+ for (auto it = range.first; it != range.second; ++it) {
QQmlType t(*it);
- if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor))
+ if (module.isEmpty() || t.availableInVersion(module, version))
return t;
- ++it;
}
return QQmlType();
}
/*!
- Returns the type (if any) that corresponds to \a typeId. Depending on \a category, the
- \a typeId is interpreted either as QVariant::Type or as QML type id returned by one of the
- qml type registration functions. Returns null if no type is registered.
+ Returns the type (if any) that corresponds to \a qmlTypeId.
+ Returns an invalid QQmlType if no such type is registered.
*/
-QQmlType QQmlMetaType::qmlType(int typeId, TypeIdCategory category)
+QQmlType QQmlMetaType::qmlTypeById(int qmlTypeId)
{
const QQmlMetaTypeDataPtr data;
-
- if (category == TypeIdCategory::MetaType) {
- QQmlTypePrivate *type = data->idToType.value(typeId);
- if (type && type->typeId == typeId)
- return QQmlType(type);
- } else if (category == TypeIdCategory::QmlType) {
- QQmlType type = data->types.value(typeId);
- if (type.isValid())
- return type;
- }
+ QQmlType type = data->types.value(qmlTypeId);
+ if (type.isValid())
+ return type;
return QQmlType();
}
/*!
+ Returns the type (if any) that corresponds to \a metaType.
+ Returns an invalid QQmlType if no such type is registered.
+*/
+QQmlType QQmlMetaType::qmlType(QMetaType metaType)
+{
+ const QQmlMetaTypeDataPtr data;
+ QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ return (type && type->typeId == metaType) ? QQmlType(type) : QQmlType();
+}
+
+QQmlType QQmlMetaType::qmlListType(QMetaType metaType)
+{
+ const QQmlMetaTypeDataPtr data;
+ QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ return (type && type->listId == metaType) ? QQmlType(type) : QQmlType();
+}
+
+/*!
Returns the type (if any) that corresponds to the given \a url in the set of
composite types added through file imports.
@@ -1205,16 +1360,149 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI
return QQmlType();
}
-QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject, int minorVersion)
+QQmlType QQmlMetaType::fetchOrCreateInlineComponentTypeForUrl(const QUrl &url)
+{
+ QQmlMetaTypeDataPtr data;
+ const auto it = data->inlineComponentTypes.constFind(url);
+ if (it != data->inlineComponentTypes.constEnd())
+ return *it;
+
+ return doRegisterInlineComponentType(data, url);
+}
+
+/*!
+Returns a QQmlPropertyCache for \a obj if one is available.
+
+If \a obj is null, being deleted or contains a dynamic meta object,
+nullptr is returned.
+*/
+QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(QObject *obj, QTypeRevision version)
+{
+ if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
+ return QQmlPropertyCache::ConstPtr();
+ return QQmlMetaType::propertyCache(obj->metaObject(), version);
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(
+ const QMetaObject *metaObject, QTypeRevision version)
{
QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
- return data->propertyCache(metaObject, minorVersion);
+ return data->propertyCache(metaObject, version);
}
-QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVersion)
+QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCache(
+ const QQmlType &type, QTypeRevision version)
{
QQmlMetaTypeDataPtr data; // not const: the cache is created on demand
- return data->propertyCache(type, minorVersion);
+ return data->propertyCache(type, version);
+}
+
+/*!
+ * \internal
+ *
+ * Look up by type's baseMetaObject.
+ */
+QQmlMetaObject QQmlMetaType::rawMetaObjectForType(QMetaType metaType)
+{
+ const QQmlMetaTypeDataPtr data;
+ if (auto composite = data->findPropertyCacheInCompositeTypes(metaType))
+ return QQmlMetaObject(composite);
+
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ return (type && type->typeId == metaType) ? type->baseMetaObject : nullptr;
+}
+
+/*!
+ * \internal
+ *
+ * Look up by type's metaObject.
+ */
+QQmlMetaObject QQmlMetaType::metaObjectForType(QMetaType metaType)
+{
+ const QQmlMetaTypeDataPtr data;
+ if (auto composite = data->findPropertyCacheInCompositeTypes(metaType))
+ return QQmlMetaObject(composite);
+
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ return (type && type->typeId == metaType)
+ ? QQmlType(type).metaObject()
+ : nullptr;
+}
+
+/*!
+ * \internal
+ *
+ * Look up by type's metaObject and version.
+ */
+QQmlPropertyCache::ConstPtr QQmlMetaType::propertyCacheForType(QMetaType metaType)
+{
+ QQmlMetaTypeDataPtr data;
+ if (auto composite = data->findPropertyCacheInCompositeTypes(metaType))
+ return composite;
+
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ if (type && type->typeId == metaType) {
+ if (const QMetaObject *mo = QQmlType(type).metaObject())
+ return data->propertyCache(mo, type->version);
+ }
+
+ return QQmlPropertyCache::ConstPtr();
+}
+
+/*!
+ * \internal
+ *
+ * Look up by type's baseMetaObject and unspecified/any version.
+ * TODO: Is this correct? Passing a plain QTypeRevision() rather than QTypeRevision::zero() or
+ * the actual type's version seems strange. The behavior has been in place for a while.
+ */
+QQmlPropertyCache::ConstPtr QQmlMetaType::rawPropertyCacheForType(QMetaType metaType)
+{
+ QQmlMetaTypeDataPtr data;
+ if (auto composite = QQmlMetaType::findPropertyCacheInCompositeTypes(metaType))
+ return composite;
+
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ if (!type || type->typeId != metaType)
+ return QQmlPropertyCache::ConstPtr();
+
+ const QMetaObject *metaObject = type->isValueType()
+ ? type->metaObjectForValueType()
+ : type->baseMetaObject;
+
+ return metaObject
+ ? data->propertyCache(metaObject, QTypeRevision())
+ : QQmlPropertyCache::ConstPtr();
+}
+
+/*!
+ * \internal
+ *
+ * Look up by QQmlType and version. We only fall back to lookup by metaobject if the type
+ * has no revisiononed attributes here. Unspecified versions are interpreted as "any".
+ */
+QQmlPropertyCache::ConstPtr QQmlMetaType::rawPropertyCacheForType(
+ QMetaType metaType, QTypeRevision version)
+{
+ QQmlMetaTypeDataPtr data;
+ if (auto composite = data->findPropertyCacheInCompositeTypes(metaType))
+ return composite;
+
+ const QQmlTypePrivate *typePriv = data->idToType.value(metaType.id());
+ if (!typePriv || typePriv->typeId != metaType)
+ return QQmlPropertyCache::ConstPtr();
+
+ const QQmlType type(typePriv);
+ if (type.containsRevisionedAttributes()) {
+ // It can only have (revisioned) properties or methods if it has a metaobject
+ Q_ASSERT(type.metaObject());
+ return data->propertyCache(type, version);
+ }
+
+ if (const QMetaObject *metaObject = type.metaObject())
+ return data->propertyCache(metaObject, version);
+
+ return QQmlPropertyCache::ConstPtr();
}
void QQmlMetaType::unregisterType(int typeIndex)
@@ -1222,6 +1510,8 @@ void QQmlMetaType::unregisterType(int typeIndex)
QQmlMetaTypeDataPtr data;
const QQmlType type = data->types.value(typeIndex);
if (const QQmlTypePrivate *d = type.priv()) {
+ if (d->regType == QQmlType::CompositeType || d->regType == QQmlType::CompositeSingletonType)
+ removeFromInlineComponents(data->inlineComponentTypes, d);
removeQQmlTypePrivate(data->idToType, d);
removeQQmlTypePrivate(data->nameToType, d);
removeQQmlTypePrivate(data->urlToType, d);
@@ -1229,12 +1519,55 @@ void QQmlMetaType::unregisterType(int typeIndex)
removeQQmlTypePrivate(data->metaObjectToType, d);
for (auto & module : data->uriToModule)
module->remove(d);
- data->clearPropertyCachesForMinorVersion(typeIndex);
+ data->clearPropertyCachesForVersion(typeIndex);
data->types[typeIndex] = QQmlType();
data->undeletableTypes.remove(type);
}
}
+void QQmlMetaType::registerMetaObjectForType(const QMetaObject *metaobject, QQmlTypePrivate *type)
+{
+ Q_ASSERT(type);
+
+ QQmlMetaTypeDataPtr data;
+ data->metaObjectToType.insert(metaobject, type);
+}
+
+static bool hasActiveInlineComponents(const QQmlMetaTypeData *data, const QQmlTypePrivate *d)
+{
+ for (auto it = data->inlineComponentTypes.begin(), end = data->inlineComponentTypes.end();
+ it != end; ++it) {
+ if (!QQmlMetaType::equalBaseUrls(it.key(), d->sourceUrl()))
+ continue;
+
+ const QQmlTypePrivate *icPriv = it->priv();
+ if (icPriv && icPriv->count() > 1)
+ return true;
+ }
+ return false;
+}
+
+static int doCountInternalCompositeTypeSelfReferences(
+ QQmlMetaTypeData *data,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+{
+ int result = 0;
+ auto doCheck = [&](const QtPrivate::QMetaTypeInterface *iface) {
+ if (!iface)
+ return;
+
+ const auto it = data->compositeTypes.constFind(iface);
+ if (it != data->compositeTypes.constEnd() && *it == compilationUnit)
+ ++result;
+ };
+
+ doCheck(compilationUnit->metaType().iface());
+ for (auto &&inlineData: compilationUnit->inlineComponentData)
+ doCheck(inlineData.qmlType.typeId().iface());
+
+ return result;
+}
+
void QQmlMetaType::freeUnusedTypesAndCaches()
{
QQmlMetaTypeDataPtr data;
@@ -1243,15 +1576,33 @@ void QQmlMetaType::freeUnusedTypesAndCaches()
if (!data.isValid())
return;
+ bool droppedAtLeastOneComposite;
+ do {
+ droppedAtLeastOneComposite = false;
+ auto it = data->compositeTypes.begin();
+ while (it != data->compositeTypes.end()) {
+ if ((*it)->count() <= doCountInternalCompositeTypeSelfReferences(data, *it)) {
+ it = data->compositeTypes.erase(it);
+ droppedAtLeastOneComposite = true;
+ } else {
+ ++it;
+ }
+ }
+ } while (droppedAtLeastOneComposite);
+
bool deletedAtLeastOneType;
do {
deletedAtLeastOneType = false;
QList<QQmlType>::Iterator it = data->types.begin();
while (it != data->types.end()) {
const QQmlTypePrivate *d = (*it).priv();
- if (d && d->count() == 1) {
+ if (d && d->count() == 1 && !hasActiveInlineComponents(data, d)) {
deletedAtLeastOneType = true;
+ if (d->regType == QQmlType::CompositeType
+ || d->regType == QQmlType::CompositeSingletonType) {
+ removeFromInlineComponents(data->inlineComponentTypes, d);
+ }
removeQQmlTypePrivate(data->idToType, d);
removeQQmlTypePrivate(data->nameToType, d);
removeQQmlTypePrivate(data->urlToType, d);
@@ -1261,7 +1612,7 @@ void QQmlMetaType::freeUnusedTypesAndCaches()
for (auto &module : data->uriToModule)
module->remove(d);
- data->clearPropertyCachesForMinorVersion(d->index);
+ data->clearPropertyCachesForVersion(d->index);
*it = QQmlType();
} else {
++it;
@@ -1272,14 +1623,10 @@ void QQmlMetaType::freeUnusedTypesAndCaches()
bool deletedAtLeastOneCache;
do {
deletedAtLeastOneCache = false;
- QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = data->propertyCaches.begin();
+ auto it = data->propertyCaches.begin();
while (it != data->propertyCaches.end()) {
-
if ((*it)->count() == 1) {
- QQmlPropertyCache *pc = nullptr;
- qSwap(pc, *it);
it = data->propertyCaches.erase(it);
- pc->release();
deletedAtLeastOneCache = true;
} else {
++it;
@@ -1296,7 +1643,7 @@ QList<QString> QQmlMetaType::qmlTypeNames()
const QQmlMetaTypeDataPtr data;
QList<QString> names;
- names.reserve(data->nameToType.count());
+ names.reserve(data->nameToType.size());
QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.cbegin();
while (it != data->nameToType.cend()) {
QQmlType t(*it);
@@ -1315,7 +1662,7 @@ QList<QQmlType> QQmlMetaType::qmlTypes()
const QQmlMetaTypeDataPtr data;
QList<QQmlType> types;
- for (QQmlTypePrivate *t : data->nameToType)
+ for (const QQmlTypePrivate *t : data->nameToType)
types.append(QQmlType(t));
return types;
@@ -1338,7 +1685,7 @@ QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
const QQmlMetaTypeDataPtr data;
QList<QQmlType> retn;
- for (const auto t : qAsConst(data->nameToType)) {
+ for (const auto t : std::as_const(data->nameToType)) {
QQmlType type(t);
if (type.isSingleton())
retn.append(type);
@@ -1346,22 +1693,47 @@ QList<QQmlType> QQmlMetaType::qmlSingletonTypes()
return retn;
}
-const QV4::CompiledData::Unit *QQmlMetaType::findCachedCompilationUnit(const QUrl &uri, CachedUnitLookupError *status)
+static bool isFullyTyped(const QQmlPrivate::CachedQmlUnit *unit)
{
+ quint32 numTypedFunctions = 0;
+ for (const QQmlPrivate::AOTCompiledFunction *function = unit->aotCompiledFunctions;
+ function; ++function) {
+ if (function->functionPtr)
+ ++numTypedFunctions;
+ else
+ return false;
+ }
+ return numTypedFunctions == unit->qmlData->functionTableSize;
+}
+
+const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(
+ const QUrl &uri, QQmlMetaType::CacheMode mode, CachedUnitLookupError *status)
+{
+ Q_ASSERT(mode != RejectAll);
const QQmlMetaTypeDataPtr data;
- for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) {
+ for (const auto lookup : std::as_const(data->lookupCachedQmlUnit)) {
if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) {
QString error;
- if (!QV4::ExecutableCompilationUnit::verifyHeader(unit->qmlData, QDateTime(), &error)) {
+ if (!unit->qmlData->verifyHeader(QDateTime(), &error)) {
qCDebug(DBG_DISK_CACHE) << "Error loading pre-compiled file " << uri << ":" << error;
if (status)
*status = CachedUnitLookupError::VersionMismatch;
return nullptr;
}
+
+ if (mode == RequireFullyTyped && !isFullyTyped(unit)) {
+ qCDebug(DBG_DISK_CACHE)
+ << "Error loading pre-compiled file " << uri
+ << ": compilation unit contains functions not compiled to native code.";
+ if (status)
+ *status = CachedUnitLookupError::NotFullyTyped;
+ return nullptr;
+ }
+
if (status)
*status = CachedUnitLookupError::NoError;
- return unit->qmlData;
+ return unit;
}
}
@@ -1409,8 +1781,8 @@ QString QQmlMetaType::prettyTypeName(const QObject *object)
marker = typeName.indexOf(QLatin1String("_QML_"));
if (marker != -1) {
- typeName = typeName.leftRef(marker) + QLatin1Char('*');
- type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1()));
+ typeName = QStringView{typeName}.left(marker) + QLatin1Char('*');
+ type = QQmlMetaType::qmlType(QMetaType::fromName(typeName.toUtf8()));
if (type.isValid()) {
QString qmlTypeName = type.qmlTypeName();
const int lastSlash = qmlTypeName.lastIndexOf(QLatin1Char('/'));
@@ -1432,31 +1804,211 @@ QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject
QList<QQmlProxyMetaObject::ProxyData> metaObjects;
mo = mo->d.superdata;
- const QQmlMetaTypeDataPtr data;
-
- while (mo) {
- QQmlTypePrivate *t = data->metaObjectToType.value(mo);
- if (t) {
+ if (!mo)
+ return metaObjects;
+
+ auto createProxyMetaObject = [&](QQmlTypePrivate *This,
+ const QMetaObject *superdataBaseMetaObject,
+ const QMetaObject *extMetaObject,
+ QObject *(*extFunc)(QObject *)) {
+ if (!extMetaObject)
+ return;
+
+ QMetaObjectBuilder builder;
+ clone(builder, extMetaObject, superdataBaseMetaObject, baseMetaObject,
+ extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly);
+ QMetaObject *mmo = builder.toMetaObject();
+ mmo->d.superdata = baseMetaObject;
+ if (!metaObjects.isEmpty())
+ metaObjects.constLast().metaObject->d.superdata = mmo;
+ else if (lastMetaObject)
+ lastMetaObject->d.superdata = mmo;
+ QQmlProxyMetaObject::ProxyData data = { mmo, extFunc, 0, 0 };
+ metaObjects << data;
+ registerMetaObjectForType(mmo, This);
+ };
+
+ for (const QQmlMetaTypeDataPtr data; mo; mo = mo->d.superdata) {
+ // TODO: There can in fact be multiple QQmlTypePrivate* for a single QMetaObject*.
+ // This algorithm only accounts for the most recently inserted one. That's pretty
+ // random. However, the availability of types depends on what documents you have
+ // loaded before. Just adding all possible extensions would also be pretty random.
+ // The right way to do this would be to take the relations between the QML modules
+ // into account. For this we would need proper module dependency information.
+ if (QQmlTypePrivate *t = data->metaObjectToType.value(mo)) {
if (t->regType == QQmlType::CppType) {
- if (t->extraData.cd->extFunc) {
- QMetaObjectBuilder builder;
- clone(builder, t->extraData.cd->extMetaObject, t->baseMetaObject, baseMetaObject);
- builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
- QMetaObject *mmo = builder.toMetaObject();
- mmo->d.superdata = baseMetaObject;
- if (!metaObjects.isEmpty())
- metaObjects.constLast().metaObject->d.superdata = mmo;
- else if (lastMetaObject)
- lastMetaObject->d.superdata = mmo;
- QQmlProxyMetaObject::ProxyData data = { mmo, t->extraData.cd->extFunc, 0, 0 };
- metaObjects << data;
- }
+ createProxyMetaObject(
+ t, t->baseMetaObject, t->extraData.cppTypeData->extMetaObject,
+ t->extraData.cppTypeData->extFunc);
+ } else if (t->regType == QQmlType::SingletonType) {
+ createProxyMetaObject(
+ t, t->baseMetaObject, t->extraData.singletonTypeData->extMetaObject,
+ t->extraData.singletonTypeData->extFunc);
}
}
- mo = mo->d.superdata;
- }
+ };
return metaObjects;
}
+static bool isInternalType(int idx)
+{
+ // Qt internal types
+ switch (idx) {
+ case QMetaType::UnknownType:
+ case QMetaType::QStringList:
+ case QMetaType::QObjectStar:
+ case QMetaType::VoidStar:
+ case QMetaType::Nullptr:
+ case QMetaType::QVariant:
+ case QMetaType::QLocale:
+ case QMetaType::QImage: // scarce type, keep as QVariant
+ case QMetaType::QPixmap: // scarce type, keep as QVariant
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool QQmlMetaType::isValueType(QMetaType type)
+{
+ if (!type.isValid() || isInternalType(type.id()))
+ return false;
+
+ return valueType(type) != nullptr;
+}
+
+const QMetaObject *QQmlMetaType::metaObjectForValueType(QMetaType metaType)
+{
+ switch (metaType.id()) {
+ case QMetaType::QPoint:
+ return &QQmlPointValueType::staticMetaObject;
+ case QMetaType::QPointF:
+ return &QQmlPointFValueType::staticMetaObject;
+ case QMetaType::QSize:
+ return &QQmlSizeValueType::staticMetaObject;
+ case QMetaType::QSizeF:
+ return &QQmlSizeFValueType::staticMetaObject;
+ case QMetaType::QRect:
+ return &QQmlRectValueType::staticMetaObject;
+ case QMetaType::QRectF:
+ return &QQmlRectFValueType::staticMetaObject;
+#if QT_CONFIG(easingcurve)
+ case QMetaType::QEasingCurve:
+ return &QQmlEasingValueType::staticMetaObject;
+#endif
+ default:
+ break;
+ }
+
+ // It doesn't have to be a gadget for a QML type to exist, but we don't want to
+ // call QObject pointers value types. Explicitly registered types also override
+ // the implicit use of gadgets.
+ if (!(metaType.flags() & QMetaType::PointerToQObject)) {
+ const QQmlMetaTypeDataPtr data;
+ const QQmlTypePrivate *type = data->idToType.value(metaType.id());
+ if (type && type->regType == QQmlType::CppType && type->typeId == metaType) {
+ if (const QMetaObject *mo = type->metaObjectForValueType())
+ return mo;
+ }
+ }
+
+ // If it _is_ a gadget, we can just use it.
+ if (metaType.flags() & QMetaType::IsGadget)
+ return metaType.metaObject();
+
+ return nullptr;
+}
+
+QQmlValueType *QQmlMetaType::valueType(QMetaType type)
+{
+ QQmlMetaTypeDataPtr data;
+
+ const auto it = data->metaTypeToValueType.constFind(type.id());
+ if (it != data->metaTypeToValueType.constEnd())
+ return *it;
+
+ if (const QMetaObject *mo = metaObjectForValueType(type))
+ return *data->metaTypeToValueType.insert(type.id(), new QQmlValueType(type, mo));
+ return *data->metaTypeToValueType.insert(type.id(), nullptr);
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaType::findPropertyCacheInCompositeTypes(QMetaType t)
+{
+ const QQmlMetaTypeDataPtr data;
+ return data->findPropertyCacheInCompositeTypes(t);
+}
+
+void QQmlMetaType::registerInternalCompositeType(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+{
+ QQmlMetaTypeDataPtr data;
+
+ auto doInsert = [&data, &compilationUnit](const QtPrivate::QMetaTypeInterface *iface) {
+ Q_ASSERT(iface);
+ Q_ASSERT(compilationUnit);
+
+ // We can't assert on anything else here. We may get a completely new type as exposed
+ // by the qmldiskcache test that changes a QML file in place during the execution
+ // of the test.
+ data->compositeTypes.insert(iface, compilationUnit);
+ };
+
+ doInsert(compilationUnit->metaType().iface());
+ for (auto &&inlineData: compilationUnit->inlineComponentData)
+ doInsert(inlineData.qmlType.typeId().iface());
+}
+
+void QQmlMetaType::unregisterInternalCompositeType(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+{
+ QQmlMetaTypeDataPtr data;
+
+ auto doRemove = [&](const QtPrivate::QMetaTypeInterface *iface) {
+ if (!iface)
+ return;
+
+ const auto it = data->compositeTypes.constFind(iface);
+ if (it != data->compositeTypes.constEnd() && *it == compilationUnit)
+ data->compositeTypes.erase(it);
+ };
+
+ doRemove(compilationUnit->metaType().iface());
+ for (auto &&inlineData: compilationUnit->inlineComponentData)
+ doRemove(inlineData.qmlType.typeId().iface());
+}
+
+int QQmlMetaType::countInternalCompositeTypeSelfReferences(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+{
+ QQmlMetaTypeDataPtr data;
+ return doCountInternalCompositeTypeSelfReferences(data, compilationUnit);
+}
+
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlMetaType::obtainCompilationUnit(
+ QMetaType type)
+{
+ const QQmlMetaTypeDataPtr data;
+ return data->compositeTypes.value(type.iface());
+}
+
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlMetaType::obtainCompilationUnit(
+ const QUrl &url)
+{
+ const QUrl normalized = QQmlTypeLoader::normalize(url);
+ QQmlMetaTypeDataPtr data;
+
+ auto found = data->urlToType.constFind(normalized);
+ if (found == data->urlToType.constEnd()) {
+ found = data->urlToNonFileImportType.constFind(normalized);
+ if (found == data->urlToNonFileImportType.constEnd())
+ return QQmlRefPointer<QV4::CompiledData::CompilationUnit>();
+ }
+
+ const auto composite = data->compositeTypes.constFind(found.value()->typeId.iface());
+ return composite == data->compositeTypes.constEnd()
+ ? QQmlRefPointer<QV4::CompiledData::CompilationUnit>()
+ : composite.value();
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 13ba4d809b..f4870d9db1 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLMETATYPE_P_H
#define QQMLMETATYPE_P_H
@@ -51,42 +15,117 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
-#include <private/qqmltype_p.h>
+#include <private/qqmldirparser_p.h>
+#include <private/qqmlmetaobject_p.h>
#include <private/qqmlproxymetaobject_p.h>
+#include <private/qqmltype_p.h>
+#include <private/qtqmlglobal_p.h>
QT_BEGIN_NAMESPACE
class QQmlTypeModule;
class QRecursiveMutex;
class QQmlError;
+class QQmlValueType;
-namespace QV4 { class ExecutableCompilationUnit; }
+namespace QV4 {
+namespace CompiledData {
+struct CompilationUnit;
+}
+}
-class Q_QML_PRIVATE_EXPORT QQmlMetaType
+class Q_QML_EXPORT QQmlMetaType
{
+ friend class QQmlDesignerMetaObject;
+
public:
+
+ enum class RegistrationResult {
+ Success,
+ Failure,
+ NoRegistrationFunction
+ };
+
+ static QUrl inlineComponentUrl(const QUrl &baseUrl, const QString &name)
+ {
+ QUrl icUrl = baseUrl;
+ icUrl.setFragment(name);
+ return icUrl;
+ }
+
+ static bool equalBaseUrls(const QUrl &aUrl, const QUrl &bUrl)
+ {
+ // Everything but fragment has to match
+ return aUrl.port() == bUrl.port()
+ && aUrl.scheme() == bUrl.scheme()
+ && aUrl.userName() == bUrl.userName()
+ && aUrl.password() == bUrl.password()
+ && aUrl.host() == bUrl.host()
+ && aUrl.path() == bUrl.path()
+ && aUrl.query() == bUrl.query();
+ }
+
+ enum CompositeTypeLookupMode {
+ NonSingleton,
+ Singleton,
+ };
+
+ static QQmlType findCompositeType(
+ const QUrl &url,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit,
+ CompositeTypeLookupMode mode = NonSingleton);
+ static QQmlType findInlineComponentType(
+ const QUrl &url,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
+ static QQmlType findInlineComponentType(
+ const QUrl &baseUrl, const QString &name,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
+ {
+ return findInlineComponentType(inlineComponentUrl(baseUrl, name), compilationUnit);
+ }
+
+ static void unregisterInternalCompositeType(QMetaType metaType, QMetaType listMetaType);
static QQmlType registerType(const QQmlPrivate::RegisterType &type);
static QQmlType registerInterface(const QQmlPrivate::RegisterInterface &type);
- static QQmlType registerSingletonType(const QQmlPrivate::RegisterSingletonType &type);
- static QQmlType registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type);
+ static QQmlType registerSingletonType(
+ const QQmlPrivate::RegisterSingletonType &type,
+ const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo);
+ static QQmlType registerCompositeSingletonType(
+ const QQmlPrivate::RegisterCompositeSingletonType &type,
+ const QQmlType::SingletonInstanceInfo::ConstPtr &siinfo);
static QQmlType registerCompositeType(const QQmlPrivate::RegisterCompositeType &type);
- static bool registerPluginTypes(QObject *instance, const QString &basePath,
- const QString &uri, const QString &typeNamespace, int vmaj,
- QList<QQmlError> *errors);
+ static RegistrationResult registerPluginTypes(QObject *instance, const QString &basePath,
+ const QString &uri, const QString &typeNamespace,
+ QTypeRevision version, QList<QQmlError> *errors);
+
static QQmlType typeForUrl(const QString &urlString, const QHashedStringRef& typeName,
- bool isCompositeSingleton, QList<QQmlError> *errors,
- int majorVersion = -1, int minorVersion = -1);
+ CompositeTypeLookupMode mode, QList<QQmlError> *errors,
+ QTypeRevision version = QTypeRevision());
+
+ static QQmlType fetchOrCreateInlineComponentTypeForUrl(const QUrl &url);
+ static QQmlType inlineComponentType(const QQmlType &outerType, const QString &name)
+ {
+ return outerType.isComposite()
+ ? fetchOrCreateInlineComponentTypeForUrl(
+ inlineComponentUrl(outerType.sourceUrl(), name))
+ : QQmlType();
+ }
static void unregisterType(int type);
- static void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
- static void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
+ static void registerMetaObjectForType(const QMetaObject *metaobject, QQmlTypePrivate *type);
+
+ static void registerModule(const char *uri, QTypeRevision version);
+ static bool protectModule(const QString &uri, QTypeRevision version,
+ bool weakProtectAllVersions = false);
- static void registerModule(const char *uri, int versionMajor, int versionMinor);
- static bool protectModule(const QString &uri, int majVersion);
+ static void registerModuleImport(const QString &uri, QTypeRevision version,
+ const QQmlDirParser::Import &import);
+ static void unregisterModuleImport(const QString &uri, QTypeRevision version,
+ const QQmlDirParser::Import &import);
+ static QList<QQmlDirParser::Import> moduleImports(const QString &uri, QTypeRevision version);
- static int typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
+ static int typeId(const char *uri, QTypeRevision version, const char *qmlName);
static void registerUndeletableType(const QQmlType &dtype);
@@ -95,20 +134,31 @@ public:
static QList<QQmlType> qmlSingletonTypes();
static QList<QQmlType> qmlAllTypes();
- enum class TypeIdCategory {
- MetaType,
- QmlType
- };
-
- static QQmlType qmlType(const QString &qualifiedName, int, int);
- static QQmlType qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int);
+ static QQmlType qmlType(const QString &qualifiedName, QTypeRevision version);
+ static QQmlType qmlType(const QHashedStringRef &name, const QHashedStringRef &module, QTypeRevision version);
static QQmlType qmlType(const QMetaObject *);
- static QQmlType qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor);
- static QQmlType qmlType(int typeId, TypeIdCategory category = TypeIdCategory::MetaType);
+ static QQmlType qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, QTypeRevision version);
+ static QQmlType qmlTypeById(int qmlTypeId);
+
+ static QQmlType qmlType(QMetaType metaType);
+ static QQmlType qmlListType(QMetaType metaType);
+
static QQmlType qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports = false);
- static QQmlPropertyCache *propertyCache(const QMetaObject *metaObject, int minorVersion = -1);
- static QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion);
+ static QQmlPropertyCache::ConstPtr propertyCache(
+ QObject *object, QTypeRevision version = QTypeRevision());
+ static QQmlPropertyCache::ConstPtr propertyCache(
+ const QMetaObject *metaObject, QTypeRevision version = QTypeRevision());
+ static QQmlPropertyCache::ConstPtr propertyCache(
+ const QQmlType &type, QTypeRevision version);
+
+ // These methods may be called from the loader thread
+ static QQmlMetaObject rawMetaObjectForType(QMetaType metaType);
+ static QQmlMetaObject metaObjectForType(QMetaType metaType);
+ static QQmlPropertyCache::ConstPtr propertyCacheForType(QMetaType metaType);
+ static QQmlPropertyCache::ConstPtr rawPropertyCacheForType(QMetaType metaType);
+ static QQmlPropertyCache::ConstPtr rawPropertyCacheForType(
+ QMetaType metaType, QTypeRevision version);
static void freeUnusedTypesAndCaches();
@@ -117,51 +167,37 @@ public:
static QMetaMethod defaultMethod(const QMetaObject *);
static QMetaMethod defaultMethod(QObject *);
- static bool isQObject(int);
static QObject *toQObject(const QVariant &, bool *ok = nullptr);
- static int listType(int);
-#if QT_DEPRECATED_SINCE(5, 14)
- static QT_DEPRECATED int attachedPropertiesFuncId(QQmlEnginePrivate *engine,
- const QMetaObject *);
- static QT_DEPRECATED QQmlAttachedPropertiesFunc attachedPropertiesFuncById(QQmlEnginePrivate *,
- int);
-#endif
+ static QMetaType listValueType(QMetaType type);
static QQmlAttachedPropertiesFunc attachedPropertiesFunc(QQmlEnginePrivate *,
const QMetaObject *);
+ static bool isInterface(QMetaType type);
+ static const char *interfaceIId(QMetaType type);
+ static bool isList(QMetaType type);
- enum TypeCategory { Unknown, Object, List };
- static TypeCategory typeCategory(int);
-
- static bool isInterface(int);
- static const char *interfaceIId(int);
- static bool isList(int);
-
- typedef QVariant (*StringConverter)(const QString &);
- static void registerCustomStringConverter(int, StringConverter);
- static StringConverter customStringConverter(int);
-
- static bool isAnyModule(const QString &uri);
- static bool isLockedModule(const QString &uri, int majorVersion);
- static bool isModule(const QString &module, int versionMajor, int versionMinor);
- static QQmlTypeModule *typeModule(const QString &uri, int majorVersion);
+ static QTypeRevision latestModuleVersion(const QString &uri);
+ static bool isStronglyLockedModule(const QString &uri, QTypeRevision version);
+ static QTypeRevision matchingModuleVersion(const QString &module, QTypeRevision version);
+ static QQmlTypeModule *typeModule(const QString &uri, QTypeRevision version);
static QList<QQmlPrivate::AutoParentFunction> parentFunctions();
enum class CachedUnitLookupError {
NoError,
NoUnitFound,
- VersionMismatch
+ VersionMismatch,
+ NotFullyTyped
};
- static const QV4::CompiledData::Unit *findCachedCompilationUnit(const QUrl &uri, CachedUnitLookupError *status);
+ enum CacheMode { RejectAll, AcceptUntyped, RequireFullyTyped };
+ static const QQmlPrivate::CachedQmlUnit *findCachedCompilationUnit(
+ const QUrl &uri, CacheMode mode, CachedUnitLookupError *status);
// used by tst_qqmlcachegen.cpp
static void prependCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler);
static void removeCachedUnitLookupFunction(QQmlPrivate::QmlUnitCacheLookupFunction handler);
- static QRecursiveMutex *typeRegistrationLock();
-
static QString prettyTypeName(const QObject *object);
template <typename QQmlTypeContainer>
@@ -176,9 +212,28 @@ public:
}
}
+ template <typename InlineComponentContainer>
+ static void removeFromInlineComponents(
+ InlineComponentContainer &container, const QQmlTypePrivate *reference)
+ {
+ const QUrl referenceUrl = QQmlType(reference).sourceUrl();
+ for (auto it = container.begin(), end = container.end(); it != end;) {
+ if (equalBaseUrls(it.key(), referenceUrl))
+ it = container.erase(it);
+ else
+ ++it;
+ }
+ }
+
+ static void registerTypeAlias(int typeId, const QString &name);
+
static int registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &autoparent);
static void unregisterAutoParentFunction(const QQmlPrivate::AutoParentFunction &function);
+ static QQmlType registerSequentialContainer(
+ const QQmlPrivate::RegisterSequentialContainer &sequenceRegistration);
+ static void unregisterSequentialContainer(int id);
+
static int registerUnitCacheHook(const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration);
static void clearTypeRegistrations();
@@ -186,15 +241,118 @@ public:
const QMetaObject *baseMetaObject,
QMetaObject *lastMetaObject);
+ enum ClonePolicy {
+ CloneAll, // default
+ CloneEnumsOnly, // skip properties and methods
+ };
static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
- const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd);
+ const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd,
+ ClonePolicy policy);
+
+ static void qmlInsertModuleRegistration(const QString &uri, void (*registerFunction)());
+ static void qmlRemoveModuleRegistration(const QString &uri);
+
+ static bool qmlRegisterModuleTypes(const QString &uri);
+
+ static bool isValueType(QMetaType type);
+ static QQmlValueType *valueType(QMetaType metaType);
+ static const QMetaObject *metaObjectForValueType(QMetaType type);
+
+ static QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t);
+ static void registerInternalCompositeType(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
+ static void unregisterInternalCompositeType(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
+ static int countInternalCompositeTypeSelfReferences(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
+ static QQmlRefPointer<QV4::CompiledData::CompilationUnit> obtainCompilationUnit(
+ QMetaType type);
+ static QQmlRefPointer<QV4::CompiledData::CompilationUnit> obtainCompilationUnit(
+ const QUrl &url);
+};
+
+Q_DECLARE_TYPEINFO(QQmlMetaType, Q_RELOCATABLE_TYPE);
- static void qmlInsertModuleRegistration(const QString &uri, int majorVersion,
- void (*registerFunction)());
- static void qmlRegisterModuleTypes(const QString &uri, int majorVersion);
+// used in QQmlListMetaType to tag the metatpye
+inline const QMetaObject *dynamicQmlListMarker(const QtPrivate::QMetaTypeInterface *) {
+ return nullptr;
};
-Q_DECLARE_TYPEINFO(QQmlMetaType, Q_MOVABLE_TYPE);
+inline const QMetaObject *dynamicQmlMetaObject(const QtPrivate::QMetaTypeInterface *iface) {
+ return QQmlMetaType::metaObjectForType(QMetaType(iface)).metaObject();
+};
+
+// metatype interface for composite QML types
+struct QQmlMetaTypeInterface : QtPrivate::QMetaTypeInterface
+{
+ const QByteArray name;
+ QQmlMetaTypeInterface(const QByteArray &name)
+ : QMetaTypeInterface {
+ /*.revision=*/ QMetaTypeInterface::CurrentRevision,
+ /*.alignment=*/ alignof(QObject *),
+ /*.size=*/ sizeof(QObject *),
+ /*.flags=*/ QtPrivate::QMetaTypeTypeFlags<QObject *>::Flags,
+ /*.typeId=*/ 0,
+ /*.metaObjectFn=*/ &dynamicQmlMetaObject,
+ /*.name=*/ name.constData(),
+ /*.defaultCtr=*/ [](const QMetaTypeInterface *, void *addr) {
+ *static_cast<QObject **>(addr) = nullptr;
+ },
+ /*.copyCtr=*/ [](const QMetaTypeInterface *, void *addr, const void *other) {
+ *static_cast<QObject **>(addr) = *static_cast<QObject *const *>(other);
+ },
+ /*.moveCtr=*/ [](const QMetaTypeInterface *, void *addr, void *other) {
+ *static_cast<QObject **>(addr) = *static_cast<QObject **>(other);
+ },
+ /*.dtor=*/ [](const QMetaTypeInterface *, void *) {},
+ /*.equals*/ nullptr,
+ /*.lessThan*/ nullptr,
+ /*.debugStream=*/ nullptr,
+ /*.dataStreamOut=*/ nullptr,
+ /*.dataStreamIn=*/ nullptr,
+ /*.legacyRegisterOp=*/ nullptr
+ }
+ , name(name) { }
+};
+
+// metatype for qml list types
+struct QQmlListMetaTypeInterface : QtPrivate::QMetaTypeInterface
+{
+ const QByteArray name;
+ // if this interface is for list<type>; valueType stores the interface for type
+ const QtPrivate::QMetaTypeInterface *valueType;
+ QQmlListMetaTypeInterface(const QByteArray &name, const QtPrivate::QMetaTypeInterface *valueType)
+ : QMetaTypeInterface {
+ /*.revision=*/ QMetaTypeInterface::CurrentRevision,
+ /*.alignment=*/ alignof(QQmlListProperty<QObject>),
+ /*.size=*/ sizeof(QQmlListProperty<QObject>),
+ /*.flags=*/ QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject>>::Flags,
+ /*.typeId=*/ 0,
+ /*.metaObjectFn=*/ &dynamicQmlListMarker,
+ /*.name=*/ name.constData(),
+ /*.defaultCtr=*/ [](const QMetaTypeInterface *, void *addr) {
+ new (addr) QQmlListProperty<QObject> ();
+ },
+ /*.copyCtr=*/ [](const QMetaTypeInterface *, void *addr, const void *other) {
+ new (addr) QQmlListProperty<QObject>(
+ *static_cast<const QQmlListProperty<QObject> *>(other));
+ },
+ /*.moveCtr=*/ [](const QMetaTypeInterface *, void *addr, void *other) {
+ new (addr) QQmlListProperty<QObject>(
+ std::move(*static_cast<QQmlListProperty<QObject> *>(other)));
+ },
+ /*.dtor=*/ [](const QMetaTypeInterface *, void *addr) {
+ static_cast<QQmlListProperty<QObject> *>(addr)->~QQmlListProperty<QObject>();
+ },
+ /*.equals*/ nullptr,
+ /*.lessThan*/ nullptr,
+ /*.debugStream=*/ nullptr,
+ /*.dataStreamOut=*/ nullptr,
+ /*.dataStreamIn=*/ nullptr,
+ /*.legacyRegisterOp=*/ nullptr
+ }
+ , name(name), valueType(valueType) { }
+};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp
index c2150225c3..bc7e762e53 100644
--- a/src/qml/qml/qqmlmetatypedata.cpp
+++ b/src/qml/qml/qqmlmetatypedata.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlmetatypedata_p.h"
@@ -51,21 +15,24 @@ QQmlMetaTypeData::QQmlMetaTypeData()
QQmlMetaTypeData::~QQmlMetaTypeData()
{
- for (TypeModules::const_iterator i = uriToModule.constBegin(), cend = uriToModule.constEnd(); i != cend; ++i)
- delete *i;
- for (QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = propertyCaches.begin(), end = propertyCaches.end();
- it != end; ++it)
- (*it)->release();
+ {
+ // Unregister all remaining composite types.
+ // Avoid deletion recursion (via QQmlTypePrivate dtor) by moving them out of the way first.
+ CompositeTypes emptyComposites;
+ emptyComposites.swap(compositeTypes);
+ }
+ propertyCaches.clear();
// Do this before the attached properties disappear.
types.clear();
undeletableTypes.clear();
+ qDeleteAll(metaTypeToValueType);
}
// This expects a "fresh" QQmlTypePrivate and adopts its reference.
void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
{
- for (int i = 0; i < types.count(); ++i) {
+ for (int i = 0; i < types.size(); ++i) {
if (!types.at(i).isValid()) {
types[i] = QQmlType(priv);
priv->index = i;
@@ -74,71 +41,119 @@ void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
}
}
types.append(QQmlType(priv));
- priv->index = types.count() - 1;
+ priv->index = types.size() - 1;
priv->release();
}
-void QQmlMetaTypeData::registerModuleTypes(const QQmlMetaTypeData::VersionedUri &versionedUri)
+QQmlMetaTypeData::VersionedUri::VersionedUri(const std::unique_ptr<QQmlTypeModule> &module)
+ : uri(module->module()), majorVersion(module->majorVersion())
{
- auto function = moduleTypeRegistrationFunctions.constFind(versionedUri);
- if (function != moduleTypeRegistrationFunctions.constEnd())
- (*function)();
}
-QQmlPropertyCache *QQmlMetaTypeData::propertyCacheForMinorVersion(int index, int minorVersion) const
+QQmlTypeModule *QQmlMetaTypeData::findTypeModule(const QString &module, QTypeRevision version)
{
- return (index < typePropertyCaches.length())
- ? typePropertyCaches.at(index).value(minorVersion).data()
+ const auto qqtm = std::lower_bound(
+ uriToModule.begin(), uriToModule.end(), VersionedUri(module, version),
+ std::less<QQmlMetaTypeData::VersionedUri>());
+ if (qqtm == uriToModule.end())
+ return nullptr;
+
+ QQmlTypeModule *candidate = qqtm->get();
+ return (candidate->module() == module && candidate->majorVersion() == version.majorVersion())
+ ? candidate
: nullptr;
}
-void QQmlMetaTypeData::setPropertyCacheForMinorVersion(int index, int minorVersion,
- QQmlPropertyCache *cache)
+QQmlTypeModule *QQmlMetaTypeData::addTypeModule(std::unique_ptr<QQmlTypeModule> module)
+{
+ QQmlTypeModule *ret = module.get();
+ uriToModule.emplace_back(std::move(module));
+ std::sort(uriToModule.begin(), uriToModule.end(),
+ [](const std::unique_ptr<QQmlTypeModule> &a,
+ const std::unique_ptr<QQmlTypeModule> &b) {
+ const int diff = a->module().compare(b->module());
+ return diff < 0 || (diff == 0 && a->majorVersion() < b->majorVersion());
+ });
+ return ret;
+}
+
+bool QQmlMetaTypeData::registerModuleTypes(const QString &uri)
+{
+ auto function = moduleTypeRegistrationFunctions.constFind(uri);
+ if (function != moduleTypeRegistrationFunctions.constEnd()) {
+ (*function)();
+ return true;
+ }
+ return false;
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCacheForVersion(
+ int index, QTypeRevision version) const
+{
+ return (index < typePropertyCaches.size())
+ ? typePropertyCaches.at(index).value(version)
+ : QQmlPropertyCache::ConstPtr();
+}
+
+void QQmlMetaTypeData::setPropertyCacheForVersion(int index, QTypeRevision version,
+ const QQmlPropertyCache::ConstPtr &cache)
{
- if (index >= typePropertyCaches.length())
+ if (index >= typePropertyCaches.size())
typePropertyCaches.resize(index + 1);
- typePropertyCaches[index][minorVersion] = cache;
+ typePropertyCaches[index][version] = cache;
}
-void QQmlMetaTypeData::clearPropertyCachesForMinorVersion(int index)
+void QQmlMetaTypeData::clearPropertyCachesForVersion(int index)
{
- if (index < typePropertyCaches.length())
+ if (index < typePropertyCaches.size())
typePropertyCaches[index].clear();
}
-QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject, int minorVersion)
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache(
+ const QMetaObject *metaObject, QTypeRevision version)
{
- if (QQmlPropertyCache *rv = propertyCaches.value(metaObject))
+ if (QQmlPropertyCache::ConstPtr rv = propertyCaches.value(metaObject))
return rv;
- if (!metaObject->superClass()) {
- QQmlPropertyCache *rv = new QQmlPropertyCache(metaObject);
+ QQmlPropertyCache::ConstPtr rv;
+ if (const QMetaObject *superMeta = metaObject->superClass())
+ rv = propertyCache(superMeta, version)->copyAndAppend(metaObject, version);
+ else
+ rv = QQmlPropertyCache::createStandalone(metaObject);
+
+ const auto *mop = reinterpret_cast<const QMetaObjectPrivate *>(metaObject->d.data);
+ if (!(mop->flags & DynamicMetaObject))
propertyCaches.insert(metaObject, rv);
- return rv;
- }
- QQmlPropertyCache *super = propertyCache(metaObject->superClass(), minorVersion);
- QQmlPropertyCache *rv = super->copyAndAppend(metaObject, minorVersion);
- propertyCaches.insert(metaObject, rv);
+
return rv;
}
-QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int minorVersion)
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::propertyCache(
+ const QQmlType &type, QTypeRevision version)
{
Q_ASSERT(type.isValid());
- if (QQmlPropertyCache *pc = propertyCacheForMinorVersion(type.index(), minorVersion))
+ if (auto pc = propertyCacheForVersion(type.index(), version))
return pc;
QVector<QQmlType> types;
- int maxMinorVersion = 0;
+ quint8 maxMinorVersion = 0;
const QMetaObject *metaObject = type.metaObject();
+ Q_ASSERT(metaObject);
+
+ const QTypeRevision combinedVersion = version.hasMajorVersion()
+ ? version
+ : (version.hasMinorVersion()
+ ? QTypeRevision::fromVersion(type.version().majorVersion(),
+ version.minorVersion())
+ : QTypeRevision::fromMajorVersion(type.version().majorVersion()));
while (metaObject) {
- QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), type.majorVersion(), minorVersion);
+ QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), combinedVersion);
if (t.isValid()) {
- maxMinorVersion = qMax(maxMinorVersion, t.minorVersion());
+ maxMinorVersion = qMax(maxMinorVersion, t.version().minorVersion());
types << t;
} else {
types << QQmlType();
@@ -147,32 +162,30 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min
metaObject = metaObject->superClass();
}
- if (QQmlPropertyCache *pc = propertyCacheForMinorVersion(type.index(), maxMinorVersion)) {
- setPropertyCacheForMinorVersion(type.index(), minorVersion, pc);
+ const QTypeRevision maxVersion = QTypeRevision::fromVersion(combinedVersion.majorVersion(),
+ maxMinorVersion);
+ if (auto pc = propertyCacheForVersion(type.index(), maxVersion)) {
+ setPropertyCacheForVersion(type.index(), maxVersion, pc);
return pc;
}
- QQmlPropertyCache *raw = propertyCache(type.metaObject(), minorVersion);
-
- bool hasCopied = false;
+ QQmlPropertyCache::ConstPtr raw = propertyCache(type.metaObject(), combinedVersion);
+ QQmlPropertyCache::Ptr copied;
- for (int ii = 0; ii < types.count(); ++ii) {
+ for (int ii = 0; ii < types.size(); ++ii) {
const QQmlType &currentType = types.at(ii);
if (!currentType.isValid())
continue;
- int rev = currentType.metaObjectRevision();
- int moIndex = types.count() - 1 - ii;
+ QTypeRevision rev = currentType.metaObjectRevision();
+ int moIndex = types.size() - 1 - ii;
if (raw->allowedRevision(moIndex) != rev) {
- if (!hasCopied) {
- // TODO: The copy should be mutable, and the original should be const
- // Considering this, the setAllowedRevision() below does not violate
- // the immutability of already published property caches.
- raw = raw->copy();
- hasCopied = true;
+ if (copied.isNull()) {
+ copied = raw->copy();
+ raw = copied;
}
- raw->setAllowedRevision(moIndex, rev);
+ copied->setAllowedRevision(moIndex, rev);
}
}
@@ -198,12 +211,12 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min
!overloadError && iter != raw->stringCache.end();
++iter) {
- QQmlPropertyData *d = *iter;
+ const QQmlPropertyData *d = *iter;
if (raw->isAllowedInRevision(d))
continue; // Not excluded - no problems
// check that a regular "name" overload isn't happening
- QQmlPropertyData *current = d;
+ const QQmlPropertyData *current = d;
while (!overloadError && current) {
current = d->overrideData(current);
if (current && raw->isAllowedInRevision(current))
@@ -219,15 +232,31 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min
}
#endif
- setPropertyCacheForMinorVersion(type.index(), minorVersion, raw);
-
- if (hasCopied)
- raw->release();
+ setPropertyCacheForVersion(type.index(), version, raw);
- if (minorVersion != maxMinorVersion)
- setPropertyCacheForMinorVersion(type.index(), maxMinorVersion, raw);
+ if (version != maxVersion)
+ setPropertyCacheForVersion(type.index(), maxVersion, raw);
return raw;
}
+static QQmlPropertyCache::ConstPtr propertyCacheForPotentialInlineComponentType(
+ QMetaType t, const QQmlMetaTypeData::CompositeTypes::const_iterator &iter) {
+ if (t != (*iter)->metaType()) {
+ // this is an inline component, and what we have in the iterator is currently the parent compilation unit
+ for (auto &&icDatum: (*iter)->inlineComponentData)
+ if (icDatum.qmlType.typeId() == t)
+ return (*iter)->propertyCaches.at(icDatum.objectIndex);
+ }
+ return (*iter)->rootPropertyCache();
+}
+
+QQmlPropertyCache::ConstPtr QQmlMetaTypeData::findPropertyCacheInCompositeTypes(QMetaType t) const
+{
+ auto iter = compositeTypes.constFind(t.iface());
+ return (iter == compositeTypes.constEnd())
+ ? QQmlPropertyCache::ConstPtr()
+ : propertyCacheForPotentialInlineComponentType(t, iter);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h
index 755a51a16e..8863bd1089 100644
--- a/src/qml/qml/qqmlmetatypedata_p.h
+++ b/src/qml/qml/qqmlmetatypedata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLMETATYPEDATA_P_H
#define QQMLMETATYPEDATA_P_H
@@ -54,10 +18,10 @@
#include <private/qqmltype_p.h>
#include <private/qqmlmetatype_p.h>
#include <private/qhashedstring_p.h>
+#include <private/qqmlvaluetype_p.h>
#include <QtCore/qset.h>
#include <QtCore/qvector.h>
-#include <QtCore/qbitarray.h>
QT_BEGIN_NAMESPACE
@@ -71,55 +35,79 @@ struct QQmlMetaTypeData
QSet<QQmlType> undeletableTypes;
typedef QHash<int, QQmlTypePrivate *> Ids;
Ids idToType;
- typedef QHash<QHashedStringRef, QQmlTypePrivate *> Names;
+
+ using Names = QMultiHash<QHashedString, const QQmlTypePrivate *>;
Names nameToType;
- typedef QHash<QUrl, QQmlTypePrivate *> Files; //For file imported composite types only
+
+ typedef QHash<QUrl, const QQmlTypePrivate *> Files; //For file imported composite types only
Files urlToType;
Files urlToNonFileImportType; // For non-file imported composite and composite
// singleton types. This way we can locate any
// of them by url, even if it was registered as
// a module via QQmlPrivate::RegisterCompositeType
- typedef QHash<const QMetaObject *, QQmlTypePrivate *> MetaObjects;
+ typedef QMultiHash<const QMetaObject *, QQmlTypePrivate *> MetaObjects;
MetaObjects metaObjectToType;
- typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
- StringConverters stringConverters;
- QVector<QHash<int, QQmlRefPointer<QQmlPropertyCache>>> typePropertyCaches;
+ QVector<QHash<QTypeRevision, QQmlPropertyCache::ConstPtr>> typePropertyCaches;
+ QHash<int, QQmlValueType *> metaTypeToValueType;
+
+ using CompositeTypes = QHash<const QtPrivate::QMetaTypeInterface *,
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit>>;
+ CompositeTypes compositeTypes;
+ QHash<QUrl, QQmlType> inlineComponentTypes;
struct VersionedUri {
- VersionedUri()
- : majorVersion(0) {}
- VersionedUri(const QHashedString &uri, int majorVersion)
- : uri(uri), majorVersion(majorVersion) {}
- bool operator==(const VersionedUri &other) const {
- return other.majorVersion == majorVersion && other.uri == uri;
+ VersionedUri() = default;
+ VersionedUri(const QString &uri, QTypeRevision version)
+ : uri(uri), majorVersion(version.majorVersion()) {}
+ VersionedUri(const std::unique_ptr<QQmlTypeModule> &module);
+
+ friend bool operator==(const VersionedUri &a, const VersionedUri &b)
+ {
+ return a.majorVersion == b.majorVersion && a.uri == b.uri;
+ }
+
+ friend size_t qHash(const VersionedUri &v, size_t seed = 0)
+ {
+ return qHashMulti(seed, v.uri, v.majorVersion);
+ }
+
+ friend bool operator<(const QQmlMetaTypeData::VersionedUri &a,
+ const QQmlMetaTypeData::VersionedUri &b)
+ {
+ const int diff = a.uri.compare(b.uri);
+ return diff < 0 || (diff == 0 && a.majorVersion < b.majorVersion);
}
- QHashedString uri;
- int majorVersion;
+
+ QString uri;
+ quint8 majorVersion = 0;
};
- typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules;
+ typedef std::vector<std::unique_ptr<QQmlTypeModule>> TypeModules;
TypeModules uriToModule;
+ QQmlTypeModule *findTypeModule(const QString &module, QTypeRevision version);
+ QQmlTypeModule *addTypeModule(std::unique_ptr<QQmlTypeModule> module);
+
+ using ModuleImports = QMultiMap<VersionedUri, QQmlDirParser::Import>;
+ ModuleImports moduleImports;
- QHash<VersionedUri, void (*)()> moduleTypeRegistrationFunctions;
- void registerModuleTypes(const VersionedUri &versionedUri);
+ QHash<QString, void (*)()> moduleTypeRegistrationFunctions;
+ bool registerModuleTypes(const QString &uri);
- QBitArray objects;
- QBitArray interfaces;
- QBitArray lists;
+ QSet<int> interfaces;
QList<QQmlPrivate::AutoParentFunction> parentFunctions;
QVector<QQmlPrivate::QmlUnitCacheLookupFunction> lookupCachedQmlUnit;
- QHash<int, int> qmlLists;
+ QHash<const QMetaObject *, QQmlPropertyCache::ConstPtr> propertyCaches;
- QHash<const QMetaObject *, QQmlPropertyCache *> propertyCaches;
+ QQmlPropertyCache::ConstPtr propertyCacheForVersion(int index, QTypeRevision version) const;
+ void setPropertyCacheForVersion(
+ int index, QTypeRevision version, const QQmlPropertyCache::ConstPtr &cache);
+ void clearPropertyCachesForVersion(int index);
- QQmlPropertyCache *propertyCacheForMinorVersion(int index, int minorVersion) const;
- void setPropertyCacheForMinorVersion(int index, int minorVersion, QQmlPropertyCache *cache);
- void clearPropertyCachesForMinorVersion(int index);
-
- QQmlPropertyCache *propertyCache(const QMetaObject *metaObject, int minorVersion);
- QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion);
+ QQmlPropertyCache::ConstPtr propertyCache(const QMetaObject *metaObject, QTypeRevision version);
+ QQmlPropertyCache::ConstPtr propertyCache(const QQmlType &type, QTypeRevision version);
+ QQmlPropertyCache::ConstPtr findPropertyCacheInCompositeTypes(QMetaType t) const;
void setTypeRegistrationFailures(QStringList *failures)
{
@@ -138,11 +126,6 @@ private:
QStringList *m_typeRegistrationFailures = nullptr;
};
-inline uint qHash(const QQmlMetaTypeData::VersionedUri &v)
-{
- return v.uri.hash() ^ qHash(v.majorVersion);
-}
-
QT_END_NAMESPACE
#endif // QQMLMETATYPEDATA_P_H
diff --git a/src/qml/qml/qqmlmoduleregistration.cpp b/src/qml/qml/qqmlmoduleregistration.cpp
index bb82ec1d95..a6d7e879b3 100644
--- a/src/qml/qml/qqmlmoduleregistration.cpp
+++ b/src/qml/qml/qqmlmoduleregistration.cpp
@@ -1,54 +1,36 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtQml/private/qqmlmetatype_p.h>
#include <QtQml/qqmlmoduleregistration.h>
-#include <QtCore/qglobalstatic.h>
+#include <QtCore/qversionnumber.h>
QT_BEGIN_NAMESPACE
+struct QQmlModuleRegistrationPrivate
+{
+ const QString uri;
+};
+
+QQmlModuleRegistration::QQmlModuleRegistration(const char *uri, void (*registerFunction)()) :
+ d(new QQmlModuleRegistrationPrivate { QString::fromUtf8(uri) })
+{
+ QQmlMetaType::qmlInsertModuleRegistration(d->uri, registerFunction);
+}
+
+#if QT_DEPRECATED_SINCE(6, 0)
QQmlModuleRegistration::QQmlModuleRegistration(
- const char *uri, int majorVersion,
- void (*registerFunction)())
+ const char *uri, int majorVersion, void (*registerFunction)()) :
+ QQmlModuleRegistration(uri, registerFunction)
+{
+ Q_UNUSED(majorVersion);
+}
+#endif
+
+QQmlModuleRegistration::~QQmlModuleRegistration()
{
- QQmlMetaType::qmlInsertModuleRegistration(QString::fromUtf8(uri), majorVersion,
- registerFunction);
+ QQmlMetaType::qmlRemoveModuleRegistration(d->uri);
+ delete d;
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmoduleregistration.h b/src/qml/qml/qqmlmoduleregistration.h
index 8924724b48..b7a0da9cb9 100644
--- a/src/qml/qml/qqmlmoduleregistration.h
+++ b/src/qml/qml/qqmlmoduleregistration.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLMODULEREGISTRATION_H
#define QQMLMODULEREGISTRATION_H
@@ -44,13 +8,21 @@
QT_BEGIN_NAMESPACE
+struct QQmlModuleRegistrationPrivate;
class Q_QML_EXPORT QQmlModuleRegistration
{
Q_DISABLE_COPY_MOVE(QQmlModuleRegistration)
-
public:
+ QQmlModuleRegistration(const char *uri, void (*registerFunction)());
+ ~QQmlModuleRegistration();
+
+#if QT_DEPRECATED_SINCE(6, 0)
+ QT_DEPRECATED_X("Use registration without major version")
QQmlModuleRegistration(const char *uri, int majorVersion, void (*registerFunction)());
- ~QQmlModuleRegistration() = default;
+#endif
+
+private:
+ QQmlModuleRegistrationPrivate *d = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
index c14a91c1fa..ed4fd34073 100644
--- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
+++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlnetworkaccessmanagerfactory.h"
@@ -54,9 +18,20 @@ QT_BEGIN_NAMESPACE
with custom QNetworkAccessManager instances with specialized caching,
proxy and cookies support.
+ \list
+ \li The QNetworkDiskCache can be used as a request cache with \l {QNetworkDiskCache}.
+ \li Using \l {QNetworkProxy}, traffic sent by the QNetworkAccessManager can be tunnelled through a proxy.
+ \li Cookies can be saved for future requests by adding a \l {QNetworkCookieJar}.
+ \endlist
+
To implement a factory, subclass QQmlNetworkAccessManagerFactory and
implement the virtual create() method, then assign it to the relevant QML
- engine using QQmlEngine::setNetworkAccessManagerFactory().
+ engine using QQmlEngine::setNetworkAccessManagerFactory(). For instance, the QNetworkAccessManager
+ objects created by the following snippet will cache requests.
+ \snippet code/src_network_access_qnetworkaccessmanager.cpp 0
+
+ The factory can then be passed to the QML engine so it can instantiate the QNetworkAccessManager with the custom behavior.
+ \snippet code/src_network_access_qnetworkaccessmanager.cpp 1
Note the QML engine may create QNetworkAccessManager instances
from multiple threads. Because of this, the implementation of the create()
@@ -80,7 +55,7 @@ QT_BEGIN_NAMESPACE
For more information about signals and threads, see
\l {Threads and QObjects} and \l {Signals and Slots Across Threads}.
- \sa {C++ Extensions: Network Access Manager Factory Example}{Network Access Manager Factory Example}
+ \sa QNetworkDiskCache
*/
/*!
diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h
index 57dec1da29..ea3a410ef6 100644
--- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h
+++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLNETWORKACCESSMANAGERFACTORY_H
#define QQMLNETWORKACCESSMANAGERFACTORY_H
diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp
index 1359586b31..e7b8799f82 100644
--- a/src/qml/qml/qqmlnotifier.cpp
+++ b/src/qml/qml/qqmlnotifier.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlnotifier_p.h"
#include "qqmlproperty_p.h"
@@ -49,12 +13,14 @@ typedef void (*Callback)(QQmlNotifierEndpoint *, void **);
void QQmlBoundSignal_callback(QQmlNotifierEndpoint *, void **);
void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **);
void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *, void **);
+void QQmlPropertyGuard_callback(QQmlNotifierEndpoint *, void **);
static Callback QQmlNotifier_callbacks[] = {
nullptr,
QQmlBoundSignal_callback,
QQmlJavaScriptExpressionGuard_callback,
- QQmlVMEMetaObjectEndpoint_callback
+ QQmlVMEMetaObjectEndpoint_callback,
+ QQmlPropertyGuard_callback
};
namespace {
@@ -118,15 +84,15 @@ void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine
disconnect();
Q_ASSERT(engine);
- if (QObjectPrivate::get(source)->threadData->threadId.loadRelaxed() !=
- QObjectPrivate::get(engine)->threadData->threadId.loadRelaxed()) {
+ if (QObjectPrivate::get(source)->threadData.loadRelaxed()->threadId.loadRelaxed() !=
+ QObjectPrivate::get(engine)->threadData.loadRelaxed()->threadId.loadRelaxed()) {
QString sourceName;
QDebug(&sourceName) << source;
- sourceName = sourceName.left(sourceName.length() - 1);
+ sourceName = sourceName.left(sourceName.size() - 1);
QString engineName;
QDebug(&engineName).nospace() << engine;
- engineName = engineName.left(engineName.length() - 1);
+ engineName = engineName.left(engineName.size() - 1);
qFatal("QQmlEngine: Illegal attempt to connect to %s that is in"
" a different thread than the QML engine %s.", qPrintable(sourceName),
diff --git a/src/qml/qml/qqmlnotifier_p.h b/src/qml/qml/qqmlnotifier_p.h
index 67d80a9d86..0ec7d5fef2 100644
--- a/src/qml/qml/qqmlnotifier_p.h
+++ b/src/qml/qml/qqmlnotifier_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLNOTIFIER_P_H
#define QQMLNOTIFIER_P_H
@@ -51,14 +15,15 @@
// We mean it.
//
-#include "qqmldata_p.h"
#include <QtCore/qmetaobject.h>
#include <private/qmetaobject_p.h>
+#include <private/qtqmlglobal_p.h>
QT_BEGIN_NAMESPACE
class QQmlNotifierEndpoint;
-class Q_QML_PRIVATE_EXPORT QQmlNotifier
+class QQmlData;
+class Q_QML_EXPORT QQmlNotifier
{
public:
inline QQmlNotifier();
@@ -90,7 +55,8 @@ public:
None = 0,
QQmlBoundSignal = 1,
QQmlJavaScriptExpressionGuard = 2,
- QQmlVMEMetaObjectEndpoint = 3
+ QQmlVMEMetaObjectEndpoint = 3,
+ QQmlPropertyGuard = 4,
};
inline QQmlNotifierEndpoint(Callback callback);
@@ -206,12 +172,15 @@ void QQmlNotifierEndpoint::disconnect()
if (next) next->prev = prev;
if (prev) *prev = next;
- if (sourceSignal != -1) {
+ if (sourceSignal != -1 && needsConnectNotify) {
QObject * const obj = senderAsObject();
Q_ASSERT(obj);
QObjectPrivate * const priv = QObjectPrivate::get(obj);
- if (needsConnectNotify)
- priv->disconnectNotify(QMetaObjectPrivate::signal(obj->metaObject(), sourceSignal));
+
+ // In some degenerate cases an object being destructed might be unable
+ // to produce a metaObject(). Therefore we check here.
+ if (const QMetaObject *mo = obj->metaObject())
+ priv->disconnectNotify(QMetaObjectPrivate::signal(mo, sourceSignal));
}
setSender(0x0);
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 44006c3f6a..a9b9140390 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlobjectcreator_p.h"
@@ -56,75 +20,95 @@
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
#include <private/qqmlscriptdata_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
#include <private/qjsvalue_p.h>
#include <private/qv4generatorobject_p.h>
+#include <private/qv4resolvedtypereference_p.h>
+#include <private/qqmlpropertybinding_p.h>
+#include <private/qqmlanybinding_p.h>
+#include <QtQml/private/qqmlvme_p.h>
-#include <qtqml_tracepoints_p.h>
+#include <QScopedValueRollback>
-QT_USE_NAMESPACE
+#include <qtqml_tracepoints_p.h>
+#include <QScopedValueRollback>
+#include <QLoggingCategory>
-namespace {
-struct ActiveOCRestorer
-{
- ActiveOCRestorer(QQmlObjectCreator *creator, QQmlEnginePrivate *ep)
- : ep(ep), oldCreator(ep->activeObjectCreator) { ep->activeObjectCreator = creator; }
- ~ActiveOCRestorer() { ep->activeObjectCreator = oldCreator; }
+Q_LOGGING_CATEGORY(lcQmlDefaultMethod, "qt.qml.defaultmethod")
- QQmlEnginePrivate *ep;
- QQmlObjectCreator *oldCreator;
-};
-}
+QT_USE_NAMESPACE
-QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *creationContext,
- QQmlIncubatorPrivate *incubator)
+Q_TRACE_PREFIX(qtqml,
+"namespace QV4 {" \
+"struct ExecutionEngine;" \
+"class ExecutableCompilationUnit;" \
+"namespace CompiledData {" \
+"struct Object;" \
+"}}" \
+"class QQmlEngine;"
+)
+
+Q_TRACE_POINT(qtqml, QQmlObjectCreator_createInstance_entry, const QV4::ExecutableCompilationUnit *compilationUnit, const QV4::CompiledData::Object *object, const QUrl &url)
+Q_TRACE_POINT(qtqml, QQmlObjectCreator_createInstance_exit, const QString &typeName)
+
+QQmlObjectCreator::QQmlObjectCreator(
+ QQmlRefPointer<QQmlContextData> parentContext,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlRefPointer<QQmlContextData> &creationContext,
+ QQmlIncubatorPrivate *incubator)
: phase(Startup)
, compilationUnit(compilationUnit)
- , propertyCaches(&compilationUnit->propertyCaches)
- , sharedState(new QQmlObjectCreatorSharedState)
+ , propertyCaches(compilationUnit->propertyCachesPtr())
+ , sharedState(new QQmlObjectCreatorSharedState, QQmlRefPointer<QQmlObjectCreatorSharedState>::Adopt)
, topLevelCreator(true)
+ , isContextObject(true)
, incubator(incubator)
{
- init(parentContext);
+ init(std::move(parentContext));
sharedState->componentAttached = nullptr;
- sharedState->allCreatedBindings.allocate(compilationUnit->totalBindingsCount);
- sharedState->allParserStatusCallbacks.allocate(compilationUnit->totalParserStatusCount);
- sharedState->allCreatedObjects.allocate(compilationUnit->totalObjectCount);
- sharedState->allJavaScriptObjects = nullptr;
+ sharedState->allCreatedBindings.allocate(compilationUnit->totalBindingsCount());
+ sharedState->allParserStatusCallbacks.allocate(compilationUnit->totalParserStatusCount());
+ sharedState->allCreatedObjects.allocate(compilationUnit->totalObjectCount());
+ sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList();
sharedState->creationContext = creationContext;
- sharedState->rootContext = nullptr;
- sharedState->hadRequiredProperties = false;
+ sharedState->rootContext.reset();
+ sharedState->hadTopLevelRequiredProperties = false;
if (auto profiler = QQmlEnginePrivate::get(engine)->profiler) {
Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler,
- sharedState->profiler.init(profiler, compilationUnit->totalParserStatusCount));
+ sharedState->profiler.init(profiler, compilationUnit->totalParserStatusCount()));
} else {
Q_UNUSED(profiler);
}
}
-QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState)
+QQmlObjectCreator::QQmlObjectCreator(QQmlRefPointer<QQmlContextData> parentContext,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ QQmlObjectCreatorSharedState *inheritedSharedState, bool isContextObject)
: phase(Startup)
, compilationUnit(compilationUnit)
- , propertyCaches(&compilationUnit->propertyCaches)
+ , propertyCaches(compilationUnit->propertyCachesPtr())
, sharedState(inheritedSharedState)
, topLevelCreator(false)
+ , isContextObject(isContextObject)
, incubator(nullptr)
{
- init(parentContext);
+ init(std::move(parentContext));
}
-void QQmlObjectCreator::init(QQmlContextData *providedParentContext)
+void QQmlObjectCreator::init(QQmlRefPointer<QQmlContextData> providedParentContext)
{
- parentContext = providedParentContext;
- engine = parentContext->engine;
+ parentContext = std::move(providedParentContext);
+ engine = parentContext->engine();
v4 = engine->handle();
- if (compilationUnit && !compilationUnit->engine)
- compilationUnit->linkToEngine(v4);
+ Q_ASSERT(compilationUnit);
+ Q_ASSERT(compilationUnit->engine == v4);
+ if (!compilationUnit->runtimeStrings)
+ compilationUnit->populate();
qmlUnit = compilationUnit->unitData();
- context = nullptr;
_qobject = nullptr;
_scopeObject = nullptr;
_bindingTarget = nullptr;
@@ -132,7 +116,6 @@ void QQmlObjectCreator::init(QQmlContextData *providedParentContext)
_compiledObject = nullptr;
_compiledObjectIndex = -1;
_ddata = nullptr;
- _propertyCache = nullptr;
_vmeMetaObject = nullptr;
_qmlContext = nullptr;
}
@@ -150,57 +133,69 @@ QQmlObjectCreator::~QQmlObjectCreator()
}
while (sharedState->componentAttached) {
QQmlComponentAttached *a = sharedState->componentAttached;
- a->rem();
+ a->removeFromList();
}
}
}
-QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlInstantiationInterrupt *interrupt)
+QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlInstantiationInterrupt *interrupt, int flags)
{
if (phase == CreatingObjectsPhase2) {
phase = ObjectsCreated;
- return context->contextObject;
+ return context->contextObject();
}
Q_ASSERT(phase == Startup);
phase = CreatingObjects;
int objectToCreate;
+ bool isComponentRoot = false; // either a "real" component of or an inline component
if (subComponentIndex == -1) {
objectToCreate = /*root object*/0;
+ isComponentRoot = true;
} else {
- const QV4::CompiledData::Object *compObj = compilationUnit->objectAt(subComponentIndex);
- objectToCreate = compObj->bindingTable()->value.objectIndex;
+ Q_ASSERT(subComponentIndex >= 0);
+ if (flags & CreationFlags::InlineComponent) {
+ if (compilationUnit->componentsAreBound()
+ && compilationUnit != parentContext->typeCompilationUnit()) {
+ recordError({}, tr("Cannot instantiate bound inline component in different file"));
+ phase = ObjectsCreated;
+ return nullptr;
+ }
+ objectToCreate = subComponentIndex;
+ isComponentRoot = true;
+ } else {
+ Q_ASSERT(flags & CreationFlags::NormalObject);
+ if (compilationUnit->componentsAreBound()
+ && sharedState->creationContext != parentContext) {
+ recordError({}, tr("Cannot instantiate bound component "
+ "outside its creation context"));
+ phase = ObjectsCreated;
+ return nullptr;
+ }
+ const QV4::CompiledData::Object *compObj = compilationUnit->objectAt(subComponentIndex);
+ objectToCreate = compObj->bindingTable()->value.objectIndex;
+ }
}
- context = new QQmlContextData;
- context->isInternal = true;
- context->imports = compilationUnit->typeNameCache;
- context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex);
- context->setParent(parentContext);
+ context = QQmlEnginePrivate::get(engine)->createInternalContext(
+ compilationUnit, parentContext, subComponentIndex, isComponentRoot);
if (!sharedState->rootContext) {
sharedState->rootContext = context;
- sharedState->rootContext->incubator = incubator;
- sharedState->rootContext->isRootObjectInCreation = true;
+ sharedState->rootContext->setIncubator(incubator);
+ sharedState->rootContext->setRootObjectInCreation(true);
}
QV4::Scope scope(v4);
- Q_ASSERT(sharedState->allJavaScriptObjects || topLevelCreator);
+ Q_ASSERT(sharedState->allJavaScriptObjects.canTrack() || topLevelCreator);
if (topLevelCreator)
- sharedState->allJavaScriptObjects = scope.alloc(compilationUnit->totalObjectCount);
-
- if (subComponentIndex == -1 && compilationUnit->dependentScripts.count()) {
- QV4::ScopedObject scripts(scope, v4->newArrayObject(compilationUnit->dependentScripts.count()));
- context->importedScripts.set(v4, scripts);
- QV4::ScopedValue v(scope);
- for (int i = 0; i < compilationUnit->dependentScripts.count(); ++i) {
- QQmlRefPointer<QQmlScriptData> s = compilationUnit->dependentScripts.at(i);
- scripts->put(i, (v = s->scriptValueForContext(context)));
- }
- } else if (sharedState->creationContext) {
- context->importedScripts = sharedState->creationContext->importedScripts;
+ sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList(scope, compilationUnit->totalObjectCount());
+
+ if (!isComponentRoot && sharedState->creationContext) {
+ // otherwise QQmlEnginePrivate::createInternalContext() handles it
+ context->setImportedScripts(sharedState->creationContext->importedScripts());
}
QObject *instance = createInstance(objectToCreate, parent, /*isContextObject*/true);
@@ -211,7 +206,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
}
if (topLevelCreator)
- sharedState->allJavaScriptObjects = nullptr;
+ sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList();
phase = CreatingObjectsPhase2;
@@ -223,72 +218,44 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
if (instance) {
if (QQmlEngineDebugService *service
= QQmlDebugConnector::service<QQmlEngineDebugService>()) {
- if (!parentContext->isInternal)
- parentContext->asQQmlContextPrivate()->instances.append(instance);
+ if (!parentContext->isInternal())
+ parentContext->asQQmlContextPrivate()->appendInstance(instance);
service->objectCreated(engine, instance);
- } else if (!parentContext->isInternal && QQmlDebugConnector::service<QV4DebugService>()) {
- parentContext->asQQmlContextPrivate()->instances.append(instance);
+ } else if (!parentContext->isInternal() && QQmlDebugConnector::service<QV4DebugService>()) {
+ parentContext->asQQmlContextPrivate()->appendInstance(instance);
}
}
return instance;
}
-void QQmlObjectCreator::beginPopulateDeferred(QQmlContextData *newContext)
+void QQmlObjectCreator::beginPopulateDeferred(const QQmlRefPointer<QQmlContextData> &newContext)
{
context = newContext;
sharedState->rootContext = newContext;
Q_ASSERT(topLevelCreator);
- Q_ASSERT(!sharedState->allJavaScriptObjects);
+ Q_ASSERT(!sharedState->allJavaScriptObjects.canTrack());
+ // FIXME (QTBUG-122956): allocating from the short lived scope does not make any sense
QV4::Scope valueScope(v4);
- sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
+ sharedState->allJavaScriptObjects = ObjectInCreationGCAnchorList(valueScope, compilationUnit->totalObjectCount());
}
void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex,
const QQmlPropertyPrivate *qmlProperty,
const QV4::CompiledData::Binding *binding)
{
- QQmlData *declarativeData = QQmlData::get(instance);
- QObject *bindingTarget = instance;
-
- QQmlRefPointer<QQmlPropertyCache> cache = declarativeData->propertyCache;
- QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance);
-
- QObject *scopeObject = instance;
- qSwap(_scopeObject, scopeObject);
-
- QV4::Scope valueScope(v4);
-
- Q_ASSERT(topLevelCreator);
- QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
-
- qSwap(_qmlContext, qmlContext);
-
- qSwap(_propertyCache, cache);
- qSwap(_qobject, instance);
-
- int objectIndex = deferredIndex;
- qSwap(_compiledObjectIndex, objectIndex);
-
- const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
- qSwap(_compiledObject, obj);
-
- qSwap(_ddata, declarativeData);
- qSwap(_bindingTarget, bindingTarget);
- qSwap(_vmeMetaObject, vmeMetaObject);
-
- if (binding) {
+ doPopulateDeferred(instance, deferredIndex, [this, qmlProperty, binding]() {
Q_ASSERT(qmlProperty);
- Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding);
+ Q_ASSERT(binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding));
QQmlListProperty<void> savedList;
qSwap(_currentList, savedList);
const QQmlPropertyData &property = qmlProperty->core;
- if (property.isQList()) {
+ if (property.propType().flags().testFlag(QMetaType::IsQmlList)) {
void *argv[1] = { (void*)&_currentList };
QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property.coreIndex(), argv);
} else if (_currentList.object) {
@@ -298,20 +265,12 @@ void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex,
setPropertyBinding(&property, binding);
qSwap(_currentList, savedList);
- } else {
- setupBindings(/*applyDeferredBindings=*/true);
- }
-
- qSwap(_vmeMetaObject, vmeMetaObject);
- qSwap(_bindingTarget, bindingTarget);
- qSwap(_ddata, declarativeData);
- qSwap(_compiledObject, obj);
- qSwap(_compiledObjectIndex, objectIndex);
- qSwap(_qobject, instance);
- qSwap(_propertyCache, cache);
+ });
+}
- qSwap(_qmlContext, qmlContext);
- qSwap(_scopeObject, scopeObject);
+void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex)
+{
+ doPopulateDeferred(instance, deferredIndex, [this]() { setupBindings(ApplyDeferred); });
}
bool QQmlObjectCreator::populateDeferredProperties(QObject *instance,
@@ -326,8 +285,22 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance,
void QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
const QV4::CompiledData::Binding *binding)
{
- populateDeferred(qmlProperty.object(), deferredIndex, QQmlPropertyPrivate::get(qmlProperty),
- binding);
+ if (binding) {
+ populateDeferred(qmlProperty.object(), deferredIndex, QQmlPropertyPrivate::get(qmlProperty),
+ binding);
+ } else {
+ populateDeferred(qmlProperty.object(), deferredIndex);
+ }
+}
+
+void QQmlObjectCreator::populateDeferredInstance(
+ QObject *outerObject, int deferredIndex, int index, QObject *instance,
+ QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding)
+{
+ doPopulateDeferred(outerObject, deferredIndex, [&]() {
+ populateInstance(index, instance, bindingTarget, valueTypeProperty, binding);
+ });
}
void QQmlObjectCreator::finalizePopulateDeferred()
@@ -340,11 +313,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | QQmlPropertyData::RemoveBindingOnAliasWrite;
QV4::Scope scope(v4);
- int propertyType = property->propType();
+ QMetaType propertyType = property->propType();
if (property->isEnum()) {
- if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) {
- propertyType = QMetaType::Int;
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum) ||
+ // TODO: For historical reasons you can assign any number to an enum property alias
+ // This can be fixed with an opt-out mechanism, for example a pragma.
+ (property->isAlias() && binding->isNumberBinding())) {
+ propertyType = property->propType().underlyingType();
} else {
// ### This should be resolved earlier at compile time and the binding value should be changed accordingly.
QVariant value = compilationUnit->bindingValueAsString(binding);
@@ -357,18 +333,18 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
auto assertOrNull = [&](bool ok)
{
- Q_ASSERT(ok || binding->type == QV4::CompiledData::Binding::Type_Null);
+ Q_ASSERT(ok || binding->type() == QV4::CompiledData::Binding::Type_Null);
Q_UNUSED(ok);
};
- auto assertType = [&](QV4::CompiledData::Binding::ValueType type)
+ auto assertType = [&](QV4::CompiledData::Binding::Type type)
{
- Q_ASSERT(binding->type == type || binding->type == QV4::CompiledData::Binding::Type_Null);
+ Q_ASSERT(binding->type()== type || binding->type() == QV4::CompiledData::Binding::Type_Null);
Q_UNUSED(type);
};
if (property->isQObject()) {
- if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Null) {
QObject *value = nullptr;
const bool ok = property->writeProperty(_qobject, &value, propertyWriteFlags);
Q_ASSERT(ok);
@@ -377,9 +353,9 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
}
}
- switch (propertyType) {
+ switch (propertyType.id()) {
case QMetaType::QVariant: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Number) {
double n = compilationUnit->bindingValueAsNumber(binding);
if (double(int(n)) == n) {
if (property->isVarProperty()) {
@@ -397,14 +373,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
}
- } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ } else if (binding->type() == QV4::CompiledData::Binding::Type_Boolean) {
if (property->isVarProperty()) {
_vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::fromBoolean(binding->valueAsBoolean()));
} else {
QVariant value(binding->valueAsBoolean());
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
- } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ } else if (binding->type() == QV4::CompiledData::Binding::Type_Null) {
if (property->isVarProperty()) {
_vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::nullValue());
} else {
@@ -417,45 +393,40 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
QV4::ScopedString s(scope, v4->newString(stringValue));
_vmeMetaObject->setVMEProperty(property->coreIndex(), s);
} else {
- // ### Qt 6: Doing the conversion here where we don't know the eventual target type is rather strange
- // and caused for instance QTBUG-78943
- QVariant value = QQmlStringConverters::variantFromString(stringValue);
+ QVariant value = stringValue;
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
}
}
break;
- case QVariant::String: {
+ case QMetaType::QString: {
assertOrNull(binding->evaluatesToString());
QString value = compilationUnit->bindingValueAsString(binding);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::StringList: {
+ case QMetaType::QStringList: {
assertOrNull(binding->evaluatesToString());
QStringList value(compilationUnit->bindingValueAsString(binding));
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::ByteArray: {
+ case QMetaType::QByteArray: {
assertType(QV4::CompiledData::Binding::Type_String);
QByteArray value(compilationUnit->bindingValueAsString(binding).toUtf8());
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Url: {
+ case QMetaType::QUrl: {
assertType(QV4::CompiledData::Binding::Type_String);
- QString string = compilationUnit->bindingValueAsString(binding);
- // Encoded dir-separators defeat QUrl processing - decode them first
- string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
- QUrl value = string.isEmpty() ? QUrl() : compilationUnit->finalUrl().resolved(QUrl(string));
- // Apply URL interceptor
- if (engine->urlInterceptor())
- value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
+ const QString string = compilationUnit->bindingValueAsString(binding);
+ QUrl value = (!string.isEmpty() && QQmlPropertyPrivate::resolveUrlsOnAssignment())
+ ? compilationUnit->finalUrl().resolved(QUrl(string))
+ : QUrl(string);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::UInt: {
+ case QMetaType::UInt: {
assertType(QV4::CompiledData::Binding::Type_Number);
double d = compilationUnit->bindingValueAsNumber(binding);
uint value = uint(d);
@@ -463,7 +434,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
}
break;
- case QVariant::Int: {
+ case QMetaType::Int: {
assertType(QV4::CompiledData::Binding::Type_Number);
double d = compilationUnit->bindingValueAsNumber(binding);
int value = int(d);
@@ -471,225 +442,247 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
}
break;
+ case QMetaType::SChar: {
+ assertType(QV4::CompiledData::Binding::Type_Number);
+ double d = compilationUnit->bindingValueAsNumber(binding);
+ qint8 value = qint8(d);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
+ break;
+ }
+ case QMetaType::UChar: {
+ assertType(QV4::CompiledData::Binding::Type_Number);
+ double d = compilationUnit->bindingValueAsNumber(binding);
+ quint8 value = quint8(d);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
+ break;
+ }
+ case QMetaType::Short: {
+ assertType(QV4::CompiledData::Binding::Type_Number);
+ double d = compilationUnit->bindingValueAsNumber(binding);
+ qint16 value = qint16(d);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
+ break;
+ }
+ case QMetaType::UShort: {
+ assertType(QV4::CompiledData::Binding::Type_Number);
+ double d = compilationUnit->bindingValueAsNumber(binding);
+ quint16 value = quint16(d);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
+ break;
+ }
+ case QMetaType::LongLong: {
+ assertType(QV4::CompiledData::Binding::Type_Number);
+ double d = compilationUnit->bindingValueAsNumber(binding);
+ qint64 value = qint64(d);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
+ break;
+ }
+ case QMetaType::ULongLong: {
+ assertType(QV4::CompiledData::Binding::Type_Number);
+ double d = compilationUnit->bindingValueAsNumber(binding);
+ quint64 value = quint64(d);
+ property->writeProperty(_qobject, &value, propertyWriteFlags);
+ break;
+ }
+ break;
case QMetaType::Float: {
assertType(QV4::CompiledData::Binding::Type_Number);
float value = float(compilationUnit->bindingValueAsNumber(binding));
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Double: {
+ case QMetaType::Double: {
assertType(QV4::CompiledData::Binding::Type_Number);
double value = compilationUnit->bindingValueAsNumber(binding);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Color: {
- bool ok = false;
- uint colorValue = QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok);
- assertOrNull(ok);
- struct { void *data[4]; } buffer;
- if (QQml_valueTypeProvider()->storeValueType(property->propType(), &colorValue, &buffer, sizeof(buffer))) {
- property->writeProperty(_qobject, &buffer, propertyWriteFlags);
+ case QMetaType::QColor: {
+ QVariant data = QQmlValueTypeProvider::createValueType(
+ compilationUnit->bindingValueAsString(binding), propertyType);
+ if (data.isValid()) {
+ property->writeProperty(_qobject, data.data(), propertyWriteFlags);
}
}
break;
#if QT_CONFIG(datestring)
- case QVariant::Date: {
+ case QMetaType::QDate: {
bool ok = false;
QDate value = QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Time: {
+ case QMetaType::QTime: {
bool ok = false;
QTime value = QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::DateTime: {
+ case QMetaType::QDateTime: {
bool ok = false;
- QDateTime value = QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok);
- // ### VME compatibility :(
- {
- const qint64 date = value.date().toJulianDay();
- const int msecsSinceStartOfDay = value.time().msecsSinceStartOfDay();
- value = QDateTime(QDate::fromJulianDay(date), QTime::fromMSecsSinceStartOfDay(msecsSinceStartOfDay));
- }
+ QDateTime value = QQmlStringConverters::dateTimeFromString(
+ compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
#endif // datestring
- case QVariant::Point: {
+ case QMetaType::QPoint: {
bool ok = false;
QPoint value = QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok).toPoint();
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::PointF: {
+ case QMetaType::QPointF: {
bool ok = false;
QPointF value = QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Size: {
+ case QMetaType::QSize: {
bool ok = false;
QSize value = QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok).toSize();
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::SizeF: {
+ case QMetaType::QSizeF: {
bool ok = false;
QSizeF value = QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Rect: {
+ case QMetaType::QRect: {
bool ok = false;
QRect value = QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok).toRect();
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::RectF: {
+ case QMetaType::QRectF: {
bool ok = false;
QRectF value = QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
assertOrNull(ok);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Bool: {
+ case QMetaType::Bool: {
assertType(QV4::CompiledData::Binding::Type_Boolean);
bool value = binding->valueAsBoolean();
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
- case QVariant::Vector2D: {
- struct {
- float xp;
- float yp;
- } vec;
- bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
- assertOrNull(ok);
- Q_UNUSED(ok);
- property->writeProperty(_qobject, &vec, propertyWriteFlags);
- }
- break;
- case QVariant::Vector3D: {
- struct {
- float xp;
- float yp;
- float zy;
- } vec;
- bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
- assertOrNull(ok);
- Q_UNUSED(ok);
- property->writeProperty(_qobject, &vec, propertyWriteFlags);
- }
- break;
- case QVariant::Vector4D: {
- struct {
- float xp;
- float yp;
- float zy;
- float wp;
- } vec;
- bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
- assertOrNull(ok);
- Q_UNUSED(ok);
- property->writeProperty(_qobject, &vec, propertyWriteFlags);
- }
- break;
- case QVariant::Quaternion: {
- struct {
- float wp;
- float xp;
- float yp;
- float zp;
- } vec;
- bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec));
- assertOrNull(ok);
- Q_UNUSED(ok);
- property->writeProperty(_qobject, &vec, propertyWriteFlags);
- }
- break;
- case QVariant::RegExp:
- assertOrNull(!"not possible");
+ case QMetaType::QVector2D:
+ case QMetaType::QVector3D:
+ case QMetaType::QVector4D:
+ case QMetaType::QQuaternion: {
+ QVariant result = QQmlValueTypeProvider::createValueType(
+ compilationUnit->bindingValueAsString(binding), propertyType);
+ assertOrNull(result.isValid());
+ property->writeProperty(_qobject, result.data(), propertyWriteFlags);
break;
+ }
default: {
// generate single literal value assignment to a list property if required
- if (property->propType() == qMetaTypeId<QList<qreal> >()) {
+ if (propertyType == QMetaType::fromType<QList<qreal>>()) {
assertType(QV4::CompiledData::Binding::Type_Number);
QList<qreal> value;
value.append(compilationUnit->bindingValueAsNumber(binding));
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (property->propType() == qMetaTypeId<QList<int> >()) {
+ } else if (propertyType == QMetaType::fromType<QList<int>>()) {
assertType(QV4::CompiledData::Binding::Type_Number);
double n = compilationUnit->bindingValueAsNumber(binding);
QList<int> value;
value.append(int(n));
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (property->propType() == qMetaTypeId<QList<bool> >()) {
+ } else if (propertyType == QMetaType::fromType<QList<bool>>()) {
assertType(QV4::CompiledData::Binding::Type_Boolean);
QList<bool> value;
value.append(binding->valueAsBoolean());
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (property->propType() == qMetaTypeId<QList<QUrl> >()) {
+ } else if (propertyType == QMetaType::fromType<QList<QUrl>>()) {
assertType(QV4::CompiledData::Binding::Type_String);
- QString urlString = compilationUnit->bindingValueAsString(binding);
- QUrl u = urlString.isEmpty() ? QUrl()
- : compilationUnit->finalUrl().resolved(QUrl(urlString));
- QList<QUrl> value;
- value.append(u);
+ const QUrl url(compilationUnit->bindingValueAsString(binding));
+ QList<QUrl> value {
+ QQmlPropertyPrivate::resolveUrlsOnAssignment()
+ ? compilationUnit->finalUrl().resolved(url)
+ : url
+ };
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (property->propType() == qMetaTypeId<QList<QString> >()) {
+ } else if (propertyType == QMetaType::fromType<QList<QString>>()) {
assertOrNull(binding->evaluatesToString());
QList<QString> value;
value.append(compilationUnit->bindingValueAsString(binding));
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
- } else if (property->propType() == qMetaTypeId<QJSValue>()) {
+ } else if (propertyType == QMetaType::fromType<QJSValue>()) {
QJSValue value;
- if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Boolean:
value = QJSValue(binding->valueAsBoolean());
- } else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double n = compilationUnit->bindingValueAsNumber(binding);
- if (double(int(n)) == n) {
+ break;
+ case QV4::CompiledData::Binding::Type_Number: {
+ const double n = compilationUnit->bindingValueAsNumber(binding);
+ if (double(int(n)) == n)
value = QJSValue(int(n));
- } else
+ else
value = QJSValue(n);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ break;
+ }
+ case QV4::CompiledData::Binding::Type_Null:
value = QJSValue::NullValue;
- } else {
+ break;
+ default:
value = QJSValue(compilationUnit->bindingValueAsString(binding));
+ break;
}
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
+ } else {
+ QVariant source;
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Boolean:
+ source = binding->valueAsBoolean();
+ break;
+ case QV4::CompiledData::Binding::Type_Number: {
+ const double n = compilationUnit->bindingValueAsNumber(binding);
+ if (double(int(n)) == n)
+ source = int(n);
+ else
+ source = n;
+ break;
+ }
+ case QV4::CompiledData::Binding::Type_Null:
+ source = QVariant::fromValue<std::nullptr_t>(nullptr);
+ break;
+ case QV4::CompiledData::Binding::Type_Invalid:
+ break;
+ default:
+ source = compilationUnit->bindingValueAsString(binding);
+ break;
+ }
+
+ QVariant target = QQmlValueTypeProvider::createValueType(source, propertyType);
+ if (target.isValid()) {
+ property->writeProperty(_qobject, target.data(), propertyWriteFlags);
+ break;
+ }
}
- // otherwise, try a custom type assignment
+ // string converters are not exposed, so ending up here indicates an error
QString stringValue = compilationUnit->bindingValueAsString(binding);
- QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType());
- Q_ASSERT(converter);
- QVariant value = (*converter)(stringValue);
-
QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex());
- if (value.isNull() || ((int)metaProperty.type() != property->propType() && metaProperty.userType() != property->propType())) {
- recordError(binding->location, tr("Cannot assign value %1 to property %2").arg(stringValue).arg(QString::fromUtf8(metaProperty.name())));
- break;
- }
-
- property->writeProperty(_qobject, value.data(), propertyWriteFlags);
+ recordError(binding->location, tr("Cannot assign value %1 to property"
+" %2").arg(stringValue, QString::fromUtf8(metaProperty.name())));
}
break;
}
@@ -706,23 +699,25 @@ static QQmlType qmlTypeForObject(QObject *object)
return type;
}
-void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
+void QQmlObjectCreator::setupBindings(BindingSetupFlags mode)
{
QQmlListProperty<void> savedList;
qSwap(_currentList, savedList);
- const QV4::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex);
+ const QV4::CompiledData::BindingPropertyData *propertyData
+ = compilationUnit->bindingPropertyDataPerObjectAt(_compiledObjectIndex);
if (_compiledObject->idNameIndex) {
- const QQmlPropertyData *idProperty = propertyData.last();
+ const QQmlPropertyData *idProperty = propertyData->last();
Q_ASSERT(!idProperty || !idProperty->isValid() || idProperty->name(_qobject) == QLatin1String("id"));
- if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType() == QMetaType::QString) {
+ if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType().id() == QMetaType::QString) {
QV4::CompiledData::Binding idBinding;
idBinding.propertyNameIndex = 0; // Not used
- idBinding.flags = 0;
- idBinding.type = QV4::CompiledData::Binding::Type_String;
+ idBinding.clearFlags();
+ idBinding.setType(QV4::CompiledData::Binding::Type_String);
idBinding.stringIndex = _compiledObject->idNameIndex;
idBinding.location = _compiledObject->location; // ###
+ idBinding.value.nullMarker = 0; // zero the value field to make codechecker happy
setPropertyValue(idProperty, &idBinding);
}
}
@@ -731,7 +726,7 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
if (_valueTypeProperty) {
QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(_bindingTarget, QQmlPropertyIndex(_valueTypeProperty->coreIndex()));
- if (binding && !binding->isValueTypeProxy()) {
+ if (binding && binding->kind() != QQmlAbstractBinding::ValueTypeProxy) {
QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(_valueTypeProperty->coreIndex()));
} else if (binding) {
QQmlValueTypeProxyBinding *proxy = static_cast<QQmlValueTypeProxyBinding *>(binding);
@@ -739,11 +734,14 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
if (qmlTypeForObject(_bindingTarget).isValid()) {
quint32 bindingSkipList = 0;
- QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty();
+ const QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty();
const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
- QQmlPropertyData *property = binding->propertyNameIndex != 0 ? _propertyCache->property(stringAt(binding->propertyNameIndex), _qobject, context) : defaultProperty;
+ const QQmlPropertyData *property = binding->propertyNameIndex != 0
+ ? _propertyCache->property(stringAt(binding->propertyNameIndex),
+ _qobject, context)
+ : defaultProperty;
if (property)
bindingSkipList |= (1 << property->coreIndex());
}
@@ -757,39 +755,66 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
- QQmlPropertyData *const property = propertyData.at(i);
+ const QQmlPropertyData *const property = propertyData->at(i);
if (property) {
- QQmlPropertyData* targetProperty = property;
+ const QQmlPropertyData *targetProperty = property;
if (targetProperty->isAlias()) {
// follow alias
- auto target = _bindingTarget;
QQmlPropertyIndex originalIndex(targetProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
- QQmlPropertyIndex propIndex;
- QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex);
- QQmlData *data = QQmlData::get(target);
+ auto [targetObject, targetIndex] = QQmlPropertyPrivate::findAliasTarget(_bindingTarget, originalIndex);
+ QQmlData *data = QQmlData::get(targetObject);
Q_ASSERT(data && data->propertyCache);
- targetProperty = data->propertyCache->property(propIndex.coreIndex());
+ targetProperty = data->propertyCache->property(targetIndex.coreIndex());
+ sharedState->requiredProperties.remove({targetObject, targetProperty});
}
- sharedState->requiredProperties.remove(targetProperty);
+ sharedState->requiredProperties.remove({_bindingTarget, property});
}
- if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsCustomParserBinding))
continue;
- if (binding->flags & QV4::CompiledData::Binding::IsDeferredBinding) {
- if (!applyDeferredBindings)
- continue;
- } else {
- if (applyDeferredBindings)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding)) {
+ if (!(mode & ApplyDeferred))
continue;
+ } else if (!(mode & ApplyImmediate)) {
+ continue;
}
- if (property && property->isQList()) {
+ if (property && property->propType().flags().testFlag(QMetaType::IsQmlList)) {
if (property->coreIndex() != currentListPropertyIndex) {
void *argv[1] = { (void*)&_currentList };
QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex(), argv);
currentListPropertyIndex = property->coreIndex();
+
+ // manage override behavior
+ const QMetaObject *const metaobject = _qobject->metaObject();
+ const int qmlListBehavorClassInfoIndex = metaobject->indexOfClassInfo("QML.ListPropertyAssignBehavior");
+ if (qmlListBehavorClassInfoIndex != -1) { // QML.ListPropertyAssignBehavior class info is set
+ const char *overrideBehavior =
+ metaobject->classInfo(qmlListBehavorClassInfoIndex).value();
+ if (!strcmp(overrideBehavior,
+ "Replace")) {
+ if (_currentList.clear) {
+ _currentList.clear(&_currentList);
+ }
+ } else {
+ bool isDefaultProperty =
+ (property->name(_qobject)
+ == QString::fromUtf8(
+ metaobject
+ ->classInfo(metaobject->indexOfClassInfo(
+ "DefaultProperty"))
+ .value()));
+ if (!isDefaultProperty
+ && (!strcmp(overrideBehavior,
+ "ReplaceIfNotDefault"))) {
+ if (_currentList.clear) {
+ _currentList.clear(&_currentList);
+ }
+ }
+ }
+ }
}
} else if (_currentList.object) {
_currentList = QQmlListProperty<void>();
@@ -805,34 +830,45 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProperty, const QV4::CompiledData::Binding *binding)
{
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
Q_ASSERT(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
QV4::ResolvedTypeReference *tr = resolvedType(binding->propertyNameIndex);
Q_ASSERT(tr);
- QQmlType attachedType = tr->type;
+ QQmlType attachedType = tr->type();
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
if (!attachedType.isValid()) {
- QQmlTypeNameCache::Result res = context->imports->query(stringAt(binding->propertyNameIndex));
+ QQmlTypeNameCache::Result res = context->imports()->query(
+ stringAt(binding->propertyNameIndex), QQmlTypeLoader::get(enginePrivate));
if (res.isValid())
attachedType = res.type;
else
return false;
}
QObject *qmlObject = qmlAttachedPropertiesObject(
- _qobject, attachedType.attachedPropertiesFunction(QQmlEnginePrivate::get(engine)));
- if (!populateInstance(binding->value.objectIndex, qmlObject, qmlObject, /*value type property*/nullptr))
+ _qobject, attachedType.attachedPropertiesFunction(enginePrivate));
+ if (!qmlObject) {
+ recordError(binding->location,
+ QStringLiteral("Could not create attached properties object '%1'")
+ .arg(QString::fromUtf8(attachedType.typeName())));
+ return false;
+ }
+
+ if (!populateInstance(binding->value.objectIndex, qmlObject, qmlObject,
+ /*value type property*/ nullptr, binding))
return false;
return true;
}
// ### resolve this at compile time
- if (bindingProperty && bindingProperty->propType() == qMetaTypeId<QQmlScriptString>()) {
+ if (bindingProperty && bindingProperty->propType() == QMetaType::fromType<QQmlScriptString>()) {
QQmlScriptString ss(compilationUnit->bindingValueAsScriptString(binding),
context->asQQmlContext(), _scopeObject);
- ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid;
- ss.d.data()->lineNumber = binding->location.line;
- ss.d.data()->columnNumber = binding->location.column;
- ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String;
- ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number;
+ ss.d.data()->bindingId = bindingType == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid;
+ ss.d.data()->lineNumber = binding->location.line();
+ ss.d.data()->columnNumber = binding->location.column();
+ ss.d.data()->isStringLiteral = bindingType == QV4::CompiledData::Binding::Type_String;
+ ss.d.data()->isNumberLiteral = bindingType == QV4::CompiledData::Binding::Type_Number;
ss.d.data()->numberValue = compilationUnit->bindingValueAsNumber(binding);
QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor |
@@ -844,26 +880,34 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
QObject *createdSubObject = nullptr;
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Object) {
createdSubObject = createInstance(binding->value.objectIndex, _bindingTarget);
if (!createdSubObject)
return false;
}
- if (!bindingProperty) // ### error
- return true;
-
- if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
+ if (bindingType == QV4::CompiledData::Binding::Type_GroupProperty) {
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(binding->value.objectIndex);
if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) {
QObject *groupObject = nullptr;
- QQmlValueType *valueType = nullptr;
+ QQmlGadgetPtrWrapper *valueType = nullptr;
const QQmlPropertyData *valueTypeProperty = nullptr;
QObject *bindingTarget = _bindingTarget;
-
- if (QQmlValueTypeFactory::isValueType(bindingProperty->propType())) {
- valueType = QQmlValueTypeFactory::valueType(bindingProperty->propType());
+ int groupObjectIndex = binding->value.objectIndex;
+
+ if (!bindingProperty) {
+ for (int i = 0, end = compilationUnit->objectCount(); i != end; ++i) {
+ const QV4::CompiledData::Object *external = compilationUnit->objectAt(i);
+ if (external->idNameIndex == binding->propertyNameIndex) {
+ bindingTarget = groupObject = context->idValue(external->objectId());
+ break;
+ }
+ }
+ if (!groupObject)
+ return true;
+ } else if (QQmlMetaType::isValueType(bindingProperty->propType())) {
+ valueType = QQmlGadgetPtrWrapper::instance(engine, bindingProperty->propType());
if (!valueType) {
recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
return false;
@@ -877,15 +921,27 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
void *argv[1] = { &groupObject };
QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, bindingProperty->coreIndex(), argv);
if (!groupObject) {
- recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
- return false;
+ QQmlPropertyIndex index(bindingProperty->coreIndex());
+ auto anyBinding = QQmlAnyBinding::ofProperty(_qobject, index);
+ if (anyBinding) {
+ // if there is a binding, try to force-evaluate it now
+ // this might instantiate a necessary part of a grouped property
+ anyBinding.refresh();
+ QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, bindingProperty->coreIndex(), argv);
+ }
+ if (!groupObject) {
+ recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex)));
+ return false;
+ }
}
bindingTarget = groupObject;
}
- if (!populateInstance(binding->value.objectIndex, groupObject, bindingTarget, valueTypeProperty))
+ if (!populateInstance(groupObjectIndex, groupObject, bindingTarget, valueTypeProperty,
+ binding)) {
return false;
+ }
if (valueType)
valueType->write(_qobject, bindingProperty->coreIndex(), QQmlPropertyData::BypassInterceptor);
@@ -894,20 +950,71 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
}
- if (_ddata->hasBindingBit(bindingProperty->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
- && !_valueTypeProperty)
- QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex()));
+ if (!bindingProperty) // ### error
+ return true;
+
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
+ const bool allowedToRemoveBinding
+ = !(bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment)
+ && !(bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver)
+ && !_valueTypeProperty;
+
+ if (allowedToRemoveBinding) {
+ if (bindingProperty->isBindable()) {
+ removePendingBinding(_bindingTarget, bindingProperty->coreIndex());
+ } else {
+ QQmlPropertyPrivate::removeBinding(
+ _bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex()));
+ }
+ }
- if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver) {
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
int signalIndex = _propertyCache->methodIndexToSignalIndex(bindingProperty->coreIndex());
- QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine);
- QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex,
- context, _scopeObject, runtimeFunction, currentQmlContext());
+ QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(
+ _bindingTarget, signalIndex, context,
+ _scopeObject, runtimeFunction, currentQmlContext());
- bs->takeExpression(expr);
+ if (bindingProperty->isBindable()) {
+ auto target = _bindingTarget;
+ if (bindingProperty->isAlias()) {
+ // If the property is an alias, we cannot obtain the bindable interface directly with qt_metacall
+ // so instead, we resolve the alias to obtain the actual target
+ // This should be faster than doing a detour through the metaobject of the target, and relying on
+ // QMetaObject::metacall doing the correct resolution
+ QQmlPropertyIndex originalIndex(bindingProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
+ auto [aliasTargetObject, aliasTargetIndex] = QQmlPropertyPrivate::findAliasTarget(target, originalIndex);
+ target = aliasTargetObject;
+ QQmlData *data = QQmlData::get(target);
+ Q_ASSERT(data && data->propertyCache);
+ bindingProperty = data->propertyCache->property(aliasTargetIndex.coreIndex());
+ }
+ auto &observer = QQmlData::get(_scopeObject)->propertyObservers.emplace_back(expr);
+ QUntypedBindable bindable;
+ void *argv[] = { &bindable };
+ target->qt_metacall(QMetaObject::BindableProperty, bindingProperty->coreIndex(), argv);
+ Q_ASSERT(bindable.isValid());
+ bindable.observe(&observer);
+ } else {
+ QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine);
+ bs->takeExpression(expr);
+ }
+ } else if (bindingProperty->isBindable()) {
+ QUntypedPropertyBinding qmlBinding;
+ if (binding->isTranslationBinding()) {
+ qmlBinding = QQmlTranslationPropertyBinding::create(bindingProperty, compilationUnit, binding);
+ } else {
+ QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
+ QQmlPropertyIndex index(bindingProperty->coreIndex(), -1);
+ qmlBinding = QQmlPropertyBinding::create(bindingProperty, runtimeFunction, _scopeObject, context, currentQmlContext(), _bindingTarget, index);
+ }
+ sharedState.data()->allQPropertyBindings.push_back(DeferredQPropertyBinding {_bindingTarget, bindingProperty->coreIndex(), qmlBinding });
+
+ QQmlData *data = QQmlData::get(_bindingTarget, true);
+ data->setBindingBit(_bindingTarget, bindingProperty->coreIndex());
} else {
// When writing bindings to grouped properties implemented as value types,
// such as point.x: { someExpression; }, then the binding is installed on
@@ -922,10 +1029,12 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
subprop = bindingProperty;
}
if (binding->isTranslationBinding()) {
- qmlBinding = QQmlBinding::createTranslationBinding(compilationUnit, binding, _scopeObject, context);
+ qmlBinding = QQmlBinding::createTranslationBinding(
+ compilationUnit, binding, _scopeObject, context);
} else {
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
- qmlBinding = QQmlBinding::create(targetProperty, runtimeFunction, _scopeObject, context, currentQmlContext());
+ qmlBinding = QQmlBinding::create(targetProperty, runtimeFunction, _scopeObject,
+ context, currentQmlContext());
}
auto bindingTarget = _bindingTarget;
@@ -956,8 +1065,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
return true;
}
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Object) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsOnAssignment) {
// ### determine value source and interceptor casts ahead of time.
QQmlType type = qmlTypeForObject(createdSubObject);
Q_ASSERT(type.isValid());
@@ -967,10 +1076,12 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(createdSubObject) + valueSourceCast);
QObject *target = createdSubObject->parent();
QQmlProperty prop;
- if (_valueTypeProperty)
- prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, bindingProperty, context);
- else
+ if (_valueTypeProperty) {
+ prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty,
+ bindingProperty, context);
+ } else {
prop = QQmlPropertyPrivate::restore(target, *bindingProperty, nullptr, context);
+ }
vs->setTarget(prop);
return true;
}
@@ -982,8 +1093,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
QQmlPropertyIndex propertyIndex;
if (bindingProperty->isAlias()) {
QQmlPropertyIndex originalIndex(bindingProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1);
- QQmlPropertyIndex propIndex;
- QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex);
+ auto aliasTarget = QQmlPropertyPrivate::findAliasTarget(target, originalIndex);
+ target = aliasTarget.targetObject;
QQmlData *data = QQmlData::get(target);
if (!data || !data->propertyCache) {
qWarning() << "can't resolve property alias for 'on' assignment";
@@ -991,16 +1102,20 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
// we can't have aliasses on subproperties of value types, so:
- QQmlPropertyData targetPropertyData = *data->propertyCache->property(propIndex.coreIndex());
- auto prop = QQmlPropertyPrivate::restore(target, targetPropertyData, nullptr, context);
+ QQmlPropertyData targetPropertyData = *data->propertyCache->property(aliasTarget.targetIndex.coreIndex());
+ auto prop = QQmlPropertyPrivate::restore(
+ target, targetPropertyData, nullptr, context);
vi->setTarget(prop);
propertyIndex = QQmlPropertyPrivate::propertyIndex(prop);
} else {
QQmlProperty prop;
- if (_valueTypeProperty)
- prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, bindingProperty, context);
- else
- prop = QQmlPropertyPrivate::restore(target, *bindingProperty, nullptr, context);
+ if (_valueTypeProperty) {
+ prop = QQmlPropertyPrivate::restore(
+ target, *_valueTypeProperty, bindingProperty, context);
+ } else {
+ prop = QQmlPropertyPrivate::restore(
+ target, *bindingProperty, nullptr, context);
+ }
vi->setTarget(prop);
propertyIndex = QQmlPropertyPrivate::propertyIndex(prop);
}
@@ -1014,8 +1129,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
return false;
}
- // Assigning object to signal property?
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
+ // Assigning object to signal property? ### Qt 7: Remove that functionality
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
if (!bindingProperty->isFunction()) {
recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(bindingProperty->name(_qobject)));
return false;
@@ -1025,11 +1140,14 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
recordError(binding->valueLocation, tr("Cannot assign object type %1 with no default method").arg(QString::fromLatin1(createdSubObject->metaObject()->className())));
return false;
}
+ qCWarning(lcQmlDefaultMethod) << "Assigning an object to a signal handler is deprecated. "
+ "Instead, create the object, give it an id, and call the desired slot "
+ "from the signal handler. The object is:" << createdSubObject;
QMetaMethod signalMethod = _qobject->metaObject()->method(bindingProperty->coreIndex());
if (!QMetaObject::checkConnectArgs(signalMethod, method)) {
recordError(binding->valueLocation,
- tr("Cannot connect mismatched signal/slot %1 %vs. %2")
+ tr("Cannot connect mismatched signal/slot %1 vs %2")
.arg(QString::fromUtf8(method.methodSignature()))
.arg(QString::fromUtf8(signalMethod.methodSignature())));
return false;
@@ -1053,7 +1171,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
recordError(binding->location, tr("Cannot assign object to interface property"));
return false;
}
- } else if (bindingProperty->propType() == QMetaType::QVariant) {
+ } else if (bindingProperty->propType() == QMetaType::fromType<QVariant>()) {
if (bindingProperty->isVarProperty()) {
QV4::Scope scope(v4);
QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(engine->handle(), createdSubObject));
@@ -1063,28 +1181,28 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
}
- } else if (bindingProperty->propType() == qMetaTypeId<QJSValue>()) {
+ } else if (bindingProperty->propType() == QMetaType::fromType<QJSValue>()) {
QV4::Scope scope(v4);
QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(engine->handle(), createdSubObject));
if (bindingProperty->isVarProperty()) {
_vmeMetaObject->setVMEProperty(bindingProperty->coreIndex(), wrappedObject);
} else {
QJSValue value;
- QJSValuePrivate::setValue(&value, v4, wrappedObject);
+ QJSValuePrivate::setValue(&value, wrappedObject);
argv[0] = &value;
QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv);
}
- } else if (bindingProperty->isQList()) {
+ } else if (bindingProperty->propType().flags().testFlag(QMetaType::IsQmlList)) {
Q_ASSERT(_currentList.object);
void *itemToAdd = createdSubObject;
- const char *iid = nullptr;
- int listItemType = QQmlEnginePrivate::get(engine)->listType(bindingProperty->propType());
- if (listItemType != -1)
- iid = QQmlMetaType::interfaceIId(listItemType);
- if (iid)
- itemToAdd = createdSubObject->qt_metacast(iid);
+ QMetaType listItemType = QQmlMetaType::listValueType(bindingProperty->propType());
+ if (listItemType.isValid()) {
+ const char *iid = QQmlMetaType::interfaceIId(listItemType);
+ if (iid)
+ itemToAdd = createdSubObject->qt_metacast(iid);
+ }
if (_currentList.append)
_currentList.append(&_currentList, itemToAdd);
@@ -1121,7 +1239,7 @@ void QQmlObjectCreator::setupFunctions()
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[*functionIdx];
const QString name = runtimeFunction->name()->toQString();
- QQmlPropertyData *property = _propertyCache->property(name, _qobject, context);
+ const QQmlPropertyData *property = _propertyCache->property(name, _qobject, context);
if (!property->isVMEFunction())
continue;
@@ -1137,21 +1255,16 @@ void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location,
{
QQmlError error;
error.setUrl(compilationUnit->url());
- error.setLine(location.line);
- error.setColumn(location.column);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
errors << error;
}
void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const
{
- if (object->id >= 0)
- context->setIdProperty(object->id, instance);
-}
-
-void QQmlObjectCreator::createQmlContext()
-{
- _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject));
+ if (object->objectId() >= 0)
+ context->setIdValue(object->objectId(), instance);
}
QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject)
@@ -1162,7 +1275,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
QString typeName;
Q_TRACE_EXIT(QQmlObjectCreator_createInstance_exit, typeName);
- ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
+ QScopedValueRollback<QQmlObjectCreator*> ocRestore(QQmlEnginePrivate::get(engine)->activeObjectCreator, this);
bool isComponent = false;
QObject *instance = nullptr;
@@ -1171,63 +1284,96 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
QQmlParserStatus *parserStatus = nullptr;
bool installPropertyCache = true;
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ if (obj->hasFlag(QV4::CompiledData::Object::IsComponent)) {
isComponent = true;
- QQmlComponent *component = new QQmlComponent(engine, compilationUnit.data(), index, parent);
+ instance = createComponent(engine, compilationUnit.data(), index, parent, context);
typeName = QStringLiteral("<component>");
- QQmlComponentPrivate::get(component)->creationContext = context;
- instance = component;
- ddata = QQmlData::get(instance, /*create*/true);
+ ddata = QQmlData::get(instance);
+ Q_ASSERT(ddata); // we just created it inside createComponent
} else {
QV4::ResolvedTypeReference *typeRef = resolvedType(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
- installPropertyCache = !typeRef->isFullyDynamicType;
- QQmlType type = typeRef->type;
- if (type.isValid()) {
+ installPropertyCache = !typeRef->isFullyDynamicType();
+ const QQmlType type = typeRef->type();
+ if (type.isValid() && !type.isInlineComponentType()) {
typeName = type.qmlTypeName();
- void *ddataMemory = nullptr;
- type.create(&instance, &ddataMemory, sizeof(QQmlData));
+ instance = type.createWithQQmlData();
if (!instance) {
recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex)));
return nullptr;
}
- {
- QQmlData *ddata = new (ddataMemory) QQmlData;
- ddata->ownMemory = false;
- QObjectPrivate* p = QObjectPrivate::get(instance);
- Q_ASSERT(!p->isDeletingChildren);
- p->declarativeData = ddata;
+ const int finalizerCast = type.finalizerCast();
+ if (finalizerCast != -1) {
+ auto hook = reinterpret_cast<QQmlFinalizerHook *>(reinterpret_cast<char *>(instance) + finalizerCast);
+ sharedState->finalizeHooks.push_back(hook);
}
-
const int parserStatusCast = type.parserStatusCast();
if (parserStatusCast != -1)
parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(instance) + parserStatusCast);
customParser = type.customParser();
- if (sharedState->rootContext && sharedState->rootContext->isRootObjectInCreation) {
+ if (sharedState->rootContext && sharedState->rootContext->isRootObjectInCreation()) {
QQmlData *ddata = QQmlData::get(instance, /*create*/true);
ddata->rootObjectInCreation = true;
- sharedState->rootContext->isRootObjectInCreation = false;
+ sharedState->rootContext->setRootObjectInCreation(false);
}
sharedState->allCreatedObjects.push(instance);
} else {
- Q_ASSERT(typeRef->compilationUnit);
- typeName = typeRef->compilationUnit->fileName();
- if (typeRef->compilationUnit->unitData()->isSingleton())
- {
+ auto compilationUnit = typeRef->compilationUnit();
+ Q_ASSERT(compilationUnit);
+ typeName = compilationUnit->fileName();
+ // compilation unit is shared between root type and its inline component types
+ // so isSingleton errorneously returns true for inline components
+ if (compilationUnit->unitData()->isSingleton() && !type.isInlineComponentType()) {
recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
return nullptr;
}
- QQmlObjectCreator subCreator(context, typeRef->compilationUnit, sharedState.data());
- instance = subCreator.create();
- if (!instance) {
- errors += subCreator.errors;
- return nullptr;
+ if (!type.isInlineComponentType()) {
+ QQmlObjectCreator subCreator(
+ context, engine->handle()->executableCompilationUnit(
+ std::move(compilationUnit)),
+ sharedState.data(), isContextObject);
+ instance = subCreator.create();
+ if (!instance) {
+ errors += subCreator.errors;
+ return nullptr;
+ }
+ } else {
+ QString subObjectName;
+ if (QString *icRootName = compilationUnit->icRootName.get()) {
+ subObjectName = type.elementName();
+ std::swap(*icRootName, subObjectName);
+ } else {
+ compilationUnit->icRootName = std::make_unique<QString>(type.elementName());
+ }
+
+ const auto guard = qScopeGuard([&] {
+ if (subObjectName.isEmpty())
+ compilationUnit->icRootName.reset();
+ else
+ std::swap(*compilationUnit->icRootName, subObjectName);
+ });
+
+ const int inlineComponentId
+ = compilationUnit->inlineComponentId(*compilationUnit->icRootName);
+ QQmlObjectCreator subCreator(
+ context,
+ engine->handle()->executableCompilationUnit(
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
+ compilationUnit)),
+ sharedState.data(),
+ isContextObject);
+ instance = subCreator.create(
+ inlineComponentId, nullptr, nullptr, CreationFlags::InlineComponent);
+ if (!instance) {
+ errors += subCreator.errors;
+ return nullptr;
+ }
}
}
if (instance->isWidgetType()) {
@@ -1248,27 +1394,17 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
compilationUnit.data(), obj, typeName, context->url()));
Q_UNUSED(typeName); // only relevant for tracing
- ddata->lineNumber = obj->location.line;
- ddata->columnNumber = obj->location.column;
+ ddata->lineNumber = obj->location.line();
+ ddata->columnNumber = obj->location.column();
ddata->setImplicitDestructible();
- if (static_cast<quint32>(index) == /*root object*/0 || ddata->rootObjectInCreation) {
- if (ddata->context) {
- Q_ASSERT(ddata->context != context);
- Q_ASSERT(ddata->outerContext);
- Q_ASSERT(ddata->outerContext != context);
- QQmlContextData *c = ddata->context;
- while (c->linkedContext) c = c->linkedContext;
- c->linkedContext = context;
- } else {
- ddata->context = context;
- }
- ddata->ownContext = ddata->context;
- } else if (!ddata->context) {
- ddata->context = context;
- }
-
- context->addObject(ddata);
+ // inline components are root objects, but their index is != 0, so we need
+ // an additional check
+ const bool documentRoot = static_cast<quint32>(index) == /*root object*/ 0
+ || ddata->rootObjectInCreation
+ || obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot);
+ context->installContext(
+ ddata, documentRoot ? QQmlContextData::DocumentRoot : QQmlContextData::OrdinaryObject);
if (parserStatus) {
parserStatus->classBegin();
@@ -1282,21 +1418,20 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
// Register the context object in the context early on in order for pending binding
// initialization to find it available.
if (isContextObject)
- context->contextObject = instance;
+ context->setContextObject(instance);
- if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) {
+ if (customParser && obj->hasFlag(QV4::CompiledData::Object::HasCustomParserBindings)) {
customParser->engine = QQmlEnginePrivate::get(engine);
- customParser->imports = compilationUnit->typeNameCache.data();
+ customParser->imports = compilationUnit->typeNameCache().data();
QList<const QV4::CompiledData::Binding *> bindings;
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(index);
const QV4::CompiledData::Binding *binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
- if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding) {
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsCustomParserBinding))
bindings << binding;
- }
}
- customParser->applyBindings(instance, compilationUnit.data(), bindings);
+ customParser->applyBindings(instance, compilationUnit, bindings);
customParser->engine = nullptr;
customParser->imports = (QQmlTypeNameCache*)nullptr;
@@ -1307,21 +1442,16 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
return instance;
}
- QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches->at(index);
+ QQmlPropertyCache::ConstPtr cache = propertyCaches->at(index);
Q_ASSERT(!cache.isNull());
- if (installPropertyCache) {
- if (ddata->propertyCache)
- ddata->propertyCache->release();;
- ddata->propertyCache = cache.data();
- ddata->propertyCache->addref();
- }
+ if (installPropertyCache)
+ ddata->propertyCache = cache;
QObject *scopeObject = instance;
qSwap(_scopeObject, scopeObject);
- Q_ASSERT(sharedState->allJavaScriptObjects);
- *sharedState->allJavaScriptObjects = QV4::QObjectWrapper::wrap(v4, instance);
- ++sharedState->allJavaScriptObjects;
+ Q_ASSERT(sharedState->allJavaScriptObjects.canTrack());
+ sharedState->allJavaScriptObjects.trackObject(v4, instance);
QV4::Scope valueScope(v4);
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
@@ -1357,13 +1487,26 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
return ok ? instance : nullptr;
}
-QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
+bool QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
{
Q_ASSERT(phase == ObjectsCreated || phase == Finalizing);
phase = Finalizing;
QQmlObjectCreatorRecursionWatcher watcher(this);
- ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
+ QScopedValueRollback<QQmlObjectCreator*> ocRestore(QQmlEnginePrivate::get(engine)->activeObjectCreator, this);
+
+ /* We install all pending bindings (both plain QML and QProperty), and remove the ones which do not
+ actually have dependencies.
+ It is necessary to install the binding so that it runs at least once, which causes it to capture any
+ dependencies.
+ We then check for the following conditions:
+ - Is the binding in an error state?
+ - Does the binding has any dependencies (from properties)?
+ - Does it depend on anything in the context, which has not been resolved yet (and thus couldn't be
+ captured)?
+ If the answer to all of those questions is "no", it is safe to remove the binding, as there is no
+ way for it to change its value afterwards from that point on.
+ */
while (!sharedState->allCreatedBindings.isEmpty()) {
QQmlAbstractBinding::Ptr b = sharedState->allCreatedBindings.pop();
@@ -1376,15 +1519,54 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru
data->clearPendingBindingBit(b->targetPropertyIndex().coreIndex());
b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
QQmlPropertyData::DontRemoveBinding);
- if (!b->isValueTypeProxy()) {
+ if (b->kind() == QQmlAbstractBinding::QmlBinding) {
QQmlBinding *binding = static_cast<QQmlBinding*>(b.data());
if (!binding->hasError() && !binding->hasDependencies()
- && binding->context() && !binding->context()->unresolvedNames)
+ && !binding->hasUnresolvedNames()) {
b->removeFromObject();
+ }
}
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
- return nullptr;
+ return false;
+ }
+
+ while (!sharedState->allQPropertyBindings.isEmpty()) {
+ auto& [target, index, qmlBinding] = sharedState->allQPropertyBindings.first();
+
+ QQmlData *data = QQmlData::get(target);
+ if (!data || !data->hasBindingBit(index)) {
+ // The target property has been overwritten since we stashed the binding.
+ sharedState->allQPropertyBindings.pop_front();
+ continue;
+ }
+
+ QUntypedBindable bindable;
+ void *argv[] = { &bindable };
+ // allow interception
+ target->metaObject()->metacall(target, QMetaObject::BindableProperty, index, argv);
+ const bool success = bindable.setBinding(qmlBinding);
+
+ const auto bindingPrivateRefCount = QPropertyBindingPrivate::get(qmlBinding)->refCount();
+
+ // Only pop_front after setting the binding as the bindings are refcounted.
+ sharedState->allQPropertyBindings.pop_front();
+
+ // If the binding was actually not set, it's deleted now.
+ if (success && bindingPrivateRefCount > 1) {
+ if (auto priv = QPropertyBindingPrivate::get(qmlBinding); priv->hasCustomVTable()) {
+ auto qmlBindingPriv = static_cast<QQmlPropertyBinding *>(priv);
+ auto jsExpression = qmlBindingPriv->jsExpression();
+ const bool canRemove = !qmlBinding.error().hasError()
+ && !qmlBindingPriv->hasDependencies()
+ && !jsExpression->hasUnresolvedNames();
+ if (canRemove)
+ bindable.takeBinding();
+ }
+ }
+
+ if (watcher.hasRecursed() || interrupt.shouldInterrupt())
+ return false;
}
if (QQmlVME::componentCompleteEnabled()) { // the qml designer does the component complete later
@@ -1398,39 +1580,34 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru
}
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
- return nullptr;
+ return false;
}
}
- for (int ii = 0; ii < sharedState->finalizeCallbacks.count(); ++ii) {
- QQmlEnginePrivate::FinalizeCallback callback = sharedState->finalizeCallbacks.at(ii);
- QObject *obj = callback.first;
- if (obj) {
- void *args[] = { nullptr };
- QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args);
- }
+ for (QQmlFinalizerHook *hook: sharedState->finalizeHooks) {
+ hook->componentFinalized();
if (watcher.hasRecursed())
- return nullptr;
+ return false;
}
- sharedState->finalizeCallbacks.clear();
+ sharedState->finalizeHooks.clear();
while (sharedState->componentAttached) {
QQmlComponentAttached *a = sharedState->componentAttached;
- a->rem();
+ a->removeFromList();
QQmlData *d = QQmlData::get(a->parent());
Q_ASSERT(d);
Q_ASSERT(d->context);
- a->add(&d->context->componentAttached);
+ d->context->addComponentAttached(a);
if (QQmlVME::componentCompleteEnabled())
emit a->completed();
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
- return nullptr;
+ return false;
}
phase = Done;
- return sharedState->rootContext;
+ return true;
}
void QQmlObjectCreator::clear()
@@ -1448,14 +1625,17 @@ void QQmlObjectCreator::clear()
while (sharedState->componentAttached) {
QQmlComponentAttached *a = sharedState->componentAttached;
- a->rem();
+ a->removeFromList();
}
phase = Done;
}
-bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty)
+bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget,
+ const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding)
{
+ Q_ASSERT(instance);
QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
qSwap(_qobject, instance);
@@ -1469,17 +1649,14 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
QV4::Scope valueScope(v4);
QV4::ScopedValue scopeObjectProtector(valueScope);
- QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches->at(_compiledObjectIndex);
+ QQmlPropertyCache::ConstPtr cache = propertyCaches->at(_compiledObjectIndex);
QQmlVMEMetaObject *vmeMetaObject = nullptr;
if (propertyCaches->needsVMEMetaObject(_compiledObjectIndex)) {
Q_ASSERT(!cache.isNull());
// install on _object
vmeMetaObject = new QQmlVMEMetaObject(v4, _qobject, cache, compilationUnit, _compiledObjectIndex);
- if (_ddata->propertyCache)
- _ddata->propertyCache->release();
- _ddata->propertyCache = cache.data();
- _ddata->propertyCache->addref();
+ _ddata->propertyCache = cache;
scopeObjectProtector = _ddata->jsWrapper.value();
} else {
vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
@@ -1490,44 +1667,158 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
qSwap(_propertyCache, cache);
qSwap(_vmeMetaObject, vmeMetaObject);
- if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings)
+ _ddata->compilationUnit = compilationUnit;
+ if (_compiledObject->hasFlag(QV4::CompiledData::Object::HasDeferredBindings))
_ddata->deferData(_compiledObjectIndex, compilationUnit, context);
+ const qsizetype oldRequiredPropertiesCount = sharedState->requiredProperties.size();
+ QSet<QString> postHocRequired;
+ for (auto it = _compiledObject->requiredPropertyExtraDataBegin(); it != _compiledObject->requiredPropertyExtraDataEnd(); ++it)
+ postHocRequired.insert(stringAt(it->nameIndex));
+ bool hadInheritedRequiredProperties = !postHocRequired.empty();
+
for (int propertyIndex = 0; propertyIndex != _compiledObject->propertyCount(); ++propertyIndex) {
const QV4::CompiledData::Property* property = _compiledObject->propertiesBegin() + propertyIndex;
- QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex);
- if (property->isRequired) {
- sharedState->hadRequiredProperties = true;
- sharedState->requiredProperties.insert(propertyData,
- RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}});
+ const QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex);
+ // only compute stringAt if there's a chance for the lookup to succeed
+ auto postHocIt = postHocRequired.isEmpty() ? postHocRequired.end() : postHocRequired.find(stringAt(property->nameIndex));
+ if (!property->isRequired() && postHocRequired.end() == postHocIt)
+ continue;
+ if (postHocIt != postHocRequired.end())
+ postHocRequired.erase(postHocIt);
+ if (isContextObject)
+ sharedState->hadTopLevelRequiredProperties = true;
+ sharedState->requiredProperties.insert({_qobject, propertyData},
+ RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}});
+
+ }
+
+ const auto getPropertyCacheRange = [&]() -> std::pair<int, int> {
+ // the logic in a nutshell: we work with QML instances here. every
+ // instance has a QQmlType:
+ // * if QQmlType is valid && not an inline component, it's a C++ type
+ // * otherwise, it's a QML-defined type (a.k.a. Composite type), where
+ // invalid type == "comes from another QML document"
+ //
+ // 1. if the type we inherit from comes from C++, we must check *all*
+ // properties in the property cache so far - since we can have
+ // required properties defined in C++
+ // 2. otherwise - the type comes from QML, it's enough to check just
+ // *own* properties in the property cache, because there's a previous
+ // type in the hierarchy that has checked the C++ properties (via 1.)
+ // 3. required attached properties are explicitly not supported. to
+ // achieve that, go through all its properties
+ // 4. required group properties: the group itself is covered by 1.
+ // required sub-properties are not properly handled (QTBUG-96544), so
+ // just return the old range here for consistency
+ QV4::ResolvedTypeReference *typeRef = resolvedType(_compiledObject->inheritedTypeNameIndex);
+ if (!typeRef) { // inside a binding on attached/group property
+ Q_ASSERT(binding);
+ if (binding->isAttachedProperty())
+ return { 0, _propertyCache->propertyCount() }; // 3.
+ Q_ASSERT(binding->isGroupProperty());
+ return { 0, _propertyCache->propertyOffset() + 1 }; // 4.
+ }
+ Q_ASSERT(!_compiledObject->hasFlag(QV4::CompiledData::Object::IsComponent));
+ QQmlType type = typeRef->type();
+ if (type.isValid() && !type.isInlineComponentType()) {
+ return { 0, _propertyCache->propertyCount() }; // 1.
+ }
+ // Q_ASSERT(type.isComposite());
+ return { _propertyCache->propertyOffset(), _propertyCache->propertyCount() }; // 2.
+ };
+ const auto [offset, count] = getPropertyCacheRange();
+ for (int i = offset; i < count; ++i) {
+ const QQmlPropertyData *propertyData = _propertyCache->maybeUnresolvedProperty(i);
+ if (!propertyData)
+ continue;
+ // TODO: the property might be a group property (in which case we need
+ // to dive into its sub-properties and check whether there are any
+ // required elements there) - QTBUG-96544
+ if (!propertyData->isRequired() && postHocRequired.isEmpty())
+ continue;
+ QString name = propertyData->name(_qobject);
+ auto postHocIt = postHocRequired.find(name);
+ if (!propertyData->isRequired() && postHocRequired.end() == postHocIt )
+ continue;
+
+ if (postHocIt != postHocRequired.end())
+ postHocRequired.erase(postHocIt);
+
+ if (isContextObject)
+ sharedState->hadTopLevelRequiredProperties = true;
+ sharedState->requiredProperties.insert(
+ {_qobject, propertyData},
+ RequiredPropertyInfo {
+ name, compilationUnit->finalUrl(), _compiledObject->location, {} });
+ }
+
+ if (binding && binding->isAttachedProperty()
+ && sharedState->requiredProperties.size() != oldRequiredPropertiesCount) {
+ recordError(
+ binding->location,
+ QLatin1String("Attached property has required properties. This is not supported"));
+ }
+
+ // Note: there's a subtle case with the above logic: if we process a random
+ // QML-defined leaf type, it could have a required attribute overwrite on an
+ // *existing* property: `import QtQuick; Text { required text }`. in this
+ // case, we must add the property to a required list
+ if (!postHocRequired.isEmpty()) {
+ // NB: go through [0, offset) range as [offset, count) is already done
+ for (int i = 0; i < offset; ++i) {
+ const QQmlPropertyData *propertyData = _propertyCache->maybeUnresolvedProperty(i);
+ if (!propertyData)
+ continue;
+ QString name = propertyData->name(_qobject);
+ auto postHocIt = postHocRequired.find(name);
+ if (postHocRequired.end() == postHocIt)
+ continue;
+ postHocRequired.erase(postHocIt);
+
+ if (isContextObject)
+ sharedState->hadTopLevelRequiredProperties = true;
+ sharedState->requiredProperties.insert(
+ {_qobject, propertyData},
+ RequiredPropertyInfo {
+ name, compilationUnit->finalUrl(), _compiledObject->location, {} });
}
}
+ if (!postHocRequired.isEmpty() && hadInheritedRequiredProperties)
+ recordError({}, QLatin1String("Property %1 was marked as required but does not exist").arg(*postHocRequired.begin()));
+
if (_compiledObject->nFunctions > 0)
setupFunctions();
- setupBindings();
+ setupBindings((binding && binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding))
+ ? BindingMode::ApplyAll
+ : BindingMode::ApplyImmediate);
for (int aliasIndex = 0; aliasIndex != _compiledObject->aliasCount(); ++aliasIndex) {
const QV4::CompiledData::Alias* alias = _compiledObject->aliasesBegin() + aliasIndex;
const auto originalAlias = alias;
- while (alias->aliasToLocalAlias)
+ while (alias->isAliasToLocalAlias())
alias = _compiledObject->aliasesBegin() + alias->localAliasIndex;
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
- if (!context->idValues->wasSet())
+ Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved));
+ if (!context->isIdValueSet(0)) // TODO: Do we really want 0 here?
continue;
- QObject *target = context->idValues[alias->targetObjectId].data();
+ QObject *target = context->idValue(alias->targetObjectId());
if (!target)
continue;
QQmlData *targetDData = QQmlData::get(target, /*create*/false);
- if (!targetDData)
+ if (targetDData == nullptr || targetDData->propertyCache.isNull())
continue;
int coreIndex = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex();
- QQmlPropertyData *const targetProperty = targetDData->propertyCache->property(coreIndex);
+ const QQmlPropertyData *const targetProperty = targetDData->propertyCache->property(coreIndex);
if (!targetProperty)
continue;
- auto it = sharedState->requiredProperties.find(targetProperty);
+ auto it = sharedState->requiredProperties.find({target, targetProperty});
if (it != sharedState->requiredProperties.end())
- it->aliasesToRequired.push_back(AliasToRequiredInfo {compilationUnit->stringAt(originalAlias->nameIndex), compilationUnit->finalUrl()});
+ it->aliasesToRequired.push_back(
+ AliasToRequiredInfo {
+ compilationUnit->stringAt(originalAlias->nameIndex()),
+ compilationUnit->finalUrl()
+ });
}
qSwap(_vmeMetaObject, vmeMetaObject);
@@ -1542,11 +1833,34 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
return errors.isEmpty();
}
-
-
+/*!
+ \internal
+*/
+QQmlComponent *QQmlObjectCreator::createComponent(QQmlEngine *engine,
+ QV4::ExecutableCompilationUnit *compilationUnit,
+ int index, QObject *parent,
+ const QQmlRefPointer<QQmlContextData> &context)
+{
+ QQmlComponent *component = new QQmlComponent(engine, compilationUnit, index, parent);
+ QQmlComponentPrivate::get(component)->creationContext = context;
+ QQmlData::get(component, /*create*/ true);
+ return component;
+}
QQmlObjectCreatorRecursionWatcher::QQmlObjectCreatorRecursionWatcher(QQmlObjectCreator *creator)
: sharedState(creator->sharedState)
, watcher(creator->sharedState.data())
{
}
+
+void ObjectInCreationGCAnchorList::trackObject(QV4::ExecutionEngine *engine, QObject *instance)
+{
+ *allJavaScriptObjects = QV4::QObjectWrapper::wrap(engine, instance);
+ // we have to handle the case where the gc is already running, but the scope is discarded
+ // before the collector runs again. In that case, rescanning won't help us. Thus, mark the
+ // object.
+ QV4::WriteBarrier::markCustom(engine, [this](QV4::MarkStack *ms) {
+ allJavaScriptObjects->heapObject()->mark(ms);
+ });
+ ++allJavaScriptObjects;
+}
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 8b6cb67341..8b1c251e2b 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLOBJECTCREATOR_P_H
#define QQMLOBJECTCREATOR_P_H
@@ -57,6 +21,9 @@
#include <private/qrecursionwatcher_p.h>
#include <private/qqmlprofiler_p.h>
#include <private/qv4qmlcontext_p.h>
+#include <private/qqmlguardedcontextdata_p.h>
+#include <private/qqmlfinalizer_p.h>
+#include <private/qqmlvmemetaobject_p.h>
#include <qpointer.h>
@@ -86,71 +53,152 @@ struct RequiredPropertyInfo
QVector<AliasToRequiredInfo> aliasesToRequired;
};
-using RequiredProperties = QHash<QQmlPropertyData*, RequiredPropertyInfo>;
+struct RequiredPropertyKey
+{
+ RequiredPropertyKey() = default;
+ RequiredPropertyKey(const QObject *object, const QQmlPropertyData *data)
+ : object(object)
+ , data(data)
+ {}
+
+ const QObject *object = nullptr;
+ const QQmlPropertyData *data = nullptr;
+
+private:
+ friend size_t qHash(const RequiredPropertyKey &key, size_t seed = 0)
+ {
+ return qHashMulti(seed, key.object, key.data);
+ }
-struct QQmlObjectCreatorSharedState : public QSharedData
+ friend bool operator==(const RequiredPropertyKey &a, const RequiredPropertyKey &b)
+ {
+ return a.object == b.object && a.data == b.data;
+ }
+};
+
+class RequiredProperties : public QHash<RequiredPropertyKey, RequiredPropertyInfo> {};
+
+struct DeferredQPropertyBinding {
+ QObject *target = nullptr;
+ int properyIndex = -1;
+ QUntypedPropertyBinding binding;
+};
+
+class ObjectInCreationGCAnchorList {
+public:
+ // this is a non owning view, rule of zero applies
+ ObjectInCreationGCAnchorList() = default;
+ ObjectInCreationGCAnchorList(const QV4::Scope &scope, int totalObjectCount)
+ {
+ allJavaScriptObjects = scope.alloc(totalObjectCount);
+ }
+ void trackObject(QV4::ExecutionEngine *engine, QObject *instance);
+ bool canTrack() const { return allJavaScriptObjects; }
+private:
+ QV4::Value *allJavaScriptObjects = nullptr; // pointer to vector on JS stack to reference JS wrappers during creation phase.
+};
+
+struct QQmlObjectCreatorSharedState final : QQmlRefCounted<QQmlObjectCreatorSharedState>
{
- QQmlContextData *rootContext;
- QQmlContextData *creationContext;
+ QQmlRefPointer<QQmlContextData> rootContext;
+ QQmlRefPointer<QQmlContextData> creationContext;
QFiniteStack<QQmlAbstractBinding::Ptr> allCreatedBindings;
QFiniteStack<QQmlParserStatus*> allParserStatusCallbacks;
- QFiniteStack<QPointer<QObject> > allCreatedObjects;
- QV4::Value *allJavaScriptObjects; // pointer to vector on JS stack to reference JS wrappers during creation phase.
+ QFiniteStack<QQmlGuard<QObject> > allCreatedObjects;
+ ObjectInCreationGCAnchorList allJavaScriptObjects; // pointer to vector on JS stack to reference JS wrappers during creation phase.
QQmlComponentAttached *componentAttached;
- QList<QQmlEnginePrivate::FinalizeCallback> finalizeCallbacks;
+ QList<QQmlFinalizerHook *> finalizeHooks;
QQmlVmeProfiler profiler;
QRecursionNode recursionNode;
RequiredProperties requiredProperties;
- bool hadRequiredProperties;
+ QList<DeferredQPropertyBinding> allQPropertyBindings;
+ bool hadTopLevelRequiredProperties;
};
-class Q_QML_PRIVATE_EXPORT QQmlObjectCreator
+class Q_QML_EXPORT QQmlObjectCreator
{
Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator)
public:
- QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *creationContext, QQmlIncubatorPrivate *incubator = nullptr);
+ QQmlObjectCreator(QQmlRefPointer<QQmlContextData> parentContext,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlRefPointer<QQmlContextData> &creationContext,
+ QQmlIncubatorPrivate *incubator = nullptr);
~QQmlObjectCreator();
- QObject *create(int subComponentIndex = -1, QObject *parent = nullptr, QQmlInstantiationInterrupt *interrupt = nullptr);
+ enum CreationFlags { NormalObject = 1, InlineComponent = 2 };
+ QObject *create(int subComponentIndex = -1, QObject *parent = nullptr,
+ QQmlInstantiationInterrupt *interrupt = nullptr, int flags = NormalObject);
bool populateDeferredProperties(QObject *instance, const QQmlData::DeferredData *deferredData);
- void beginPopulateDeferred(QQmlContextData *context);
+ void beginPopulateDeferred(const QQmlRefPointer<QQmlContextData> &context);
void populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
const QV4::CompiledData::Binding *binding);
+ void populateDeferredInstance(QObject *outerObject, int deferredIndex,
+ int index, QObject *instance, QObject *bindingTarget,
+ const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding = nullptr);
void finalizePopulateDeferred();
- QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt);
+ bool finalize(QQmlInstantiationInterrupt &interrupt);
void clear();
+ QQmlRefPointer<QQmlContextData> rootContext() const { return sharedState->rootContext; }
QQmlComponentAttached **componentAttachment() { return &sharedState->componentAttached; }
- QList<QQmlEnginePrivate::FinalizeCallback> *finalizeCallbacks() { return &sharedState->finalizeCallbacks; }
-
QList<QQmlError> errors;
- QQmlContextData *parentContextData() const { return parentContext.contextData(); }
- QFiniteStack<QPointer<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; }
+ QQmlRefPointer<QQmlContextData> parentContextData() const
+ {
+ return parentContext.contextData();
+ }
+ QFiniteStack<QQmlGuard<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; }
+
+ RequiredProperties *requiredProperties() {return &sharedState->requiredProperties;}
+ bool componentHadTopLevelRequiredProperties() const {return sharedState->hadTopLevelRequiredProperties;}
- RequiredProperties &requiredProperties() {return sharedState->requiredProperties;}
- bool componentHadRequiredProperties() const {return sharedState->hadRequiredProperties;}
+ static QQmlComponent *createComponent(QQmlEngine *engine,
+ QV4::ExecutableCompilationUnit *compilationUnit,
+ int index, QObject *parent,
+ const QQmlRefPointer<QQmlContextData> &context);
+
+ void removePendingBinding(QObject *target, int propertyIndex)
+ {
+ QList<DeferredQPropertyBinding> &pendingBindings = sharedState.data()->allQPropertyBindings;
+ pendingBindings.removeIf([&](const DeferredQPropertyBinding &deferred) {
+ return deferred.properyIndex == propertyIndex && deferred.target == target;
+ });
+ }
private:
- QQmlObjectCreator(QQmlContextData *contextData, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState);
+ QQmlObjectCreator(QQmlRefPointer<QQmlContextData> contextData,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ QQmlObjectCreatorSharedState *inheritedSharedState,
+ bool isContextObject);
- void init(QQmlContextData *parentContext);
+ void init(QQmlRefPointer<QQmlContextData> parentContext);
QObject *createInstance(int index, QObject *parent = nullptr, bool isContextObject = false);
- bool populateInstance(int index, QObject *instance,
- QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty);
+ bool populateInstance(int index, QObject *instance, QObject *bindingTarget,
+ const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding = nullptr);
// If qmlProperty and binding are null, populate all properties, otherwise only the given one.
+ void populateDeferred(QObject *instance, int deferredIndex);
void populateDeferred(QObject *instance, int deferredIndex,
- const QQmlPropertyPrivate *qmlProperty = nullptr,
- const QV4::CompiledData::Binding *binding = nullptr);
-
- void setupBindings(bool applyDeferredBindings = false);
+ const QQmlPropertyPrivate *qmlProperty,
+ const QV4::CompiledData::Binding *binding);
+
+ enum BindingMode {
+ ApplyNone = 0x0,
+ ApplyImmediate = 0x1,
+ ApplyDeferred = 0x2,
+ ApplyAll = ApplyImmediate | ApplyDeferred,
+ };
+ Q_DECLARE_FLAGS(BindingSetupFlags, BindingMode);
+
+ void setupBindings(BindingSetupFlags mode = BindingMode::ApplyImmediate);
bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setupFunctions();
@@ -161,7 +209,6 @@ private:
void registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const;
inline QV4::QmlContext *currentQmlContext();
- Q_NEVER_INLINE void createQmlContext();
QV4::ResolvedTypeReference *resolvedType(int id) const
{
return compilationUnit->resolvedType(id);
@@ -181,10 +228,11 @@ private:
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
const QV4::CompiledData::Unit *qmlUnit;
QQmlGuardedContextData parentContext;
- QQmlContextData *context;
+ QQmlRefPointer<QQmlContextData> context;
const QQmlPropertyCacheVector *propertyCaches;
- QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState;
+ QQmlRefPointer<QQmlObjectCreatorSharedState> sharedState;
bool topLevelCreator;
+ bool isContextObject;
QQmlIncubatorPrivate *incubator;
QObject *_qobject;
@@ -195,7 +243,7 @@ private:
int _compiledObjectIndex;
const QV4::CompiledData::Object *_compiledObject;
QQmlData *_ddata;
- QQmlRefPointer<QQmlPropertyCache> _propertyCache;
+ QQmlPropertyCache::ConstPtr _propertyCache;
QQmlVMEMetaObject *_vmeMetaObject;
QQmlListProperty<void> _currentList;
QV4::QmlContext *_qmlContext;
@@ -204,6 +252,58 @@ private:
typedef std::function<bool(QQmlObjectCreatorSharedState *sharedState)> PendingAliasBinding;
std::vector<PendingAliasBinding> pendingAliasBindings;
+
+ template<typename Functor>
+ void doPopulateDeferred(QObject *instance, int deferredIndex, Functor f)
+ {
+ QQmlData *declarativeData = QQmlData::get(instance);
+
+ // We're in the process of creating the object. We sure hope it's still alive.
+ Q_ASSERT(declarativeData && declarativeData->propertyCache);
+
+ QObject *bindingTarget = instance;
+
+ QQmlPropertyCache::ConstPtr cache = declarativeData->propertyCache;
+ QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance);
+
+ QObject *scopeObject = instance;
+ qt_ptr_swap(_scopeObject, scopeObject);
+
+ QV4::Scope valueScope(v4);
+ QScopedValueRollback<ObjectInCreationGCAnchorList> jsObjectGuard(
+ sharedState->allJavaScriptObjects,
+ ObjectInCreationGCAnchorList(valueScope, compilationUnit->totalObjectCount()));
+
+ Q_ASSERT(topLevelCreator);
+ QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
+
+ qt_ptr_swap(_qmlContext, qmlContext);
+
+ _propertyCache.swap(cache);
+ qt_ptr_swap(_qobject, instance);
+
+ int objectIndex = deferredIndex;
+ std::swap(_compiledObjectIndex, objectIndex);
+
+ const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
+ qt_ptr_swap(_compiledObject, obj);
+ qt_ptr_swap(_ddata, declarativeData);
+ qt_ptr_swap(_bindingTarget, bindingTarget);
+ qt_ptr_swap(_vmeMetaObject, vmeMetaObject);
+
+ f();
+
+ qt_ptr_swap(_vmeMetaObject, vmeMetaObject);
+ qt_ptr_swap(_bindingTarget, bindingTarget);
+ qt_ptr_swap(_ddata, declarativeData);
+ qt_ptr_swap(_compiledObject, obj);
+ std::swap(_compiledObjectIndex, objectIndex);
+ qt_ptr_swap(_qobject, instance);
+ _propertyCache.swap(cache);
+
+ qt_ptr_swap(_qmlContext, qmlContext);
+ qt_ptr_swap(_scopeObject, scopeObject);
+ }
};
struct QQmlObjectCreatorRecursionWatcher
@@ -213,7 +313,7 @@ struct QQmlObjectCreatorRecursionWatcher
bool hasRecursed() const { return watcher.hasRecursed(); }
private:
- QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState;
+ QQmlRefPointer<QQmlObjectCreatorSharedState> sharedState;
QRecursionWatcher<QQmlObjectCreatorSharedState, &QQmlObjectCreatorSharedState::recursionNode> watcher;
};
diff --git a/src/qml/qml/qqmlobjectorgadget.cpp b/src/qml/qml/qqmlobjectorgadget.cpp
index 1d4916d7d1..bc70138144 100644
--- a/src/qml/qml/qqmlobjectorgadget.cpp
+++ b/src/qml/qml/qqmlobjectorgadget.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlobjectorgadget_p.h"
@@ -44,14 +8,13 @@ QT_BEGIN_NAMESPACE
void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv) const
{
if (ptr.isNull()) {
- const QMetaObject *metaObject = _m.asT2();
- metaObject->d.static_metacall(nullptr, type, index, argv);
+ _m->d.static_metacall(nullptr, type, index, argv);
}
else if (ptr.isT1()) {
QMetaObject::metacall(ptr.asT1(), type, index, argv);
}
else {
- const QMetaObject *metaObject = _m.asT1()->metaObject();
+ const QMetaObject *metaObject = _m;
QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &index);
metaObject->d.static_metacall(reinterpret_cast<QObject*>(ptr.asT2()), type, index, argv);
}
diff --git a/src/qml/qml/qqmlobjectorgadget_p.h b/src/qml/qml/qqmlobjectorgadget_p.h
index c5f5f58a3a..ddce295c9d 100644
--- a/src/qml/qml/qqmlobjectorgadget_p.h
+++ b/src/qml/qml/qqmlobjectorgadget_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLOBJECTORGADGET_P_H
#define QQMLOBJECTORGADGET_P_H
@@ -52,6 +16,7 @@
//
#include <private/qqmlmetaobject_p.h>
+#include <private/qbipointer_p.h>
QT_BEGIN_NAMESPACE
@@ -62,20 +27,21 @@ public:
: QQmlMetaObject(obj),
ptr(obj)
{}
- QQmlObjectOrGadget(QQmlPropertyCache *propertyCache, void *gadget)
- : QQmlMetaObject(propertyCache)
+ QQmlObjectOrGadget(const QMetaObject *metaObject, void *gadget)
+ : QQmlMetaObject(metaObject)
, ptr(gadget)
{}
+ QQmlObjectOrGadget(const QMetaObject* metaObject)
+ : QQmlMetaObject(metaObject)
+ {}
void metacall(QMetaObject::Call type, int index, void **argv) const;
+ bool isNull() const { return ptr.isNull(); }
+ QObject *qObject() const { return ptr.isT1() ? ptr.asT1() : nullptr; }
+
private:
QBiPointer<QObject, void> ptr;
-
-protected:
- QQmlObjectOrGadget(const QMetaObject* metaObject)
- : QQmlMetaObject(metaObject)
- {}
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp
index fe0946c6de..2d0a78c6cb 100644
--- a/src/qml/qml/qqmlopenmetaobject.cpp
+++ b/src/qml/qml/qqmlopenmetaobject.cpp
@@ -1,48 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlopenmetaobject_p.h"
#include <private/qqmlpropertycache_p.h>
#include <private/qqmldata_p.h>
+#include <private/qqmlmetatype_p.h>
+
#include <private/qmetaobjectbuilder_p.h>
-#include <qqmlengine.h>
#include <qdebug.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qset.h>
QT_BEGIN_NAMESPACE
@@ -50,7 +17,7 @@ QT_BEGIN_NAMESPACE
class QQmlOpenMetaObjectTypePrivate
{
public:
- QQmlOpenMetaObjectTypePrivate() : mem(nullptr), cache(nullptr), engine(nullptr) {}
+ QQmlOpenMetaObjectTypePrivate() : mem(nullptr) {}
void init(const QMetaObject *metaObj);
@@ -59,15 +26,19 @@ public:
QHash<QByteArray, int> names;
QMetaObjectBuilder mob;
QMetaObject *mem;
- QQmlPropertyCache *cache;
- QQmlEngine *engine;
+
+ // TODO: We need to make sure that this does not escape into other threads.
+ // In particular, all its non-const uses are probably wrong. You should
+ // only set the open metaobject to "cached" once it's not going to be
+ // modified anymore.
+ QQmlPropertyCache::Ptr cache;
+
QSet<QQmlOpenMetaObject*> referers;
};
-QQmlOpenMetaObjectType::QQmlOpenMetaObjectType(const QMetaObject *base, QQmlEngine *engine)
- : QQmlCleanup(engine), d(new QQmlOpenMetaObjectTypePrivate)
+QQmlOpenMetaObjectType::QQmlOpenMetaObjectType(const QMetaObject *base)
+ : d(new QQmlOpenMetaObjectTypePrivate)
{
- d->engine = engine;
d->init(base);
}
@@ -75,16 +46,9 @@ QQmlOpenMetaObjectType::~QQmlOpenMetaObjectType()
{
if (d->mem)
free(d->mem);
- if (d->cache)
- d->cache->release();
delete d;
}
-void QQmlOpenMetaObjectType::clear()
-{
- d->engine = nullptr;
-}
-
int QQmlOpenMetaObjectType::propertyOffset() const
{
return d->propertyOffset;
@@ -97,24 +61,19 @@ int QQmlOpenMetaObjectType::signalOffset() const
int QQmlOpenMetaObjectType::propertyCount() const
{
- return d->names.count();
+ return d->names.size();
}
QByteArray QQmlOpenMetaObjectType::propertyName(int idx) const
{
- Q_ASSERT(idx >= 0 && idx < d->names.count());
+ Q_ASSERT(idx >= 0 && idx < d->names.size());
return d->mob.property(idx).name();
}
-QMetaObject *QQmlOpenMetaObjectType::metaObject() const
-{
- return d->mem;
-}
-
void QQmlOpenMetaObjectType::createProperties(const QVector<QByteArray> &names)
{
- for (int i = 0; i < names.count(); ++i) {
+ for (int i = 0; i < names.size(); ++i) {
const QByteArray &name = names.at(i);
const int id = d->mob.propertyCount();
d->mob.addSignal("__" + QByteArray::number(id) + "()");
@@ -136,13 +95,13 @@ void QQmlOpenMetaObjectType::createProperties(const QVector<QByteArray> &names)
int QQmlOpenMetaObjectType::createProperty(const QByteArray &name)
{
- int id = d->mob.propertyCount();
- d->mob.addSignal("__" + QByteArray::number(id) + "()");
- QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", id);
- propertyCreated(id, build);
+ const int signalIdx = d->mob.addSignal(
+ "__" + QByteArray::number(d->mob.propertyCount()) + "()").index();
+ QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", signalIdx);
+ propertyCreated(build.index(), build);
free(d->mem);
d->mem = d->mob.toMetaObject();
- d->names.insert(name, id);
+ d->names.insert(name, build.index());
QSet<QQmlOpenMetaObject*>::iterator it = d->referers.begin();
while (it != d->referers.end()) {
QQmlOpenMetaObject *omo = *it;
@@ -152,12 +111,12 @@ int QQmlOpenMetaObjectType::createProperty(const QByteArray &name)
++it;
}
- return d->propertyOffset + id;
+ return d->propertyOffset + build.index();
}
void QQmlOpenMetaObjectType::propertyCreated(int id, QMetaPropertyBuilder &builder)
{
- if (d->referers.count())
+ if (d->referers.size())
(*d->referers.begin())->propertyCreated(id, builder);
}
@@ -166,7 +125,7 @@ void QQmlOpenMetaObjectTypePrivate::init(const QMetaObject *metaObj)
if (!mem) {
mob.setSuperClass(metaObj);
mob.setClassName(metaObj->className());
- mob.setFlags(QMetaObjectBuilder::DynamicMetaObject);
+ mob.setFlags(MetaObjectFlag::DynamicMetaObject);
mem = mob.toMetaObject();
@@ -180,8 +139,8 @@ void QQmlOpenMetaObjectTypePrivate::init(const QMetaObject *metaObj)
class QQmlOpenMetaObjectPrivate
{
public:
- QQmlOpenMetaObjectPrivate(QQmlOpenMetaObject *_q, bool _autoCreate, QObject *obj)
- : q(_q), object(obj), autoCreate(_autoCreate) {}
+ QQmlOpenMetaObjectPrivate(QQmlOpenMetaObject *_q, QObject *obj)
+ : q(_q), object(obj) {}
struct Property {
private:
@@ -191,7 +150,7 @@ public:
bool valueSet = false;
QVariant value() const {
- if (QMetaType::typeFlags(m_value.userType()) & QMetaType::PointerToQObject
+ if (m_value.metaType().flags() & QMetaType::PointerToQObject
&& qobjectTracker.isNull())
return QVariant::fromValue<QObject*>(nullptr);
return m_value;
@@ -200,19 +159,19 @@ public:
void setValue(const QVariant &v) {
m_value = v;
valueSet = true;
- if (QMetaType::typeFlags(v.userType()) & QMetaType::PointerToQObject)
+ if (v.metaType().flags() & QMetaType::PointerToQObject)
qobjectTracker = m_value.value<QObject*>();
}
};
inline void setPropertyValue(int idx, const QVariant &value) {
- if (data.count() <= idx)
+ if (data.size() <= idx)
data.resize(idx + 1);
data[idx].setValue(value);
}
inline Property &propertyRef(int idx) {
- if (data.count() <= idx)
+ if (data.size() <= idx)
data.resize(idx + 1);
Property &prop = data[idx];
if (!prop.valueSet)
@@ -231,40 +190,47 @@ public:
}
inline bool hasProperty(int idx) const {
- if (idx >= data.count())
+ if (idx >= data.size())
return false;
return data[idx].valueSet;
}
+ void dropPropertyCache() {
+ if (QQmlData *ddata = QQmlData::get(object, /*create*/false))
+ ddata->propertyCache.reset();
+ }
+
QQmlOpenMetaObject *q;
- QAbstractDynamicMetaObject *parent = nullptr;
+ QDynamicMetaObjectData *parent = nullptr;
QVector<Property> data;
QObject *object;
QQmlRefPointer<QQmlOpenMetaObjectType> type;
- bool autoCreate;
+ QVector<QByteArray> *deferredPropertyNames = nullptr;
+ bool autoCreate = true;
bool cacheProperties = false;
};
-QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, const QMetaObject *base, bool automatic)
-: d(new QQmlOpenMetaObjectPrivate(this, automatic, obj))
+QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, const QMetaObject *base)
+: d(new QQmlOpenMetaObjectPrivate(this, obj))
{
- d->type.adopt(new QQmlOpenMetaObjectType(base ? base : obj->metaObject(), nullptr));
+ d->type.adopt(new QQmlOpenMetaObjectType(base ? base : obj->metaObject()));
d->type->d->referers.insert(this);
QObjectPrivate *op = QObjectPrivate::get(obj);
- d->parent = static_cast<QAbstractDynamicMetaObject *>(op->metaObject);
+ d->parent = op->metaObject;
*static_cast<QMetaObject *>(this) = *d->type->d->mem;
op->metaObject = this;
}
-QQmlOpenMetaObject::QQmlOpenMetaObject(QObject *obj, QQmlOpenMetaObjectType *type, bool automatic)
-: d(new QQmlOpenMetaObjectPrivate(this, automatic, obj))
+QQmlOpenMetaObject::QQmlOpenMetaObject(
+ QObject *obj, const QQmlRefPointer<QQmlOpenMetaObjectType> &type)
+: d(new QQmlOpenMetaObjectPrivate(this, obj))
{
d->type = type;
d->type->d->referers.insert(this);
QObjectPrivate *op = QObjectPrivate::get(obj);
- d->parent = static_cast<QAbstractDynamicMetaObject *>(op->metaObject);
+ d->parent = op->metaObject;
*static_cast<QMetaObject *>(this) = *d->type->d->mem;
op->metaObject = this;
}
@@ -290,6 +256,11 @@ void QQmlOpenMetaObject::emitPropertyNotification(const QByteArray &propertyName
activate(d->object, *iter + d->type->d->signalOffset, nullptr);
}
+void QQmlOpenMetaObject::unparent()
+{
+ d->parent = nullptr;
+}
+
int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void **a)
{
Q_ASSERT(d->object == o);
@@ -301,7 +272,7 @@ int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void *
propertyRead(propId);
*reinterpret_cast<QVariant *>(a[0]) = d->propertyValue(propId);
} else if (c == QMetaObject::WriteProperty) {
- if (propId >= d->data.count() || d->data.at(propId).value() != *reinterpret_cast<QVariant *>(a[0])) {
+ if (propId >= d->data.size() || d->data.at(propId).value() != *reinterpret_cast<QVariant *>(a[0])) {
propertyWrite(propId);
d->setPropertyValue(propId, propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0])));
propertyWritten(propId);
@@ -317,11 +288,21 @@ int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void *
}
}
-QAbstractDynamicMetaObject *QQmlOpenMetaObject::parent() const
+QDynamicMetaObjectData *QQmlOpenMetaObject::parent() const
{
return d->parent;
}
+bool QQmlOpenMetaObject::checkedSetValue(int index, const QVariant &value, bool force)
+{
+ if (!force && d->propertyValue(index) == value)
+ return false;
+
+ d->setPropertyValue(index, value);
+ activate(d->object, index + d->type->d->signalOffset, nullptr);
+ return true;
+}
+
QVariant QQmlOpenMetaObject::value(int id) const
{
return d->propertyValue(id);
@@ -361,16 +342,43 @@ bool QQmlOpenMetaObject::setValue(const QByteArray &name, const QVariant &val, b
id = *iter;
}
- if (id >= 0) {
- if (!force && d->propertyValue(id) == val)
- return false;
+ if (id >= 0)
+ return checkedSetValue(id, val, force);
- d->setPropertyValue(id, val);
- activate(d->object, id + d->type->d->signalOffset, nullptr);
- return true;
+ return false;
+}
+
+void QQmlOpenMetaObject::setValues(const QHash<QByteArray, QVariant> &values, bool force)
+{
+ QVector<QByteArray> missingProperties;
+ d->deferredPropertyNames = &missingProperties;
+ const auto &names = d->type->d->names;
+
+ for (auto valueIt = values.begin(), end = values.end(); valueIt != end; ++valueIt) {
+ const auto nameIt = names.constFind(valueIt.key());
+ if (nameIt == names.constEnd()) {
+ const int id = createProperty(valueIt.key(), "") - d->type->d->propertyOffset;
+
+ // If id >= 0 some override of createProperty() created it. Then set it.
+ // Else it either ends up in missingProperties and we create it later
+ // or it cannot be created.
+
+ if (id >= 0)
+ checkedSetValue(id, valueIt.value(), force);
+ } else {
+ checkedSetValue(*nameIt, valueIt.value(), force);
+ }
}
- return false;
+ d->deferredPropertyNames = nullptr;
+ if (missingProperties.isEmpty())
+ return;
+
+ d->type->createProperties(missingProperties);
+ d->dropPropertyCache();
+
+ for (const QByteArray &name : std::as_const(missingProperties))
+ checkedSetValue(names[name], values[name], force);
}
// returns true if this value has been initialized by a call to either value() or setValue()
@@ -381,37 +389,47 @@ bool QQmlOpenMetaObject::hasValue(int id) const
void QQmlOpenMetaObject::setCached(bool c)
{
- if (c == d->cacheProperties || !d->type->d->engine)
+ if (c == d->cacheProperties)
return;
d->cacheProperties = c;
QQmlData *qmldata = QQmlData::get(d->object, true);
if (d->cacheProperties) {
+ // As the propertyCache is not saved in QQmlMetaType (due to it being dynamic)
+ // we cannot leak it to other places before we're done with it. Yes, it's still
+ // terrible.
if (!d->type->d->cache)
- d->type->d->cache = new QQmlPropertyCache(this);
+ d->type->d->cache = QQmlPropertyCache::createStandalone(this);
qmldata->propertyCache = d->type->d->cache;
- d->type->d->cache->addref();
} else {
- if (d->type->d->cache)
- d->type->d->cache->release();
- qmldata->propertyCache = nullptr;
+ d->type->d->cache.reset();
+ qmldata->propertyCache.reset();
}
}
+bool QQmlOpenMetaObject::autoCreatesProperties() const
+{
+ return d->autoCreate;
+}
+
+void QQmlOpenMetaObject::setAutoCreatesProperties(bool autoCreate)
+{
+ d->autoCreate = autoCreate;
+}
+
int QQmlOpenMetaObject::createProperty(const char *name, const char *)
{
if (d->autoCreate) {
- int result = d->type->createProperty(name);
-
- if (QQmlData *ddata = QQmlData::get(d->object, /*create*/false)) {
- if (ddata->propertyCache) {
- ddata->propertyCache->release();
- ddata->propertyCache = nullptr;
- }
+ if (d->deferredPropertyNames) {
+ // Defer the creation of new properties. See setValues(QHash<QByteArray, QVariant>)
+ d->deferredPropertyNames->append(name);
+ return -1;
}
+ const int result = d->type->createProperty(name);
+ d->dropPropertyCache();
return result;
} else
return -1;
@@ -445,12 +463,12 @@ QVariant QQmlOpenMetaObject::initialValue(int)
int QQmlOpenMetaObject::count() const
{
- return d->type->d->names.count();
+ return d->type->d->names.size();
}
QByteArray QQmlOpenMetaObject::name(int idx) const
{
- Q_ASSERT(idx >= 0 && idx < d->type->d->names.count());
+ Q_ASSERT(idx >= 0 && idx < d->type->d->names.size());
return d->type->d->mob.property(idx).name();
}
diff --git a/src/qml/qml/qqmlopenmetaobject_p.h b/src/qml/qml/qqmlopenmetaobject_p.h
index 168a2a6f7f..35e595ec15 100644
--- a/src/qml/qml/qqmlopenmetaobject_p.h
+++ b/src/qml/qml/qqmlopenmetaobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLOPENMETAOBJECT_H
#define QQMLOPENMETAOBJECT_H
@@ -55,7 +19,6 @@
#include <QtCore/QObject>
#include <private/qqmlrefcount_p.h>
-#include <private/qqmlcleanup_p.h>
#include <private/qtqmlglobal_p.h>
#include <private/qobject_p.h>
@@ -65,11 +28,12 @@ QT_BEGIN_NAMESPACE
class QQmlEngine;
class QMetaPropertyBuilder;
class QQmlOpenMetaObjectTypePrivate;
-class Q_QML_PRIVATE_EXPORT QQmlOpenMetaObjectType : public QQmlRefCount, public QQmlCleanup
+class Q_QML_EXPORT QQmlOpenMetaObjectType final
+ : public QQmlRefCounted<QQmlOpenMetaObjectType>
{
public:
- QQmlOpenMetaObjectType(const QMetaObject *base, QQmlEngine *engine);
- ~QQmlOpenMetaObjectType() override;
+ QQmlOpenMetaObjectType(const QMetaObject *base);
+ ~QQmlOpenMetaObjectType();
void createProperties(const QVector<QByteArray> &names);
int createProperty(const QByteArray &name);
@@ -79,11 +43,9 @@ public:
int propertyCount() const;
QByteArray propertyName(int) const;
- QMetaObject *metaObject() const;
protected:
virtual void propertyCreated(int, QMetaPropertyBuilder &);
- void clear() override;
private:
QQmlOpenMetaObjectTypePrivate *d;
@@ -92,15 +54,16 @@ private:
};
class QQmlOpenMetaObjectPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlOpenMetaObject : public QAbstractDynamicMetaObject
+class Q_QML_EXPORT QQmlOpenMetaObject : public QAbstractDynamicMetaObject
{
public:
- QQmlOpenMetaObject(QObject *, const QMetaObject * = nullptr, bool = true);
- QQmlOpenMetaObject(QObject *, QQmlOpenMetaObjectType *, bool = true);
+ QQmlOpenMetaObject(QObject *, const QMetaObject * = nullptr);
+ QQmlOpenMetaObject(QObject *, const QQmlRefPointer<QQmlOpenMetaObjectType> &);
~QQmlOpenMetaObject() override;
QVariant value(const QByteArray &) const;
bool setValue(const QByteArray &, const QVariant &, bool force = false);
+ void setValues(const QHash<QByteArray, QVariant> &, bool force = false);
QVariant value(int) const;
void setValue(int, const QVariant &);
QVariant &valueRef(const QByteArray &);
@@ -116,9 +79,13 @@ public:
// longer automatically called for new properties.
void setCached(bool);
+ bool autoCreatesProperties() const;
+ void setAutoCreatesProperties(bool autoCreate);
+
QQmlOpenMetaObjectType *type() const;
void emitPropertyNotification(const QByteArray &propertyName);
+ void unparent();
protected:
int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override;
@@ -130,7 +97,9 @@ protected:
virtual void propertyWritten(int);
virtual void propertyCreated(int, QMetaPropertyBuilder &);
- QAbstractDynamicMetaObject *parent() const;
+ QDynamicMetaObjectData *parent() const;
+
+ bool checkedSetValue(int index, const QVariant &value, bool force);
private:
QQmlOpenMetaObjectPrivate *d;
diff --git a/src/qml/qml/qqmlparserstatus.cpp b/src/qml/qml/qqmlparserstatus.cpp
index b8f4bb8c19..522b829e68 100644
--- a/src/qml/qml/qqmlparserstatus.cpp
+++ b/src/qml/qml/qqmlparserstatus.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlparserstatus.h"
@@ -68,19 +32,7 @@ QT_BEGIN_NAMESPACE
To use QQmlParserStatus, you must inherit both a QObject-derived class
and QQmlParserStatus, and use the Q_INTERFACES() macro.
- \code
- class MyObject : public QObject, public QQmlParserStatus
- {
- Q_OBJECT
- Q_INTERFACES(QQmlParserStatus)
-
- public:
- MyObject(QObject *parent = 0);
- ...
- void classBegin();
- void componentComplete();
- }
- \endcode
+ \snippet code/src_qml_qqmlparserstatus.cpp 0
*/
/*! \internal */
diff --git a/src/qml/qml/qqmlparserstatus.h b/src/qml/qml/qqmlparserstatus.h
index f6bcb32a14..9cfb544358 100644
--- a/src/qml/qml/qqmlparserstatus.h
+++ b/src/qml/qml/qqmlparserstatus.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPARSERSTATUS_H
#define QQMLPARSERSTATUS_H
diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp
index 0acf20bbb4..dbd54b5f11 100644
--- a/src/qml/qml/qqmlplatform.cpp
+++ b/src/qml/qml/qqmlplatform.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlplatform_p.h"
#include "qqmlglobal_p.h"
@@ -66,14 +30,14 @@ QString QQmlPlatform::os()
return QStringLiteral("tvos");
#elif defined(Q_OS_MAC)
return QStringLiteral("osx");
-#elif defined(Q_OS_WINRT)
- return QStringLiteral("winrt");
#elif defined(Q_OS_WIN)
return QStringLiteral("windows");
#elif defined(Q_OS_LINUX)
return QStringLiteral("linux");
#elif defined(Q_OS_QNX)
return QStringLiteral("qnx");
+#elif defined(Q_OS_WASM)
+ return QStringLiteral("wasm");
#elif defined(Q_OS_UNIX)
return QStringLiteral("unix");
#else
diff --git a/src/qml/qml/qqmlplatform_p.h b/src/qml/qml/qqmlplatform_p.h
index af33dffca3..b8d2167fd5 100644
--- a/src/qml/qml/qqmlplatform_p.h
+++ b/src/qml/qml/qqmlplatform_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPLATFORM_P_H
#define QQMLPLATFORM_P_H
@@ -57,11 +21,13 @@
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlPlatform : public QObject
+class Q_QML_EXPORT QQmlPlatform : public QObject
{
Q_OBJECT
Q_PROPERTY(QString os READ os CONSTANT)
Q_PROPERTY(QString pluginName READ pluginName CONSTANT)
+ QML_ANONYMOUS
+ QML_ADDED_IN_VERSION(2, 0)
public:
explicit QQmlPlatform(QObject *parent = nullptr);
@@ -76,6 +42,4 @@ private:
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlPlatform)
-
#endif // QQMLPLATFORM_P_H
diff --git a/src/qml/qml/qqmlpluginimporter.cpp b/src/qml/qml/qqmlpluginimporter.cpp
new file mode 100644
index 0000000000..24f12891b9
--- /dev/null
+++ b/src/qml/qml/qqmlpluginimporter.cpp
@@ -0,0 +1,612 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmlpluginimporter_p.h"
+#include "qqmlimport_p.h"
+
+#include <private/qqmlextensionplugin_p.h>
+#include <private/qqmltypeloader_p.h>
+#include <private/qqmlglobal_p.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qpluginloader.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qjsonarray.h>
+
+#include <unordered_map>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcQmlImport)
+
+struct QmlPlugin {
+ std::unique_ptr<QPluginLoader> loader;
+};
+
+class PluginMap
+{
+ Q_DISABLE_COPY_MOVE(PluginMap)
+public:
+ PluginMap() = default;
+ ~PluginMap() = default;
+
+ // This is a std::unordered_map because QHash cannot handle move-only types.
+ using Container = std::unordered_map<QString, QmlPlugin>;
+
+private:
+ QBasicMutex mutex;
+ Container plugins;
+ friend class PluginMapPtr;
+};
+
+class PluginMapPtr
+{
+ Q_DISABLE_COPY_MOVE(PluginMapPtr)
+public:
+ PluginMapPtr(PluginMap *map) : map(map), locker(&map->mutex) {}
+ ~PluginMapPtr() = default;
+
+ PluginMap::Container &operator*() { return map->plugins; }
+ const PluginMap::Container &operator*() const { return map->plugins; }
+
+ PluginMap::Container *operator->() { return &map->plugins; }
+ const PluginMap::Container *operator->() const { return &map->plugins; }
+
+private:
+ PluginMap *map;
+ QMutexLocker<QBasicMutex> locker;
+};
+
+Q_GLOBAL_STATIC(PluginMap, qmlPluginsById); // stores the uri and the PluginLoaders
+
+static QVector<QStaticPlugin> makePlugins()
+{
+ QVector<QStaticPlugin> plugins;
+ // To avoid traversing all static plugins for all imports, we cut down
+ // the list the first time called to only contain QML plugins:
+ const auto staticPlugins = QPluginLoader::staticPlugins();
+ for (const QStaticPlugin &plugin : staticPlugins) {
+ const QString iid = plugin.metaData().value(QLatin1String("IID")).toString();
+ if (iid == QLatin1String(QQmlEngineExtensionInterface_iid)
+ || iid == QLatin1String(QQmlExtensionInterface_iid)
+ || iid == QLatin1String(QQmlExtensionInterface_iid_old)) {
+ if (Q_UNLIKELY(iid == QLatin1String(QQmlExtensionInterface_iid_old))) {
+ qWarning()
+ << "Found plugin with old IID, this will be unsupported in upcoming Qt releases:"
+ << plugin.metaData();
+ }
+ plugins.append(plugin);
+ }
+ }
+ return plugins;
+}
+
+/*
+ Returns the list of possible versioned URI combinations. For example, if \a uri is
+ QtQml.Models, \a vmaj is 2, and \a vmin is 0, this method returns the following:
+ [QtQml.Models.2.0, QtQml.2.0.Models, QtQml.Models.2, QtQml.2.Models, QtQml.Models]
+ */
+static QStringList versionUriList(const QString &uri, QTypeRevision version)
+{
+ QStringList result;
+ for (int mode = QQmlImports::FullyVersioned; mode <= QQmlImports::Unversioned; ++mode) {
+ int index = uri.size();
+ do {
+ QString versionUri = uri;
+ versionUri.insert(index, QQmlImports::versionString(
+ version, QQmlImports::ImportVersion(mode)));
+ result += versionUri;
+
+ index = uri.lastIndexOf(u'.', index - 1);
+ } while (index > 0 && mode != QQmlImports::Unversioned);
+ }
+ return result;
+}
+
+static bool unloadPlugin(const std::pair<const QString, QmlPlugin> &plugin)
+{
+ const auto &loader = plugin.second.loader;
+ if (!loader)
+ return false;
+
+#if QT_CONFIG(library)
+ if (auto extensionPlugin = qobject_cast<QQmlExtensionPlugin *>(loader->instance()))
+ extensionPlugin->unregisterTypes();
+
+# ifndef Q_OS_MACOS
+ if (!loader->unload()) {
+ qWarning("Unloading %s failed: %s", qPrintable(plugin.first),
+ qPrintable(loader->errorString()));
+ return false;
+ }
+# endif
+#endif
+
+ return true;
+}
+
+void qmlClearEnginePlugins()
+{
+ PluginMapPtr plugins(qmlPluginsById());
+ for (const auto &plugin : std::as_const(*plugins))
+ unloadPlugin(plugin);
+ plugins->clear();
+}
+
+bool QQmlPluginImporter::removePlugin(const QString &pluginId)
+{
+ PluginMapPtr plugins(qmlPluginsById());
+
+ auto it = plugins->find(pluginId);
+ if (it == plugins->end())
+ return false;
+
+ const bool success = unloadPlugin(*it);
+
+ plugins->erase(it);
+ return success;
+}
+
+QStringList QQmlPluginImporter::plugins()
+{
+ PluginMapPtr plugins(qmlPluginsById());
+ QStringList results;
+ for (auto it = plugins->cbegin(), end = plugins->cend(); it != end; ++it) {
+ if (it->second.loader != nullptr)
+ results.append(it->first);
+ }
+ return results;
+}
+
+QString QQmlPluginImporter::truncateToDirectory(const QString &qmldirFilePath)
+{
+ const int slash = qmldirFilePath.lastIndexOf(u'/');
+ return slash > 0 ? qmldirFilePath.left(slash) : qmldirFilePath;
+}
+
+void QQmlPluginImporter::finalizePlugin(QObject *instance, const QString &pluginId) {
+ // The plugin's per-engine initialization does not need lock protection, as this function is
+ // only called from the engine specific loader thread and importDynamicPlugin as well as
+ // importStaticPlugin are the only places of access.
+
+ database->initializedPlugins.insert(pluginId);
+ if (auto *extensionIface = qobject_cast<QQmlExtensionInterface *>(instance))
+ typeLoader->initializeEngine(extensionIface, uri.toUtf8().constData());
+ else if (auto *engineIface = qobject_cast<QQmlEngineExtensionInterface *>(instance))
+ typeLoader->initializeEngine(engineIface, uri.toUtf8().constData());
+}
+
+QTypeRevision QQmlPluginImporter::importStaticPlugin(QObject *instance, const QString &pluginId) {
+ // Dynamic plugins are differentiated by their filepath. For static plugins we
+ // don't have that information so we use their address as key instead.
+ QTypeRevision importVersion = version;
+ {
+ PluginMapPtr plugins(qmlPluginsById());
+
+ // Plugin types are global across all engines and should only be
+ // registered once. But each engine still needs to be initialized.
+ bool typesRegistered = plugins->find(pluginId) != plugins->end();
+
+ if (!typesRegistered) {
+ plugins->insert(std::make_pair(pluginId, QmlPlugin()));
+ if (QQmlMetaType::registerPluginTypes(
+ instance, QFileInfo(qmldirPath).absoluteFilePath(), uri,
+ qmldir->typeNamespace(), importVersion, errors)
+ == QQmlMetaType::RegistrationResult::Failure) {
+ return QTypeRevision();
+ }
+
+ importVersion = QQmlImportDatabase::lockModule(
+ uri, qmldir->typeNamespace(), importVersion, errors);
+ if (!importVersion.isValid())
+ return QTypeRevision();
+ }
+
+ // Release the lock on plugins early as we're done with the global part. Releasing the lock
+ // also allows other QML loader threads to acquire the lock while this thread is blocking
+ // in the initializeEngine call to the gui thread (which in turn may be busy waiting for
+ // other QML loader threads and thus not process the initializeEngine call).
+ }
+
+ if (!database->initializedPlugins.contains(pluginId))
+ finalizePlugin(instance, pluginId);
+
+ return QQmlImports::validVersion(importVersion);
+}
+
+QTypeRevision QQmlPluginImporter::importDynamicPlugin(
+ const QString &filePath, const QString &pluginId, bool optional)
+{
+ QObject *instance = nullptr;
+ QTypeRevision importVersion = version;
+
+ const bool engineInitialized = database->initializedPlugins.contains(pluginId);
+ {
+ PluginMapPtr plugins(qmlPluginsById());
+ bool typesRegistered = plugins->find(pluginId) != plugins->end();
+
+ if (!engineInitialized || !typesRegistered) {
+ const QFileInfo fileInfo(filePath);
+ if (!typesRegistered && optional) {
+ switch (QQmlMetaType::registerPluginTypes(
+ nullptr, fileInfo.absolutePath(), uri, qmldir->typeNamespace(),
+ importVersion, errors)) {
+ case QQmlMetaType::RegistrationResult::NoRegistrationFunction:
+ // try again with plugin
+ break;
+ case QQmlMetaType::RegistrationResult::Success:
+ importVersion = QQmlImportDatabase::lockModule(
+ uri, qmldir->typeNamespace(), importVersion, errors);
+ if (!importVersion.isValid())
+ return QTypeRevision();
+ // instance and loader intentionally left at nullptr
+ plugins->insert(std::make_pair(pluginId, QmlPlugin()));
+ // Not calling initializeEngine with null instance
+ database->initializedPlugins.insert(pluginId);
+ return importVersion;
+ case QQmlMetaType::RegistrationResult::Failure:
+ return QTypeRevision();
+ }
+ }
+
+#if QT_CONFIG(library)
+ if (!typesRegistered) {
+
+ // Check original filePath. If that one is empty, not being able
+ // to load the plugin is not an error. We were just checking if
+ // the types are already available. absoluteFilePath can still be
+ // empty if filePath is not.
+ if (filePath.isEmpty())
+ return QTypeRevision();
+
+ const QString absoluteFilePath = fileInfo.absoluteFilePath();
+ if (!QQml_isFileCaseCorrect(absoluteFilePath)) {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(
+ QQmlImportDatabase::tr("File name case mismatch for \"%1\"")
+ .arg(absoluteFilePath));
+ errors->prepend(error);
+ }
+ return QTypeRevision();
+ }
+
+ QmlPlugin plugin;
+ plugin.loader = std::make_unique<QPluginLoader>(absoluteFilePath);
+ if (!plugin.loader->load()) {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(plugin.loader->errorString());
+ errors->prepend(error);
+ }
+ return QTypeRevision();
+ }
+
+ instance = plugin.loader->instance();
+ plugins->insert(std::make_pair(pluginId, std::move(plugin)));
+
+ // Continue with shared code path for dynamic and static plugins:
+ if (QQmlMetaType::registerPluginTypes(
+ instance, fileInfo.absolutePath(), uri, qmldir->typeNamespace(),
+ importVersion, errors)
+ == QQmlMetaType::RegistrationResult::Failure) {
+ return QTypeRevision();
+ }
+
+ importVersion = QQmlImportDatabase::lockModule(
+ uri, qmldir->typeNamespace(), importVersion, errors);
+ if (!importVersion.isValid())
+ return QTypeRevision();
+ } else {
+ auto it = plugins->find(pluginId);
+ if (it != plugins->end() && it->second.loader)
+ instance = it->second.loader->instance();
+ }
+#else
+ // Here plugin is not optional and NOT QT_CONFIG(library)
+ // Cannot finalize such plugin and return valid, because no types are registered.
+ // Just return invalid.
+ if (!optional)
+ return QTypeRevision();
+#endif // QT_CONFIG(library)
+ }
+
+ // Release the lock on plugins early as we're done with the global part. Releasing the lock
+ // also allows other QML loader threads to acquire the lock while this thread is blocking
+ // in the initializeEngine call to the gui thread (which in turn may be busy waiting for
+ // other QML loader threads and thus not process the initializeEngine call).
+ }
+
+ if (!engineInitialized)
+ finalizePlugin(instance, pluginId);
+
+ return QQmlImports::validVersion(importVersion);
+}
+
+/*!
+ \internal
+
+ Searches for a plugin called \a baseName in \a qmldirPluginPath, taking the
+ path of the qmldir file itself, and the plugin paths of the QQmlImportDatabase
+ into account.
+
+ The baseName is amended with a platform-dependent prefix and suffix to
+ construct the final plugin file name:
+
+ \table
+ \header \li Platform \li Prefix \li Valid suffixes
+ \row \li Windows \li \li \c .dll, \c .d.dll
+ \row \li Unix/Linux \li lib \li \c .so
+ \row \li \macos \li lib \li \c .dylib, \c _debug.dylib \c .bundle, \c .so
+ \row \li Android \li lib \li \c .so, \c _<ABI>.so
+ \endtable
+
+ If the \a qmldirPluginPath is absolute, it is searched first. Then each of the
+ filePluginPath entries in the QQmlImportDatabase is checked in turn. If the
+ entry is relative, it is resolved on top of the path of the qmldir file,
+ otherwise it is taken verbatim. If a "." is found in the filePluginPath, and
+ \a qmldirPluginPath is relative, then \a qmldirPluginPath is used in its
+ place.
+
+ TODO: Document the android special casing.
+
+ TODO: The above paragraph, as well as the code implementing it makes very
+ little sense and is mostly here for backwards compatibility.
+ */
+QString QQmlPluginImporter::resolvePlugin(const QString &qmldirPluginPath, const QString &baseName)
+{
+#if defined(Q_OS_WIN)
+ static const QString prefix;
+ static const QStringList suffixes = {
+ # ifdef QT_DEBUG
+ QLatin1String("d.dll"), // try a qmake-style debug build first
+ QLatin1String(".dll")
+ #else
+ QLatin1String(".dll"),
+ QLatin1String("d.dll") // try a qmake-style debug build after
+ # endif
+ };
+#elif defined(Q_OS_DARWIN)
+ static const QString prefix = QLatin1String("lib");
+ static const QStringList suffixes = {
+ # ifdef QT_DEBUG
+ QLatin1String("_debug.dylib"), // try a qmake-style debug build first
+ QLatin1String(".dylib"),
+ # else
+ QLatin1String(".dylib"),
+ QLatin1String("_debug.dylib"), // try a qmake-style debug build after
+ # endif
+ QLatin1String(".so"),
+ QLatin1String(".bundle")
+ };
+#else // Unix
+ static const QString prefix = QLatin1String("lib");
+ static const QStringList suffixes = {
+ # if defined(Q_OS_ANDROID)
+ QStringLiteral(LIBS_SUFFIX),
+ # endif
+ QLatin1String(".so")
+ };
+#endif
+
+ QStringList searchPaths = database->filePluginPath;
+ bool qmldirPluginPathIsRelative = QDir::isRelativePath(qmldirPluginPath);
+ if (!qmldirPluginPathIsRelative)
+ searchPaths.prepend(qmldirPluginPath);
+
+ for (const QString &pluginPath : std::as_const(searchPaths)) {
+ QString resolvedBasePath;
+ if (pluginPath == QLatin1String(".")) {
+ if (qmldirPluginPathIsRelative && !qmldirPluginPath.isEmpty()
+ && qmldirPluginPath != QLatin1String(".")) {
+ resolvedBasePath = QDir::cleanPath(qmldirPath + u'/' + qmldirPluginPath);
+ } else {
+ resolvedBasePath = qmldirPath;
+ }
+ } else {
+ if (QDir::isRelativePath(pluginPath))
+ resolvedBasePath = QDir::cleanPath(qmldirPath + u'/' + pluginPath);
+ else
+ resolvedBasePath = pluginPath;
+ }
+
+ // hack for resources, should probably go away
+ if (resolvedBasePath.startsWith(u':'))
+ resolvedBasePath = QCoreApplication::applicationDirPath();
+
+ if (!resolvedBasePath.endsWith(u'/'))
+ resolvedBasePath += u'/';
+
+ QString resolvedPath = resolvedBasePath + prefix + baseName;
+ for (const QString &suffix : suffixes) {
+ QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + suffix);
+ if (!absolutePath.isEmpty())
+ return absolutePath;
+ }
+
+#if defined(Q_OS_ANDROID)
+ if (qmldirPath.size() > 25 && qmldirPath.at(0) == QLatin1Char(':')
+ && qmldirPath.at(1) == QLatin1Char('/')
+ && qmldirPath.startsWith(QStringLiteral(":/android_rcc_bundle/qml/"),
+ Qt::CaseInsensitive)) {
+ QString pluginName = qmldirPath.mid(21) + u'/' + baseName;
+ pluginName.replace(QLatin1Char('/'), QLatin1Char('_'));
+ QString bundledPath = resolvedBasePath + QLatin1String("lib") + pluginName;
+ for (const QString &suffix : suffixes) {
+ const QString absolutePath = typeLoader->absoluteFilePath(bundledPath + suffix);
+ if (!absolutePath.isEmpty()) {
+ qWarning("The implicit resolving of Qml plugin locations using the URI "
+ "embedded in the filename has been deprecated. Please use the "
+ "modern CMake API to create QML modules or set the name of "
+ "QML plugin in qmldir file, that matches the name of plugin "
+ "on file system. The correct plugin name is '%s'.",
+ qPrintable(pluginName));
+ return absolutePath;
+ }
+ }
+ }
+#endif
+ }
+
+ qCDebug(lcQmlImport) << "resolvePlugin" << "Could not resolve dynamic plugin with base name"
+ << baseName << "in" << qmldirPath
+ << " file does not exist";
+
+ return QString();
+}
+
+/*
+ Get all static plugins that are QML plugins and has a meta data URI that matches with one of
+ \a versionUris, which is a list of all possible versioned URI combinations - see versionUriList()
+ above.
+ */
+bool QQmlPluginImporter::populatePluginDataVector(QVector<StaticPluginData> &result, const QStringList &versionUris)
+{
+ static const QVector<QStaticPlugin> plugins = makePlugins();
+ for (const QStaticPlugin &plugin : plugins) {
+ // Since a module can list more than one plugin,
+ // we keep iterating even after we found a match.
+ QObject *instance = plugin.instance();
+ if (qobject_cast<QQmlEngineExtensionPlugin *>(instance)
+ || qobject_cast<QQmlExtensionPlugin *>(instance)) {
+ const QJsonArray metaTagsUriList = plugin.metaData().value(
+ QStringLiteral("uri")).toArray();
+ if (metaTagsUriList.isEmpty()) {
+ if (errors) {
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr(
+ "static plugin for module \"%1\" with name \"%2\" "
+ "has no metadata URI")
+ .arg(uri, QString::fromUtf8(
+ instance->metaObject()->className())));
+ error.setUrl(QUrl::fromLocalFile(qmldir->qmldirLocation()));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ // A plugin can be set up to handle multiple URIs, so go through the list:
+ for (const QJsonValueConstRef metaTagUri : metaTagsUriList) {
+ if (versionUris.contains(metaTagUri.toString())) {
+ result.append({ plugin, metaTagsUriList });
+ break;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+QTypeRevision QQmlPluginImporter::importPlugins() {
+ const auto qmldirPlugins = qmldir->plugins();
+ const int qmldirPluginCount = qmldirPlugins.size();
+ QTypeRevision importVersion = version;
+
+ // If the path contains a version marker or if we have more than one plugin,
+ // we need to use paths. In that case we cannot fall back to other instances
+ // of the same module if a qmldir is rejected. However, as we don't generate
+ // such modules, it shouldn't be a problem.
+ const bool canUseUris = qmldirPluginCount == 1
+ && qmldirPath.endsWith(u'/' + QString(uri).replace(u'.', u'/'));
+ const QString moduleId = canUseUris ? uri : qmldir->qmldirLocation();
+
+ if (!database->modulesForWhichPluginsHaveBeenLoaded.contains(moduleId)) {
+ // First search for listed qmldir plugins dynamically. If we cannot resolve them all, we
+ // continue searching static plugins that has correct metadata uri. Note that since we
+ // only know the uri for a static plugin, and not the filename, we cannot know which
+ // static plugin belongs to which listed plugin inside qmldir. And for this reason,
+ // mixing dynamic and static plugins inside a single module is not recommended.
+
+ int dynamicPluginsFound = 0;
+ int staticPluginsFound = 0;
+
+ for (const QQmlDirParser::Plugin &plugin : qmldirPlugins) {
+ const QString resolvedFilePath = resolvePlugin(plugin.path, plugin.name);
+
+ if (!canUseUris && resolvedFilePath.isEmpty())
+ continue;
+
+ importVersion = importDynamicPlugin(
+ resolvedFilePath,
+ canUseUris ? uri : QFileInfo(resolvedFilePath).absoluteFilePath(),
+ plugin.optional);
+ if (importVersion.isValid())
+ ++dynamicPluginsFound;
+ else if (!resolvedFilePath.isEmpty())
+ return QTypeRevision();
+ }
+
+ if (dynamicPluginsFound < qmldirPluginCount) {
+ // Check if the missing plugins can be resolved statically. We do this by looking at
+ // the URIs embedded in a plugins meta data. Since those URIs can be anything from
+ // fully versioned to unversioned, we need to compare with differnt version strings.
+ // If a module has several plugins, they must all have the same version. Start by
+ // populating pluginPairs with relevant plugins to cut the list short early on:
+ const QStringList versionUris = versionUriList(uri, importVersion);
+ QVector<StaticPluginData> pluginPairs;
+ if (!populatePluginDataVector(pluginPairs, versionUris))
+ return QTypeRevision();
+
+ for (const QString &versionUri : versionUris) {
+ for (const StaticPluginData &pair : std::as_const(pluginPairs)) {
+ for (const QJsonValueConstRef metaTagUri : pair.uriList) {
+ if (versionUri == metaTagUri.toString()) {
+ staticPluginsFound++;
+ QObject *instance = pair.plugin.instance();
+ importVersion = importStaticPlugin(
+ instance,
+ canUseUris ? uri : QString::asprintf("%p", instance));
+ if (!importVersion.isValid()){
+ if (errors) {
+ Q_ASSERT(!errors->isEmpty());
+ const QQmlError poppedError = errors->takeFirst();
+ QQmlError error;
+ error.setDescription(
+ QQmlImportDatabase::tr(
+ "static plugin for module \"%1\" with "
+ "name \"%2\" cannot be loaded: %3")
+ .arg(uri, QString::fromUtf8(
+ instance->metaObject()->className()),
+ poppedError.description()));
+ error.setUrl(QUrl::fromLocalFile(qmldir->qmldirLocation()));
+ errors->prepend(error);
+ }
+ return QTypeRevision();
+ }
+
+ qCDebug(lcQmlImport)
+ << "importExtension" << "loaded static plugin " << versionUri;
+
+ break;
+ }
+ }
+ }
+ if (staticPluginsFound > 0)
+ break;
+ }
+ }
+
+ if ((dynamicPluginsFound + staticPluginsFound) < qmldirPluginCount) {
+ if (errors) {
+ QQmlError error;
+ if (qmldirPluginCount > 1 && staticPluginsFound > 0) {
+ error.setDescription(QQmlImportDatabase::tr(
+ "could not resolve all plugins for module \"%1\"")
+ .arg(uri));
+ } else {
+ error.setDescription(QQmlImportDatabase::tr(
+ "module \"%1\" plugin \"%2\" not found")
+ .arg(uri, qmldirPlugins[dynamicPluginsFound].name));
+ }
+ error.setUrl(QUrl::fromLocalFile(qmldir->qmldirLocation()));
+ errors->prepend(error);
+ }
+ return QTypeRevision();
+ }
+
+ database->modulesForWhichPluginsHaveBeenLoaded.insert(moduleId);
+ }
+ return QQmlImports::validVersion(importVersion);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpluginimporter_p.h b/src/qml/qml/qqmlpluginimporter_p.h
new file mode 100644
index 0000000000..b0056e8e33
--- /dev/null
+++ b/src/qml/qml/qqmlpluginimporter_p.h
@@ -0,0 +1,81 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLPLUGINIMPORTER_P_H
+#define QQMLPLUGINIMPORTER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtqmlglobal_p.h>
+#include <private/qqmlimport_p.h>
+#include <private/qqmltypeloaderqmldircontent_p.h>
+
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qplugin.h>
+#include <QtCore/qversionnumber.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlPluginImporter
+{
+ Q_DISABLE_COPY_MOVE(QQmlPluginImporter)
+
+public:
+ QQmlPluginImporter(const QString &uri, QTypeRevision version, QQmlImportDatabase *database,
+ const QQmlTypeLoaderQmldirContent *qmldir, QQmlTypeLoader *typeLoader,
+ QList<QQmlError> *errors)
+ : uri(uri)
+ , qmldirPath(truncateToDirectory(qmldir->qmldirLocation()))
+ , qmldir(qmldir)
+ , database(database)
+ , typeLoader(typeLoader)
+ , errors(errors)
+ , version(version)
+ {}
+
+ ~QQmlPluginImporter() = default;
+
+ QTypeRevision importDynamicPlugin(
+ const QString &filePath, const QString &pluginId, bool optional);
+ QTypeRevision importStaticPlugin(QObject *instance, const QString &pluginId);
+ QTypeRevision importPlugins();
+
+ static bool removePlugin(const QString &pluginId);
+ static QStringList plugins();
+
+private:
+ struct StaticPluginData {
+ QStaticPlugin plugin;
+ QJsonArray uriList;
+ };
+
+ static QString truncateToDirectory(const QString &qmldirFilePath);
+ bool populatePluginDataVector(QVector<StaticPluginData> &result,
+ const QStringList &versionUris);
+
+ QString resolvePlugin(const QString &qmldirPluginPath, const QString &baseName);
+ void finalizePlugin(QObject *instance, const QString &path);
+
+ const QString uri;
+ const QString qmldirPath;
+
+ const QQmlTypeLoaderQmldirContent *qmldir = nullptr;
+ QQmlImportDatabase *database = nullptr;
+ QQmlTypeLoader *typeLoader = nullptr;
+ QList<QQmlError> *errors = nullptr;
+
+ const QTypeRevision version;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLPLUGINIMPORTER_P_H
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index 9504fc37dc..92c9765509 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPRIVATE_H
#define QQMLPRIVATE_H
@@ -51,39 +15,32 @@
// We mean it.
//
-#include <functional>
-#include <type_traits>
-
-#include <QtQml/qtqmlglobal.h>
-#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qjsprimitivevalue.h>
+#include <QtQml/qjsvalue.h>
#include <QtQml/qqmllist.h>
+#include <QtQml/qqmlparserstatus.h>
#include <QtQml/qqmlpropertyvaluesource.h>
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qdebug.h>
#include <QtCore/qglobal.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qurl.h>
-#include <QtCore/qpointer.h>
-
+#include <QtCore/qmetacontainer.h>
#include <QtCore/qmetaobject.h>
-#include <QtCore/qdebug.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qversionnumber.h>
-#define QML_GETTYPENAMES \
- const char *className = T::staticMetaObject.className(); \
- const int nameLen = int(strlen(className)); \
- QVarLengthArray<char,48> pointerName(nameLen+2); \
- memcpy(pointerName.data(), className, size_t(nameLen)); \
- pointerName[nameLen] = '*'; \
- pointerName[nameLen+1] = '\0'; \
- const int listLen = int(strlen("QQmlListProperty<")); \
- QVarLengthArray<char,64> listName(listLen + nameLen + 2); \
- memcpy(listName.data(), "QQmlListProperty<", size_t(listLen)); \
- memcpy(listName.data()+listLen, className, size_t(nameLen)); \
- listName[listLen+nameLen] = '>'; \
- listName[listLen+nameLen+1] = '\0';
+#include <functional>
+#include <limits>
+#include <type_traits>
QT_BEGIN_NAMESPACE
class QQmlPropertyValueInterceptor;
+class QQmlContextData;
+class QQmlFinalizerHook;
namespace QQmlPrivate {
struct CachedQmlUnit;
@@ -93,9 +50,9 @@ using QQmlAttachedPropertiesFunc = A *(*)(QObject *);
namespace QV4 {
struct ExecutionEngine;
+class ExecutableCompilationUnit;
namespace CompiledData {
struct Unit;
-struct CompilationUnit;
}
}
namespace QmlIR {
@@ -105,7 +62,7 @@ typedef void (*IRLoaderFunction)(Document *, const QQmlPrivate::CachedQmlUnit *)
using QQmlAttachedPropertiesFunc = QQmlPrivate::QQmlAttachedPropertiesFunc<QObject>;
-inline uint qHash(QQmlAttachedPropertiesFunc func, uint seed = 0)
+inline size_t qHash(QQmlAttachedPropertiesFunc func, size_t seed = 0)
{
return qHash(quintptr(func), seed);
}
@@ -120,10 +77,14 @@ public:
};
-class QJSValue;
class QJSEngine;
class QQmlEngine;
class QQmlCustomParser;
+class QQmlTypeNotAvailable;
+
+class QQmlV4Function;
+using QQmlV4FunctionPtr = QQmlV4Function *;
+using QQmlV4ExecutionEnginePtr = QV4::ExecutionEngine *;
template<class T>
QQmlCustomParser *qmlCreateCustomParser()
@@ -149,67 +110,202 @@ namespace QQmlPrivate
// the size that was allocated.
::operator delete (ptr);
}
+#ifdef Q_CC_MSVC
static void operator delete(void *, void *) {
// Deliberately empty placement delete operator.
// Silences MSVC warning C4291: no matching operator delete found
+ // On MinGW it causes -Wmismatched-new-delete, though.
}
+#endif
};
- template<typename T>
- constexpr bool isConstructible()
+ enum class SingletonConstructionMode
{
- return std::is_default_constructible<T>::value && std::is_base_of<QObject, T>::value;
+ None,
+ Constructor,
+ Factory,
+ FactoryWrapper
+ };
+
+ template<typename T, typename WrapperT = T, typename = std::void_t<>>
+ struct HasSingletonFactory
+ {
+ static constexpr bool value = false;
+ };
+
+ template<typename T, typename WrapperT>
+ struct HasSingletonFactory<T, WrapperT, std::void_t<decltype(WrapperT::create(
+ static_cast<QQmlEngine *>(nullptr),
+ static_cast<QJSEngine *>(nullptr)))>>
+ {
+ static constexpr bool value = std::is_same_v<
+ decltype(WrapperT::create(static_cast<QQmlEngine *>(nullptr),
+ static_cast<QJSEngine *>(nullptr))), T *>;
+ };
+
+ template<typename T, typename WrapperT>
+ constexpr SingletonConstructionMode singletonConstructionMode()
+ {
+ if constexpr (!std::is_base_of<QObject, T>::value)
+ return SingletonConstructionMode::None;
+ if constexpr (!std::is_same_v<T, WrapperT> && HasSingletonFactory<T, WrapperT>::value)
+ return SingletonConstructionMode::FactoryWrapper;
+ if constexpr (std::is_default_constructible<T>::value)
+ return SingletonConstructionMode::Constructor;
+ if constexpr (HasSingletonFactory<T>::value)
+ return SingletonConstructionMode::Factory;
+
+ return SingletonConstructionMode::None;
}
- template<typename T>
- void createInto(void *memory) { new (memory) QQmlElement<T>; }
+ template<typename>
+ struct QmlMarkerFunction;
+
+ template<typename Ret, typename Class>
+ struct QmlMarkerFunction<Ret (Class::*)()>
+ {
+ using ClassType = Class;
+ };
+
+ template<typename T, typename Marker>
+ using QmlTypeHasMarker = std::is_same<T, typename QmlMarkerFunction<Marker>::ClassType>;
template<typename T>
- QObject *createSingletonInstance(QQmlEngine *, QJSEngine *) { return new T; }
+ void createInto(void *memory, void *) { new (memory) QQmlElement<T>; }
+
+ template<typename T, typename WrapperT, SingletonConstructionMode Mode>
+ QObject *createSingletonInstance(QQmlEngine *q, QJSEngine *j)
+ {
+ Q_UNUSED(q);
+ Q_UNUSED(j);
+ if constexpr (Mode == SingletonConstructionMode::Constructor)
+ return new T;
+ else if constexpr (Mode == SingletonConstructionMode::Factory)
+ return T::create(q, j);
+ else if constexpr (Mode == SingletonConstructionMode::FactoryWrapper)
+ return WrapperT::create(q, j);
+ else
+ return nullptr;
+ }
template<typename T>
QObject *createParent(QObject *p) { return new T(p); }
- using CreateIntoFunction = void (*)(void *);
+ using CreateIntoFunction = void (*)(void *, void *);
using CreateSingletonFunction = QObject *(*)(QQmlEngine *, QJSEngine *);
using CreateParentFunction = QObject *(*)(QObject *);
+ using CreateValueTypeFunction = QVariant (*)(const QJSValue &);
- template<typename T, bool Constructible = isConstructible<T>()>
+ template<typename T, typename WrapperT = T,
+ SingletonConstructionMode Mode = singletonConstructionMode<T, WrapperT>()>
struct Constructors;
- template<typename T>
- struct Constructors<T, true>
+ template<typename T, typename WrapperT>
+ struct Constructors<T, WrapperT, SingletonConstructionMode::Constructor>
{
static constexpr CreateIntoFunction createInto
= QQmlPrivate::createInto<T>;
static constexpr CreateSingletonFunction createSingletonInstance
- = QQmlPrivate::createSingletonInstance<T>;
+ = QQmlPrivate::createSingletonInstance<
+ T, WrapperT, SingletonConstructionMode::Constructor>;
};
- template<typename T>
- struct Constructors<T, false>
+ template<typename T, typename WrapperT>
+ struct Constructors<T, WrapperT, SingletonConstructionMode::None>
{
static constexpr CreateIntoFunction createInto = nullptr;
static constexpr CreateSingletonFunction createSingletonInstance = nullptr;
};
- template<typename T, bool IsVoid = std::is_void<T>::value>
+ template<typename T, typename WrapperT>
+ struct Constructors<T, WrapperT, SingletonConstructionMode::Factory>
+ {
+ static constexpr CreateIntoFunction createInto = nullptr;
+ static constexpr CreateSingletonFunction createSingletonInstance
+ = QQmlPrivate::createSingletonInstance<
+ T, WrapperT, SingletonConstructionMode::Factory>;
+ };
+
+ template<typename T, typename WrapperT>
+ struct Constructors<T, WrapperT, SingletonConstructionMode::FactoryWrapper>
+ {
+ static constexpr CreateIntoFunction createInto = nullptr;
+ static constexpr CreateSingletonFunction createSingletonInstance
+ = QQmlPrivate::createSingletonInstance<
+ T, WrapperT, SingletonConstructionMode::FactoryWrapper>;
+ };
+
+ template<typename T,
+ bool IsObject = std::is_base_of<QObject, T>::value,
+ bool IsGadget = QtPrivate::IsGadgetHelper<T>::IsRealGadget>
struct ExtendedType;
- // void means "not an extended type"
template<typename T>
- struct ExtendedType<T, true>
+ struct ExtendedType<T, false, false>
{
static constexpr const CreateParentFunction createParent = nullptr;
- static constexpr const QMetaObject *staticMetaObject = nullptr;
+ static const QMetaObject *staticMetaObject() { return nullptr; }
};
- // If it's not void, we actually want an error if the ctor or the metaobject is missing.
+ // If it's a QObject, we actually want an error if the ctor or the metaobject is missing.
template<typename T>
- struct ExtendedType<T, false>
+ struct ExtendedType<T, true, false>
{
static constexpr const CreateParentFunction createParent = QQmlPrivate::createParent<T>;
- static constexpr const QMetaObject *staticMetaObject = &T::staticMetaObject;
+ static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; }
+ };
+
+ // If it's a Q_GADGET, we don't want the ctor.
+ template<typename T>
+ struct ExtendedType<T, false, true>
+ {
+ static constexpr const CreateParentFunction createParent = nullptr;
+ static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; }
+ };
+
+ template<typename F, typename Result = void>
+ struct ValueTypeFactory
+ {
+ static constexpr const Result (*create)(const QJSValue &) = nullptr;
+ };
+
+ template<typename F>
+ struct ValueTypeFactory<F, std::void_t<decltype(F::create(QJSValue()))>>
+ {
+ static decltype(F::create(QJSValue())) create(const QJSValue &params)
+ {
+ return F::create(params);
+ }
+ };
+
+ template<typename T, typename F,
+ bool HasCtor = std::is_constructible_v<T, QJSValue>,
+ bool HasFactory = std::is_constructible_v<
+ QVariant, decltype(ValueTypeFactory<F>::create(QJSValue()))>>
+ struct ValueType;
+
+ template<typename T, typename F>
+ struct ValueType<T, F, false, false>
+ {
+ static constexpr const CreateValueTypeFunction create = nullptr;
+ };
+
+ template<typename T, typename F, bool HasCtor>
+ struct ValueType<T, F, HasCtor, true>
+ {
+ static QVariant create(const QJSValue &params)
+ {
+ return F::create(params);
+ }
+ };
+
+ template<typename T, typename F>
+ struct ValueType<T, F, true, false>
+ {
+ static QVariant create(const QJSValue &params)
+ {
+ return QVariant::fromValue(T(params));
+ }
};
template<class From, class To, int N>
@@ -239,9 +335,6 @@ namespace QQmlPrivate
}
};
- template<typename...>
- using QmlVoidT = void;
-
// You can prevent subclasses from using the same attached type by specialzing this.
// This is reserved for internal types, though.
template<class T, class A>
@@ -250,7 +343,7 @@ namespace QQmlPrivate
using Type = A;
};
- template<class T, class = QmlVoidT<>, bool OldStyle = QQmlTypeInfo<T>::hasAttachedProperties>
+ template<class T, class = std::void_t<>, bool OldStyle = QQmlTypeInfo<T>::hasAttachedProperties>
struct QmlAttached
{
using Type = void;
@@ -261,7 +354,7 @@ namespace QQmlPrivate
// Defined inline via QML_ATTACHED
template<class T>
- struct QmlAttached<T, QmlVoidT<typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type>, false>
+ struct QmlAttached<T, std::void_t<typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type>, false>
{
// Normal attached properties
template <typename Parent, typename Attached>
@@ -277,11 +370,13 @@ namespace QQmlPrivate
struct Properties<Parent, void>
{
using Func = QQmlAttachedPropertiesFunc<QObject>;
- static const QMetaObject *staticMetaObject() { return nullptr; };
- static Func attachedPropertiesFunc() { return nullptr; };
+ static const QMetaObject *staticMetaObject() { return nullptr; }
+ static Func attachedPropertiesFunc() { return nullptr; }
};
- using Type = typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type;
+ using Type = typename std::conditional<
+ QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_attached)>::value,
+ typename OverridableAttachedType<T, typename T::QmlAttachedType>::Type, void>::type;
using Func = typename Properties<T, Type>::Func;
static const QMetaObject *staticMetaObject()
@@ -297,7 +392,7 @@ namespace QQmlPrivate
// Separately defined via QQmlTypeInfo
template<class T>
- struct QmlAttached<T, QmlVoidT<decltype(T::qmlAttachedProperties)>, true>
+ struct QmlAttached<T, std::void_t<decltype(T::qmlAttachedProperties)>, true>
{
using Type = typename std::remove_pointer<decltype(T::qmlAttachedProperties(nullptr))>::type;
using Func = QQmlAttachedPropertiesFunc<Type>;
@@ -341,18 +436,33 @@ namespace QQmlPrivate
enum AutoParentResult { Parented, IncompatibleObject, IncompatibleParent };
typedef AutoParentResult (*AutoParentFunction)(QObject *object, QObject *parent);
+ enum class ValueTypeCreationMethod { None, Construct, Structured };
+
struct RegisterType {
- int version;
+ enum StructVersion: int {
+ Base = 0,
+ FinalizerCast = 1,
+ CreationMethod = 2,
+ CurrentVersion = CreationMethod,
+ };
+
+ bool has(StructVersion v) const { return structVersion >= int(v); }
- int typeId;
- int listId;
+ int structVersion;
+
+ QMetaType typeId;
+ QMetaType listId;
int objectSize;
- void (*create)(void *);
+ // The second parameter of create is for userdata
+ void (*create)(void *, void *);
+ void *userdata;
QString noCreationReason;
+ // ### Qt7: Get rid of this. It can be covered by creationMethod below.
+ QVariant (*createValueType)(const QJSValue &);
+
const char *uri;
- int versionMajor;
- int versionMinor;
+ QTypeRevision version;
const char *elementName;
const QMetaObject *metaObject;
@@ -368,20 +478,26 @@ namespace QQmlPrivate
QQmlCustomParser *customParser;
- int revision;
+ QTypeRevision revision;
+ int finalizerCast;
+
+ ValueTypeCreationMethod creationMethod;
// If this is extended ensure "version" is bumped!!!
};
struct RegisterTypeAndRevisions {
- int version;
+ int structVersion;
- int typeId;
- int listId;
+ QMetaType typeId;
+ QMetaType listId;
int objectSize;
- void (*create)(void *);
+ void (*create)(void *, void *);
+ void *userdata;
+
+ QVariant (*createValueType)(const QJSValue &);
const char *uri;
- int versionMajor;
+ QTypeRevision version;
const QMetaObject *metaObject;
const QMetaObject *classInfoMetaObject;
@@ -397,78 +513,253 @@ namespace QQmlPrivate
const QMetaObject *extensionMetaObject;
QQmlCustomParser *(*customParserFactory)();
+ QVector<int> *qmlTypeIds;
+ int finalizerCast;
+
+ bool forceAnonymous;
+ QMetaSequence listMetaSequence;
};
struct RegisterInterface {
- int version;
+ int structVersion;
- int typeId;
- int listId;
+ QMetaType typeId;
+ QMetaType listId;
const char *iid;
+
+ const char *uri;
+ QTypeRevision version;
};
struct RegisterAutoParent {
- int version;
+ int structVersion;
AutoParentFunction function;
};
struct RegisterSingletonType {
- int version;
+ int structVersion;
const char *uri;
- int versionMajor;
- int versionMinor;
+ QTypeRevision version;
const char *typeName;
- QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *);
- QObject *(*qobjectApi)(QQmlEngine *, QJSEngine *);
- const QMetaObject *instanceMetaObject; // new in version 1
- int typeId; // new in version 2
- int revision; // new in version 2
- std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3
- // If this is extended ensure "version" is bumped!!!
+ std::function<QJSValue(QQmlEngine *, QJSEngine *)> scriptApi;
+ std::function<QObject*(QQmlEngine *, QJSEngine *)> qObjectApi;
+
+ const QMetaObject *instanceMetaObject;
+ QMetaType typeId;
+
+ QObject *(*extensionObjectCreate)(QObject *);
+ const QMetaObject *extensionMetaObject;
+
+ QTypeRevision revision;
};
struct RegisterSingletonTypeAndRevisions {
- int version;
+ int structVersion;
const char *uri;
- int versionMajor;
+ QTypeRevision version;
+
+ std::function<QObject*(QQmlEngine *, QJSEngine *)> qObjectApi;
- QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *);
const QMetaObject *instanceMetaObject;
const QMetaObject *classInfoMetaObject;
- int typeId;
- std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3
+ QMetaType typeId;
+
+ QObject *(*extensionObjectCreate)(QObject *);
+ const QMetaObject *extensionMetaObject;
+
+ QVector<int> *qmlTypeIds;
};
struct RegisterCompositeType {
+ int structVersion;
QUrl url;
const char *uri;
- int versionMajor;
- int versionMinor;
+ QTypeRevision version;
const char *typeName;
};
struct RegisterCompositeSingletonType {
+ int structVersion;
QUrl url;
const char *uri;
- int versionMajor;
- int versionMinor;
+ QTypeRevision version;
const char *typeName;
};
+ struct RegisterSequentialContainer {
+ int structVersion;
+ const char *uri;
+ QTypeRevision version;
+
+ // ### Qt7: Remove typeName. It's ignored because the only valid name is "list",
+ // and that's automatic.
+ const char *typeName;
+
+ QMetaType typeId;
+ QMetaSequence metaSequence;
+ QTypeRevision revision;
+ };
+
+ struct RegisterSequentialContainerAndRevisions {
+ int structVersion;
+ const char *uri;
+ QTypeRevision version;
+
+ const QMetaObject *classInfoMetaObject;
+ QMetaType typeId;
+ QMetaSequence metaSequence;
+
+ QVector<int> *qmlTypeIds;
+ };
+
+ struct Q_QML_EXPORT AOTCompiledContext {
+ enum: uint { InvalidStringId = (std::numeric_limits<uint>::max)() };
+
+ QQmlContextData *qmlContext;
+ QObject *qmlScopeObject;
+ QJSEngine *engine;
+ union {
+ QV4::ExecutableCompilationUnit *compilationUnit;
+ qintptr extraData;
+ };
+
+ QObject *thisObject() const;
+ QQmlEngine *qmlEngine() const;
+
+ QJSValue jsMetaType(int index) const;
+ void setInstructionPointer(int offset) const;
+ void setReturnValueUndefined() const;
+
+ // Run QQmlPropertyCapture::captureProperty() without retrieving the value.
+ bool captureLookup(uint index, QObject *object) const;
+ bool captureQmlContextPropertyLookup(uint index) const;
+ void captureTranslation() const;
+ QString translationContext() const;
+ QMetaType lookupResultMetaType(uint index) const;
+ void storeNameSloppy(uint nameIndex, void *value, QMetaType type) const;
+ QJSValue javaScriptGlobalProperty(uint nameIndex) const;
+
+ const QLoggingCategory *resolveLoggingCategory(QObject *wrapper, bool *ok) const;
+
+ void writeToConsole(
+ QtMsgType type, const QString &message,
+ const QLoggingCategory *loggingCategory) const;
+
+ QVariant constructValueType(
+ QMetaType resultMetaType, const QMetaObject *resultMetaObject,
+ int ctorIndex, void *ctorArg) const;
+
+ // Those are explicit arguments to the Date() ctor, not implicit coercions.
+ QDateTime constructDateTime(double timestamp) const;
+ QDateTime constructDateTime(const QString &string) const;
+ QDateTime constructDateTime(const QJSPrimitiveValue &arg) const
+ {
+ return arg.type() == QJSPrimitiveValue::String
+ ? constructDateTime(arg.toString())
+ : constructDateTime(arg.toDouble());
+ }
+
+ QDateTime constructDateTime(
+ double year, double month, double day = 1,
+ double hours = 0, double minutes = 0, double seconds = 0, double msecs = 0) const;
+
+ // All of these lookup functions should be used as follows:
+ //
+ // while (!fooBarLookup(...)) {
+ // setInstructionPointer(...);
+ // initFooBarLookup(...);
+ // if (engine->hasException()) {
+ // ...
+ // break;
+ // }
+ // }
+ //
+ // The bool-returning *Lookup functions exclusively run the happy path and return false if
+ // that fails in any way. The failure may either be in the lookup structs not being
+ // initialized or an exception being thrown.
+ // The init*Lookup functions initialize the lookup structs and amend any exceptions
+ // previously thrown with line numbers. They might also throw their own exceptions. If an
+ // exception is present after the initialization there is no way to carry out the lookup and
+ // the exception should be propagated. If not, the original lookup can be tried again.
+
+ bool callQmlContextPropertyLookup(
+ uint index, void **args, const QMetaType *types, int argc) const;
+ void initCallQmlContextPropertyLookup(uint index) const;
+
+ bool loadContextIdLookup(uint index, void *target) const;
+ void initLoadContextIdLookup(uint index) const;
+
+ bool callObjectPropertyLookup(uint index, QObject *object,
+ void **args, const QMetaType *types, int argc) const;
+ void initCallObjectPropertyLookup(uint index) const;
+
+ bool callGlobalLookup(uint index, void **args, const QMetaType *types, int argc) const;
+ void initCallGlobalLookup(uint index) const;
+
+ bool loadGlobalLookup(uint index, void *target, QMetaType type) const;
+ void initLoadGlobalLookup(uint index) const;
+
+ bool loadScopeObjectPropertyLookup(uint index, void *target) const;
+ bool writeBackScopeObjectPropertyLookup(uint index, void *source) const;
+ void initLoadScopeObjectPropertyLookup(uint index, QMetaType type) const;
+
+ bool loadSingletonLookup(uint index, void *target) const;
+ void initLoadSingletonLookup(uint index, uint importNamespace) const;
+
+ bool loadAttachedLookup(uint index, QObject *object, void *target) const;
+ void initLoadAttachedLookup(uint index, uint importNamespace, QObject *object) const;
+
+ bool loadTypeLookup(uint index, void *target) const;
+ void initLoadTypeLookup(uint index, uint importNamespace) const;
+
+ bool getObjectLookup(uint index, QObject *object, void *target) const;
+ bool writeBackObjectLookup(uint index, QObject *object, void *source) const;
+ void initGetObjectLookup(uint index, QObject *object, QMetaType type) const;
+
+ bool getValueLookup(uint index, void *value, void *target) const;
+ bool writeBackValueLookup(uint index, void *value, void *source) const;
+ void initGetValueLookup(uint index, const QMetaObject *metaObject, QMetaType type) const;
+
+ bool getEnumLookup(uint index, void *target) const;
+#if QT_QML_REMOVED_SINCE(6, 6)
+ bool getEnumLookup(uint index, int *target) const;
+#endif
+ void initGetEnumLookup(uint index, const QMetaObject *metaObject,
+ const char *enumerator, const char *enumValue) const;
+
+ bool setObjectLookup(uint index, QObject *object, void *value) const;
+ void initSetObjectLookup(uint index, QObject *object, QMetaType type) const;
+
+ bool setValueLookup(uint index, void *target, void *value) const;
+ void initSetValueLookup(uint index, const QMetaObject *metaObject, QMetaType type) const;
+ };
+
+ struct AOTCompiledFunction {
+ int functionIndex;
+ int numArguments;
+ void (*signature)(QV4::ExecutableCompilationUnit *unit, QMetaType *argTypes);
+ void (*functionPtr)(const AOTCompiledContext *context, void **argv);
+ };
+
+#if QT_DEPRECATED_SINCE(6, 6)
+ QT_DEPRECATED_VERSION_X(6, 6, "Use AOTCompiledFunction instead")
+ typedef AOTCompiledFunction TypedFunction;
+#endif
+
struct CachedQmlUnit {
const QV4::CompiledData::Unit *qmlData;
- void *unused1;
+ const AOTCompiledFunction *aotCompiledFunctions;
void *unused2;
};
typedef const CachedQmlUnit *(*QmlUnitCacheLookupFunction)(const QUrl &url);
struct RegisterQmlUnitCacheHook {
- int version;
+ int structVersion;
QmlUnitCacheLookupFunction lookupCachedQmlUnit;
};
@@ -481,26 +772,45 @@ namespace QQmlPrivate
CompositeSingletonRegistration = 5,
QmlUnitCacheHookRegistration = 6,
TypeAndRevisionsRegistration = 7,
- SingletonAndRevisionsRegistration = 8
+ SingletonAndRevisionsRegistration = 8,
+ SequentialContainerRegistration = 9,
+ SequentialContainerAndRevisionsRegistration = 10,
};
int Q_QML_EXPORT qmlregister(RegistrationType, void *);
void Q_QML_EXPORT qmlunregister(RegistrationType, quintptr);
- struct Q_QML_EXPORT RegisterSingletonFunctor
+
+#if QT_DEPRECATED_SINCE(6, 3)
+ struct Q_QML_EXPORT SingletonFunctor
+ {
+ QT_DEPRECATED QObject *operator()(QQmlEngine *, QJSEngine *);
+ QPointer<QObject> m_object;
+ bool alreadyCalled = false;
+ };
+#endif
+
+ struct Q_QML_EXPORT SingletonInstanceFunctor
{
QObject *operator()(QQmlEngine *, QJSEngine *);
QPointer<QObject> m_object;
- bool alreadyCalled = false;
+
+ // Not a QPointer, so that you cannot assign it to a different
+ // engine when the first one is deleted.
+ // That would mess up the QML contexts.
+ QQmlEngine *m_engine = nullptr;
};
- static int indexOfOwnClassInfo(const QMetaObject *metaObject, const char *key)
+ static int indexOfOwnClassInfo(const QMetaObject *metaObject, const char *key, int startOffset = -1)
{
if (!metaObject || !key)
return -1;
const int offset = metaObject->classInfoOffset();
- for (int i = metaObject->classInfoCount() + offset - 1; i >= offset; --i)
+ const int start = (startOffset == -1)
+ ? (metaObject->classInfoCount() + offset - 1)
+ : startOffset;
+ for (int i = start; i >= offset; --i)
if (qstrcmp(key, metaObject->classInfo(i).name()) == 0) {
return i;
}
@@ -512,92 +822,229 @@ namespace QQmlPrivate
return metaObject->classInfo(indexOfOwnClassInfo(metaObject, key)).value();
}
- inline int intClassInfo(const QMetaObject *metaObject, const char *key, int defaultValue = 0)
+ inline QTypeRevision revisionClassInfo(const QMetaObject *metaObject, const char *key,
+ QTypeRevision defaultValue = QTypeRevision())
{
const int index = indexOfOwnClassInfo(metaObject, key);
return (index == -1) ? defaultValue
- : QByteArray(metaObject->classInfo(index).value()).toInt();
+ : QTypeRevision::fromEncodedVersion(
+ QLatin1StringView(metaObject->classInfo(index).value()).toInt());
}
+ Q_QML_EXPORT QList<QTypeRevision> revisionClassInfos(const QMetaObject *metaObject, const char *key);
+
inline bool boolClassInfo(const QMetaObject *metaObject, const char *key,
bool defaultValue = false)
{
const int index = indexOfOwnClassInfo(metaObject, key);
- return (index == -1) ? defaultValue
- : (QByteArray(metaObject->classInfo(index).value()) == "true");
+ if (index == -1)
+ return defaultValue;
+ return qstrcmp(metaObject->classInfo(index).value(), "true") == 0;
}
- inline const char *classElementName(const QMetaObject *metaObject)
+ template<class T, class = std::void_t<>>
+ struct QmlExtended
{
- const char *elementName = classInfo(metaObject, "QML.Element");
- if (qstrcmp(elementName, "auto") == 0)
- return metaObject->className();
- if (qstrcmp(elementName, "anonymous") == 0)
- return nullptr;
-
- if (!elementName || elementName[0] < 'A' || elementName[0] > 'Z') {
- qWarning() << "Missing or unusable QML.Element class info \"" << elementName << "\""
- << "for" << metaObject->className();
- }
+ using Type = void;
+ };
- return elementName;
- }
+ template<class T>
+ struct QmlExtended<T, std::void_t<typename T::QmlExtendedType>>
+ {
+ using Type = typename std::conditional<
+ QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_extended)>::value,
+ typename T::QmlExtendedType, void>::type;
+ };
- template<class T, class = QmlVoidT<>>
- struct QmlExtended
+ template<class T, class = std::void_t<>>
+ struct QmlExtendedNamespace
{
- using Type = void;
+ static constexpr const QMetaObject *metaObject() { return nullptr; }
};
template<class T>
- struct QmlExtended<T, QmlVoidT<typename T::QmlExtendedType>>
+ struct QmlExtendedNamespace<T, std::void_t<decltype(T::qmlExtendedNamespace())>>
{
- using Type = typename T::QmlExtendedType;
+ static constexpr const QMetaObject *metaObject()
+ {
+ if constexpr (QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_extendedNamespace)>::value)
+ return T::qmlExtendedNamespace();
+ else
+ return nullptr;
+ }
};
- template<class T, class = QmlVoidT<>>
+ template<class T, class = std::void_t<>>
struct QmlResolved
{
using Type = T;
};
template<class T>
- struct QmlResolved<T, QmlVoidT<typename T::QmlForeignType>>
+ struct QmlResolved<T, std::void_t<typename T::QmlForeignType>>
+ {
+ using Type = typename std::conditional<
+ QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_foreign)>::value,
+ typename T::QmlForeignType, T>::type;
+ };
+
+ template<class T, class = std::void_t<>>
+ struct QmlUncreatable
+ {
+ static constexpr bool Value = false;
+ };
+
+ template<class T>
+ struct QmlUncreatable<T, std::void_t<typename T::QmlIsUncreatable>>
+ {
+ static constexpr bool Value =
+ QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_uncreatable)>::value
+ && bool(T::QmlIsUncreatable::yes);
+ };
+
+ template<class T, class = std::void_t<>>
+ struct QmlAnonymous
+ {
+ static constexpr bool Value = false;
+ };
+
+ template<class T>
+ struct QmlAnonymous<T, std::void_t<typename T::QmlIsAnonymous>>
{
- using Type = typename T::QmlForeignType;
+ static constexpr bool Value =
+ QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_anonymous)>::value
+ && bool(T::QmlIsAnonymous::yes);
};
- template<class T, class = QmlVoidT<>>
+
+ template<class T, class = std::void_t<>>
struct QmlSingleton
{
static constexpr bool Value = false;
};
template<class T>
- struct QmlSingleton<T, QmlVoidT<typename T::QmlIsSingleton>>
+ struct QmlSingleton<T, std::void_t<typename T::QmlIsSingleton>>
{
- static constexpr bool Value = bool(T::QmlIsSingleton::yes);
+ static constexpr bool Value =
+ QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_singleton)>::value
+ && bool(T::QmlIsSingleton::yes);
};
- template<typename T>
- void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor,
- const QMetaObject *classInfoMetaObject)
+ template<class T, class = std::void_t<>>
+ struct QmlSequence
+ {
+ static constexpr bool Value = false;
+ };
+
+ template<class T>
+ struct QmlSequence<T, std::void_t<typename T::QmlIsSequence>>
+ {
+ Q_STATIC_ASSERT((std::is_same_v<typename T::QmlSequenceValueType,
+ typename QmlResolved<T>::Type::value_type>));
+ static constexpr bool Value = bool(T::QmlIsSequence::yes);
+ };
+
+ template<class T, class = std::void_t<>>
+ struct QmlInterface
+ {
+ static constexpr bool Value = false;
+ };
+
+ template<class T>
+ struct QmlInterface<T, std::void_t<typename T::QmlIsInterface, decltype(qobject_interface_iid<T *>())>>
{
- QML_GETTYPENAMES
+ static constexpr bool Value = bool(T::QmlIsInterface::yes);
+ };
+
+ template<class T, typename = std::void_t<>>
+ struct StaticMetaObject
+ {
+ static const QMetaObject *staticMetaObject() { return nullptr; }
+ };
+
+ template<class T>
+ struct StaticMetaObject<T, std::void_t<decltype(T::staticMetaObject)>>
+ {
+ static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; }
+ };
+
+ template<class T>
+ struct QmlMetaType
+ {
+ static constexpr bool hasAcceptableCtors()
+ {
+ if constexpr (!std::is_default_constructible_v<T>)
+ return false;
+ else if constexpr (std::is_base_of_v<QObject, T>)
+ return true;
+ else
+ return std::is_copy_constructible_v<T>;
+ }
+ static constexpr QMetaType self()
+ {
+ if constexpr (std::is_base_of_v<QObject, T>)
+ return QMetaType::fromType<T*>();
+ else
+ return QMetaType::fromType<T>();
+ }
+
+ static constexpr QMetaType list()
+ {
+ if constexpr (std::is_base_of_v<QObject, T>)
+ return QMetaType::fromType<QQmlListProperty<T>>();
+ else
+ return QMetaType::fromType<QList<T>>();
+ }
+
+ static constexpr QMetaSequence sequence()
+ {
+ if constexpr (std::is_base_of_v<QObject, T>)
+ return QMetaSequence();
+ else
+ return QMetaSequence::fromContainer<QList<T>>();
+ }
+
+ static constexpr int size()
+ {
+ return sizeof(T);
+ }
+ };
+
+ template<>
+ struct QmlMetaType<void>
+ {
+ static constexpr bool hasAcceptableCtors() { return true; }
+ static constexpr QMetaType self() { return QMetaType(); }
+ static constexpr QMetaType list() { return QMetaType(); }
+ static constexpr QMetaSequence sequence() { return QMetaSequence(); }
+ static constexpr int size() { return 0; }
+ };
+
+ template<typename T, typename E, typename WrapperT = T>
+ void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor,
+ const QMetaObject *classInfoMetaObject,
+ QVector<int> *qmlTypeIds, const QMetaObject *extension)
+ {
+ static_assert(std::is_base_of_v<QObject, T>);
RegisterSingletonTypeAndRevisions api = {
0,
uri,
- versionMajor,
+ QTypeRevision::fromMajorVersion(versionMajor),
- nullptr,
+ Constructors<T, WrapperT>::createSingletonInstance,
- &T::staticMetaObject,
+ StaticMetaObject<T>::staticMetaObject(),
classInfoMetaObject,
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- Constructors<T>::createSingletonInstance
+ QmlMetaType<T>::self(),
+
+ ExtendedType<E>::createParent,
+ extension ? extension : ExtendedType<E>::staticMetaObject(),
+
+ qmlTypeIds
};
qmlregister(SingletonAndRevisionsRegistration, &api);
@@ -605,21 +1052,23 @@ namespace QQmlPrivate
template<typename T, typename E>
void qmlRegisterTypeAndRevisions(const char *uri, int versionMajor,
- const QMetaObject *classInfoMetaObject)
+ const QMetaObject *classInfoMetaObject,
+ QVector<int> *qmlTypeIds, const QMetaObject *extension,
+ bool forceAnonymous = false)
{
- QML_GETTYPENAMES
-
RegisterTypeAndRevisions type = {
- 0,
- qRegisterNormalizedMetaType<T *>(pointerName.constData()),
- qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()),
- int(sizeof(T)),
+ 3,
+ QmlMetaType<T>::self(),
+ QmlMetaType<T>::list(),
+ QmlMetaType<T>::size(),
Constructors<T>::createInto,
+ nullptr,
+ ValueType<T, E>::create,
uri,
- versionMajor,
+ QTypeRevision::fromMajorVersion(versionMajor),
- &T::staticMetaObject,
+ StaticMetaObject<T>::staticMetaObject(),
classInfoMetaObject,
attachedPropertiesFunc<T>(),
@@ -630,15 +1079,89 @@ namespace QQmlPrivate
StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(),
ExtendedType<E>::createParent,
- ExtendedType<E>::staticMetaObject,
+ extension ? extension : ExtendedType<E>::staticMetaObject(),
- &qmlCreateCustomParser<T>
+ &qmlCreateCustomParser<T>,
+ qmlTypeIds,
+ StaticCastSelector<T, QQmlFinalizerHook>::cast(),
+
+ forceAnonymous,
+ QmlMetaType<T>::sequence(),
};
+ // Initialize the extension so that we can find it by name or ID.
+ qMetaTypeId<E>();
+
qmlregister(TypeAndRevisionsRegistration, &type);
}
+
+ template<typename T>
+ void qmlRegisterSequenceAndRevisions(const char *uri, int versionMajor,
+ const QMetaObject *classInfoMetaObject,
+ QVector<int> *qmlTypeIds)
+ {
+ RegisterSequentialContainerAndRevisions type = {
+ 0,
+ uri,
+ QTypeRevision::fromMajorVersion(versionMajor),
+ classInfoMetaObject,
+ QMetaType::fromType<T>(),
+ QMetaSequence::fromContainer<T>(),
+ qmlTypeIds
+ };
+
+ qmlregister(SequentialContainerAndRevisionsRegistration, &type);
+ }
+
+ template<>
+ void Q_QML_EXPORT qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>(
+ const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject,
+ QVector<int> *qmlTypeIds, const QMetaObject *, bool);
+
+ constexpr QtPrivate::QMetaTypeInterface metaTypeForNamespace(
+ const QtPrivate::QMetaTypeInterface::MetaObjectFn &metaObjectFunction, const char *name)
+ {
+ return {
+ /*.revision=*/ 0,
+ /*.alignment=*/ 0,
+ /*.size=*/ 0,
+ /*.flags=*/ 0,
+ /*.typeId=*/ {},
+ /*.metaObject=*/ metaObjectFunction,
+ /*.name=*/ name,
+ /*.defaultCtr=*/ nullptr,
+ /*.copyCtr=*/ nullptr,
+ /*.moveCtr=*/ nullptr,
+ /*.dtor=*/ nullptr,
+ /*.equals*/ nullptr,
+ /*.lessThan*/ nullptr,
+ /*.debugStream=*/ nullptr,
+ /*.dataStreamOut=*/ nullptr,
+ /*.dataStreamIn=*/ nullptr,
+ /*.legacyRegisterOp=*/ nullptr
+ };
+ }
+
+ Q_QML_EXPORT QObject *qmlExtendedObject(QObject *, int);
+
+ enum QmlRegistrationWarning {
+ UnconstructibleType,
+ UnconstructibleSingleton,
+ NonQObjectWithAtached,
+ };
+
+ Q_QML_EXPORT void qmlRegistrationWarning(QmlRegistrationWarning warning, QMetaType type);
+
+ Q_QML_EXPORT QMetaType compositeMetaType(
+ QV4::ExecutableCompilationUnit *unit, const QString &elementName);
+ Q_QML_EXPORT QMetaType compositeListMetaType(
+ QV4::ExecutableCompilationUnit *unit, const QString &elementName);
+
} // namespace QQmlPrivate
QT_END_NAMESPACE
+Q_DECLARE_OPAQUE_POINTER(QQmlV4FunctionPtr)
+Q_DECLARE_OPAQUE_POINTER(QQmlV4ExecutionEnginePtr)
+
#endif // QQMLPRIVATE_H
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index eff3e94fbd..7c78fbb984 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1,77 +1,41 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlproperty.h"
-#include "qqmlproperty_p.h"
-
-#include "qqml.h"
-#include "qqmlbinding_p.h"
-#include "qqmlboundsignal_p.h"
-#include "qqmlcontext.h"
-#include "qqmlcontext_p.h"
-#include "qqmlboundsignal_p.h"
-#include "qqmlengine.h"
-#include "qqmlengine_p.h"
-#include "qqmldata_p.h"
-#include "qqmlstringconverters_p.h"
-#include "qqmllist_p.h"
-#include "qqmlvmemetaobject_p.h"
-#include "qqmlexpression_p.h"
-#include "qqmlvaluetypeproxybinding_p.h"
-#include <private/qjsvalue_p.h>
-#include <private/qv4functionobject_p.h>
-#include <QStringList>
-#include <QVector>
+#include <private/qjsvalue_p.h>
#include <private/qmetaobject_p.h>
+#include <private/qproperty_p.h>
+#include <private/qqmlboundsignal_p.h>
+#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmldata_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlirbuilder_p.h>
+#include <private/qqmllist_p.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmlsignalnames_p.h>
+#include <private/qqmlstringconverters_p.h>
+#include <private/qqmlvaluetypeproxybinding_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlpropertymap.h>
+
#include <QtCore/qdebug.h>
-#include <cmath>
+#include <QtCore/qsequentialiterable.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvector.h>
-Q_DECLARE_METATYPE(QList<int>)
-Q_DECLARE_METATYPE(QList<qreal>)
-Q_DECLARE_METATYPE(QList<bool>)
-Q_DECLARE_METATYPE(QList<QString>)
-Q_DECLARE_METATYPE(QList<QUrl>)
+#include <cmath>
QT_BEGIN_NAMESPACE
+DEFINE_BOOL_CONFIG_OPTION(compatResolveUrlsOnAssigment, QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT);
+
/*!
\class QQmlProperty
\since 5.0
@@ -116,10 +80,7 @@ qWarning() << "Pixel size should now be 24:" << property.read().toInt();
/*!
Create an invalid QQmlProperty.
*/
-QQmlProperty::QQmlProperty()
-: d(nullptr)
-{
-}
+QQmlProperty::QQmlProperty() = default;
/*! \internal */
QQmlProperty::~QQmlProperty()
@@ -148,8 +109,10 @@ QQmlProperty::QQmlProperty(QObject *obj)
QQmlProperty::QQmlProperty(QObject *obj, QQmlContext *ctxt)
: d(new QQmlPropertyPrivate)
{
- d->context = ctxt?QQmlContextData::get(ctxt):nullptr;
- d->engine = ctxt?ctxt->engine():nullptr;
+ if (ctxt) {
+ d->context = QQmlContextData::get(ctxt);
+ d->engine = ctxt->engine();
+ }
d->initDefault(obj);
}
@@ -162,7 +125,6 @@ QQmlProperty::QQmlProperty(QObject *obj, QQmlContext *ctxt)
QQmlProperty::QQmlProperty(QObject *obj, QQmlEngine *engine)
: d(new QQmlPropertyPrivate)
{
- d->context = nullptr;
d->engine = engine;
d->initDefault(obj);
}
@@ -201,10 +163,17 @@ QQmlProperty::QQmlProperty(QObject *obj, const QString &name)
QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlContext *ctxt)
: d(new QQmlPropertyPrivate)
{
- d->context = ctxt?QQmlContextData::get(ctxt):nullptr;
- d->engine = ctxt?ctxt->engine():nullptr;
+ if (ctxt) {
+ d->context = QQmlContextData::get(ctxt);
+ d->engine = ctxt->engine();
+ }
+
d->initProperty(obj, name);
- if (!isValid()) { d->object = nullptr; d->context = nullptr; d->engine = nullptr; }
+ if (!isValid()) {
+ d->object = nullptr;
+ d->context.reset();
+ d->engine = nullptr;
+ }
}
/*!
@@ -215,82 +184,97 @@ QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlContext *ctxt)
QQmlProperty::QQmlProperty(QObject *obj, const QString &name, QQmlEngine *engine)
: d(new QQmlPropertyPrivate)
{
- d->context = nullptr;
d->engine = engine;
d->initProperty(obj, name);
- if (!isValid()) { d->object = nullptr; d->context = nullptr; d->engine = nullptr; }
+ if (!isValid()) {
+ d->object = nullptr;
+ d->context.reset();
+ d->engine = nullptr;
+ }
}
-QQmlProperty QQmlPropertyPrivate::create(QObject *target, const QString &propertyName, QQmlContextData *context)
+QQmlProperty QQmlPropertyPrivate::create(QObject *target, const QString &propertyName,
+ const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyPrivate::InitFlags flags)
{
QQmlProperty result;
auto d = new QQmlPropertyPrivate;
result.d = d;
d->context = context;
- d->engine = context ? context->engine : nullptr;
- d->initProperty(target, propertyName);
+ d->engine = context ? context->engine() : nullptr;
+ d->initProperty(target, propertyName, flags);
if (!result.isValid()) {
d->object = nullptr;
- d->context = nullptr;
+ d->context.reset();
d->engine = nullptr;
}
return result;
}
-QQmlPropertyPrivate::QQmlPropertyPrivate()
-: context(nullptr), engine(nullptr), object(nullptr), isNameCached(false)
+bool QQmlPropertyPrivate::resolveUrlsOnAssignment()
{
+ return ::compatResolveUrlsOnAssigment();
}
-QQmlContextData *QQmlPropertyPrivate::effectiveContext() const
+QQmlRefPointer<QQmlContextData> QQmlPropertyPrivate::effectiveContext() const
{
- if (context) return context;
- else if (engine) return QQmlContextData::get(engine->rootContext());
- else return nullptr;
+ if (context)
+ return context;
+ else if (engine)
+ return QQmlContextData::get(engine->rootContext());
+ else
+ return nullptr;
}
-void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
+// ### Qt7: Do not accept the "onFoo" syntax for signals anymore, and change the flags accordingly.
+void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name,
+ QQmlPropertyPrivate::InitFlags flags)
{
- if (!obj) return;
-
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache = context?context->imports:nullptr;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache = context ? context->imports() : nullptr;
QObject *currentObject = obj;
- QVector<QStringRef> path;
- QStringRef terminal(&name);
+ QList<QStringView> path;
+ QStringView terminal(name);
if (name.contains(QLatin1Char('.'))) {
- path = name.splitRef(QLatin1Char('.'));
+ path = QStringView{name}.split(QLatin1Char('.'));
if (path.isEmpty()) return;
// Everything up to the last property must be an "object type" property
- for (int ii = 0; ii < path.count() - 1; ++ii) {
- const QStringRef &pathName = path.at(ii);
+ for (int ii = 0; ii < path.size() - 1; ++ii) {
+ const QStringView &pathName = path.at(ii);
// Types must begin with an uppercase letter (see checkRegistration()
// in qqmlmetatype.cpp for the enforcement of this).
if (typeNameCache && !pathName.isEmpty() && pathName.at(0).isUpper()) {
- QQmlTypeNameCache::Result r = typeNameCache->query(pathName);
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
+ QQmlTypeLoader *typeLoader = QQmlTypeLoader::get(enginePrivate);
+ QQmlTypeNameCache::Result r = typeNameCache->query(pathName, typeLoader);
if (r.isValid()) {
if (r.type.isValid()) {
- QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
if (!func) return; // Not an attachable type
currentObject = qmlAttachedPropertiesObject(currentObject, func);
if (!currentObject) return; // Something is broken with the attachable type
} else if (r.importNamespace) {
- if ((ii + 1) == path.count()) return; // No type following the namespace
+ if (++ii == path.size())
+ return; // No type following the namespace
- ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace);
- if (!r.type.isValid()) return; // Invalid type in namespace
+ // TODO: Do we really _not_ want to query the namespaced types here?
+ r = typeNameCache->query<QQmlTypeNameCache::QueryNamespaced::No>(
+ path.at(ii), r.importNamespace, typeLoader);
+
+ if (!r.type.isValid())
+ return; // Invalid type in namespace
- QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
- if (!func) return; // Not an attachable type
+ if (!func)
+ return; // Not an attachable type
currentObject = qmlAttachedPropertiesObject(currentObject, func);
- if (!currentObject) return; // Something is broken with the attachable type
+ if (!currentObject)
+ return; // Something is broken with the attachable type
} else if (r.scriptIndex != -1) {
return; // Not a type
@@ -303,16 +287,35 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
}
QQmlPropertyData local;
- QQmlPropertyData *property =
- QQmlPropertyCache::property(engine, currentObject, pathName, context, local);
+ const QQmlPropertyData *property = currentObject
+ ? QQmlPropertyCache::property(currentObject, pathName, context, &local)
+ : nullptr;
+
+ if (!property) {
+ // Not a property; Might be an ID
+ // You can't look up an ID on a non-null object, though.
+ if (currentObject || !(flags & InitFlag::AllowId))
+ return;
+
+ for (auto idContext = context; idContext; idContext = idContext->parent()) {
+ const int objectId = idContext->propertyIndex(pathName.toString());
+ if (objectId != -1 && objectId < idContext->numIdValues()) {
+ currentObject = context->idValue(objectId);
+ break;
+ }
+ }
- if (!property) return; // Not a property
- if (property->isFunction())
+ if (!currentObject)
+ return;
+
+ continue;
+ } else if (property->isFunction()) {
return; // Not an object property
+ }
- if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType())) {
+ if (ii == (path.size() - 2) && QQmlMetaType::isValueType(property->propType())) {
// We're now at a value type property
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType());
+ const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(property->propType());
if (!valueTypeMetaObject) return; // Not a value type
int idx = valueTypeMetaObject->indexOfProperty(path.last().toUtf8().constData());
@@ -320,21 +323,25 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
QMetaProperty vtProp = valueTypeMetaObject->property(idx);
- Q_ASSERT(vtProp.userType() <= 0x0000FFFF);
Q_ASSERT(idx <= 0x0000FFFF);
object = currentObject;
core = *property;
valueTypeData.setFlags(QQmlPropertyData::flagsForProperty(vtProp));
- valueTypeData.setPropType(vtProp.userType());
+ valueTypeData.setPropType(vtProp.metaType());
valueTypeData.setCoreIndex(idx);
return;
} else {
- if (!property->isQObject())
- return; // Not an object property
+ if (!property->isQObject()) {
+ if (auto asPropertyMap = qobject_cast<QQmlPropertyMap*>(currentObject))
+ currentObject = asPropertyMap->value(path.at(ii).toString()).value<QObject*>();
+ else
+ return; // Not an object property, and not a property map
+ } else {
+ property->readProperty(currentObject, &currentObject);
+ }
- property->readProperty(currentObject, &currentObject);
if (!currentObject) return; // No value
}
@@ -342,66 +349,119 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
}
terminal = path.last();
+ } else if (!currentObject) {
+ return;
}
- if (terminal.count() >= 3 &&
- terminal.at(0) == QLatin1Char('o') &&
- terminal.at(1) == QLatin1Char('n') &&
- terminal.at(2).isUpper()) {
+ auto findSignalInMetaObject = [&](const QByteArray &signalName) {
+ const QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName);
+ if (!method.isValid())
+ return false;
- QString signalName = terminal.mid(2).toString();
- signalName[0] = signalName.at(0).toLower();
+ object = currentObject;
+ core.load(method);
+ return true;
+ };
+
+ QQmlData *ddata = QQmlData::get(currentObject, false);
+ auto findChangeSignal = [&](QStringView signalName) {
+ if (auto propName = QQmlSignalNames::changedSignalNameToPropertyName(signalName)) {
+ const QQmlPropertyData *d =
+ ddata->propertyCache->property(*propName, currentObject, context);
+ while (d && d->isFunction())
+ d = ddata->propertyCache->overrideData(d);
- // XXX - this code treats methods as signals
+ if (d && d->notifyIndex() != -1) {
+ object = currentObject;
+ core = *ddata->propertyCache->signal(d->notifyIndex());
+ return true;
+ }
+ }
+ return false;
+ };
- QQmlData *ddata = QQmlData::get(currentObject, false);
+ const auto findSignal = [&](const QString &signalName) {
if (ddata && ddata->propertyCache) {
-
// Try method
- QQmlPropertyData *d = ddata->propertyCache->property(signalName, currentObject, context);
+ const QQmlPropertyData *d
+ = ddata->propertyCache->property(signalName, currentObject, context);
+
+ // ### Qt7: This code treats methods as signals. It should use d->isSignal().
+ // That would be a change in behavior, though. Right now you can construct a
+ // QQmlProperty from such a thing.
while (d && !d->isFunction())
d = ddata->propertyCache->overrideData(d);
if (d) {
object = currentObject;
core = *d;
- return;
+ return true;
}
- // Try property
- if (signalName.endsWith(QLatin1String("Changed"))) {
- const QStringRef propName = signalName.midRef(0, signalName.length() - 7);
- QQmlPropertyData *d = ddata->propertyCache->property(propName, currentObject, context);
- while (d && d->isFunction())
- d = ddata->propertyCache->overrideData(d);
+ return findChangeSignal(signalName);
+ }
- if (d && d->notifyIndex() != -1) {
- object = currentObject;
- core = *ddata->propertyCache->signal(d->notifyIndex());
- return;
- }
+ return findSignalInMetaObject(signalName.toUtf8());
+ };
+
+ auto signalName = QQmlSignalNames::handlerNameToSignalName(terminal);
+ if (signalName) {
+ if (findSignal(*signalName))
+ return;
+ } else {
+ signalName = QQmlSignalNames::badHandlerNameToSignalName(terminal);
+ if (signalName) {
+ if (findSignal(*signalName)) {
+ qWarning()
+ << terminal
+ << "is not a properly capitalized signal handler name."
+ << QQmlSignalNames::signalNameToHandlerName(*signalName)
+ << "would be correct.";
+ return;
}
+ }
+ }
- } else {
- QMetaMethod method = findSignalByName(currentObject->metaObject(),
- signalName.toLatin1());
- if (method.isValid()) {
+ if (ddata && ddata->propertyCache) {
+ const QQmlPropertyData *property = ddata->propertyCache->property(
+ terminal, currentObject, context);
+
+ // Technically, we might find an override that is not a function.
+ while (property && !property->isSignal()) {
+ if (!property->isFunction()) {
object = currentObject;
- core.load(method);
+ core = *property;
+ nameCache = terminal.toString();
return;
}
+ property = ddata->propertyCache->overrideData(property);
}
- }
- // Property
- QQmlPropertyData local;
- QQmlPropertyData *property =
- QQmlPropertyCache::property(engine, currentObject, terminal, context, local);
- if (property && !property->isFunction()) {
- object = currentObject;
- core = *property;
- nameCache = terminal.toString();
- isNameCached = true;
+ if (!(flags & InitFlag::AllowSignal))
+ return;
+
+ if (property) {
+ Q_ASSERT(property->isSignal());
+ object = currentObject;
+ core = *property;
+ return;
+ }
+
+ // At last: Try the change signal.
+ findChangeSignal(terminal);
+ } else {
+ // We might still find the property in the metaobject, even without property cache.
+ const QByteArray propertyName = terminal.toUtf8();
+ const QMetaProperty prop = findPropertyByName(currentObject->metaObject(), propertyName);
+
+ if (prop.isValid()) {
+ object = currentObject;
+ core.load(prop);
+ return;
+ }
+
+ if (flags & InitFlag::AllowSignal)
+ findSignalInMetaObject(terminal.toUtf8());
}
}
@@ -464,10 +524,10 @@ QQmlPropertyPrivate::propertyTypeCategory() const
if (isValueType()) {
return QQmlProperty::Normal;
} else if (type & QQmlProperty::Property) {
- int type = propertyType();
- if (type == QVariant::Invalid)
+ QMetaType type = propertyType();
+ if (!type.isValid())
return QQmlProperty::InvalidCategory;
- else if (QQmlValueTypeFactory::isValueType((uint)type))
+ else if (QQmlMetaType::isValueType(type))
return QQmlProperty::Normal;
else if (core.isQObject())
return QQmlProperty::Object;
@@ -489,7 +549,7 @@ const char *QQmlProperty::propertyTypeName() const
if (!d)
return nullptr;
if (d->isValueType()) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d->core.propType());
+ const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(d->core.propType());
Q_ASSERT(valueTypeMetaObject);
return valueTypeMetaObject->property(d->valueTypeData.coreIndex()).typeName();
} else if (d->object && type() & Property && d->core.isValid()) {
@@ -515,12 +575,24 @@ bool QQmlProperty::operator==(const QQmlProperty &other) const
}
/*!
- Returns the QVariant type of the property, or QVariant::Invalid if the
- property has no QVariant type.
+ Returns the metatype id of the property, or QMetaType::UnknownType if the
+ property has no metatype.
+
+ \sa propertyMetaType
*/
int QQmlProperty::propertyType() const
{
- return d ? d->propertyType() : int(QVariant::Invalid);
+ return d ? d->propertyType().id() : int(QMetaType::UnknownType);
+}
+
+/*!
+ Returns the metatype of the property.
+
+ \sa propertyType
+ */
+QMetaType QQmlProperty::propertyMetaType() const
+{
+ return d ? d->propertyType() : QMetaType {};
}
bool QQmlPropertyPrivate::isValueType() const
@@ -528,7 +600,7 @@ bool QQmlPropertyPrivate::isValueType() const
return valueTypeData.isValid();
}
-int QQmlPropertyPrivate::propertyType() const
+QMetaType QQmlPropertyPrivate::propertyType() const
{
uint type = this->type();
if (isValueType()) {
@@ -536,7 +608,7 @@ int QQmlPropertyPrivate::propertyType() const
} else if (type & QQmlProperty::Property) {
return core.propType();
} else {
- return QVariant::Invalid;
+ return QMetaType();
}
}
@@ -587,12 +659,8 @@ QObject *QQmlProperty::object() const
*/
QQmlProperty &QQmlProperty::operator=(const QQmlProperty &other)
{
- if (d)
- d->release();
- d = other.d;
- if (d)
- d->addref();
-
+ QQmlProperty copied(other);
+ qSwap(d, copied.d);
return *this;
}
@@ -616,6 +684,21 @@ bool QQmlProperty::isWritable() const
}
/*!
+ \internal
+ Returns true if the property is bindable, otherwise false.
+ */
+bool QQmlProperty::isBindable() const
+{
+ if (!d)
+ return false;
+ if (!d->object)
+ return false;
+ if (d->core.isValid())
+ return d->core.isBindable();
+ return false;
+}
+
+/*!
Returns true if the property is designable, otherwise false.
*/
bool QQmlProperty::isDesignable() const
@@ -659,23 +742,20 @@ QString QQmlProperty::name() const
{
if (!d)
return QString();
- if (!d->isNameCached) {
- // ###
+ if (d->nameCache.isEmpty()) {
if (!d->object) {
} else if (d->isValueType()) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d->core.propType());
+ const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(d->core.propType());
Q_ASSERT(valueTypeMetaObject);
const char *vtName = valueTypeMetaObject->property(d->valueTypeData.coreIndex()).name();
d->nameCache = d->core.name(d->object) + QLatin1Char('.') + QString::fromUtf8(vtName);
} else if (type() & SignalProperty) {
- QString name = QLatin1String("on") + d->core.name(d->object);
- name[2] = name.at(2).toUpper();
- d->nameCache = name;
+ // ### Qt7: Return the original signal name here. Do not prepend "on"
+ d->nameCache = QQmlSignalNames::signalNameToHandlerName(d->core.name(d->object));
} else {
d->nameCache = d->core.name(d->object);
}
- d->isNameCached = true;
}
return d->nameCache;
@@ -732,9 +812,6 @@ QQmlPropertyPrivate::binding(const QQmlProperty &that)
Ownership of \a newBinding transfers to QML. Ownership of the return value
is assumed by the caller.
-
- \a flags is passed through to the binding and is used for the initial update (when
- the binding sets the initial value, it will use these flags for the write).
*/
void
QQmlPropertyPrivate::setBinding(const QQmlProperty &that, QQmlAbstractBinding *newBinding)
@@ -772,14 +849,14 @@ static void removeOldBinding(QObject *object, QQmlPropertyIndex index, QQmlPrope
if (!oldBinding)
return;
- if (valueTypeIndex != -1 && oldBinding->isValueTypeProxy())
+ if (valueTypeIndex != -1 && oldBinding->kind() == QQmlAbstractBinding::ValueTypeProxy)
oldBinding = static_cast<QQmlValueTypeProxyBinding *>(oldBinding.data())->binding(index);
if (!oldBinding)
return;
if (!(flags & QQmlPropertyPrivate::DontEnable))
- oldBinding->setEnabled(false, nullptr);
+ oldBinding->setEnabled(false, {});
oldBinding->removeFromObject();
}
@@ -792,9 +869,7 @@ void QQmlPropertyPrivate::removeBinding(QObject *o, QQmlPropertyIndex index)
{
Q_ASSERT(o);
- QObject *target;
- QQmlPropertyIndex targetIndex;
- findAliasTarget(o, index, &target, &targetIndex);
+ auto [target, targetIndex] = findAliasTarget(o, index);
removeOldBinding(target, targetIndex);
}
@@ -809,7 +884,9 @@ void QQmlPropertyPrivate::removeBinding(const QQmlProperty &that)
QQmlAbstractBinding *
QQmlPropertyPrivate::binding(QObject *object, QQmlPropertyIndex index)
{
- findAliasTarget(object, index, &object, &index);
+ auto aliasTarget = findAliasTarget(object, index);
+ object = aliasTarget.targetObject;
+ index = aliasTarget.targetIndex;
QQmlData *data = QQmlData::get(object);
if (!data)
@@ -827,9 +904,8 @@ QQmlPropertyPrivate::binding(QObject *object, QQmlPropertyIndex index)
binding = binding->nextBinding();
if (binding && valueTypeIndex != -1) {
- if (binding->isValueTypeProxy()) {
+ if (binding->kind() == QQmlAbstractBinding::ValueTypeProxy)
binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index);
- }
}
return binding;
@@ -844,7 +920,7 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, QQmlPropertyIndex bin
int coreIndex = bindingIndex.coreIndex();
int valueTypeIndex = bindingIndex.valueTypeIndex();
- QQmlPropertyData *propertyData =
+ const QQmlPropertyData *propertyData =
data->propertyCache?data->propertyCache->property(coreIndex):nullptr;
if (propertyData && propertyData->isAlias()) {
QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
@@ -871,6 +947,14 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, QQmlPropertyIndex bin
*targetBindingIndex = bindingIndex;
}
+QQmlPropertyPrivate::ResolvedAlias QQmlPropertyPrivate::findAliasTarget(QObject *baseObject, QQmlPropertyIndex baseIndex)
+{
+ ResolvedAlias resolved;
+ findAliasTarget(baseObject, baseIndex, &resolved.targetObject, &resolved.targetIndex);
+ return resolved;
+}
+
+
void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, QQmlPropertyData::WriteFlags writeFlags)
{
@@ -884,7 +968,7 @@ void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags
int coreIndex = index.coreIndex();
QQmlData *data = QQmlData::get(object, true);
if (data->propertyCache) {
- QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
+ const QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
Q_ASSERT(propertyData);
}
#endif
@@ -907,6 +991,8 @@ QQmlPropertyPrivate::signalExpression(const QQmlProperty &that)
if (!(that.type() & QQmlProperty::SignalProperty))
return nullptr;
+ if (!that.d->object)
+ return nullptr;
QQmlData *data = QQmlData::get(that.d->object);
if (!data)
return nullptr;
@@ -946,6 +1032,8 @@ void QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that,
return;
}
+ if (!that.d->object)
+ return;
QQmlData *data = QQmlData::get(that.d->object, nullptr != expr);
if (!data)
return;
@@ -963,7 +1051,7 @@ void QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that,
if (expr) {
int signalIndex = QQmlPropertyPrivate::get(that)->signalIndex();
QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, signalIndex, that.d->object,
- expr->context()->engine);
+ expr->engine());
signal->takeExpression(expr);
}
}
@@ -1038,18 +1126,24 @@ QVariant QQmlProperty::read(const QObject *object, const QString &name, QQmlEngi
QVariant QQmlPropertyPrivate::readValueProperty()
{
- if (isValueType()) {
-
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(core.propType());
- Q_ASSERT(valueType);
- valueType->read(object, core.coreIndex());
- return valueType->metaObject()->property(valueTypeData.coreIndex()).read(valueType);
+ auto doRead = [&](QQmlGadgetPtrWrapper *wrapper) {
+ wrapper->read(object, core.coreIndex());
+ return wrapper->readOnGadget(wrapper->property(valueTypeData.coreIndex()));
+ };
+ if (isValueType()) {
+ if (QQmlGadgetPtrWrapper *wrapper = QQmlGadgetPtrWrapper::instance(engine, core.propType()))
+ return doRead(wrapper);
+ if (QQmlValueType *valueType = QQmlMetaType::valueType(core.propType())) {
+ QQmlGadgetPtrWrapper wrapper(valueType, nullptr);
+ return doRead(&wrapper);
+ }
+ return QVariant();
} else if (core.isQList()) {
QQmlListProperty<QObject> prop;
core.readProperty(object, &prop);
- return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType(), engine));
+ return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType()));
} else if (core.isQObject()) {
@@ -1059,63 +1153,59 @@ QVariant QQmlPropertyPrivate::readValueProperty()
} else {
- if (!core.propType()) // Unregistered type
+ if (!core.propType().isValid()) // Unregistered type
return object->metaObject()->property(core.coreIndex()).read(object);
QVariant value;
int status = -1;
void *args[] = { nullptr, &value, &status };
- if (core.propType() == QMetaType::QVariant) {
+ if (core.propType() == QMetaType::fromType<QVariant>()) {
args[0] = &value;
} else {
value = QVariant(core.propType(), (void*)nullptr);
args[0] = value.data();
}
core.readPropertyWithArgs(object, args);
- if (core.propType() != QMetaType::QVariant && args[0] != value.data())
- return QVariant((QVariant::Type)core.propType(), args[0]);
+ if (core.propType() != QMetaType::fromType<QVariant>() && args[0] != value.data())
+ return QVariant(QMetaType(core.propType()), args[0]);
return value;
}
}
// helper function to allow assignment / binding to QList<QUrl> properties.
-QVariant QQmlPropertyPrivate::resolvedUrlSequence(const QVariant &value, QQmlContextData *context)
+QList<QUrl> QQmlPropertyPrivate::urlSequence(const QVariant &value)
{
+ if (value.metaType() == QMetaType::fromType<QList<QUrl>>())
+ return value.value<QList<QUrl> >();
+
QList<QUrl> urls;
- if (value.userType() == qMetaTypeId<QUrl>()) {
+ if (value.metaType() == QMetaType::fromType<QUrl>()) {
urls.append(value.toUrl());
- } else if (value.userType() == qMetaTypeId<QString>()) {
+ } else if (value.metaType() == QMetaType::fromType<QString>()) {
urls.append(QUrl(value.toString()));
- } else if (value.userType() == qMetaTypeId<QByteArray>()) {
+ } else if (value.metaType() == QMetaType::fromType<QByteArray>()) {
urls.append(QUrl(QString::fromUtf8(value.toByteArray())));
- } else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
- urls = value.value<QList<QUrl> >();
- } else if (value.userType() == qMetaTypeId<QStringList>()) {
+ } else if (value.metaType() == QMetaType::fromType<QStringList>()) {
QStringList urlStrings = value.value<QStringList>();
const int urlStringsSize = urlStrings.size();
urls.reserve(urlStringsSize);
for (int i = 0; i < urlStringsSize; ++i)
urls.append(QUrl(urlStrings.at(i)));
- } else if (value.userType() == qMetaTypeId<QList<QString> >()) {
- QList<QString> urlStrings = value.value<QList<QString> >();
- const int urlStringsSize = urlStrings.size();
- urls.reserve(urlStringsSize);
- for (int i = 0; i < urlStringsSize; ++i)
- urls.append(QUrl(urlStrings.at(i)));
} // note: QList<QByteArray> is not currently supported.
+ return urls;
+}
- QList<QUrl> resolvedUrls;
- const int urlsSize = urls.size();
- resolvedUrls.reserve(urlsSize);
- for (int i = 0; i < urlsSize; ++i) {
- QUrl u = urls.at(i);
- if (context && u.isRelative() && !u.isEmpty())
- u = context->resolvedUrl(u);
- resolvedUrls.append(u);
- }
+// ### Qt7: Get rid of this
+QList<QUrl> QQmlPropertyPrivate::urlSequence(
+ const QVariant &value, const QQmlRefPointer<QQmlContextData> &ctxt)
+{
+ QList<QUrl> urls = urlSequence(value);
+
+ for (auto urlIt = urls.begin(); urlIt != urls.end(); ++urlIt)
+ *urlIt = ctxt->resolvedUrl(*urlIt);
- return QVariant::fromValue<QList<QUrl> >(resolvedUrls);
+ return urls;
}
//writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
@@ -1125,13 +1215,9 @@ bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx,
return false;
QVariant v = value;
- if (prop.isEnumType()) {
+ if (prop.isEnumType() && v.metaType() != prop.metaType()) {
QMetaEnum menum = prop.enumerator();
- if (v.userType() == QVariant::String
-#ifdef QT3_SUPPORT
- || v.userType() == QVariant::CString
-#endif
- ) {
+ if (v.userType() == QMetaType::QString) {
bool ok;
if (prop.isFlagType())
v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
@@ -1139,13 +1225,9 @@ bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx,
v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
if (!ok)
return false;
- } else if (v.userType() != QVariant::Int && v.userType() != QVariant::UInt) {
- int enumMetaTypeId = QMetaType::type(QByteArray(menum.scope() + QByteArray("::") + menum.name()));
- if ((enumMetaTypeId == QMetaType::UnknownType) || (v.userType() != enumMetaTypeId) || !v.constData())
- return false;
- v = QVariant(*reinterpret_cast<const int *>(v.constData()));
}
- v.convert(QVariant::Int);
+ if (!v.convert(prop.metaType())) // ### TODO: underlyingType might be faster?
+ return false;
}
// the status variable is changed by qt_metacall to indicate what it did
@@ -1164,71 +1246,275 @@ bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, QQmlProperty
return writeValueProperty(object, core, valueTypeData, value, effectiveContext(), flags);
}
-bool
-QQmlPropertyPrivate::writeValueProperty(QObject *object,
- const QQmlPropertyData &core,
- const QQmlPropertyData &valueTypeData,
- const QVariant &value,
- QQmlContextData *context,QQmlPropertyData::WriteFlags flags)
+static void removeValuePropertyBinding(
+ QObject *object, const QQmlPropertyData &core,
+ const QQmlPropertyData &valueTypeData, QQmlPropertyData::WriteFlags flags)
{
// Remove any existing bindings on this property
- if (!(flags & QQmlPropertyData::DontRemoveBinding) && object)
- removeBinding(object, encodedIndex(core, valueTypeData));
-
- bool rv = false;
- if (valueTypeData.isValid()) {
- QQmlValueType *writeBack = QQmlValueTypeFactory::valueType(core.propType());
- writeBack->read(object, core.coreIndex());
- rv = write(writeBack, valueTypeData, value, context, flags);
- writeBack->write(object, core.coreIndex(), flags);
- } else {
- rv = write(object, core, value, context, flags);
+ if (!(flags & QQmlPropertyData::DontRemoveBinding) && object) {
+ QQmlPropertyPrivate::removeBinding(
+ object, QQmlPropertyPrivate::encodedIndex(core, valueTypeData));
}
+}
+template<typename Op>
+bool changePropertyAndWriteBack(
+ QObject *object, int coreIndex, QQmlGadgetPtrWrapper *wrapper,
+ QQmlPropertyData::WriteFlags flags, int internalIndex, Op op)
+{
+ wrapper->read(object, coreIndex);
+ const bool rv = op(wrapper);
+ wrapper->write(object, coreIndex, flags, internalIndex);
return rv;
}
-bool QQmlPropertyPrivate::write(QObject *object,
- const QQmlPropertyData &property,
- const QVariant &value, QQmlContextData *context,
- QQmlPropertyData::WriteFlags flags)
+template<typename Op>
+bool changeThroughGadgetPtrWrapper(
+ QObject *object, const QQmlPropertyData &core,
+ const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags,
+ int internalIndex, Op op)
+{
+ if (QQmlGadgetPtrWrapper *wrapper = context
+ ? QQmlGadgetPtrWrapper::instance(context->engine(), core.propType())
+ : nullptr) {
+ return changePropertyAndWriteBack(
+ object, core.coreIndex(), wrapper, flags, internalIndex, op);
+ }
+
+ if (QQmlValueType *valueType = QQmlMetaType::valueType(core.propType())) {
+ QQmlGadgetPtrWrapper wrapper(valueType, nullptr);
+ return changePropertyAndWriteBack(
+ object, core.coreIndex(), &wrapper, flags, internalIndex, op);
+ }
+
+ return false;
+}
+
+bool QQmlPropertyPrivate::writeValueProperty(
+ QObject *object, const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
+ const QVariant &value, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyData::WriteFlags flags)
+{
+ removeValuePropertyBinding(object, core, valueTypeData, flags);
+
+ if (!valueTypeData.isValid())
+ return write(object, core, value, context, flags);
+
+ return changeThroughGadgetPtrWrapper(
+ object, core, context, flags | QQmlPropertyData::HasInternalIndex,
+ valueTypeData.coreIndex(), [&](QQmlGadgetPtrWrapper *wrapper) {
+ return write(wrapper, valueTypeData, value, context, flags);
+ });
+}
+
+bool QQmlPropertyPrivate::resetValueProperty(
+ QObject *object, const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData,
+ const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags)
+{
+ removeValuePropertyBinding(object, core, valueTypeData, flags);
+
+ if (!valueTypeData.isValid())
+ return reset(object, core, flags);
+
+ return changeThroughGadgetPtrWrapper(
+ object, core, context, flags | QQmlPropertyData::HasInternalIndex,
+ valueTypeData.coreIndex(), [&](QQmlGadgetPtrWrapper *wrapper) {
+ return reset(wrapper, valueTypeData, flags);
+ });
+}
+
+// We need to prevent new-style bindings from being removed.
+struct BindingFixer
+{
+ Q_DISABLE_COPY_MOVE(BindingFixer);
+
+ BindingFixer(QObject *object, const QQmlPropertyData &property,
+ QQmlPropertyData::WriteFlags flags)
+ {
+ if (!property.isBindable() || !(flags & QQmlPropertyData::DontRemoveBinding))
+ return;
+
+ QUntypedBindable bindable;
+ void *argv[] = {&bindable};
+ QMetaObject::metacall(object, QMetaObject::BindableProperty, property.coreIndex(), argv);
+ untypedBinding = bindable.binding();
+ if (auto priv = QPropertyBindingPrivate::get(untypedBinding))
+ priv->setSticky(true);
+ }
+
+ ~BindingFixer()
+ {
+ if (untypedBinding.isNull())
+ return;
+ auto priv = QPropertyBindingPrivate::get(untypedBinding);
+ priv->setSticky(false);
+ }
+
+private:
+ QUntypedPropertyBinding untypedBinding;
+};
+
+struct ConvertAndAssignResult {
+ bool couldConvert = false;
+ bool couldWrite = false;
+
+ operator bool() const { return couldConvert; }
+};
+
+static ConvertAndAssignResult tryConvertAndAssign(
+ QObject *object, const QQmlPropertyData &property, const QVariant &value,
+ QQmlPropertyData::WriteFlags flags, QMetaType propertyMetaType, QMetaType variantMetaType,
+ bool isUrl) {
+
+ if (isUrl
+ || variantMetaType == QMetaType::fromType<QString>()
+ || propertyMetaType == QMetaType::fromType<QList<QUrl>>()
+ || property.isQList()) {
+ return {false, false};
+ }
+
+ if (variantMetaType == QMetaType::fromType<QJSValue>()) {
+ // Handle Qt.binding bindings here to avoid mistaken conversion below
+ const QJSValue &jsValue = get<QJSValue>(value);
+ const QV4::FunctionObject *f
+ = QJSValuePrivate::asManagedType<QV4::FunctionObject>(&jsValue);
+ if (f && f->isBinding()) {
+ QV4::QObjectWrapper::setProperty(
+ f->engine(), object, &property, f->asReturnedValue());
+ return {true, true};
+ }
+ }
+
+ // common cases:
+ switch (propertyMetaType.id()) {
+ case QMetaType::Bool:
+ if (value.canConvert(propertyMetaType)) {
+ bool b = value.toBool();
+ return {true, property.writeProperty(object, &b, flags)};
+ }
+ return {false, false};
+ case QMetaType::Int: {
+ bool ok = false;
+ int i = value.toInt(&ok);
+ return {ok, ok && property.writeProperty(object, &i, flags)};
+ }
+ case QMetaType::UInt: {
+ bool ok = false;
+ uint u = value.toUInt(&ok);
+ return {ok, ok && property.writeProperty(object, &u, flags)};
+ }
+ case QMetaType::Double: {
+ bool ok = false;
+ double d = value.toDouble(&ok);
+ return {ok, ok && property.writeProperty(object, &d, flags)};
+ }
+ case QMetaType::Float: {
+ bool ok = false;
+ float f = value.toFloat(&ok);
+ return {ok, ok && property.writeProperty(object, &f, flags)};
+ }
+ case QMetaType::QString:
+ if (value.canConvert(propertyMetaType)) {
+ QString s = value.toString();
+ return {true, property.writeProperty(object, &s, flags)};
+ }
+ return {false, false};
+ case QMetaType::QVariantMap:
+ if (value.canConvert(propertyMetaType)) {
+ QVariantMap m = value.toMap();
+ return {true, property.writeProperty(object, &m, flags)};
+ }
+ return {false, false};
+ default: {
+ break;
+ }
+ }
+
+ QVariant converted = QQmlValueTypeProvider::createValueType(value, propertyMetaType);
+ if (!converted.isValid()) {
+ converted = QVariant(propertyMetaType);
+ if (!QMetaType::convert(value.metaType(), value.constData(),
+ propertyMetaType, converted.data())) {
+ return {false, false};
+ }
+ }
+ return {true, property.writeProperty(object, converted.data(), flags)};
+};
+
+template<typename Op>
+bool iterateQObjectContainer(QMetaType metaType, const void *data, Op op)
+{
+ QSequentialIterable iterable;
+ if (!QMetaType::convert(metaType, data, QMetaType::fromType<QSequentialIterable>(), &iterable))
+ return false;
+
+ const QMetaSequence metaSequence = iterable.metaContainer();
+
+ if (!metaSequence.hasConstIterator()
+ || !metaSequence.canGetValueAtConstIterator()
+ || !iterable.valueMetaType().flags().testFlag(QMetaType::PointerToQObject)) {
+ return false;
+ }
+
+ const void *container = iterable.constIterable();
+ void *it = metaSequence.constBegin(container);
+ const void *end = metaSequence.constEnd(container);
+ QObject *o = nullptr;
+ while (!metaSequence.compareConstIterator(it, end)) {
+ metaSequence.valueAtConstIterator(it, &o);
+ op(o);
+ metaSequence.advanceConstIterator(it, 1);
+ }
+ metaSequence.destroyConstIterator(it);
+ metaSequence.destroyConstIterator(end);
+ return true;
+}
+
+bool QQmlPropertyPrivate::write(
+ QObject *object, const QQmlPropertyData &property, const QVariant &value,
+ const QQmlRefPointer<QQmlContextData> &context, QQmlPropertyData::WriteFlags flags)
{
- const int propertyType = property.propType();
- const int variantType = value.userType();
+ const QMetaType propertyMetaType = property.propType();
+ const QMetaType variantMetaType = value.metaType();
+
+ const BindingFixer bindingFixer(object, property, flags);
if (property.isEnum()) {
QMetaProperty prop = object->metaObject()->property(property.coreIndex());
QVariant v = value;
// Enum values come through the script engine as doubles
- if (variantType == QVariant::Double) {
+ if (variantMetaType == QMetaType::fromType<double>()) {
double integral;
double fractional = std::modf(value.toDouble(), &integral);
if (qFuzzyIsNull(fractional))
- v.convert(QVariant::Int);
+ v.convert(QMetaType::fromType<qint32>());
}
return writeEnumProperty(prop, property.coreIndex(), object, v, flags);
}
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context);
- const bool isUrl = propertyType == QVariant::Url; // handled separately
+ const bool isUrl = propertyMetaType == QMetaType::fromType<QUrl>(); // handled separately
// The cases below are in approximate order of likelyhood:
- if (propertyType == variantType && !isUrl && propertyType != qMetaTypeId<QList<QUrl>>() && !property.isQList()) {
+ if (propertyMetaType == variantMetaType && !isUrl
+ && propertyMetaType != QMetaType::fromType<QList<QUrl>>() && !property.isQList()) {
return property.writeProperty(object, const_cast<void *>(value.constData()), flags);
} else if (property.isQObject()) {
QVariant val = value;
- int varType = variantType;
- if (variantType == QMetaType::Nullptr) {
+ QMetaType varType;
+ if (variantMetaType == QMetaType::fromType<std::nullptr_t>()) {
// This reflects the fact that you can assign a nullptr to a QObject pointer
// Without the change to QObjectStar, rawMetaObjectForType would not give us a QQmlMetaObject
- varType = QMetaType::QObjectStar;
- val = QVariant(QMetaType::QObjectStar, nullptr);
+ varType = QMetaType::fromType<QObject*>();
+ val = QVariant(varType, nullptr);
+ } else {
+ varType = variantMetaType;
}
- QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, varType);
- if (valMo.isNull())
+ QQmlMetaObject valMo = rawMetaObjectForType(varType);
+ if (valMo.isNull() || !varType.flags().testFlag(QMetaType::PointerToQObject))
return false;
QObject *o = *static_cast<QObject *const *>(val.constData());
- QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType);
+ QQmlMetaObject propMo = rawMetaObjectForType(propertyMetaType);
if (o)
valMo = o;
@@ -1243,165 +1529,189 @@ bool QQmlPropertyPrivate::write(QObject *object,
} else {
return false;
}
- } else if (value.canConvert(propertyType) && !isUrl && variantType != QVariant::String && propertyType != qMetaTypeId<QList<QUrl>>() && !property.isQList()) {
- // common cases:
- switch (propertyType) {
- case QMetaType::Bool: {
- bool b = value.toBool();
- return property.writeProperty(object, &b, flags);
- }
- case QMetaType::Int: {
- int i = value.toInt();
- return property.writeProperty(object, &i, flags);
- }
- case QMetaType::Double: {
- double d = value.toDouble();
- return property.writeProperty(object, &d, flags);
- }
- case QMetaType::Float: {
- float f = value.toFloat();
- return property.writeProperty(object, &f, flags);
- }
- case QMetaType::QString: {
- QString s = value.toString();
- return property.writeProperty(object, &s, flags);
- }
- default: { // "fallback":
- QVariant v = value;
- v.convert(propertyType);
- return property.writeProperty(object, const_cast<void *>(v.constData()), flags);
- }
- }
- } else if (propertyType == qMetaTypeId<QVariant>()) {
+ } else if (ConvertAndAssignResult result = tryConvertAndAssign(
+ object, property, value, flags, propertyMetaType, variantMetaType, isUrl)) {
+ return result.couldWrite;
+ } else if (propertyMetaType == QMetaType::fromType<QVariant>()) {
return property.writeProperty(object, const_cast<QVariant *>(&value), flags);
} else if (isUrl) {
QUrl u;
- if (variantType == QVariant::Url) {
+ if (variantMetaType == QMetaType::fromType<QUrl>()) {
u = value.toUrl();
- } else if (variantType == QVariant::ByteArray) {
- QString input(QString::fromUtf8(value.toByteArray()));
- // Encoded dir-separators defeat QUrl processing - decode them first
- input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
- u = QUrl(input);
- } else if (variantType == QVariant::String) {
- QString input(value.toString());
- // Encoded dir-separators defeat QUrl processing - decode them first
- input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
- u = QUrl(input);
- } else {
- return false;
+ if (compatResolveUrlsOnAssigment() && context && u.isRelative() && !u.isEmpty())
+ u = context->resolvedUrl(u);
}
+ else if (variantMetaType == QMetaType::fromType<QByteArray>())
+ u = QUrl(QString::fromUtf8(value.toByteArray()));
+ else if (variantMetaType == QMetaType::fromType<QString>())
+ u = QUrl(value.toString());
+ else
+ return false;
- if (context && u.isRelative() && !u.isEmpty())
- u = context->resolvedUrl(u);
return property.writeProperty(object, &u, flags);
- } else if (propertyType == qMetaTypeId<QList<QUrl>>()) {
- QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl>>();
+ } else if (propertyMetaType == QMetaType::fromType<QList<QUrl>>()) {
+ QList<QUrl> urlSeq = compatResolveUrlsOnAssigment()
+ ? urlSequence(value, context)
+ : urlSequence(value);
return property.writeProperty(object, &urlSeq, flags);
} else if (property.isQList()) {
- QQmlMetaObject listType;
-
- if (enginePriv) {
- listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType()));
- } else {
- QQmlType type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType()));
- if (!type.isValid())
+ if (propertyMetaType.flags() & QMetaType::IsQmlList) {
+ QMetaType listValueType = QQmlMetaType::listValueType(propertyMetaType);
+ QQmlMetaObject valueMetaObject = QQmlMetaType::rawMetaObjectForType(listValueType);
+ if (valueMetaObject.isNull())
return false;
- listType = type.baseMetaObject();
- }
- if (listType.isNull())
- return false;
- QQmlListProperty<void> prop;
- property.readProperty(object, &prop);
+ QQmlListProperty<QObject> prop;
+ property.readProperty(object, &prop);
- if (!prop.clear)
- return false;
+ if (!prop.clear || !prop.append)
+ return false;
- prop.clear(&prop);
+ const bool useNonsignalingListOps = prop.clear == &QQmlVMEMetaObject::list_clear
+ && prop.append == &QQmlVMEMetaObject::list_append;
- if (variantType == qMetaTypeId<QQmlListReference>()) {
- QQmlListReference qdlr = value.value<QQmlListReference>();
+ auto propClear =
+ useNonsignalingListOps ? &QQmlVMEMetaObject::list_clear_nosignal : prop.clear;
+ auto propAppend =
+ useNonsignalingListOps ? &QQmlVMEMetaObject::list_append_nosignal : prop.append;
- for (int ii = 0; ii < qdlr.count(); ++ii) {
- QObject *o = qdlr.at(ii);
- if (o && !QQmlMetaObject::canConvert(o, listType))
- o = nullptr;
- prop.append(&prop, o);
- }
- } else if (variantType == qMetaTypeId<QList<QObject *> >()) {
- const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
+ propClear(&prop);
- for (int ii = 0; ii < list.count(); ++ii) {
- QObject *o = list.at(ii);
- if (o && !QQmlMetaObject::canConvert(o, listType))
+ const auto doAppend = [&](QObject *o) {
+ if (o && !QQmlMetaObject::canConvert(o, valueMetaObject))
o = nullptr;
- prop.append(&prop, o);
+ propAppend(&prop, o);
+ };
+
+ if (variantMetaType == QMetaType::fromType<QQmlListReference>()) {
+ QQmlListReference qdlr = value.value<QQmlListReference>();
+ for (qsizetype ii = 0; ii < qdlr.count(); ++ii)
+ doAppend(qdlr.at(ii));
+ } else if (variantMetaType == QMetaType::fromType<QList<QObject *>>()) {
+ const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value);
+ for (qsizetype ii = 0; ii < list.size(); ++ii)
+ doAppend(list.at(ii));
+ } else if (variantMetaType == QMetaType::fromType<QList<QVariant>>()) {
+ const QList<QVariant> &list
+ = *static_cast<const QList<QVariant> *>(value.constData());
+ for (const QVariant &entry : list)
+ doAppend(QQmlMetaType::toQObject(entry));
+ } else if (!iterateQObjectContainer(variantMetaType, value.data(), doAppend)) {
+ doAppend(QQmlMetaType::toQObject(value));
+ }
+ if (useNonsignalingListOps) {
+ Q_ASSERT(QQmlVMEMetaObject::get(object));
+ QQmlVMEResolvedList(&prop).activateSignal();
}
+ } else if (variantMetaType == propertyMetaType) {
+ QVariant v = value;
+ property.writeProperty(object, v.data(), flags);
} else {
- QObject *o = enginePriv?enginePriv->toQObject(value):QQmlMetaType::toQObject(value);
- if (o && !QQmlMetaObject::canConvert(o, listType))
- o = nullptr;
- prop.append(&prop, o);
+ QVariant list(propertyMetaType);
+ const QQmlType type = QQmlMetaType::qmlType(propertyMetaType);
+ const QMetaSequence sequence = type.listMetaSequence();
+ if (sequence.canAddValue())
+ sequence.addValue(list.data(), value.data());
+ property.writeProperty(object, list.data(), flags);
}
+ } else if (enginePriv && propertyMetaType == QMetaType::fromType<QJSValue>()) {
+ // We can convert everything into a QJSValue if we have an engine.
+ QJSValue jsValue = QJSValuePrivate::fromReturnedValue(
+ enginePriv->v4engine()->metaTypeToJS(variantMetaType, value.constData()));
+ return property.writeProperty(object, &jsValue, flags);
} else {
- Q_ASSERT(variantType != propertyType);
+ Q_ASSERT(variantMetaType != propertyMetaType);
bool ok = false;
QVariant v;
- if (variantType == QVariant::String)
- v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
+ if (variantMetaType == QMetaType::fromType<QString>())
+ v = QQmlStringConverters::variantFromString(value.toString(), propertyMetaType, &ok);
if (!ok) {
v = value;
- if (v.convert(propertyType)) {
+ if (v.convert(propertyMetaType)) {
ok = true;
- } else if (v.isValid() && value.isNull()) {
- // For historical reasons converting a null QVariant to another type will do the trick
- // but return false anyway. This is caught with the above condition and considered a
- // successful conversion.
- Q_ASSERT(v.userType() == propertyType);
- ok = true;
- } else if (static_cast<uint>(propertyType) >= QVariant::UserType &&
- variantType == QVariant::String) {
- QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType);
- if (con) {
- v = con(value.toString());
- if (v.userType() == propertyType)
- ok = true;
- }
}
}
if (!ok) {
- // the only other option is that they are assigning a single value
- // to a sequence type property (eg, an int to a QList<int> property).
+ // the only other options are that they are assigning a single value
+ // or a QVariantList to a sequence type property (eg, an int to a
+ // QList<int> property) or that we encountered an interface type.
// Note that we've already handled single-value assignment to QList<QUrl> properties.
- if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
- QList<int> list;
- list << value.toInt();
- v = QVariant::fromValue<QList<int> >(list);
- ok = true;
- } else if ((variantType == QVariant::Double || variantType == QVariant::Int)
- && (propertyType == qMetaTypeId<QList<qreal> >())) {
- QList<qreal> list;
- list << value.toReal();
- v = QVariant::fromValue<QList<qreal> >(list);
- ok = true;
- } else if (variantType == QVariant::Bool && propertyType == qMetaTypeId<QList<bool> >()) {
- QList<bool> list;
- list << value.toBool();
- v = QVariant::fromValue<QList<bool> >(list);
- ok = true;
- } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QList<QString> >()) {
- QList<QString> list;
- list << value.toString();
- v = QVariant::fromValue<QList<QString> >(list);
- ok = true;
- } else if (variantType == QVariant::String && propertyType == qMetaTypeId<QStringList>()) {
- QStringList list;
- list << value.toString();
- v = QVariant::fromValue<QStringList>(list);
- ok = true;
+ QSequentialIterable iterable;
+ v = QVariant(propertyMetaType);
+ if (QMetaType::view(
+ propertyMetaType, v.data(),
+ QMetaType::fromType<QSequentialIterable>(),
+ &iterable)) {
+ const QMetaSequence propertyMetaSequence = iterable.metaContainer();
+ if (propertyMetaSequence.canAddValueAtEnd()) {
+ const QMetaType elementMetaType = iterable.valueMetaType();
+ void *propertyContainer = iterable.mutableIterable();
+
+ if (variantMetaType == elementMetaType) {
+ propertyMetaSequence.addValueAtEnd(propertyContainer, value.constData());
+ ok = true;
+ } else if (variantMetaType == QMetaType::fromType<QVariantList>()) {
+ const QVariantList list = value.value<QVariantList>();
+ for (const QVariant &valueElement : list) {
+ if (valueElement.metaType() == elementMetaType) {
+ propertyMetaSequence.addValueAtEnd(
+ propertyContainer, valueElement.constData());
+ } else {
+ QVariant converted(elementMetaType);
+ QMetaType::convert(
+ valueElement.metaType(), valueElement.constData(),
+ elementMetaType, converted.data());
+ propertyMetaSequence.addValueAtEnd(
+ propertyContainer, converted.constData());
+ }
+ }
+ ok = true;
+ } else if (elementMetaType.flags().testFlag(QMetaType::PointerToQObject)) {
+ const QMetaObject *elementMetaObject = elementMetaType.metaObject();
+ Q_ASSERT(elementMetaObject);
+
+ const auto doAppend = [&](QObject *o) {
+ QObject *casted = elementMetaObject->cast(o);
+ propertyMetaSequence.addValueAtEnd(propertyContainer, &casted);
+ };
+
+ if (variantMetaType.flags().testFlag(QMetaType::PointerToQObject)) {
+ doAppend(*static_cast<QObject *const *>(value.data()));
+ ok = true;
+ } else if (variantMetaType == QMetaType::fromType<QQmlListReference>()) {
+ const QQmlListReference *reference
+ = static_cast<const QQmlListReference *>(value.constData());
+ Q_ASSERT(elementMetaObject);
+ for (int i = 0, end = reference->size(); i < end; ++i)
+ doAppend(reference->at(i));
+ ok = true;
+ } else if (!iterateQObjectContainer(
+ variantMetaType, value.data(), doAppend)) {
+ doAppend(QQmlMetaType::toQObject(value));
+ }
+ } else {
+ QVariant converted = value;
+ if (converted.convert(elementMetaType)) {
+ propertyMetaSequence.addValueAtEnd(propertyContainer, converted.constData());
+ ok = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (!ok && QQmlMetaType::isInterface(propertyMetaType)) {
+ auto valueAsQObject = qvariant_cast<QObject *>(value);
+
+ if (void *iface = valueAsQObject
+ ? valueAsQObject->qt_metacast(QQmlMetaType::interfaceIId(propertyMetaType))
+ : nullptr;
+ iface) {
+ // this case can occur when object has an interface type
+ // and the variant contains a type implementing the interface
+ return property.writeProperty(object, &iface, flags);
}
}
@@ -1415,17 +1725,22 @@ bool QQmlPropertyPrivate::write(QObject *object,
return true;
}
-QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType)
+bool QQmlPropertyPrivate::reset(
+ QObject *object, const QQmlPropertyData &property,
+ QQmlPropertyData::WriteFlags flags)
{
- QMetaType metaType(userType);
- if ((metaType.flags() & QMetaType::PointerToQObject) && metaType.metaObject())
- return metaType.metaObject();
- if (engine)
- return engine->rawMetaObjectForType(userType);
- QQmlType type = QQmlMetaType::qmlType(userType);
- if (type.isValid())
- return QQmlMetaObject(type.baseMetaObject());
- return QQmlMetaObject();
+ const BindingFixer bindingFixer(object, property, flags);
+ property.resetProperty(object, flags);
+ return true;
+}
+
+QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QMetaType metaType)
+{
+ if (metaType.flags() & QMetaType::PointerToQObject) {
+ if (const QMetaObject *metaObject = metaType.metaObject())
+ return metaObject;
+ }
+ return QQmlMetaType::rawMetaObjectForType(metaType);
}
/*!
@@ -1435,7 +1750,7 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi
*/
bool QQmlProperty::write(const QVariant &value) const
{
- return QQmlPropertyPrivate::write(*this, value, nullptr);
+ return QQmlPropertyPrivate::write(*this, value, {});
}
/*!
@@ -1608,14 +1923,15 @@ QQmlPropertyIndex QQmlPropertyPrivate::propertyIndex(const QQmlProperty &that)
QQmlProperty
QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data,
- const QQmlPropertyData *valueTypeData, QQmlContextData *ctxt)
+ const QQmlPropertyData *valueTypeData,
+ const QQmlRefPointer<QQmlContextData> &ctxt)
{
QQmlProperty prop;
prop.d = new QQmlPropertyPrivate;
prop.d->object = object;
prop.d->context = ctxt;
- prop.d->engine = ctxt ? ctxt->engine : nullptr;
+ prop.d->engine = ctxt ? ctxt->engine() : nullptr;
prop.d->core = data;
if (valueTypeData)
@@ -1640,9 +1956,8 @@ QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const Q
// If no signal is found, but the signal is of the form "onBlahChanged",
// return the notify signal for the property "Blah"
- if (name.endsWith("Changed")) {
- QByteArray propName = name.mid(0, name.length() - 7);
- int propIdx = mo->indexOfProperty(propName.constData());
+ if (auto propName = QQmlSignalNames::changedSignalNameToPropertyName(name)) {
+ int propIdx = mo->indexOfProperty(propName->constData());
if (propIdx >= 0) {
QMetaProperty prop = mo->property(propIdx);
if (prop.hasNotifySignal())
@@ -1653,6 +1968,16 @@ QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const Q
return QMetaMethod();
}
+/*!
+ Return the property corresponding to \a name
+*/
+QMetaProperty QQmlPropertyPrivate::findPropertyByName(const QMetaObject *mo, const QByteArray &name)
+{
+ Q_ASSERT(mo);
+ const int i = mo->indexOfProperty(name);
+ return i < 0 ? QMetaProperty() : mo->property(i);
+}
+
/*! \internal
If \a indexInSignalRange is true, \a index is treated as a signal index
(see QObjectPrivate::signalIndex()), otherwise it is treated as a
@@ -1662,7 +1987,7 @@ static inline void flush_vme_signal(const QObject *object, int index, bool index
{
QQmlData *data = QQmlData::get(object);
if (data && data->propertyCache) {
- QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index)
+ const QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index)
: data->propertyCache->method(index);
if (property && property->isVMESignal()) {
@@ -1705,3 +2030,5 @@ void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlproperty.cpp"
diff --git a/src/qml/qml/qqmlproperty.h b/src/qml/qml/qqmlproperty.h
index 34eab8208c..0878034bab 100644
--- a/src/qml/qml/qqmlproperty.h
+++ b/src/qml/qml/qqmlproperty.h
@@ -1,47 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTY_H
#define QQMLPROPERTY_H
+#include <QtCore/qstring.h>
+#include <QtCore/qhashfunctions.h>
#include <QtQml/qtqmlglobal.h>
#include <QtCore/qmetaobject.h>
+#include <QtQml/qqmlregistration.h>
QT_BEGIN_NAMESPACE
@@ -54,6 +21,12 @@ class QQmlEngine;
class QQmlPropertyPrivate;
class Q_QML_EXPORT QQmlProperty
{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_ADDED_IN_VERSION(2, 15)
+
+ Q_PROPERTY(QObject *object READ object CONSTANT FINAL)
+ Q_PROPERTY(QString name READ name CONSTANT FINAL)
public:
enum PropertyTypeCategory {
InvalidCategory,
@@ -82,6 +55,10 @@ public:
QQmlProperty(const QQmlProperty &);
QQmlProperty &operator=(const QQmlProperty &);
+ QQmlProperty(QQmlProperty &&other) noexcept : d(std::exchange(other.d, nullptr)) {}
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QQmlProperty)
+
+ void swap(QQmlProperty &other) noexcept { qt_ptr_swap(d, other.d); }
bool operator==(const QQmlProperty &) const;
Type type() const;
@@ -90,6 +67,7 @@ public:
bool isSignalProperty() const;
int propertyType() const;
+ QMetaType propertyMetaType() const;
PropertyTypeCategory propertyTypeCategory() const;
const char *propertyTypeName() const;
@@ -113,6 +91,7 @@ public:
bool connectNotifySignal(QObject *dest, int method) const;
bool isWritable() const;
+ bool isBindable() const;
bool isDesignable() const;
bool isResettable() const;
QObject *object() const;
@@ -123,16 +102,16 @@ public:
private:
friend class QQmlPropertyPrivate;
- QQmlPropertyPrivate *d;
+ QQmlPropertyPrivate *d = nullptr;
};
typedef QList<QQmlProperty> QQmlProperties;
-inline uint qHash (const QQmlProperty &key)
+inline size_t qHash (const QQmlProperty &key, size_t seed = 0)
{
- return qHash(key.object()) + qHash(key.name());
+ return qHashMulti(seed, key.object(), key.name());
}
-Q_DECLARE_TYPEINFO(QQmlProperty, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QQmlProperty, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index 285c34d7fa..fd07547d60 100644
--- a/src/qml/qml/qqmlproperty_p.h
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTY_P_H
#define QQMLPROPERTY_P_H
@@ -52,14 +16,17 @@
//
#include "qqmlproperty.h"
-#include "qqmlengine.h"
#include <private/qobject_p.h>
-#include <private/qtqmlglobal_p.h>
-#include <private/qqmlrefcount_p.h>
-#include <private/qqmlcontext_p.h>
-#include <private/qqmlboundsignalexpressionpointer_p.h>
+#include <private/qqmlcontextdata_p.h>
#include <private/qqmlpropertydata_p.h>
+#include <private/qqmlpropertyindex_p.h>
+#include <private/qqmlrefcount_p.h>
+#include <private/qtqmlglobal_p.h>
+
+#include <QtQml/qqmlengine.h>
+
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -67,51 +34,81 @@ class QQmlContext;
class QQmlEnginePrivate;
class QQmlJavaScriptExpression;
class QQmlMetaObject;
+class QQmlAbstractBinding;
+class QQmlBoundSignalExpression;
-class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount
+class Q_QML_EXPORT QQmlPropertyPrivate final : public QQmlRefCounted<QQmlPropertyPrivate>
{
public:
- QQmlContextData *context;
+ enum class InitFlag {
+ None = 0x0,
+ AllowId = 0x1,
+ AllowSignal = 0x2
+ };
+ Q_DECLARE_FLAGS(InitFlags, InitFlag);
+
+ QQmlRefPointer<QQmlContextData> context;
QPointer<QQmlEngine> engine;
QPointer<QObject> object;
QQmlPropertyData core;
QQmlPropertyData valueTypeData;
- bool isNameCached:1;
QString nameCache;
- QQmlPropertyPrivate();
+ // ### Qt7: Get rid of this.
+ static bool resolveUrlsOnAssignment();
+
+ QQmlPropertyPrivate() {}
QQmlPropertyIndex encodedIndex() const
{ return encodedIndex(core, valueTypeData); }
static QQmlPropertyIndex encodedIndex(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData)
{ return QQmlPropertyIndex(core.coreIndex(), valueTypeData.coreIndex()); }
- inline QQmlContextData *effectiveContext() const;
+ QQmlRefPointer<QQmlContextData> effectiveContext() const;
- void initProperty(QObject *obj, const QString &name);
+ void initProperty(QObject *obj, const QString &name, InitFlags flags = InitFlag::None);
void initDefault(QObject *obj);
bool isValueType() const;
- int propertyType() const;
+ QMetaType propertyType() const;
QQmlProperty::Type type() const;
QQmlProperty::PropertyTypeCategory propertyTypeCategory() const;
QVariant readValueProperty();
bool writeValueProperty(const QVariant &, QQmlPropertyData::WriteFlags);
- static QQmlMetaObject rawMetaObjectForType(QQmlEnginePrivate *, int);
+ static QQmlMetaObject rawMetaObjectForType(QMetaType metaType);
static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object,
const QVariant &value, int flags);
static bool writeValueProperty(QObject *,
const QQmlPropertyData &, const QQmlPropertyData &valueTypeData,
- const QVariant &, QQmlContextData *,
- QQmlPropertyData::WriteFlags flags = nullptr);
+ const QVariant &, const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData::WriteFlags flags = {});
+ static bool resetValueProperty(QObject *,
+ const QQmlPropertyData &, const QQmlPropertyData &valueTypeData,
+ const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData::WriteFlags flags = {});
static bool write(QObject *, const QQmlPropertyData &, const QVariant &,
- QQmlContextData *, QQmlPropertyData::WriteFlags flags = nullptr);
+ const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData::WriteFlags flags = {});
+ static bool reset(QObject *, const QQmlPropertyData &,
+ QQmlPropertyData::WriteFlags flags = {});
static void findAliasTarget(QObject *, QQmlPropertyIndex, QObject **, QQmlPropertyIndex *);
+ struct ResolvedAlias
+ {
+ QObject *targetObject;
+ QQmlPropertyIndex targetIndex;
+ };
+ /*!
+ \internal
+ Given an alias property specified by \a baseObject and \a baseIndex, this function
+ computes the alias target.
+ */
+ static ResolvedAlias findAliasTarget(QObject *baseObject, QQmlPropertyIndex baseIndex);
+
enum BindingFlag {
None = 0,
DontEnable = 0x1
@@ -126,7 +123,8 @@ public:
static void removeBinding(QQmlAbstractBinding *b);
static QQmlAbstractBinding *binding(QObject *, QQmlPropertyIndex index);
- static QQmlProperty restore(QObject *, const QQmlPropertyData &, const QQmlPropertyData *, QQmlContextData *);
+ static QQmlProperty restore(QObject *, const QQmlPropertyData &, const QQmlPropertyData *,
+ const QQmlRefPointer<QQmlContextData> &);
int signalIndex() const;
@@ -141,17 +139,24 @@ public:
static bool write(const QQmlProperty &that, const QVariant &, QQmlPropertyData::WriteFlags);
static QQmlPropertyIndex propertyIndex(const QQmlProperty &that);
static QMetaMethod findSignalByName(const QMetaObject *mo, const QByteArray &);
+ static QMetaProperty findPropertyByName(const QMetaObject *mo, const QByteArray &);
static bool connect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index,
int type = 0, int *types = nullptr);
static void flushSignal(const QObject *sender, int signal_index);
- static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context);
- static QQmlProperty create(QObject *target, const QString &propertyName, QQmlContextData *context);
+ static QList<QUrl> urlSequence(const QVariant &value);
+ static QList<QUrl> urlSequence(
+ const QVariant &value, const QQmlRefPointer<QQmlContextData> &ctxt);
+ static QQmlProperty create(
+ QObject *target, const QString &propertyName,
+ const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyPrivate::InitFlags flags);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::BindingFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::InitFlags);
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertybinding.cpp b/src/qml/qml/qqmlpropertybinding.cpp
new file mode 100644
index 0000000000..c8a7e6256a
--- /dev/null
+++ b/src/qml/qml/qqmlpropertybinding.cpp
@@ -0,0 +1,383 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmlpropertybinding_p.h"
+
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlglobal_p.h>
+#include <private/qqmlscriptstring_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4jscall_p.h>
+#include <private/qv4qmlcontext_p.h>
+
+#include <QtQml/qqmlinfo.h>
+
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::Literals::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcQQPropertyBinding, "qt.qml.propertybinding");
+
+QUntypedPropertyBinding QQmlPropertyBinding::create(const QQmlPropertyData *pd, QV4::Function *function,
+ QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::ExecutionContext *scope, QObject *target, QQmlPropertyIndex targetIndex)
+{
+ Q_ASSERT(pd);
+ return create(pd->propType(), function, obj, ctxt, scope, target, targetIndex);
+}
+
+QUntypedPropertyBinding QQmlPropertyBinding::create(QMetaType propertyType, QV4::Function *function,
+ QObject *obj,
+ const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::ExecutionContext *scope, QObject *target,
+ QQmlPropertyIndex targetIndex)
+{
+ auto buffer = new std::byte[QQmlPropertyBinding::getSizeEnsuringAlignment()
+ + sizeof(QQmlPropertyBindingJS)+jsExpressionOffsetLength()]; // QQmlPropertyBinding uses delete[]
+ auto binding = new (buffer) QQmlPropertyBinding(propertyType, target, targetIndex,
+ TargetData::WithoutBoundFunction);
+ auto js = new(buffer + QQmlPropertyBinding::getSizeEnsuringAlignment() + jsExpressionOffsetLength()) QQmlPropertyBindingJS();
+ Q_ASSERT(binding->jsExpression() == js);
+ Q_ASSERT(js->asBinding() == binding);
+ Q_UNUSED(js);
+ binding->jsExpression()->setNotifyOnValueChanged(true);
+ binding->jsExpression()->setContext(ctxt);
+ binding->jsExpression()->setScopeObject(obj);
+ binding->jsExpression()->setupFunction(scope, function);
+ return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(QPropertyBindingPrivatePtr(binding).data()));
+}
+
+QUntypedPropertyBinding QQmlPropertyBinding::createFromCodeString(const QQmlPropertyData *pd, const QString& str, QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt, const QString &url, quint16 lineNumber, QObject *target, QQmlPropertyIndex targetIndex)
+{
+ auto buffer = new std::byte[QQmlPropertyBinding::getSizeEnsuringAlignment()
+ + sizeof(QQmlPropertyBindingJS)+jsExpressionOffsetLength()]; // QQmlPropertyBinding uses delete[]
+ auto binding = new(buffer) QQmlPropertyBinding(QMetaType(pd->propType()), target, targetIndex, TargetData::WithoutBoundFunction);
+ auto js = new(buffer + QQmlPropertyBinding::getSizeEnsuringAlignment() + jsExpressionOffsetLength()) QQmlPropertyBindingJS();
+ Q_ASSERT(binding->jsExpression() == js);
+ Q_ASSERT(js->asBinding() == binding);
+ Q_UNUSED(js);
+ binding->jsExpression()->setNotifyOnValueChanged(true);
+ binding->jsExpression()->setContext(ctxt);
+ binding->jsExpression()->createQmlBinding(ctxt, obj, str, url, lineNumber);
+ return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(QPropertyBindingPrivatePtr(binding).data()));
+}
+
+QUntypedPropertyBinding QQmlPropertyBinding::createFromScriptString(const QQmlPropertyData *property, const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt, QObject *target, QQmlPropertyIndex targetIndex)
+{
+ const QQmlScriptStringPrivate *scriptPrivate = script.d.data();
+ // without a valid context, we cannot create anything
+ if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid())) {
+ return {};
+ }
+
+ auto scopeObject = obj ? obj : scriptPrivate->scope;
+
+ QV4::Function *runtimeFunction = nullptr;
+ QString url;
+ QQmlRefPointer<QQmlContextData> ctxtdata = QQmlContextData::get(scriptPrivate->context);
+ QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
+ if (engine && ctxtdata && !ctxtdata->urlString().isEmpty() && ctxtdata->typeCompilationUnit()) {
+ url = ctxtdata->urlString();
+ if (scriptPrivate->bindingId != QQmlBinding::Invalid)
+ runtimeFunction = ctxtdata->typeCompilationUnit()->runtimeFunctions.at(scriptPrivate->bindingId);
+ }
+ // Do we actually have a function in the script string? If not, this becomes createCodeFromString
+ if (!runtimeFunction)
+ return createFromCodeString(property, scriptPrivate->script, obj, ctxtdata, url, scriptPrivate->lineNumber, target, targetIndex);
+
+ auto buffer = new std::byte[QQmlPropertyBinding::getSizeEnsuringAlignment()
+ + sizeof(QQmlPropertyBindingJS)+jsExpressionOffsetLength()]; // QQmlPropertyBinding uses delete[]
+ auto binding = new(buffer) QQmlPropertyBinding(QMetaType(property->propType()), target, targetIndex, TargetData::WithoutBoundFunction);
+ auto js = new(buffer + QQmlPropertyBinding::getSizeEnsuringAlignment() + jsExpressionOffsetLength()) QQmlPropertyBindingJS();
+ Q_ASSERT(binding->jsExpression() == js);
+ Q_ASSERT(js->asBinding() == binding);
+ js->setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
+
+ QV4::ExecutionEngine *v4 = engine->v4engine();
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxtdata, scopeObject));
+ js->setupFunction(qmlContext, runtimeFunction);
+ return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(QPropertyBindingPrivatePtr(binding).data()));
+}
+
+QUntypedPropertyBinding QQmlPropertyBinding::createFromBoundFunction(const QQmlPropertyData *pd, QV4::BoundFunction *function, QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope, QObject *target, QQmlPropertyIndex targetIndex)
+{
+ auto buffer = new std::byte[QQmlPropertyBinding::getSizeEnsuringAlignment()
+ + sizeof(QQmlPropertyBindingJSForBoundFunction)+jsExpressionOffsetLength()]; // QQmlPropertyBinding uses delete[]
+ auto binding = new(buffer) QQmlPropertyBinding(QMetaType(pd->propType()), target, targetIndex, TargetData::HasBoundFunction);
+ auto js = new(buffer + QQmlPropertyBinding::getSizeEnsuringAlignment() + jsExpressionOffsetLength()) QQmlPropertyBindingJSForBoundFunction();
+ Q_ASSERT(binding->jsExpression() == js);
+ Q_ASSERT(js->asBinding() == binding);
+ Q_UNUSED(js);
+ binding->jsExpression()->setNotifyOnValueChanged(true);
+ binding->jsExpression()->setContext(ctxt);
+ binding->jsExpression()->setScopeObject(obj);
+ binding->jsExpression()->setupFunction(scope, function->function());
+ js->m_boundFunction.set(function->engine(), *function);
+ return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(QPropertyBindingPrivatePtr(binding).data()));
+}
+
+/*!
+ \fn bool QQmlPropertyBindingJS::hasDependencies()
+ \internal
+
+ Returns true if this binding has dependencies.
+ Dependencies can be either QProperty dependencies or dependencies of
+ the JS expression (aka activeGuards). Translations end up as a QProperty
+ dependency, so they do not need any special handling
+ Note that a QQmlPropertyBinding never stores qpropertyChangeTriggers.
+ */
+
+
+void QQmlPropertyBindingJS::expressionChanged()
+{
+ auto binding = asBinding();
+ if (!binding->propertyDataPtr)
+ return;
+ const auto currentTag = m_error.tag();
+ if (currentTag == InEvaluationLoop) {
+ QQmlError err;
+ auto location = QQmlJavaScriptExpression::sourceLocation();
+ err.setUrl(QUrl{location.sourceFile});
+ err.setLine(location.line);
+ err.setColumn(location.column);
+ const auto ctxt = context();
+ QQmlEngine *engine = ctxt ? ctxt->engine() : nullptr;
+ if (engine)
+ err.setDescription(asBinding()->createBindingLoopErrorDescription());
+ else
+ err.setDescription(QString::fromLatin1("Binding loop detected"));
+ err.setObject(asBinding()->target());
+ qmlWarning(this->scopeObject(), err);
+ return;
+ }
+ m_error.setTag(InEvaluationLoop);
+ PendingBindingObserverList bindingObservers;
+ binding->evaluateRecursive(bindingObservers);
+ binding->notifyNonRecursive(bindingObservers);
+ m_error.setTag(NoTag);
+}
+
+QQmlPropertyBinding::QQmlPropertyBinding(QMetaType mt, QObject *target, QQmlPropertyIndex targetIndex, TargetData::BoundFunction hasBoundFunction)
+ : QPropertyBindingPrivate(mt,
+ bindingFunctionVTableForQQmlPropertyBinding(mt),
+ QPropertyBindingSourceLocation(), true)
+{
+ static_assert (std::is_trivially_destructible_v<TargetData>);
+ static_assert (sizeof(TargetData) + sizeof(DeclarativeErrorCallback) <= sizeof(QPropertyBindingSourceLocation));
+ static_assert (alignof(TargetData) <= alignof(QPropertyBindingSourceLocation));
+ const auto state = hasBoundFunction ? TargetData::HasBoundFunction : TargetData::WithoutBoundFunction;
+ new (&declarativeExtraData) TargetData {target, targetIndex, state};
+ errorCallBack = bindingErrorCallback;
+}
+
+static QtPrivate::QPropertyBindingData *bindingDataFromPropertyData(QUntypedPropertyData *dataPtr, QMetaType type)
+{
+ // XXX Qt 7: We need a clean way to access the binding data
+ /* This function makes the (dangerous) assumption that if we could not get the binding data
+ from the binding storage, we must have been handed a QProperty.
+ This does hold for anything a user could write, as there the only ways of providing a bindable property
+ are to use the Q_X_BINDABLE macros, or to directly expose a QProperty.
+ As long as we can ensure that any "fancier" property we implement is not resettable, we should be fine.
+ We procede to calculate the address of the binding data pointer from the address of the data pointer
+ */
+ Q_ASSERT(dataPtr);
+ std::byte *qpropertyPointer = reinterpret_cast<std::byte *>(dataPtr);
+ qpropertyPointer += type.sizeOf();
+ constexpr auto alignment = alignof(QtPrivate::QPropertyBindingData *);
+ auto aligned = (quintptr(qpropertyPointer) + alignment - 1) & ~(alignment - 1); // ensure pointer alignment
+ return reinterpret_cast<QtPrivate::QPropertyBindingData *>(aligned);
+}
+
+void QQmlPropertyBinding::handleUndefinedAssignment(QQmlEnginePrivate *ep, void *dataPtr)
+{
+ const QQmlPropertyData *propertyData = nullptr;
+ QQmlPropertyData valueTypeData;
+ QQmlData *data = QQmlData::get(target(), false);
+ Q_ASSERT(data);
+ if (Q_UNLIKELY(!data->propertyCache))
+ data->propertyCache = QQmlMetaType::propertyCache(target()->metaObject());
+
+ propertyData = data->propertyCache->property(targetIndex().coreIndex());
+ Q_ASSERT(propertyData);
+ Q_ASSERT(!targetIndex().hasValueTypeIndex());
+ QQmlProperty prop = QQmlPropertyPrivate::restore(target(), *propertyData, &valueTypeData, nullptr);
+ // helper function for writing back value into dataPtr
+ // this is necessary for QObjectCompatProperty, which doesn't give us the "real" dataPtr
+ // if we don't write the correct value, we would otherwise set the default constructed value
+ auto writeBackCurrentValue = [&](QVariant &&currentValue) {
+ if (currentValue.metaType() != valueMetaType())
+ currentValue.convert(valueMetaType());
+ auto metaType = valueMetaType();
+ metaType.destruct(dataPtr);
+ metaType.construct(dataPtr, currentValue.constData());
+ };
+ if (prop.isResettable()) {
+ // Normally a reset would remove any existing binding; but now we need to keep the binding alive
+ // to handle the case where this binding becomes defined again
+ // We therefore detach the binding, call reset, and reattach again
+ const auto storage = qGetBindingStorage(target());
+ auto bindingData = storage->bindingData(propertyDataPtr);
+ if (!bindingData)
+ bindingData = bindingDataFromPropertyData(propertyDataPtr, propertyData->propType());
+ QPropertyBindingDataPointer bindingDataPointer{bindingData};
+ auto firstObserver = takeObservers();
+ bindingData->d_ref() = 0;
+ if (firstObserver) {
+ bindingDataPointer.setObservers(firstObserver.ptr);
+ }
+ Q_ASSERT(!bindingData->hasBinding());
+ setIsUndefined(true);
+ //suspend binding evaluation state for reset and subsequent read
+ auto state = QtPrivate::suspendCurrentBindingStatus();
+ prop.reset(); // May re-allocate the bindingData
+ QVariant currentValue = QVariant(prop.propertyMetaType(), propertyDataPtr);
+ QtPrivate::restoreBindingStatus(state);
+ writeBackCurrentValue(std::move(currentValue));
+
+ // Re-fetch binding data
+ bindingData = storage->bindingData(propertyDataPtr);
+ if (!bindingData)
+ bindingData = bindingDataFromPropertyData(propertyDataPtr, propertyData->propType());
+ bindingDataPointer = QPropertyBindingDataPointer {bindingData};
+
+ // reattach the binding (without causing a new notification)
+ if (Q_UNLIKELY(bindingData->d() & QtPrivate::QPropertyBindingData::BindingBit)) {
+ qCWarning(lcQQPropertyBinding) << "Resetting " << prop.name() << "due to the binding becoming undefined caused a new binding to be installed\n"
+ << "The old binding binding will be abandoned";
+ deref();
+ return;
+ }
+ // reset might have changed observers (?), so refresh firstObserver
+ firstObserver = bindingDataPointer.firstObserver();
+ bindingData->d_ref() = reinterpret_cast<quintptr>(this) | QtPrivate::QPropertyBindingData::BindingBit;
+ if (firstObserver)
+ prependObserver(firstObserver);
+ } else {
+ QQmlError qmlError;
+ auto location = jsExpression()->sourceLocation();
+ qmlError.setColumn(location.column);
+ qmlError.setLine(location.line);
+ qmlError.setUrl(QUrl {location.sourceFile});
+ const QString description = QStringLiteral(R"(QML %1: Unable to assign [undefined] to "%2")").arg(QQmlMetaType::prettyTypeName(target()) , prop.name());
+ qmlError.setDescription(description);
+ qmlError.setObject(target());
+ ep->warning(qmlError);
+ }
+}
+
+QString QQmlPropertyBinding::createBindingLoopErrorDescription()
+{
+ const QQmlPropertyData *propertyData = nullptr;
+ QQmlPropertyData valueTypeData;
+ QQmlData *data = QQmlData::get(target(), false);
+ Q_ASSERT(data);
+ if (Q_UNLIKELY(!data->propertyCache))
+ data->propertyCache = QQmlMetaType::propertyCache(target()->metaObject());
+
+ propertyData = data->propertyCache->property(targetIndex().coreIndex());
+ Q_ASSERT(propertyData);
+ Q_ASSERT(!targetIndex().hasValueTypeIndex());
+ QQmlProperty prop = QQmlPropertyPrivate::restore(target(), *propertyData, &valueTypeData, nullptr);
+ return R"(QML %1: Binding loop detected for property "%2")"_L1.arg(QQmlMetaType::prettyTypeName(target()) , prop.name());
+}
+
+void QQmlPropertyBinding::bindingErrorCallback(QPropertyBindingPrivate *that)
+{
+ auto This = static_cast<QQmlPropertyBinding *>(that);
+ auto target = This->target();
+ auto engine = qmlEngine(target);
+ if (!engine)
+ return;
+
+ auto error = This->bindingError();
+ QQmlError qmlError;
+ auto location = This->jsExpression()->sourceLocation();
+ qmlError.setColumn(location.column);
+ qmlError.setLine(location.line);
+ qmlError.setUrl(QUrl {location.sourceFile});
+ auto description = error.description();
+ if (error.type() == QPropertyBindingError::BindingLoop) {
+ description = This->createBindingLoopErrorDescription();
+ }
+ qmlError.setDescription(description);
+ qmlError.setObject(target);
+ QQmlEnginePrivate::get(engine)->warning(qmlError);
+}
+
+template<typename TranslateWithUnit>
+auto qQmlTranslationPropertyBindingCreateBinding(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ TranslateWithUnit &&translateWithUnit)
+{
+ return [compilationUnit, translateWithUnit](QMetaType metaType, void *dataPtr) -> bool {
+ // Create a dependency to the translationLanguage
+ QQmlEnginePrivate::get(compilationUnit->engine)->translationLanguage.value();
+
+ QVariant resultVariant(translateWithUnit(compilationUnit));
+ if (metaType != QMetaType::fromType<QString>())
+ resultVariant.convert(metaType);
+
+ const bool hasChanged = !metaType.equals(resultVariant.constData(), dataPtr);
+ metaType.destruct(dataPtr);
+ metaType.construct(dataPtr, resultVariant.constData());
+ return hasChanged;
+ };
+}
+
+QUntypedPropertyBinding QQmlTranslationPropertyBinding::create(
+ const QQmlPropertyData *pd,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QV4::CompiledData::Binding *binding)
+{
+ auto translationBinding = qQmlTranslationPropertyBindingCreateBinding(
+ compilationUnit,
+ [binding](const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit) {
+ return compilationUnit->bindingValueAsString(binding);
+ });
+
+ return QUntypedPropertyBinding(QMetaType(pd->propType()), translationBinding,
+ QPropertyBindingSourceLocation());
+}
+
+QUntypedPropertyBinding QQmlTranslationPropertyBinding::create(
+ const QMetaType &propertyType,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlTranslation &translationData)
+{
+ auto translationBinding = qQmlTranslationPropertyBindingCreateBinding(
+ compilationUnit,
+ [translationData](
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit) {
+ Q_UNUSED(compilationUnit);
+ return translationData.translate();
+ });
+
+ return QUntypedPropertyBinding(propertyType, translationBinding,
+ QPropertyBindingSourceLocation());
+}
+
+QV4::ReturnedValue QQmlPropertyBindingJSForBoundFunction::evaluate(bool *isUndefined)
+{
+ QV4::ExecutionEngine *v4 = engine()->handle();
+ int argc = 0;
+ const QV4::Value *argv = nullptr;
+ const QV4::Value *thisObject = nullptr;
+ QV4::BoundFunction *b = nullptr;
+ if ((b = m_boundFunction.as<QV4::BoundFunction>())) {
+ QV4::Heap::MemberData *args = b->boundArgs();
+ if (args) {
+ argc = args->values.size;
+ argv = args->values.data();
+ }
+ thisObject = &b->d()->boundThis;
+ }
+ QV4::Scope scope(v4);
+ QV4::JSCallData jsCall(thisObject, argv, argc);
+
+ return QQmlJavaScriptExpression::evaluate(jsCall.callData(scope), isUndefined);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertybinding_p.h b/src/qml/qml/qqmlpropertybinding_p.h
new file mode 100644
index 0000000000..840239285e
--- /dev/null
+++ b/src/qml/qml/qqmlpropertybinding_p.h
@@ -0,0 +1,421 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLPROPERTYBINDING_P_H
+#define QQMLPROPERTYBINDING_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmljavascriptexpression_p.h>
+#include <private/qqmlpropertydata_p.h>
+#include <private/qv4alloca_p.h>
+#include <private/qqmltranslation_p.h>
+
+#include <QtCore/qproperty.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+ struct BoundFunction;
+}
+
+class QQmlPropertyBinding;
+class QQmlScriptString;
+
+class Q_QML_EXPORT QQmlPropertyBindingJS : public QQmlJavaScriptExpression
+{
+ bool mustCaptureBindableProperty() const final {return false;}
+
+ friend class QQmlPropertyBinding;
+ void expressionChanged() override;
+ QQmlPropertyBinding *asBinding()
+ {
+ return const_cast<QQmlPropertyBinding *>(static_cast<const QQmlPropertyBindingJS *>(this)->asBinding());
+ }
+
+ inline QQmlPropertyBinding const *asBinding() const;
+};
+
+class Q_QML_EXPORT QQmlPropertyBindingJSForBoundFunction : public QQmlPropertyBindingJS
+{
+public:
+ QV4::ReturnedValue evaluate(bool *isUndefined);
+ QV4::PersistentValue m_boundFunction;
+};
+
+class Q_QML_EXPORT QQmlPropertyBinding : public QPropertyBindingPrivate
+
+{
+ friend class QQmlPropertyBindingJS;
+
+ static constexpr std::size_t jsExpressionOffsetLength() {
+ struct composite { QQmlPropertyBinding b; QQmlPropertyBindingJS js; };
+ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF
+ return sizeof (QQmlPropertyBinding) - offsetof(composite, js);
+ QT_WARNING_POP
+ }
+
+public:
+
+ QQmlPropertyBindingJS *jsExpression()
+ {
+ return const_cast<QQmlPropertyBindingJS *>(static_cast<const QQmlPropertyBinding *>(this)->jsExpression());
+ }
+
+ QQmlPropertyBindingJS const *jsExpression() const
+ {
+ return std::launder(reinterpret_cast<QQmlPropertyBindingJS const *>(
+ reinterpret_cast<std::byte const*>(this)
+ + QPropertyBindingPrivate::getSizeEnsuringAlignment()
+ + jsExpressionOffsetLength()));
+ }
+
+ static QUntypedPropertyBinding create(const QQmlPropertyData *pd, QV4::Function *function,
+ QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::ExecutionContext *scope, QObject *target,
+ QQmlPropertyIndex targetIndex);
+ static QUntypedPropertyBinding create(QMetaType propertyType, QV4::Function *function,
+ QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::ExecutionContext *scope, QObject *target,
+ QQmlPropertyIndex targetIndex);
+ static QUntypedPropertyBinding createFromCodeString(const QQmlPropertyData *property,
+ const QString &str, QObject *obj,
+ const QQmlRefPointer<QQmlContextData> &ctxt,
+ const QString &url, quint16 lineNumber,
+ QObject *target, QQmlPropertyIndex targetIndex);
+ static QUntypedPropertyBinding createFromScriptString(const QQmlPropertyData *property,
+ const QQmlScriptString& script, QObject *obj,
+ QQmlContext *ctxt, QObject *target,
+ QQmlPropertyIndex targetIndex);
+
+ static QUntypedPropertyBinding createFromBoundFunction(const QQmlPropertyData *pd, QV4::BoundFunction *function,
+ QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt,
+ QV4::ExecutionContext *scope, QObject *target,
+ QQmlPropertyIndex targetIndex);
+
+ static bool isUndefined(const QUntypedPropertyBinding &binding)
+ {
+ return isUndefined(QPropertyBindingPrivate::get(binding));
+ }
+
+ static bool isUndefined(const QPropertyBindingPrivate *binding)
+ {
+ if (!(binding && binding->hasCustomVTable()))
+ return false;
+ return static_cast<const QQmlPropertyBinding *>(binding)->isUndefined();
+ }
+
+ template<QMetaType::Type type>
+ static bool doEvaluate(QMetaType metaType, QUntypedPropertyData *dataPtr, void *f) {
+ auto address = static_cast<std::byte*>(f);
+ address -= QPropertyBindingPrivate::getSizeEnsuringAlignment(); // f now points to QPropertyBindingPrivate suboject
+ // and that has the same address as QQmlPropertyBinding
+ return reinterpret_cast<QQmlPropertyBinding *>(address)->evaluate<type>(metaType, dataPtr);
+ }
+
+ bool hasDependencies()
+ {
+ return (dependencyObserverCount > 0) || !jsExpression()->activeGuards.isEmpty();
+ }
+
+private:
+ template <QMetaType::Type type>
+ bool evaluate(QMetaType metaType, void *dataPtr);
+
+ Q_NEVER_INLINE void handleUndefinedAssignment(QQmlEnginePrivate *ep, void *dataPtr);
+
+ QString createBindingLoopErrorDescription();
+
+ struct TargetData {
+ enum BoundFunction : bool {
+ WithoutBoundFunction = false,
+ HasBoundFunction = true,
+ };
+ TargetData(QObject *target, QQmlPropertyIndex index, BoundFunction state)
+ : target(target), targetIndex(index), hasBoundFunction(state)
+ {}
+ QObject *target;
+ QQmlPropertyIndex targetIndex;
+ bool hasBoundFunction;
+ bool isUndefined = false;
+ };
+ QQmlPropertyBinding(QMetaType metaType, QObject *target, QQmlPropertyIndex targetIndex, TargetData::BoundFunction hasBoundFunction);
+
+ QObject *target()
+ {
+ return std::launder(reinterpret_cast<TargetData *>(&declarativeExtraData))->target;
+ }
+
+ QQmlPropertyIndex targetIndex()
+ {
+ return std::launder(reinterpret_cast<TargetData *>(&declarativeExtraData))->targetIndex;
+ }
+
+ bool hasBoundFunction()
+ {
+ return std::launder(reinterpret_cast<TargetData *>(&declarativeExtraData))->hasBoundFunction;
+ }
+
+ bool isUndefined() const
+ {
+ return std::launder(reinterpret_cast<TargetData const *>(&declarativeExtraData))->isUndefined;
+ }
+
+ void setIsUndefined(bool isUndefined)
+ {
+ std::launder(reinterpret_cast<TargetData *>(&declarativeExtraData))->isUndefined = isUndefined;
+ }
+
+ static void bindingErrorCallback(QPropertyBindingPrivate *);
+};
+
+template <auto I>
+struct Print {};
+
+namespace QtPrivate {
+template<QMetaType::Type type>
+inline constexpr BindingFunctionVTable bindingFunctionVTableForQQmlPropertyBinding = {
+ &QQmlPropertyBinding::doEvaluate<type>,
+ [](void *qpropertyBinding){
+ QQmlPropertyBinding *binding = reinterpret_cast<QQmlPropertyBinding *>(qpropertyBinding);
+ binding->jsExpression()->~QQmlPropertyBindingJS();
+ binding->~QQmlPropertyBinding();
+ auto address = static_cast<std::byte*>(qpropertyBinding);
+ delete[] address;
+ },
+ [](void *, void *){},
+ 0
+};
+}
+
+inline const QtPrivate::BindingFunctionVTable *bindingFunctionVTableForQQmlPropertyBinding(QMetaType type)
+{
+#define FOR_TYPE(TYPE) \
+ case TYPE: return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<TYPE>
+ switch (type.id()) {
+ FOR_TYPE(QMetaType::Int);
+ FOR_TYPE(QMetaType::QString);
+ FOR_TYPE(QMetaType::Double);
+ FOR_TYPE(QMetaType::Float);
+ FOR_TYPE(QMetaType::Bool);
+ default:
+ if (type.flags() & QMetaType::PointerToQObject)
+ return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<QMetaType::QObjectStar>;
+ return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<QMetaType::UnknownType>;
+ }
+#undef FOR_TYPE
+}
+
+class QQmlTranslationPropertyBinding
+{
+public:
+ static QUntypedPropertyBinding Q_QML_EXPORT create(const QQmlPropertyData *pd,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QV4::CompiledData::Binding *binding);
+ static QUntypedPropertyBinding Q_QML_EXPORT
+ create(const QMetaType &pd,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlTranslation &translationData);
+};
+
+inline const QQmlPropertyBinding *QQmlPropertyBindingJS::asBinding() const
+{
+ return std::launder(reinterpret_cast<QQmlPropertyBinding const *>(
+ reinterpret_cast<std::byte const*>(this)
+ - QPropertyBindingPrivate::getSizeEnsuringAlignment()
+ - QQmlPropertyBinding::jsExpressionOffsetLength()));
+}
+
+static_assert(sizeof(QQmlPropertyBinding) == sizeof(QPropertyBindingPrivate)); // else the whole offset computatation will break
+template<typename T>
+bool compareAndAssign(void *dataPtr, const void *result)
+{
+ if (*static_cast<const T *>(result) == *static_cast<const T *>(dataPtr))
+ return false;
+ *static_cast<T *>(dataPtr) = *static_cast<const T *>(result);
+ return true;
+}
+
+template <QMetaType::Type type>
+bool QQmlPropertyBinding::evaluate(QMetaType metaType, void *dataPtr)
+{
+ const auto ctxt = jsExpression()->context();
+ QQmlEngine *engine = ctxt ? ctxt->engine() : nullptr;
+ if (!engine) {
+ QPropertyBindingError error(QPropertyBindingError::EvaluationError);
+ if (auto currentBinding = QPropertyBindingPrivate::currentlyEvaluatingBinding())
+ currentBinding->setError(std::move(error));
+ return false;
+ }
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ ep->referenceScarceResources();
+
+ const auto handleErrorAndUndefined = [&](bool evaluatedToUndefined) {
+ ep->dereferenceScarceResources();
+ if (jsExpression()->hasError()) {
+ QPropertyBindingError error(QPropertyBindingError::UnknownError,
+ jsExpression()->delayedError()->error().description());
+ QPropertyBindingPrivate::currentlyEvaluatingBinding()->setError(std::move(error));
+ bindingErrorCallback(this);
+ return false;
+ }
+
+ if (evaluatedToUndefined) {
+ handleUndefinedAssignment(ep, dataPtr);
+ // if property has been changed due to reset, reset is responsible for
+ // notifying observers
+ return false;
+ } else if (isUndefined()) {
+ setIsUndefined(false);
+ }
+
+ return true;
+ };
+
+ if (!hasBoundFunction()) {
+ Q_ASSERT(metaType.sizeOf() > 0);
+
+ using Tuple = std::tuple<qsizetype, bool, bool>;
+ const auto [size, needsConstruction, needsDestruction] = [&]() -> Tuple {
+ switch (type) {
+ case QMetaType::QObjectStar: return Tuple(sizeof(QObject *), false, false);
+ case QMetaType::Bool: return Tuple(sizeof(bool), false, false);
+ case QMetaType::Int: return Tuple(sizeof(int), false, false);
+ case QMetaType::Double: return Tuple(sizeof(double), false, false);
+ case QMetaType::Float: return Tuple(sizeof(float), false, false);
+ case QMetaType::QString: return Tuple(sizeof(QString), true, true);
+ default: {
+ const auto flags = metaType.flags();
+ return Tuple(
+ metaType.sizeOf(),
+ flags & QMetaType::NeedsConstruction,
+ flags & QMetaType::NeedsDestruction);
+ }
+ }
+ }();
+ Q_ALLOCA_VAR(void, result, size);
+ if (needsConstruction)
+ metaType.construct(result);
+
+ const bool evaluatedToUndefined = !jsExpression()->evaluate(&result, &metaType, 0);
+ if (!handleErrorAndUndefined(evaluatedToUndefined))
+ return false;
+
+ switch (type) {
+ case QMetaType::QObjectStar:
+ return compareAndAssign<QObject *>(dataPtr, result);
+ case QMetaType::Bool:
+ return compareAndAssign<bool>(dataPtr, result);
+ case QMetaType::Int:
+ return compareAndAssign<int>(dataPtr, result);
+ case QMetaType::Double:
+ return compareAndAssign<double>(dataPtr, result);
+ case QMetaType::Float:
+ return compareAndAssign<float>(dataPtr, result);
+ case QMetaType::QString: {
+ const bool hasChanged = compareAndAssign<QString>(dataPtr, result);
+ static_cast<QString *>(result)->~QString();
+ return hasChanged;
+ }
+ default:
+ break;
+ }
+
+ const bool hasChanged = !metaType.equals(result, dataPtr);
+ if (hasChanged) {
+ if (needsDestruction)
+ metaType.destruct(dataPtr);
+ metaType.construct(dataPtr, result);
+ }
+ if (needsDestruction)
+ metaType.destruct(result);
+ return hasChanged;
+ }
+
+ bool evaluatedToUndefined = false;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedValue result(scope, static_cast<QQmlPropertyBindingJSForBoundFunction *>(
+ jsExpression())->evaluate(&evaluatedToUndefined));
+
+ if (!handleErrorAndUndefined(evaluatedToUndefined))
+ return false;
+
+ switch (type) {
+ case QMetaType::Bool: {
+ bool b;
+ if (result->isBoolean())
+ b = result->booleanValue();
+ else
+ b = result->toBoolean();
+ if (b == *static_cast<bool *>(dataPtr))
+ return false;
+ *static_cast<bool *>(dataPtr) = b;
+ return true;
+ }
+ case QMetaType::Int: {
+ int i;
+ if (result->isInteger())
+ i = result->integerValue();
+ else if (result->isNumber()) {
+ i = QV4::StaticValue::toInteger(result->doubleValue());
+ } else {
+ break;
+ }
+ if (i == *static_cast<int *>(dataPtr))
+ return false;
+ *static_cast<int *>(dataPtr) = i;
+ return true;
+ }
+ case QMetaType::Double:
+ if (result->isNumber()) {
+ double d = result->asDouble();
+ if (d == *static_cast<double *>(dataPtr))
+ return false;
+ *static_cast<double *>(dataPtr) = d;
+ return true;
+ }
+ break;
+ case QMetaType::Float:
+ if (result->isNumber()) {
+ float d = float(result->asDouble());
+ if (d == *static_cast<float *>(dataPtr))
+ return false;
+ *static_cast<float *>(dataPtr) = d;
+ return true;
+ }
+ break;
+ case QMetaType::QString:
+ if (result->isString()) {
+ QString s = result->toQStringNoThrow();
+ if (s == *static_cast<QString *>(dataPtr))
+ return false;
+ *static_cast<QString *>(dataPtr) = s;
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ QVariant resultVariant(QV4::ExecutionEngine::toVariant(result, metaType));
+ resultVariant.convert(metaType);
+ const bool hasChanged = !metaType.equals(resultVariant.constData(), dataPtr);
+ metaType.destruct(dataPtr);
+ metaType.construct(dataPtr, resultVariant.constData());
+ return hasChanged;
+}
+
+QT_END_NAMESPACE
+
+#endif // QQMLPROPERTYBINDING_P_H
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 69957ab282..a225f94a3f 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertycache_p.h"
@@ -46,13 +10,14 @@
#include <private/qmetaobject_p.h>
#include <private/qmetaobjectbuilder_p.h>
#include <private/qqmlpropertycachemethodarguments_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <private/qv4value_p.h>
#include <QtCore/qdebug.h>
#include <QtCore/QCryptographicHash>
+#include <QtCore/private/qtools_p.h>
-#include <ctype.h> // for toupper
#include <limits.h>
#include <algorithm>
@@ -65,49 +30,6 @@ QT_BEGIN_NAMESPACE
#define Q_INT16_MAX 32767
-// Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
-// to load
-static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
-{
- QQmlPropertyData::Flags flags;
-
- flags.isConstant = p.isConstant();
- flags.isWritable = p.isWritable();
- flags.isResettable = p.isResettable();
- flags.isFinal = p.isFinal();
-
- if (p.isEnumType())
- flags.type = QQmlPropertyData::Flags::EnumType;
-
- return flags;
-}
-
-// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to
-// load
-static void flagsForPropertyType(int propType, QQmlPropertyData::Flags &flags)
-{
- Q_ASSERT(propType != -1);
-
- if (propType == QMetaType::QObjectStar) {
- flags.type = QQmlPropertyData::Flags::QObjectDerivedType;
- } else if (propType == QMetaType::QVariant) {
- flags.type = QQmlPropertyData::Flags::QVariantType;
- } else if (propType < static_cast<int>(QVariant::UserType)) {
- // nothing to do
- } else if (propType == qMetaTypeId<QQmlBinding *>()) {
- flags.type = QQmlPropertyData::Flags::QmlBindingType;
- } else if (propType == qMetaTypeId<QJSValue>()) {
- flags.type = QQmlPropertyData::Flags::QJSValueType;
- } else {
- QQmlMetaType::TypeCategory cat = QQmlMetaType::typeCategory(propType);
-
- if (cat == QQmlMetaType::Object || QMetaType::typeFlags(propType) & QMetaType::PointerToQObject)
- flags.type = QQmlPropertyData::Flags::QObjectDerivedType;
- else if (cat == QQmlMetaType::List)
- flags.type = QQmlPropertyData::Flags::QListType;
- }
-}
-
static int metaObjectSignalCount(const QMetaObject *metaObject)
{
int signalCount = 0;
@@ -119,114 +41,120 @@ static int metaObjectSignalCount(const QMetaObject *metaObject)
QQmlPropertyData::Flags
QQmlPropertyData::flagsForProperty(const QMetaProperty &p)
{
- auto flags = fastFlagsForProperty(p);
- flagsForPropertyType(p.userType(), flags);
- return flags;
-}
+ QQmlPropertyData::Flags flags;
-static void populate(QQmlPropertyData *data, const QMetaProperty &p)
-{
- Q_ASSERT(p.revision() <= Q_INT16_MAX);
- data->setCoreIndex(p.propertyIndex());
- data->setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal()));
- data->setFlags(fastFlagsForProperty(p));
- data->setRevision(p.revision());
-}
+ flags.setIsConstant(p.isConstant());
+ flags.setIsWritable(p.isWritable());
+ flags.setIsResettable(p.isResettable());
+ flags.setIsFinal(p.isFinal());
+ flags.setIsRequired(p.isRequired());
+ flags.setIsBindable(p.isBindable());
-void QQmlPropertyData::lazyLoad(const QMetaProperty &p)
-{
- populate(this, p);
- int type = static_cast<int>(p.type());
- if (type == QMetaType::QObjectStar) {
- setPropType(type);
- m_flags.type = Flags::QObjectDerivedType;
- } else if (type == QMetaType::QVariant) {
- setPropType(type);
- m_flags.type = Flags::QVariantType;
- } else if (type == QVariant::UserType || type == -1) {
- m_flags.notFullyResolved = true;
- } else {
- setPropType(type);
+
+ const QMetaType metaType = p.metaType();
+ int propType = metaType.id();
+ if (p.isEnumType()) {
+ flags.setType(QQmlPropertyData::Flags::EnumType);
+ } else if (metaType.flags() & QMetaType::PointerToQObject) {
+ flags.setType(QQmlPropertyData::Flags::QObjectDerivedType);
+ } else if (propType == QMetaType::QVariant) {
+ flags.setType(QQmlPropertyData::Flags::QVariantType);
+ } else if (metaType.flags() & QMetaType::IsQmlList) {
+ flags.setType(QQmlPropertyData::Flags::QListType);
}
+
+ return flags;
}
void QQmlPropertyData::load(const QMetaProperty &p)
{
- populate(this, p);
- setPropType(p.userType());
- flagsForPropertyType(propType(), m_flags);
+ Q_ASSERT(p.revision() <= std::numeric_limits<quint16>::max());
+ setCoreIndex(p.propertyIndex());
+ setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal()));
+ setFlags(flagsForProperty(p));
+ setRevision(QTypeRevision::fromEncodedVersion(p.revision()));
+ QMetaType type = p.metaType();
+ setPropType(type);
}
void QQmlPropertyData::load(const QMetaMethod &m)
{
setCoreIndex(m.methodIndex());
- setArguments(nullptr);
-
- setPropType(m.returnType());
-
- m_flags.type = Flags::FunctionType;
- if (m.methodType() == QMetaMethod::Signal) {
- m_flags.isSignal = true;
- } else if (m.methodType() == QMetaMethod::Constructor) {
- m_flags.isConstructor = true;
- setPropType(QMetaType::QObjectStar);
+ m_flags.setType(Flags::FunctionType);
+
+ // We need to set the constructor, signal, constant, arguments, V4Function, cloned flags.
+ // These are specific to methods and change with each method.
+ // The same QQmlPropertyData may be loaded with multiple methods in sequence.
+
+ switch (m.methodType()) {
+ case QMetaMethod::Signal:
+ m_flags.setIsSignal(true);
+ m_flags.setIsConstructor(false);
+ setPropType(m.returnMetaType());
+ break;
+ case QMetaMethod::Constructor:
+ m_flags.setIsSignal(false);
+ m_flags.setIsConstructor(true);
+ setPropType(QMetaType::fromType<QObject *>());
+ break;
+ default:
+ m_flags.setIsSignal(false);
+ m_flags.setIsConstructor(false);
+ setPropType(m.returnMetaType());
+ break;
}
+ m_flags.setIsConstant(m.isConst());
+
const int paramCount = m.parameterCount();
if (paramCount) {
- m_flags.hasArguments = true;
- if ((paramCount == 1) && (m.parameterTypes().constFirst() == "QQmlV4Function*"))
- m_flags.isV4Function = true;
+ m_flags.setHasArguments(true);
+ m_flags.setIsV4Function(
+ paramCount == 1 &&
+ m.parameterMetaType(0) == QMetaType::fromType<QQmlV4FunctionPtr>());
+ } else {
+ m_flags.setHasArguments(false);
+ m_flags.setIsV4Function(false);
}
- if (m.attributes() & QMetaMethod::Cloned)
- m_flags.isCloned = true;
+ m_flags.setIsCloned(m.attributes() & QMetaMethod::Cloned);
- Q_ASSERT(m.revision() <= Q_INT16_MAX);
- setRevision(m.revision());
-}
-
-void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
-{
- load(m);
-
- const char *returnType = m.typeName();
- if (!returnType)
- returnType = "\0";
- if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
- m_flags.notFullyResolved = true;
- }
+ Q_ASSERT(m.revision() <= std::numeric_limits<quint16>::max());
+ setRevision(QTypeRevision::fromEncodedVersion(m.revision()));
}
/*!
-Creates a new empty QQmlPropertyCache.
+ Creates a standalone QQmlPropertyCache of \a metaObject. It is separate from the usual
+ QQmlPropertyCache hierarchy. It's parent is not equal to any other QQmlPropertyCache
+ created from QObject::staticMetaObject, for example.
*/
-QQmlPropertyCache::QQmlPropertyCache()
- : _parent(nullptr), propertyIndexCacheStart(0), methodIndexCacheStart(0),
- signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
- _metaObject(nullptr), argumentsCache(nullptr), _jsFactoryMethodIndex(-1)
-{
-}
-
-/*!
-Creates a new QQmlPropertyCache of \a metaObject.
-*/
-QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject, int metaObjectRevision)
- : QQmlPropertyCache()
+QQmlPropertyCache::Ptr QQmlPropertyCache::createStandalone(
+ const QMetaObject *metaObject, QTypeRevision metaObjectRevision)
{
Q_ASSERT(metaObject);
- update(metaObject);
+ Ptr result;
+ if (const QMetaObject *super = metaObject->superClass()) {
+ result = createStandalone(
+ super, metaObjectRevision)->copyAndAppend(metaObject, metaObjectRevision);
+ } else {
+ result.adopt(new QQmlPropertyCache(metaObject));
+ result->update(metaObject);
+ }
- if (metaObjectRevision > 0) {
+ if (metaObjectRevision.isValid() && metaObjectRevision != QTypeRevision::zero()) {
// Set the revision of the meta object that this cache describes to be
// 'metaObjectRevision'. This is useful when constructing a property cache
// from a type that was created directly in C++, and not through QML. For such
// types, the revision for each recorded QMetaObject would normally be zero, which
// would exclude any revisioned properties.
- for (int metaObjectOffset = 0; metaObjectOffset < allowedRevisionCache.size(); ++metaObjectOffset)
- allowedRevisionCache[metaObjectOffset] = metaObjectRevision;
+ for (int metaObjectOffset = 0; metaObjectOffset < result->allowedRevisionCache.size();
+ ++metaObjectOffset) {
+ result->allowedRevisionCache[metaObjectOffset] = metaObjectRevision;
+ }
}
+
+ return result;
}
QQmlPropertyCache::~QQmlPropertyCache()
@@ -234,7 +162,6 @@ QQmlPropertyCache::~QQmlPropertyCache()
QQmlPropertyCacheMethodArguments *args = argumentsCache;
while (args) {
QQmlPropertyCacheMethodArguments *next = args->next;
- delete args->signalParameterStringForJS;
delete args->names;
free(args);
args = next;
@@ -243,44 +170,38 @@ QQmlPropertyCache::~QQmlPropertyCache()
// We must clear this prior to releasing the parent incase it is a
// linked hash
stringCache.clear();
- if (_parent) _parent->release();
-
- if (_ownMetaObject) free(const_cast<QMetaObject *>(_metaObject));
- _metaObject = nullptr;
- _parent = nullptr;
}
-QQmlPropertyCache *QQmlPropertyCache::copy(int reserve)
+QQmlPropertyCache::Ptr QQmlPropertyCache::copy(const QQmlMetaObjectPointer &mo, int reserve) const
{
- QQmlPropertyCache *cache = new QQmlPropertyCache();
- cache->_parent = this;
- cache->_parent->addref();
- cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart;
- cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart;
- cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.count() + signalHandlerIndexCacheStart;
+ QQmlPropertyCache::Ptr cache = QQmlPropertyCache::Ptr(
+ new QQmlPropertyCache(mo), QQmlPropertyCache::Ptr::Adopt);
+ cache->_parent.reset(this);
+ cache->propertyIndexCacheStart = propertyIndexCache.size() + propertyIndexCacheStart;
+ cache->methodIndexCacheStart = methodIndexCache.size() + methodIndexCacheStart;
+ cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.size() + signalHandlerIndexCacheStart;
cache->stringCache.linkAndReserve(stringCache, reserve);
cache->allowedRevisionCache = allowedRevisionCache;
- cache->_metaObject = _metaObject;
cache->_defaultPropertyName = _defaultPropertyName;
+ cache->_listPropertyAssignBehavior = _listPropertyAssignBehavior;
return cache;
}
-QQmlPropertyCache *QQmlPropertyCache::copy()
+QQmlPropertyCache::Ptr QQmlPropertyCache::copy() const
{
- return copy(0);
+ return copy(_metaObject, 0);
}
-QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(int propertyCount, int methodCount,
- int signalCount, int enumCount)
+QQmlPropertyCache::Ptr QQmlPropertyCache::copyAndReserve(
+ int propertyCount, int methodCount, int signalCount, int enumCount) const
{
- QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount);
+ QQmlPropertyCache::Ptr rv = copy(
+ QQmlMetaObjectPointer(), propertyCount + methodCount + signalCount);
rv->propertyIndexCache.reserve(propertyCount);
rv->methodIndexCache.reserve(methodCount);
rv->signalHandlerIndexCache.reserve(signalCount);
rv->enumCache.reserve(enumCount);
- rv->_metaObject = nullptr;
-
return rv;
}
@@ -290,89 +211,89 @@ QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(int propertyCount, int meth
This is different from QMetaMethod::methodIndex().
*/
void QQmlPropertyCache::appendProperty(const QString &name, QQmlPropertyData::Flags flags,
- int coreIndex, int propType, int minorVersion, int notifyIndex)
+ int coreIndex, QMetaType propType, QTypeRevision version,
+ int notifyIndex)
{
QQmlPropertyData data;
data.setPropType(propType);
data.setCoreIndex(coreIndex);
data.setNotifyIndex(notifyIndex);
data.setFlags(flags);
- data.setTypeMinorVersion(minorVersion);
+ data.setTypeVersion(version);
- QQmlPropertyData *old = findNamedProperty(name);
- if (old)
- data.markAsOverrideOf(old);
+ const OverrideResult overrideResult = handleOverride(name, &data);
+ if (overrideResult == InvalidOverride)
+ return;
- int index = propertyIndexCache.count();
+ int index = propertyIndexCache.size();
propertyIndexCache.append(data);
- setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != nullptr));
+ setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index);
}
void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flags flags,
- int coreIndex, const int *types,
+ int coreIndex, const QMetaType *types,
const QList<QByteArray> &names)
{
QQmlPropertyData data;
- data.setPropType(QVariant::Invalid);
+ data.setPropType(QMetaType());
data.setCoreIndex(coreIndex);
data.setFlags(flags);
data.setArguments(nullptr);
QQmlPropertyData handler = data;
- handler.m_flags.isSignalHandler = true;
+ handler.m_flags.setIsSignalHandler(true);
if (types) {
- int argumentCount = *types;
+ const auto argumentCount = names.size();
QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
- ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
- args->argumentsValid = true;
+ new (args->types) QMetaType; // Invalid return type
+ ::memcpy(args->types + 1, types, argumentCount * sizeof(QMetaType));
data.setArguments(args);
}
- QQmlPropertyData *old = findNamedProperty(name);
- if (old)
- data.markAsOverrideOf(old);
+ const OverrideResult overrideResult = handleOverride(name, &data);
+ if (overrideResult == InvalidOverride)
+ return;
- int methodIndex = methodIndexCache.count();
+ int methodIndex = methodIndexCache.size();
methodIndexCache.append(data);
- int signalHandlerIndex = signalHandlerIndexCache.count();
+ int signalHandlerIndex = signalHandlerIndexCache.size();
signalHandlerIndexCache.append(handler);
- QString handlerName = QLatin1String("on") + name;
- handlerName[2] = handlerName.at(2).toUpper();
+ const QString handlerName = QQmlSignalNames::signalNameToHandlerName(name);
- setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != nullptr));
- setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != nullptr));
+ setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex);
+ setNamedProperty(handlerName, signalHandlerIndex + signalOffset(),
+ signalHandlerIndexCache.data() + signalHandlerIndex);
}
void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flags flags,
- int coreIndex, int returnType, const QList<QByteArray> &names,
- const QVector<int> &parameterTypes)
+ int coreIndex, QMetaType returnType,
+ const QList<QByteArray> &names,
+ const QVector<QMetaType> &parameterTypes)
{
- int argumentCount = names.count();
+ int argumentCount = names.size();
QQmlPropertyData data;
data.setPropType(returnType);
data.setCoreIndex(coreIndex);
+ data.setFlags(flags);
+ const OverrideResult overrideResult = handleOverride(name, &data);
+ if (overrideResult == InvalidOverride)
+ return;
QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
+ new (args->types) QMetaType(returnType);
for (int ii = 0; ii < argumentCount; ++ii)
- args->arguments[ii + 1] = parameterTypes.at(ii);
- args->argumentsValid = true;
+ new (args->types + ii + 1) QMetaType(parameterTypes.at(ii));
data.setArguments(args);
- data.setFlags(flags);
-
- QQmlPropertyData *old = findNamedProperty(name);
- if (old)
- data.markAsOverrideOf(old);
-
- int methodIndex = methodIndexCache.count();
+ int methodIndex = methodIndexCache.size();
methodIndexCache.append(data);
- setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != nullptr));
+ setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex);
}
void QQmlPropertyCache::appendEnum(const QString &name, const QVector<QQmlEnumValue> &values)
@@ -384,76 +305,84 @@ void QQmlPropertyCache::appendEnum(const QString &name, const QVector<QQmlEnumVa
}
// Returns this property cache's metaObject, creating it if necessary.
-const QMetaObject *QQmlPropertyCache::createMetaObject()
+const QMetaObject *QQmlPropertyCache::createMetaObject() const
{
- if (!_metaObject) {
- _ownMetaObject = true;
-
+ if (_metaObject.isNull()) {
QMetaObjectBuilder builder;
toMetaObjectBuilder(builder);
builder.setSuperClass(_parent->createMetaObject());
- _metaObject = builder.toMetaObject();
+ _metaObject.setSharedOnce(builder.toMetaObject());
}
- return _metaObject;
+ return _metaObject.metaObject();
}
-QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
+const QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(int index) const
{
- return property(defaultPropertyName(), nullptr, nullptr);
+ if (index < 0 || index >= propertyCount())
+ return nullptr;
+
+ const QQmlPropertyData *rv = nullptr;
+ if (index < propertyIndexCacheStart)
+ return _parent->maybeUnresolvedProperty(index);
+ else
+ rv = const_cast<const QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
+ return rv;
}
-void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent)
+const QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
{
- if (_parent == newParent)
- return;
- if (_parent)
- _parent->release();
- _parent = newParent;
- _parent->addref();
+ return property(defaultPropertyName(), nullptr, nullptr);
}
-QQmlPropertyCache *
-QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject,
- QQmlPropertyData::Flags propertyFlags,
- QQmlPropertyData::Flags methodFlags,
- QQmlPropertyData::Flags signalFlags)
+void QQmlPropertyCache::setParent(QQmlPropertyCache::ConstPtr newParent)
{
- return copyAndAppend(metaObject, -1, propertyFlags, methodFlags, signalFlags);
+ if (_parent != newParent)
+ _parent = std::move(newParent);
}
-QQmlPropertyCache *
+QQmlPropertyCache::Ptr
QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject,
- int typeMinorVersion,
+ QTypeRevision typeVersion,
QQmlPropertyData::Flags propertyFlags,
QQmlPropertyData::Flags methodFlags,
- QQmlPropertyData::Flags signalFlags)
+ QQmlPropertyData::Flags signalFlags) const
{
Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
// Reserve enough space in the name hash for all the methods (including signals), all the
// signal handlers and all the properties. This assumes no name clashes, but this is the
// common case.
- QQmlPropertyCache *rv = copy(QMetaObjectPrivate::get(metaObject)->methodCount +
- QMetaObjectPrivate::get(metaObject)->signalCount +
- QMetaObjectPrivate::get(metaObject)->propertyCount);
+ QQmlPropertyCache::Ptr rv = copy(
+ metaObject,
+ QMetaObjectPrivate::get(metaObject)->methodCount
+ + QMetaObjectPrivate::get(metaObject)->signalCount
+ + QMetaObjectPrivate::get(metaObject)->propertyCount);
- rv->append(metaObject, typeMinorVersion, propertyFlags, methodFlags, signalFlags);
+ rv->append(metaObject, typeVersion, propertyFlags, methodFlags, signalFlags);
return rv;
}
+static QHashedString signalNameToHandlerName(const QHashedString &methodName)
+{
+ return QQmlSignalNames::signalNameToHandlerName(methodName);
+}
+
+static QHashedString signalNameToHandlerName(const QHashedCStringRef &methodName)
+{
+ return QQmlSignalNames::signalNameToHandlerName(
+ QLatin1StringView{ methodName.constData(), methodName.length() });
+}
+
+
void QQmlPropertyCache::append(const QMetaObject *metaObject,
- int typeMinorVersion,
+ QTypeRevision typeVersion,
QQmlPropertyData::Flags propertyFlags,
QQmlPropertyData::Flags methodFlags,
QQmlPropertyData::Flags signalFlags)
{
- _metaObject = metaObject;
-
- bool dynamicMetaObject = isDynamicMetaObject(metaObject);
-
- allowedRevisionCache.append(0);
+ allowedRevisionCache.append(QTypeRevision::zero());
int methodCount = metaObject->methodCount();
Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
@@ -473,6 +402,8 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
_jsFactoryMethodIndex = metaObject->indexOfSlot(factoryMethod);
if (_jsFactoryMethodIndex != -1)
_jsFactoryMethodIndex -= metaObject->methodOffset();
+ } else if (0 == qstrcmp(name, "QML.ListPropertyAssignBehavior")) {
+ _listPropertyAssignBehavior = mci.value();
}
}
}
@@ -482,7 +413,9 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
// These indices don't apply to gadgets, so don't block them.
- const bool preventDestruction = metaObject->superClass() || metaObject == &QObject::staticMetaObject;
+ // It is enough to check for QObject::staticMetaObject here because the loop below excludes
+ // methods of parent classes: It starts at metaObject->methodOffset()
+ const bool preventDestruction = (metaObject == &QObject::staticMetaObject);
int methodOffset = metaObject->methodOffset();
int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
@@ -518,61 +451,42 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
else
data->setFlags(methodFlags);
- data->lazyLoad(m);
- data->m_flags.isDirect = !dynamicMetaObject;
+ data->load(m);
- Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
- data->setMetaObjectOffset(allowedRevisionCache.count() - 1);
+ Q_ASSERT((allowedRevisionCache.size() - 1) < Q_INT16_MAX);
+ data->setMetaObjectOffset(allowedRevisionCache.size() - 1);
if (data->isSignal()) {
sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
*sigdata = *data;
- sigdata->m_flags.isSignalHandler = true;
+ sigdata->m_flags.setIsSignalHandler(true);
}
QQmlPropertyData *old = nullptr;
- if (utf8) {
- QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName));
- if (StringCache::mapped_type *it = stringCache.value(methodName))
- old = it->second;
- setNamedProperty(methodName, ii, data, (old != nullptr));
-
- if (data->isSignal()) {
- QHashedString on(QLatin1String("on") % methodName.at(0).toUpper() % methodName.midRef(1));
- setNamedProperty(on, ii, sigdata, (old != nullptr));
- ++signalHandlerIndex;
+ const auto doSetNamedProperty = [&](const auto &methodName) {
+ if (StringCache::mapped_type *it = stringCache.value(methodName)) {
+ if (handleOverride(methodName, data, (old = it->second)) == InvalidOverride)
+ return;
}
- } else {
- QHashedCStringRef methodName(rawName, cptr - rawName);
- if (StringCache::mapped_type *it = stringCache.value(methodName))
- old = it->second;
- setNamedProperty(methodName, ii, data, (old != nullptr));
+
+ setNamedProperty(methodName, ii, data);
if (data->isSignal()) {
- int length = methodName.length();
-
- QVarLengthArray<char, 128> str(length+3);
- str[0] = 'o';
- str[1] = 'n';
- str[2] = toupper(rawName[0]);
- if (length > 1)
- memcpy(&str[3], &rawName[1], length - 1);
- str[length + 2] = '\0';
-
- QHashedString on(QString::fromLatin1(str.data()));
- setNamedProperty(on, ii, data, (old != nullptr));
+
+ // TODO: Remove this once we can. Signals should not be overridable.
+ if (!utf8)
+ data->m_flags.setIsOverridableSignal(true);
+
+ setNamedProperty(signalNameToHandlerName(methodName), ii, sigdata);
++signalHandlerIndex;
}
- }
-
- if (old) {
- // We only overload methods in the same class, exactly like C++
- if (old->isFunction() && old->coreIndex() >= methodOffset)
- data->m_flags.isOverload = true;
+ };
- data->markAsOverrideOf(old);
- }
+ if (utf8)
+ doSetNamedProperty(QHashedString(QString::fromUtf8(rawName, cptr - rawName)));
+ else
+ doSetNamedProperty(QHashedCStringRef(rawName, cptr - rawName));
}
int propCount = metaObject->propertyCount();
@@ -597,26 +511,28 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
data->setFlags(propertyFlags);
- data->lazyLoad(p);
- data->setTypeMinorVersion(typeMinorVersion);
-
- data->m_flags.isDirect = !dynamicMetaObject;
+ data->load(p);
+ data->setTypeVersion(typeVersion);
- Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
- data->setMetaObjectOffset(allowedRevisionCache.count() - 1);
+ Q_ASSERT((allowedRevisionCache.size() - 1) < Q_INT16_MAX);
+ data->setMetaObjectOffset(allowedRevisionCache.size() - 1);
QQmlPropertyData *old = nullptr;
if (utf8) {
QHashedString propName(QString::fromUtf8(str, cptr - str));
- if (StringCache::mapped_type *it = stringCache.value(propName))
- old = it->second;
- setNamedProperty(propName, ii, data, (old != nullptr));
+ if (StringCache::mapped_type *it = stringCache.value(propName)) {
+ if (handleOverride(propName, data, (old = it->second)) == InvalidOverride)
+ continue;
+ }
+ setNamedProperty(propName, ii, data);
} else {
QHashedCStringRef propName(str, cptr - str);
- if (StringCache::mapped_type *it = stringCache.value(propName))
- old = it->second;
- setNamedProperty(propName, ii, data, (old != nullptr));
+ if (StringCache::mapped_type *it = stringCache.value(propName)) {
+ if (handleOverride(propName, data, (old = it->second)) == InvalidOverride)
+ continue;
+ }
+ setNamedProperty(propName, ii, data);
}
bool isGadget = true;
@@ -625,67 +541,12 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
isGadget = false;
}
- if (isGadget) // always dispatch over a 'normal' meta-call so the QQmlValueType can intercept
- data->m_flags.isDirect = false;
- else
+ // otherwise always dispatch over a 'normal' meta-call so the QQmlValueType can intercept
+ if (!isGadget)
data->trySetStaticMetaCallFunction(metaObject->d.static_metacall, ii - propOffset);
- if (old)
- data->markAsOverrideOf(old);
}
}
-void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
-{
- Q_ASSERT(data->notFullyResolved());
- data->m_flags.notFullyResolved = false;
-
- const QMetaObject *mo = firstCppMetaObject();
- if (data->isFunction()) {
- auto metaMethod = mo->method(data->coreIndex());
- const char *retTy = metaMethod.typeName();
- if (!retTy)
- retTy = "\0";
- data->setPropType(QMetaType::type(retTy));
- } else {
- auto metaProperty = mo->property(data->coreIndex());
- data->setPropType(QMetaType::type(metaProperty.typeName()));
- }
-
- if (!data->isFunction()) {
- if (data->propType() == QMetaType::UnknownType) {
- QQmlPropertyCache *p = _parent;
- while (p && (!mo || _ownMetaObject)) {
- mo = p->_metaObject;
- p = p->_parent;
- }
-
- int propOffset = mo->propertyOffset();
- if (mo && data->coreIndex() < propOffset + mo->propertyCount()) {
- while (data->coreIndex() < propOffset) {
- mo = mo->superClass();
- propOffset = mo->propertyOffset();
- }
-
- int registerResult = -1;
- void *argv[] = { &registerResult };
- mo->static_metacall(QMetaObject::RegisterPropertyMetaType, data->coreIndex() - propOffset, argv);
- data->setPropType(registerResult == -1 ? QMetaType::UnknownType : registerResult);
- }
- }
- flagsForPropertyType(data->propType(), data->m_flags);
- }
-}
-
-void QQmlPropertyCache::updateRecur(const QMetaObject *metaObject)
-{
- if (!metaObject)
- return;
-
- updateRecur(metaObject->superClass());
-
- append(metaObject, -1);
-}
-
void QQmlPropertyCache::update(const QMetaObject *metaObject)
{
Q_ASSERT(metaObject);
@@ -705,7 +566,8 @@ void QQmlPropertyCache::update(const QMetaObject *metaObject)
// cached in a parent cache.
stringCache.reserve(pc + mc + sc);
- updateRecur(metaObject);
+ if (metaObject)
+ append(metaObject, QTypeRevision());
}
/*! \internal
@@ -718,7 +580,6 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
methodIndexCache.clear();
signalHandlerIndexCache.clear();
- _hasPropertyOverrides = false;
argumentsCache = nullptr;
int pc = metaObject->propertyCount();
@@ -727,11 +588,11 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
int reserve = pc + mc + sc;
if (parent()) {
- propertyIndexCacheStart = parent()->propertyIndexCache.count() + parent()->propertyIndexCacheStart;
- methodIndexCacheStart = parent()->methodIndexCache.count() + parent()->methodIndexCacheStart;
- signalHandlerIndexCacheStart = parent()->signalHandlerIndexCache.count() + parent()->signalHandlerIndexCacheStart;
+ propertyIndexCacheStart = parent()->propertyIndexCache.size() + parent()->propertyIndexCacheStart;
+ methodIndexCacheStart = parent()->methodIndexCache.size() + parent()->methodIndexCacheStart;
+ signalHandlerIndexCacheStart = parent()->signalHandlerIndexCache.size() + parent()->signalHandlerIndexCacheStart;
stringCache.linkAndReserve(parent()->stringCache, reserve);
- append(metaObject, -1);
+ append(metaObject, QTypeRevision());
} else {
propertyIndexCacheStart = 0;
methodIndexCacheStart = 0;
@@ -740,7 +601,9 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
}
}
-QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const
+const QQmlPropertyData *QQmlPropertyCache::findProperty(
+ StringCache::ConstIterator it, QObject *object,
+ const QQmlRefPointer<QQmlContextData> &context) const
{
QQmlData *data = (object ? QQmlData::get(object) : nullptr);
const QQmlVMEMetaObject *vmemo = nullptr;
@@ -753,14 +616,15 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it,
namespace {
-inline bool contextHasNoExtensions(QQmlContextData *context)
+inline bool contextHasNoExtensions(const QQmlRefPointer<QQmlContextData> &context)
{
// This context has no extension if its parent is the engine's rootContext,
// which has children but no imports
- return (!context->parent || !context->parent->imports);
+ const QQmlRefPointer<QQmlContextData> parent = context->parent();
+ return (!parent || !parent->imports());
}
-inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount, const int signalCount, const int propertyCount)
+inline int maximumIndexForProperty(const QQmlPropertyData *prop, const int methodCount, const int signalCount, const int propertyCount)
{
return prop->isFunction() ? methodCount
: prop->isSignalHandler() ? signalCount
@@ -769,12 +633,14 @@ inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount
}
-QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo, QQmlContextData *context) const
+const QQmlPropertyData *QQmlPropertyCache::findProperty(
+ StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo,
+ const QQmlRefPointer<QQmlContextData> &context) const
{
StringCache::ConstIterator end = stringCache.end();
if (it != end) {
- QQmlPropertyData *result = it.value().second;
+ const QQmlPropertyData *result = it.value().second;
// If there exists a typed property (not a function or signal handler), of the
// right name available to the specified context, we need to return that
@@ -783,7 +649,7 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it,
if (vmemo && context && !contextHasNoExtensions(context)) {
// Find the meta-object that corresponds to the supplied context
do {
- if (vmemo->ctxt == context)
+ if (vmemo->ctxt.contextData().data() == context.data())
break;
vmemo = vmemo->parentVMEMetaObject();
@@ -815,7 +681,7 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it,
} while (it != end);
}
- return ensureResolved(result);
+ return result;
}
return nullptr;
@@ -844,22 +710,24 @@ QString QQmlPropertyData::name(const QMetaObject *metaObject) const
}
}
-void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
+bool QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
{
+ Q_ASSERT(predecessor != this);
+ if (predecessor->isFinal())
+ return false;
+
setOverrideIndexIsProperty(!predecessor->isFunction());
setOverrideIndex(predecessor->coreIndex());
-
- predecessor->m_flags.isOverridden = true;
+ predecessor->m_flags.setIsOverridden(true);
+ Q_ASSERT(predecessor->isOverridden());
+ return true;
}
-QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(int argc, const QList<QByteArray> &names)
+QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(
+ int argc, const QList<QByteArray> &names)
{
typedef QQmlPropertyCacheMethodArguments A;
- A *args = static_cast<A *>(malloc(sizeof(A) + (argc) * sizeof(int)));
- args->arguments[0] = argc;
- args->argumentsValid = false;
- args->signalParameterStringForJS = nullptr;
- args->parameterError = false;
+ A *args = static_cast<A *>(malloc(sizeof(A) + argc * sizeof(QMetaType)));
args->names = argc ? new QList<QByteArray>(names) : nullptr;
args->next = argumentsCache;
argumentsCache = args;
@@ -872,13 +740,17 @@ QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engi
const QSet<QString> &illegalNames = engine->illegalNames();
QString parameters;
- for (int i = 0; i < parameterNameList.count(); ++i) {
+ const qsizetype count = parameterNameList.size();
+ if (count > std::numeric_limits<quint16>::max())
+ *errorString = QCoreApplication::translate("QQmlRewrite", "Signal has an excessive number of parameters: %1").arg(count);
+
+ for (qsizetype i = 0; i < count; ++i) {
if (i > 0)
parameters += QLatin1Char(',');
const QByteArray &param = parameterNameList.at(i);
- if (param.isEmpty())
+ if (param.isEmpty()) {
unnamedParameter = true;
- else if (unnamedParameter) {
+ } else if (unnamedParameter) {
if (errorString)
*errorString = QCoreApplication::translate("QQmlRewrite", "Signal uses unnamed parameter followed by named parameter.");
return QString();
@@ -893,19 +765,19 @@ QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engi
return parameters;
}
-int QQmlPropertyCache::originalClone(int index)
+int QQmlPropertyCache::originalClone(int index) const
{
while (signal(index)->isCloned())
--index;
return index;
}
-int QQmlPropertyCache::originalClone(QObject *object, int index)
+int QQmlPropertyCache::originalClone(const QObject *object, int index)
{
- QQmlData *data = QQmlData::get(object, false);
+ QQmlData *data = QQmlData::get(object);
if (data && data->propertyCache) {
- QQmlPropertyCache *cache = data->propertyCache;
- QQmlPropertyData *sig = cache->signal(index);
+ const QQmlPropertyCache *cache = data->propertyCache.data();
+ const QQmlPropertyData *sig = cache->signal(index);
while (sig && sig->isCloned()) {
--index;
sig = cache->signal(index);
@@ -981,7 +853,7 @@ static inline const char *qQmlPropertyCacheToString(QLatin1String string)
return string.data();
}
-static inline QByteArray qQmlPropertyCacheToString(const QStringRef &string)
+static inline QByteArray qQmlPropertyCacheToString(QStringView string)
{
return string.toUtf8();
}
@@ -992,99 +864,84 @@ static inline QByteArray qQmlPropertyCacheToString(const QV4::String *string)
}
template<typename T>
-QQmlPropertyData *
-qQmlPropertyCacheProperty(QJSEngine *engine, QObject *obj, T name,
- QQmlContextData *context, QQmlPropertyData &local)
+const QQmlPropertyData *
+qQmlPropertyCacheProperty(QObject *obj, T name, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyData *local)
{
- QQmlPropertyCache *cache = nullptr;
+ const QQmlPropertyCache *cache = nullptr;
QQmlData *ddata = QQmlData::get(obj, false);
if (ddata && ddata->propertyCache) {
- cache = ddata->propertyCache;
- } else if (engine) {
- QJSEnginePrivate *ep = QJSEnginePrivate::get(engine);
- cache = ep->cache(obj);
- if (cache) {
- ddata = QQmlData::get(obj, true);
- cache->addref();
- ddata->propertyCache = cache;
- }
+ cache = ddata->propertyCache.data();
+ } else if (auto newCache = QQmlMetaType::propertyCache(obj)) {
+ cache = newCache.data();
+ ddata = QQmlData::get(obj, true);
+ ddata->propertyCache = std::move(newCache);
}
- QQmlPropertyData *rv = nullptr;
+ const QQmlPropertyData *rv = nullptr;
if (cache) {
rv = cache->property(name, obj, context);
- } else {
- local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
- if (local.isValid())
- rv = &local;
+ } else if (local) {
+ *local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
+ if (local->isValid())
+ rv = local;
}
return rv;
}
-QQmlPropertyData *
-QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, const QV4::String *name,
- QQmlContextData *context, QQmlPropertyData &local)
+const QQmlPropertyData *QQmlPropertyCache::property(
+ QObject *obj, const QV4::String *name, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyData *local)
{
- return qQmlPropertyCacheProperty<const QV4::String *>(engine, obj, name, context, local);
+ return qQmlPropertyCacheProperty<const QV4::String *>(obj, name, context, local);
}
-QQmlPropertyData *
-QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, const QStringRef &name,
- QQmlContextData *context, QQmlPropertyData &local)
+const QQmlPropertyData *QQmlPropertyCache::property(
+ QObject *obj, QStringView name, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyData *local)
{
- return qQmlPropertyCacheProperty<const QStringRef &>(engine, obj, name, context, local);
+ return qQmlPropertyCacheProperty<const QStringView &>(obj, name, context, local);
}
-QQmlPropertyData *
-QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, const QLatin1String &name,
- QQmlContextData *context, QQmlPropertyData &local)
+const QQmlPropertyData *QQmlPropertyCache::property(
+ QObject *obj, const QLatin1String &name, const QQmlRefPointer<QQmlContextData> &context,
+ QQmlPropertyData *local)
{
- return qQmlPropertyCacheProperty<const QLatin1String &>(engine, obj, name, context, local);
+ return qQmlPropertyCacheProperty<const QLatin1String &>(obj, name, context, local);
}
-// these two functions are copied from qmetaobject.cpp
-static inline const QMetaObjectPrivate *priv(const uint* data)
-{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
-
+// this function is copied from qmetaobject.cpp
static inline const QByteArray stringData(const QMetaObject *mo, int index)
{
- Q_ASSERT(priv(mo->d.data)->revision >= 7);
- const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo->d.stringdata[index]) };
- Q_ASSERT(data.ptr->ref.isStatic());
- Q_ASSERT(data.ptr->alloc == 0);
- Q_ASSERT(data.ptr->capacityReserved == 0);
- Q_ASSERT(data.ptr->size >= 0);
- return data;
-}
-
-bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
-{
- return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
+ uint offset = mo->d.stringdata[2*index];
+ uint length = mo->d.stringdata[2*index + 1];
+ const char *string = reinterpret_cast<const char *>(mo->d.stringdata) + offset;
+ return QByteArray::fromRawData(string, length);
}
const char *QQmlPropertyCache::className() const
{
- if (!_ownMetaObject && _metaObject)
- return _metaObject->className();
+ if (const QMetaObject *mo = _metaObject.metaObject())
+ return mo->className();
else
return _dynamicClassName.constData();
}
-void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
+void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) const
{
- struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs,
- const QPair<QString, QQmlPropertyData *> &rhs) {
+ struct Sort { static bool lt(const QPair<QString, const QQmlPropertyData *> &lhs,
+ const QPair<QString, const QQmlPropertyData *> &rhs) {
return lhs.second->coreIndex() < rhs.second->coreIndex();
} };
- struct Insert { static void in(QQmlPropertyCache *This,
- QList<QPair<QString, QQmlPropertyData *> > &properties,
- QList<QPair<QString, QQmlPropertyData *> > &methods,
- StringCache::ConstIterator iter, QQmlPropertyData *data) {
+ struct Insert { static void in(const QQmlPropertyCache *This,
+ QList<QPair<QString, const QQmlPropertyData *> > &properties,
+ QList<QPair<QString, const QQmlPropertyData *> > &methods,
+ StringCache::ConstIterator iter, const QQmlPropertyData *data) {
if (data->isSignalHandler())
return;
@@ -1092,7 +949,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
if (data->coreIndex() < This->methodIndexCacheStart)
return;
- QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
+ QPair<QString, const QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
// Overrides can cause the entry to already exist
if (!methods.contains(entry)) methods.append(entry);
@@ -1102,7 +959,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
if (data->coreIndex() < This->propertyIndexCacheStart)
return;
- QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
+ QPair<QString, const QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
// Overrides can cause the entry to already exist
if (!properties.contains(entry)) properties.append(entry);
@@ -1114,40 +971,43 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
builder.setClassName(_dynamicClassName);
- QList<QPair<QString, QQmlPropertyData *> > properties;
- QList<QPair<QString, QQmlPropertyData *> > methods;
+ QList<QPair<QString, const QQmlPropertyData *> > properties;
+ QList<QPair<QString, const QQmlPropertyData *> > methods;
for (StringCache::ConstIterator iter = stringCache.begin(), cend = stringCache.end(); iter != cend; ++iter)
Insert::in(this, properties, methods, iter, iter.value().second);
- Q_ASSERT(properties.count() == propertyIndexCache.count());
- Q_ASSERT(methods.count() == methodIndexCache.count());
+ Q_ASSERT(properties.size() == propertyIndexCache.size());
+ Q_ASSERT(methods.size() == methodIndexCache.size());
std::sort(properties.begin(), properties.end(), Sort::lt);
std::sort(methods.begin(), methods.end(), Sort::lt);
- for (int ii = 0; ii < properties.count(); ++ii) {
- QQmlPropertyData *data = properties.at(ii).second;
+ for (int ii = 0; ii < properties.size(); ++ii) {
+ const QQmlPropertyData *data = properties.at(ii).second;
int notifierId = -1;
if (data->notifyIndex() != -1)
notifierId = data->notifyIndex() - signalHandlerIndexCacheStart;
QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
- QMetaType::typeName(data->propType()),
+ data->propType().name(),
+ data->propType(),
notifierId);
property.setReadable(true);
property.setWritable(data->isWritable());
property.setResettable(data->isResettable());
+ property.setBindable(data->isBindable());
+ property.setAlias(data->isAlias());
}
- for (int ii = 0; ii < methods.count(); ++ii) {
- QQmlPropertyData *data = methods.at(ii).second;
+ for (int ii = 0; ii < methods.size(); ++ii) {
+ const QQmlPropertyData *data = methods.at(ii).second;
QByteArray returnType;
- if (data->propType() != 0)
- returnType = QMetaType::typeName(data->propType());
+ if (data->propType().isValid())
+ returnType = data->propType().name();
QByteArray signature;
// '+=' reserves extra capacity. Follow-up appending will be probably free.
@@ -1155,11 +1015,12 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
QQmlPropertyCacheMethodArguments *arguments = nullptr;
if (data->hasArguments()) {
- arguments = (QQmlPropertyCacheMethodArguments *)data->arguments();
- Q_ASSERT(arguments->argumentsValid);
- for (int ii = 0; ii < arguments->arguments[0]; ++ii) {
- if (ii != 0) signature.append(',');
- signature.append(QMetaType::typeName(arguments->arguments[1 + ii]));
+ arguments = data->arguments();
+ for (int ii = 0, end = arguments->names ? arguments->names->size() : 0;
+ ii < end; ++ii) {
+ if (ii != 0)
+ signature.append(',');
+ signature.append(arguments->types[1 + ii].name());
}
}
@@ -1180,23 +1041,26 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
method.setReturnType(returnType);
}
- for (int ii = 0; ii < enumCache.count(); ++ii) {
+ for (int ii = 0; ii < enumCache.size(); ++ii) {
const QQmlEnumData &enumData = enumCache.at(ii);
QMetaEnumBuilder enumeration = builder.addEnumerator(enumData.name.toUtf8());
enumeration.setIsScoped(true);
- for (int jj = 0; jj < enumData.values.count(); ++jj) {
+ for (int jj = 0; jj < enumData.values.size(); ++jj) {
const QQmlEnumValue &value = enumData.values.at(jj);
enumeration.addKey(value.namedValue.toUtf8(), value.value);
}
}
if (!_defaultPropertyName.isEmpty()) {
- QQmlPropertyData *dp = property(_defaultPropertyName, nullptr, nullptr);
+ const QQmlPropertyData *dp = property(_defaultPropertyName, nullptr, nullptr);
if (dp && dp->coreIndex() >= propertyIndexCacheStart) {
Q_ASSERT(!dp->isFunction());
builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
}
}
+
+ if (!_listPropertyAssignBehavior.isEmpty())
+ builder.addClassInfo("QML.ListPropertyAssignBehavior", _listPropertyAssignBehavior);
}
namespace {
@@ -1204,14 +1068,12 @@ template <typename StringVisitor, typename TypeInfoVisitor>
int visitMethods(const QMetaObject &mo, int methodOffset, int methodCount,
StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
{
- const int intsPerMethod = 5;
-
int fieldsForParameterData = 0;
bool hasRevisionedMethods = false;
for (int i = 0; i < methodCount; ++i) {
- const int handle = methodOffset + i * intsPerMethod;
+ const int handle = methodOffset + i * QMetaObjectPrivate::IntsPerMethod;
const uint flags = mo.d.data[handle + 4];
if (flags & MethodRevisioned)
@@ -1241,42 +1103,23 @@ int visitMethods(const QMetaObject &mo, int methodOffset, int methodCount,
if (hasRevisionedMethods)
fieldsForRevisions = methodCount;
- return methodCount * intsPerMethod + fieldsForRevisions + fieldsForParameterData;
+ return methodCount * QMetaObjectPrivate::IntsPerMethod
+ + fieldsForRevisions + fieldsForParameterData;
}
template <typename StringVisitor, typename TypeInfoVisitor>
int visitProperties(const QMetaObject &mo, StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
{
const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
- const int intsPerProperty = 3;
-
- bool hasRevisionedProperties = false;
- bool hasNotifySignals = false;
for (int i = 0; i < priv->propertyCount; ++i) {
- const int handle = priv->propertyData + i * intsPerProperty;
-
- const auto flags = mo.d.data[handle + 2];
- if (flags & Revisioned) {
- hasRevisionedProperties = true;
- }
- if (flags & Notify)
- hasNotifySignals = true;
+ const int handle = priv->propertyData + i * QMetaObjectPrivate::IntsPerProperty;
visitString(mo.d.data[handle]); // name
visitTypeInfo(mo.d.data[handle + 1]);
}
- int fieldsForPropertyRevisions = 0;
- if (hasRevisionedProperties)
- fieldsForPropertyRevisions = priv->propertyCount;
-
- int fieldsForNotifySignals = 0;
- if (hasNotifySignals)
- fieldsForNotifySignals = priv->propertyCount;
-
- return priv->propertyCount * intsPerProperty + fieldsForPropertyRevisions
- + fieldsForNotifySignals;
+ return priv->propertyCount * QMetaObjectPrivate::IntsPerProperty;
}
template <typename StringVisitor>
@@ -1299,21 +1142,19 @@ template <typename StringVisitor>
int visitEnumerations(const QMetaObject &mo, StringVisitor visitString)
{
const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
- const int intsPerEnumerator = priv->revision >= 8 ? 5 : 4;
- int fieldCount = priv->enumeratorCount * intsPerEnumerator;
+ int fieldCount = priv->enumeratorCount * QMetaObjectPrivate::IntsPerEnum;
for (int i = 0; i < priv->enumeratorCount; ++i) {
- const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * intsPerEnumerator;
+ const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * QMetaObjectPrivate::IntsPerEnum;
- const uint keyCount = enumeratorData[intsPerEnumerator == 5 ? 3 : 2];
+ const uint keyCount = enumeratorData[3];
fieldCount += keyCount * 2;
visitString(enumeratorData[0]); // name
- if (intsPerEnumerator == 5)
- visitString(enumeratorData[1]); // enum name
+ visitString(enumeratorData[1]); // enum name
- const uint keyOffset = enumeratorData[intsPerEnumerator == 5 ? 4 : 3];
+ const uint keyOffset = enumeratorData[4];
for (uint j = 0; j < keyCount; ++j) {
visitString(mo.d.data[keyOffset + 2 * j]);
@@ -1349,13 +1190,14 @@ int countMetaObjectFields(const QMetaObject &mo, StringVisitor stringVisitor)
} // anonymous namespace
+static_assert(QMetaObjectPrivate::OutputRevision == 12, "Check and adjust determineMetaObjectSizes");
+
bool QQmlPropertyCache::determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount,
int *stringCount)
{
const QMetaObjectPrivate *priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
- if (priv->revision < 7 || priv->revision > 8) {
+ if (priv->revision != QMetaObjectPrivate::OutputRevision)
return false;
- }
uint highestStringIndex = 0;
const auto stringIndexVisitor = [&highestStringIndex](uint index) {
@@ -1376,7 +1218,7 @@ bool QQmlPropertyCache::addToHash(QCryptographicHash &hash, const QMetaObject &m
return false;
}
- hash.addData(reinterpret_cast<const char *>(mo.d.data), fieldCount * sizeof(uint));
+ hash.addData({reinterpret_cast<const char *>(mo.d.data), qsizetype(fieldCount * sizeof(uint))});
for (int i = 0; i < stringCount; ++i) {
hash.addData(stringData(&mo, i));
}
@@ -1384,35 +1226,41 @@ bool QQmlPropertyCache::addToHash(QCryptographicHash &hash, const QMetaObject &m
return true;
}
-QByteArray QQmlPropertyCache::checksum(bool *ok)
+QByteArray QQmlPropertyCache::checksum(QHash<quintptr, QByteArray> *checksums, bool *ok) const
{
- if (!_checksum.isEmpty()) {
+ auto it = checksums->constFind(quintptr(this));
+ if (it != checksums->constEnd()) {
*ok = true;
- return _checksum;
+ return *it;
}
// Generate a checksum on the meta-object data only on C++ types.
- if (!_metaObject || _ownMetaObject) {
+ if (_metaObject.isShared()) {
*ok = false;
- return _checksum;
+ return QByteArray();
}
QCryptographicHash hash(QCryptographicHash::Md5);
if (_parent) {
- hash.addData(_parent->checksum(ok));
+ hash.addData(_parent->checksum(checksums, ok));
if (!*ok)
return QByteArray();
}
- if (!addToHash(hash, *createMetaObject())) {
+ if (!addToHash(hash, *_metaObject.metaObject())) {
*ok = false;
return QByteArray();
}
- _checksum = hash.result();
- *ok = !_checksum.isEmpty();
- return _checksum;
+ const QByteArray result = hash.result();
+ if (result.isEmpty()) {
+ *ok = false;
+ } else {
+ *ok = true;
+ checksums->insert(quintptr(this), result);
+ }
+ return result;
}
/*! \internal
@@ -1421,7 +1269,7 @@ QByteArray QQmlPropertyCache::checksum(bool *ok)
*/
QList<QByteArray> QQmlPropertyCache::signalParameterNames(int index) const
{
- QQmlPropertyData *signalData = signal(index);
+ const QQmlPropertyData *signalData = signal(index);
if (signalData && signalData->hasArguments()) {
QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments();
if (args && args->names)
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index bfd78eef88..7ff499460d 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYCACHE_P_H
#define QQMLPROPERTYCACHE_P_H
@@ -51,20 +15,15 @@
// We mean it.
//
+#include <private/qlinkedstringhash_p.h>
+#include <private/qqmlenumdata_p.h>
+#include <private/qqmlenumvalue_p.h>
+#include <private/qqmlpropertydata_p.h>
#include <private/qqmlrefcount_p.h>
-#include <private/qflagpointer_p.h>
-#include "qqmlcleanup_p.h"
-#include "qqmlnotifier_p.h"
-#include <private/qqmlpropertyindex_p.h>
-#include <private/qlinkedstringhash_p.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qvector.h>
-
-#include <private/qv4value_p.h>
-#include <private/qqmlpropertydata_p.h>
-#include <private/qqmlenumdata_p.h>
-#include <private/qqmlenumvalue_p.h>
+#include <QtCore/qversionnumber.h>
#include <limits>
@@ -73,81 +32,176 @@ QT_BEGIN_NAMESPACE
class QCryptographicHash;
class QJSEngine;
class QMetaObjectBuilder;
-class QQmlVMEMetaObject;
+class QQmlContextData;
+class QQmlPropertyCache;
class QQmlPropertyCacheMethodArguments;
+class QQmlVMEMetaObject;
-class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount
+class QQmlMetaObjectPointer
{
public:
- QQmlPropertyCache();
- QQmlPropertyCache(const QMetaObject *, int metaObjectRevision = 0);
- ~QQmlPropertyCache() override;
+ Q_NODISCARD_CTOR QQmlMetaObjectPointer() = default;
+
+ Q_NODISCARD_CTOR QQmlMetaObjectPointer(const QMetaObject *staticMetaObject)
+ : d(quintptr(staticMetaObject))
+ {
+ Q_ASSERT((d.loadRelaxed() & Shared) == 0);
+ }
+
+ ~QQmlMetaObjectPointer()
+ {
+ const auto dd = d.loadAcquire();
+ if (dd & Shared)
+ reinterpret_cast<SharedHolder *>(dd ^ Shared)->release();
+ }
+
+private:
+ friend class QQmlPropertyCache;
+ Q_NODISCARD_CTOR QQmlMetaObjectPointer(const QQmlMetaObjectPointer &other)
+ : d(other.d.loadRelaxed())
+ {
+ // other has to survive until this ctor is done. So d cannot disappear before.
+ const auto od = other.d.loadRelaxed();
+ if (od & Shared)
+ reinterpret_cast<SharedHolder *>(od ^ Shared)->addref();
+ }
+
+ QQmlMetaObjectPointer(QQmlMetaObjectPointer &&other) = delete;
+ QQmlMetaObjectPointer &operator=(QQmlMetaObjectPointer &&other) = delete;
+ QQmlMetaObjectPointer &operator=(const QQmlMetaObjectPointer &other) = delete;
+
+public:
+ void setSharedOnce(QMetaObject *shared) const
+ {
+ SharedHolder *holder = new SharedHolder(shared);
+ if (!d.testAndSetRelease(0, quintptr(holder) | Shared))
+ holder->release();
+ }
+
+ const QMetaObject *metaObject() const
+ {
+ const auto dd = d.loadAcquire();
+ if (dd & Shared)
+ return reinterpret_cast<SharedHolder *>(dd ^ Shared)->metaObject;
+ return reinterpret_cast<const QMetaObject *>(dd);
+ }
+
+ bool isShared() const
+ {
+ // This works because static metaobjects need to be set in the ctor and once a shared
+ // metaobject has been set, it cannot be removed anymore.
+ const auto dd = d.loadRelaxed();
+ return !dd || (dd & Shared);
+ }
+
+ bool isNull() const
+ {
+ return d.loadRelaxed() == 0;
+ }
+
+private:
+ enum Tag {
+ Static = 0,
+ Shared = 1
+ };
+
+ struct SharedHolder final : public QQmlRefCounted<SharedHolder>
+ {
+ Q_DISABLE_COPY_MOVE(SharedHolder)
+ SharedHolder(QMetaObject *shared) : metaObject(shared) {}
+ ~SharedHolder() { free(metaObject); }
+ QMetaObject *metaObject;
+ };
+
+ mutable QBasicAtomicInteger<quintptr> d = 0;
+};
+
+class Q_QML_EXPORT QQmlPropertyCache final
+ : public QQmlRefCounted<QQmlPropertyCache>
+{
+public:
+ using Ptr = QQmlRefPointer<QQmlPropertyCache>;
+
+ struct ConstPtr : public QQmlRefPointer<const QQmlPropertyCache>
+ {
+ using QQmlRefPointer<const QQmlPropertyCache>::QQmlRefPointer;
+
+ ConstPtr(const Ptr &ptr) : ConstPtr(ptr.data(), AddRef) {}
+ ConstPtr(Ptr &&ptr) : ConstPtr(ptr.take(), Adopt) {}
+ ConstPtr &operator=(const Ptr &ptr) { return operator=(ConstPtr(ptr)); }
+ ConstPtr &operator=(Ptr &&ptr) { return operator=(ConstPtr(std::move(ptr))); }
+ };
+
+ static Ptr createStandalone(
+ const QMetaObject *, QTypeRevision metaObjectRevision = QTypeRevision::zero());
+
+ QQmlPropertyCache() = default;
+ ~QQmlPropertyCache();
void update(const QMetaObject *);
void invalidate(const QMetaObject *);
- QQmlPropertyCache *copy();
+ QQmlPropertyCache::Ptr copy() const;
- QQmlPropertyCache *copyAndAppend(const QMetaObject *,
- QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
- QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(),
- QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags());
- QQmlPropertyCache *copyAndAppend(const QMetaObject *, int typeMinorVersion,
+ QQmlPropertyCache::Ptr copyAndAppend(
+ const QMetaObject *, QTypeRevision typeVersion,
QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(),
- QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags());
+ QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags()) const;
- QQmlPropertyCache *copyAndReserve(int propertyCount,
- int methodCount, int signalCount, int enumCount);
+ QQmlPropertyCache::Ptr copyAndReserve(
+ int propertyCount, int methodCount, int signalCount, int enumCount) const;
void appendProperty(const QString &, QQmlPropertyData::Flags flags, int coreIndex,
- int propType, int revision, int notifyIndex);
+ QMetaType propType, QTypeRevision revision, int notifyIndex);
void appendSignal(const QString &, QQmlPropertyData::Flags, int coreIndex,
- const int *types = nullptr, const QList<QByteArray> &names = QList<QByteArray>());
- void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex, int returnType,
- const QList<QByteArray> &names, const QVector<int> &parameterTypes);
+ const QMetaType *types = nullptr,
+ const QList<QByteArray> &names = QList<QByteArray>());
+ void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex,
+ QMetaType returnType, const QList<QByteArray> &names,
+ const QVector<QMetaType> &parameterTypes);
void appendEnum(const QString &, const QVector<QQmlEnumValue> &);
const QMetaObject *metaObject() const;
- const QMetaObject *createMetaObject();
+ const QMetaObject *createMetaObject() const;
const QMetaObject *firstCppMetaObject() const;
template<typename K>
- QQmlPropertyData *property(const K &key, QObject *object, QQmlContextData *context) const
+ const QQmlPropertyData *property(const K &key, QObject *object,
+ const QQmlRefPointer<QQmlContextData> &context) const
{
return findProperty(stringCache.find(key), object, context);
}
- QQmlPropertyData *property(int) const;
- QQmlPropertyData *method(int) const;
- QQmlPropertyData *signal(int index) const;
+ const QQmlPropertyData *property(int) const;
+ const QQmlPropertyData *maybeUnresolvedProperty(int) const;
+ const QQmlPropertyData *method(int) const;
+ const QQmlPropertyData *signal(int index) const;
QQmlEnumData *qmlEnum(int) const;
int methodIndexToSignalIndex(int) const;
QString defaultPropertyName() const;
- QQmlPropertyData *defaultProperty() const;
- QQmlPropertyCache *parent() const;
- // is used by the Qml Designer
- void setParent(QQmlPropertyCache *newParent);
+ const QQmlPropertyData *defaultProperty() const;
- inline QQmlPropertyData *overrideData(QQmlPropertyData *) const;
- inline bool isAllowedInRevision(QQmlPropertyData *) const;
+ // Return a reference here so that we don't have to addref/release all the time
+ inline const QQmlPropertyCache::ConstPtr &parent() const;
- static QQmlPropertyData *property(QJSEngine *, QObject *, const QStringRef &,
- QQmlContextData *, QQmlPropertyData &);
- static QQmlPropertyData *property(QJSEngine *, QObject *, const QLatin1String &,
- QQmlContextData *, QQmlPropertyData &);
- static QQmlPropertyData *property(QJSEngine *, QObject *, const QV4::String *,
- QQmlContextData *, QQmlPropertyData &);
+ // is used by the Qml Designer
+ void setParent(QQmlPropertyCache::ConstPtr newParent);
- static QQmlPropertyData *property(QJSEngine *engine, QObject *obj, const QString &name,
- QQmlContextData *context, QQmlPropertyData &local)
- {
- return property(engine, obj, QStringRef(&name), context, local);
- }
+ inline const QQmlPropertyData *overrideData(const QQmlPropertyData *) const;
+ inline bool isAllowedInRevision(const QQmlPropertyData *) const;
+
+ static const QQmlPropertyData *property(
+ QObject *, QStringView, const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData *);
+ static const QQmlPropertyData *property(QObject *, const QLatin1String &, const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData *);
+ static const QQmlPropertyData *property(QObject *, const QV4::String *, const QQmlRefPointer<QQmlContextData> &,
+ QQmlPropertyData *);
//see QMetaObjectPrivate::originalClone
- int originalClone(int index);
- static int originalClone(QObject *, int index);
+ int originalClone(int index) const;
+ static int originalClone(const QObject *, int index);
QList<QByteArray> signalParameterNames(int index) const;
static QString signalParameterStringForJS(QV4::ExecutionEngine *engine, const QList<QByteArray> &parameterNameList, QString *errorString = nullptr);
@@ -162,31 +216,31 @@ public:
inline int signalOffset() const;
inline int qmlEnumCount() const;
- static bool isDynamicMetaObject(const QMetaObject *);
-
- void toMetaObjectBuilder(QMetaObjectBuilder &);
+ void toMetaObjectBuilder(QMetaObjectBuilder &) const;
inline bool callJSFactoryMethod(QObject *object, void **args) const;
static bool determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount);
static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo);
- QByteArray checksum(bool *ok);
+ QByteArray checksum(QHash<quintptr, QByteArray> *checksums, bool *ok) const;
- int allowedRevision(int index) const { return allowedRevisionCache[index]; }
- void setAllowedRevision(int index, int allowed) { allowedRevisionCache[index] = allowed; }
+ QTypeRevision allowedRevision(int index) const { return allowedRevisionCache[index]; }
+ void setAllowedRevision(int index, QTypeRevision allowed) { allowedRevisionCache[index] = allowed; }
private:
friend class QQmlEnginePrivate;
friend class QQmlCompiler;
template <typename T> friend class QQmlPropertyCacheCreator;
template <typename T> friend class QQmlPropertyCacheAliasCreator;
- friend class QQmlComponentAndAliasResolver;
+ template <typename T> friend class QQmlComponentAndAliasResolver;
friend class QQmlMetaObject;
- inline QQmlPropertyCache *copy(int reserve);
+ QQmlPropertyCache(const QQmlMetaObjectPointer &metaObject) : _metaObject(metaObject) {}
- void append(const QMetaObject *, int typeMinorVersion,
+ inline QQmlPropertyCache::Ptr copy(const QQmlMetaObjectPointer &mo, int reserve) const;
+
+ void append(const QMetaObject *, QTypeRevision typeVersion,
QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(),
QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(),
QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags());
@@ -195,15 +249,12 @@ private:
typedef QVector<QQmlPropertyData> IndexCache;
typedef QLinkedStringMultiHash<QPair<int, QQmlPropertyData *> > StringCache;
- typedef QVector<int> AllowedRevisionCache;
-
- QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *, QQmlContextData *) const;
- QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *, QQmlContextData *) const;
+ typedef QVector<QTypeRevision> AllowedRevisionCache;
- QQmlPropertyData *ensureResolved(QQmlPropertyData*) const;
-
- Q_NEVER_INLINE void resolve(QQmlPropertyData *) const;
- void updateRecur(const QMetaObject *);
+ const QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *,
+ const QQmlRefPointer<QQmlContextData> &) const;
+ const QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *,
+ const QQmlRefPointer<QQmlContextData> &) const;
template<typename K>
QQmlPropertyData *findNamedProperty(const K &key) const
@@ -213,17 +264,36 @@ private:
}
template<typename K>
- void setNamedProperty(const K &key, int index, QQmlPropertyData *data, bool isOverride)
+ void setNamedProperty(const K &key, int index, QQmlPropertyData *data)
{
stringCache.insert(key, qMakePair(index, data));
- _hasPropertyOverrides |= isOverride;
}
private:
- QQmlPropertyCache *_parent;
- int propertyIndexCacheStart;
- int methodIndexCacheStart;
- int signalHandlerIndexCacheStart;
+ enum OverrideResult { NoOverride, InvalidOverride, ValidOverride };
+
+ template<typename String>
+ OverrideResult handleOverride(const String &name, QQmlPropertyData *data, QQmlPropertyData *old)
+ {
+ if (!old)
+ return NoOverride;
+
+ if (data->markAsOverrideOf(old))
+ return ValidOverride;
+
+ qWarning("Final member %s is overridden in class %s. The override won't be used.",
+ qPrintable(name), className());
+ return InvalidOverride;
+ }
+
+ template<typename String>
+ OverrideResult handleOverride(const String &name, QQmlPropertyData *data)
+ {
+ return handleOverride(name, data, findNamedProperty(name));
+ }
+
+ int propertyIndexCacheStart = 0; // placed here to avoid gap between QQmlRefCount and _parent
+ QQmlPropertyCache::ConstPtr _parent;
IndexCache propertyIndexCache;
IndexCache methodIndexCache;
@@ -232,84 +302,75 @@ private:
AllowedRevisionCache allowedRevisionCache;
QVector<QQmlEnumData> enumCache;
- bool _hasPropertyOverrides : 1;
- bool _ownMetaObject : 1;
- const QMetaObject *_metaObject;
+ QQmlMetaObjectPointer _metaObject;
QByteArray _dynamicClassName;
QByteArray _dynamicStringData;
+ QByteArray _listPropertyAssignBehavior;
QString _defaultPropertyName;
- QQmlPropertyCacheMethodArguments *argumentsCache;
- int _jsFactoryMethodIndex;
- QByteArray _checksum;
+ QQmlPropertyCacheMethodArguments *argumentsCache = nullptr;
+ int methodIndexCacheStart = 0;
+ int signalHandlerIndexCacheStart = 0;
+ int _jsFactoryMethodIndex = -1;
};
-inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const
-{
- if (p && Q_UNLIKELY(p->notFullyResolved()))
- resolve(p);
-
- return p;
-}
-
// Returns this property cache's metaObject. May be null if it hasn't been created yet.
inline const QMetaObject *QQmlPropertyCache::metaObject() const
{
- return _metaObject;
+ return _metaObject.metaObject();
}
// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
// QML
inline const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
{
- while (_parent && (_metaObject == nullptr || _ownMetaObject))
- return _parent->firstCppMetaObject();
- return _metaObject;
+ const QQmlPropertyCache *p = this;
+ while (p->_metaObject.isShared())
+ p = p->parent().data();
+ return p->_metaObject.metaObject();
}
-inline QQmlPropertyData *QQmlPropertyCache::property(int index) const
+inline const QQmlPropertyData *QQmlPropertyCache::property(int index) const
{
- if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
+ if (index < 0 || index >= propertyCount())
return nullptr;
if (index < propertyIndexCacheStart)
return _parent->property(index);
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
- return ensureResolved(rv);
+ return &propertyIndexCache.at(index - propertyIndexCacheStart);
}
-inline QQmlPropertyData *QQmlPropertyCache::method(int index) const
+inline const QQmlPropertyData *QQmlPropertyCache::method(int index) const
{
- if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+ if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.size()))
return nullptr;
if (index < methodIndexCacheStart)
return _parent->method(index);
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
- return ensureResolved(rv);
+ return const_cast<const QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
}
/*! \internal
\a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
This is different from QMetaMethod::methodIndex().
*/
-inline QQmlPropertyData *QQmlPropertyCache::signal(int index) const
+inline const QQmlPropertyData *QQmlPropertyCache::signal(int index) const
{
- if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
+ if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.size()))
return nullptr;
if (index < signalHandlerIndexCacheStart)
return _parent->signal(index);
- QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
+ const QQmlPropertyData *rv = const_cast<const QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
Q_ASSERT(rv->isSignal() || rv->coreIndex() == -1);
- return ensureResolved(rv);
+ return rv;
}
inline QQmlEnumData *QQmlPropertyCache::qmlEnum(int index) const
{
- if (index < 0 || index >= enumCache.count())
+ if (index < 0 || index >= enumCache.size())
return nullptr;
return const_cast<QQmlEnumData *>(&enumCache.at(index));
@@ -317,7 +378,7 @@ inline QQmlEnumData *QQmlPropertyCache::qmlEnum(int index) const
inline int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
{
- if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+ if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.size()))
return index;
if (index < methodIndexCacheStart)
@@ -332,13 +393,13 @@ inline QString QQmlPropertyCache::defaultPropertyName() const
return _defaultPropertyName;
}
-inline QQmlPropertyCache *QQmlPropertyCache::parent() const
+inline const QQmlPropertyCache::ConstPtr &QQmlPropertyCache::parent() const
{
return _parent;
}
-QQmlPropertyData *
-QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
+const QQmlPropertyData *
+QQmlPropertyCache::overrideData(const QQmlPropertyData *data) const
{
if (!data->hasOverride())
return nullptr;
@@ -349,15 +410,30 @@ QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
return method(data->overrideIndex());
}
-bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const
+bool QQmlPropertyCache::isAllowedInRevision(const QQmlPropertyData *data) const
{
- return (data->metaObjectOffset() == -1 && data->revision() == 0) ||
- (allowedRevisionCache[data->metaObjectOffset()] >= data->revision());
+ const QTypeRevision requested = data->revision();
+ const int offset = data->metaObjectOffset();
+ if (offset == -1 && requested == QTypeRevision::zero())
+ return true;
+
+ Q_ASSERT(offset >= 0);
+ Q_ASSERT(offset < allowedRevisionCache.size());
+ const QTypeRevision allowed = allowedRevisionCache[offset];
+
+ if (requested.hasMajorVersion()) {
+ if (requested.majorVersion() > allowed.majorVersion())
+ return false;
+ if (requested.majorVersion() < allowed.majorVersion())
+ return true;
+ }
+
+ return !requested.hasMinorVersion() || requested.minorVersion() <= allowed.minorVersion();
}
int QQmlPropertyCache::propertyCount() const
{
- return propertyIndexCacheStart + propertyIndexCache.count();
+ return propertyIndexCacheStart + int(propertyIndexCache.size());
}
int QQmlPropertyCache::propertyOffset() const
@@ -367,7 +443,7 @@ int QQmlPropertyCache::propertyOffset() const
int QQmlPropertyCache::methodCount() const
{
- return methodIndexCacheStart + methodIndexCache.count();
+ return methodIndexCacheStart + int(methodIndexCache.size());
}
int QQmlPropertyCache::methodOffset() const
@@ -377,7 +453,7 @@ int QQmlPropertyCache::methodOffset() const
int QQmlPropertyCache::signalCount() const
{
- return signalHandlerIndexCacheStart + signalHandlerIndexCache.count();
+ return signalHandlerIndexCacheStart + int(signalHandlerIndexCache.size());
}
int QQmlPropertyCache::signalOffset() const
@@ -387,14 +463,18 @@ int QQmlPropertyCache::signalOffset() const
int QQmlPropertyCache::qmlEnumCount() const
{
- return enumCache.count();
+ return int(enumCache.size());
}
bool QQmlPropertyCache::callJSFactoryMethod(QObject *object, void **args) const
{
if (_jsFactoryMethodIndex != -1) {
- _metaObject->d.static_metacall(object, QMetaObject::InvokeMetaMethod, _jsFactoryMethodIndex, args);
- return true;
+ if (const QMetaObject *mo = _metaObject.metaObject()) {
+ mo->d.static_metacall(object, QMetaObject::InvokeMetaMethod,
+ _jsFactoryMethodIndex, args);
+ return true;
+ }
+ return false;
}
if (_parent)
return _parent->callJSFactoryMethod(object, args);
diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp
index 034ebfc743..06b405c7e4 100644
--- a/src/qml/qml/qqmlpropertycachecreator.cpp
+++ b/src/qml/qml/qqmlpropertycachecreator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertycachecreator_p.h"
@@ -45,37 +9,61 @@ QT_BEGIN_NAMESPACE
QAtomicInt QQmlPropertyCacheCreatorBase::classIndexCounter(0);
+template<typename BaseNameHandler, typename FailHandler>
+auto processUrlForClassName(
+ const QUrl &url, BaseNameHandler &&baseNameHandler, FailHandler &&failHandler)
+{
+ const QString path = url.path();
+
+ // Not a reusable type if we don't have an absolute Url
+ const qsizetype lastSlash = path.lastIndexOf(QLatin1Char('/'));
+ if (lastSlash <= -1)
+ return failHandler();
+
+ // ### this might not be correct for .ui.qml files
+ const QStringView baseName = QStringView{path}.mid(lastSlash + 1, path.size() - lastSlash - 5);
+
+ // Not a reusable type if it doesn't start with a upper case letter.
+ return (!baseName.isEmpty() && baseName.at(0).isUpper())
+ ? baseNameHandler(baseName)
+ : failHandler();
+}
+
+bool QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(const QUrl &url)
+{
+ return processUrlForClassName(url, [](QStringView) {
+ return true;
+ }, []() {
+ return false;
+ });
+}
-int QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(QV4::CompiledData::BuiltinType type)
+QByteArray QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(const QUrl &url)
{
- switch (type) {
- case QV4::CompiledData::BuiltinType::Var: return QMetaType::QVariant;
- case QV4::CompiledData::BuiltinType::Variant: return QMetaType::QVariant;
- case QV4::CompiledData::BuiltinType::Int: return QMetaType::Int;
- case QV4::CompiledData::BuiltinType::Bool: return QMetaType::Bool;
- case QV4::CompiledData::BuiltinType::Real: return QMetaType::Double;
- case QV4::CompiledData::BuiltinType::String: return QMetaType::QString;
- case QV4::CompiledData::BuiltinType::Url: return QMetaType::QUrl;
- case QV4::CompiledData::BuiltinType::Color: return QMetaType::QColor;
- case QV4::CompiledData::BuiltinType::Font: return QMetaType::QFont;
- case QV4::CompiledData::BuiltinType::Time: return QMetaType::QTime;
- case QV4::CompiledData::BuiltinType::Date: return QMetaType::QDate;
- case QV4::CompiledData::BuiltinType::DateTime: return QMetaType::QDateTime;
- case QV4::CompiledData::BuiltinType::Rect: return QMetaType::QRectF;
- case QV4::CompiledData::BuiltinType::Point: return QMetaType::QPointF;
- case QV4::CompiledData::BuiltinType::Size: return QMetaType::QSizeF;
- case QV4::CompiledData::BuiltinType::Vector2D: return QMetaType::QVector2D;
- case QV4::CompiledData::BuiltinType::Vector3D: return QMetaType::QVector3D;
- case QV4::CompiledData::BuiltinType::Vector4D: return QMetaType::QVector4D;
- case QV4::CompiledData::BuiltinType::Matrix4x4: return QMetaType::QMatrix4x4;
- case QV4::CompiledData::BuiltinType::Quaternion: return QMetaType::QQuaternion;
- case QV4::CompiledData::BuiltinType::InvalidBuiltin: break;
- };
- return QMetaType::UnknownType;
+ return processUrlForClassName(url, [](QStringView nameBase) {
+ return nameBase.toUtf8() + QByteArray("_QMLTYPE_");
+ }, []() {
+ return QByteArray("ANON_QML_TYPE_");
+ }) + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
}
-QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding,
- const QString &instantiatingPropertyName, QQmlPropertyCache *referencingObjectPropertyCache)
+QByteArray QQmlPropertyCacheCreatorBase::createClassNameForInlineComponent(
+ const QUrl &baseUrl, const QString &name)
+{
+ QByteArray baseName = processUrlForClassName(baseUrl, [](QStringView nameBase) {
+ return QByteArray(nameBase.toUtf8() + "_QMLTYPE_");
+ }, []() {
+ return QByteArray("ANON_QML_IC_");
+ });
+ return baseName + name.toUtf8() + '_'
+ + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
+}
+
+QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(
+ int referencingObjectIndex,
+ const QV4::CompiledData::Binding *instantiatingBinding,
+ const QString &instantiatingPropertyName,
+ const QQmlPropertyCache::ConstPtr &referencingObjectPropertyCache)
: referencingObjectIndex(referencingObjectIndex)
, instantiatingBinding(instantiatingBinding)
, instantiatingPropertyName(instantiatingPropertyName)
@@ -85,11 +73,15 @@ QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencing
bool QQmlBindingInstantiationContext::resolveInstantiatingProperty()
{
- if (!instantiatingBinding || instantiatingBinding->type != QV4::CompiledData::Binding::Type_GroupProperty)
+ if (!instantiatingBinding
+ || instantiatingBinding->type() != QV4::CompiledData::Binding::Type_GroupProperty) {
return true;
+ }
+
+ if (!referencingObjectPropertyCache)
+ return false;
Q_ASSERT(referencingObjectIndex >= 0);
- Q_ASSERT(referencingObjectPropertyCache);
Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
bool notInRevision = false;
@@ -99,19 +91,34 @@ bool QQmlBindingInstantiationContext::resolveInstantiatingProperty()
return instantiatingProperty != nullptr;
}
-QQmlRefPointer<QQmlPropertyCache> QQmlBindingInstantiationContext::instantiatingPropertyCache(QQmlEnginePrivate *enginePrivate) const
+QQmlPropertyCache::ConstPtr QQmlBindingInstantiationContext::instantiatingPropertyCache() const
{
if (instantiatingProperty) {
if (instantiatingProperty->isQObject()) {
- return enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType(), instantiatingProperty->typeMinorVersion());
- } else if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(instantiatingProperty->propType())) {
- return enginePrivate->cache(vtmo, instantiatingProperty->typeMinorVersion());
+ // rawPropertyCacheForType assumes a given unspecified version means "any version".
+ // There is another overload that takes no version, which we shall not use here.
+ auto result = QQmlMetaType::rawPropertyCacheForType(instantiatingProperty->propType(),
+ instantiatingProperty->typeVersion());
+ if (result)
+ return result;
+ /* We might end up here if there's a grouped property, and the type hasn't been registered.
+ Still try to get a property cache, as long as the type of the property is well-behaved
+ (i.e., not dynamic)*/
+ if (auto metaObject = instantiatingProperty->propType().metaObject(); metaObject) {
+ // we'll warn about dynamic meta-object later in the property validator
+ if (!(QMetaObjectPrivate::get(metaObject)->flags & DynamicMetaObject))
+ return QQmlMetaType::propertyCache(metaObject);
+ }
+ // fall through intentional
+ } else if (const QMetaObject *vtmo = QQmlMetaType::metaObjectForValueType(instantiatingProperty->propType())) {
+ return QQmlMetaType::propertyCache(vtmo, instantiatingProperty->typeVersion());
}
}
- return QQmlRefPointer<QQmlPropertyCache>();
+ return QQmlPropertyCache::ConstPtr();
}
-void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(QQmlEnginePrivate *enginePrivate, QQmlPropertyCacheVector *propertyCaches) const
+void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(
+ QQmlPropertyCacheVector *propertyCaches) const
{
for (QQmlBindingInstantiationContext pendingBinding: *this) {
const int groupPropertyObjectIndex = pendingBinding.instantiatingBinding->value.objectIndex;
@@ -119,10 +126,16 @@ void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(QQmlEnginePr
if (propertyCaches->at(groupPropertyObjectIndex))
continue;
+ Q_ASSERT(!pendingBinding.instantiatingPropertyName.isEmpty());
+
+ if (!pendingBinding.referencingObjectPropertyCache) {
+ pendingBinding.referencingObjectPropertyCache
+ = propertyCaches->at(pendingBinding.referencingObjectIndex);
+ }
+
if (!pendingBinding.resolveInstantiatingProperty())
continue;
-
- auto cache = pendingBinding.instantiatingPropertyCache(enginePrivate);
+ auto cache = pendingBinding.instantiatingPropertyCache();
propertyCaches->set(groupPropertyObjectIndex, cache);
}
}
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index 39778aa328..4d49ca6ed4 100644
--- a/src/qml/qml/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYCACHECREATOR_P_H
#define QQMLPROPERTYCACHECREATOR_P_H
@@ -55,69 +19,168 @@
#include <private/qqmlmetaobject_p.h>
#include <private/qqmlpropertyresolver_p.h>
#include <private/qqmltypedata_p.h>
+#include <private/inlinecomponentutils_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qqmlsignalnames_p.h>
+
+#include <QScopedValueRollback>
+
+#if QT_CONFIG(regularexpression)
+#include <QtCore/qregularexpression.h>
+#endif
+
+#include <vector>
QT_BEGIN_NAMESPACE
-inline QQmlJS::DiagnosticMessage qQmlCompileError(const QV4::CompiledData::Location &location,
+inline QQmlError qQmlCompileError(const QV4::CompiledData::Location &location,
const QString &description)
{
- QQmlJS::DiagnosticMessage error;
- error.line = location.line;
- error.column = location.column;
- error.message = description;
+ QQmlError error;
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
+ error.setDescription(description);
return error;
}
struct QQmlBindingInstantiationContext {
QQmlBindingInstantiationContext() {}
- QQmlBindingInstantiationContext(int referencingObjectIndex,
- const QV4::CompiledData::Binding *instantiatingBinding,
- const QString &instantiatingPropertyName,
- QQmlPropertyCache *referencingObjectPropertyCache);
+ QQmlBindingInstantiationContext(
+ int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding,
+ const QString &instantiatingPropertyName,
+ const QQmlPropertyCache::ConstPtr &referencingObjectPropertyCache);
bool resolveInstantiatingProperty();
- QQmlRefPointer<QQmlPropertyCache> instantiatingPropertyCache(QQmlEnginePrivate *enginePrivate) const;
+ QQmlPropertyCache::ConstPtr instantiatingPropertyCache() const;
int referencingObjectIndex = -1;
const QV4::CompiledData::Binding *instantiatingBinding = nullptr;
QString instantiatingPropertyName;
- QQmlRefPointer<QQmlPropertyCache> referencingObjectPropertyCache;
- QQmlPropertyData *instantiatingProperty = nullptr;
+ QQmlPropertyCache::ConstPtr referencingObjectPropertyCache;
+ const QQmlPropertyData *instantiatingProperty = nullptr;
};
struct QQmlPendingGroupPropertyBindings : public QVector<QQmlBindingInstantiationContext>
{
- void resolveMissingPropertyCaches(QQmlEnginePrivate *enginePrivate, QQmlPropertyCacheVector *propertyCaches) const;
+ void resolveMissingPropertyCaches(
+ QQmlPropertyCacheVector *propertyCaches) const;
};
struct QQmlPropertyCacheCreatorBase
{
Q_DECLARE_TR_FUNCTIONS(QQmlPropertyCacheCreatorBase)
public:
- static QAtomicInt classIndexCounter;
+ static QAtomicInt Q_AUTOTEST_EXPORT classIndexCounter;
+
+ static QMetaType metaTypeForPropertyType(QV4::CompiledData::CommonType type)
+ {
+ switch (type) {
+ case QV4::CompiledData::CommonType::Void: return QMetaType();
+ case QV4::CompiledData::CommonType::Var: return QMetaType::fromType<QVariant>();
+ case QV4::CompiledData::CommonType::Int: return QMetaType::fromType<int>();
+ case QV4::CompiledData::CommonType::Bool: return QMetaType::fromType<bool>();
+ case QV4::CompiledData::CommonType::Real: return QMetaType::fromType<qreal>();
+ case QV4::CompiledData::CommonType::String: return QMetaType::fromType<QString>();
+ case QV4::CompiledData::CommonType::Url: return QMetaType::fromType<QUrl>();
+ case QV4::CompiledData::CommonType::Time: return QMetaType::fromType<QTime>();
+ case QV4::CompiledData::CommonType::Date: return QMetaType::fromType<QDate>();
+ case QV4::CompiledData::CommonType::DateTime: return QMetaType::fromType<QDateTime>();
+#if QT_CONFIG(regularexpression)
+ case QV4::CompiledData::CommonType::RegExp: return QMetaType::fromType<QRegularExpression>();
+#else
+ case QV4::CompiledData::CommonType::RegExp: return QMetaType();
+#endif
+ case QV4::CompiledData::CommonType::Rect: return QMetaType::fromType<QRectF>();
+ case QV4::CompiledData::CommonType::Point: return QMetaType::fromType<QPointF>();
+ case QV4::CompiledData::CommonType::Size: return QMetaType::fromType<QSizeF>();
+ case QV4::CompiledData::CommonType::Invalid: break;
+ };
+ return QMetaType {};
+ }
+
+ static QMetaType listTypeForPropertyType(QV4::CompiledData::CommonType type)
+ {
+ switch (type) {
+ case QV4::CompiledData::CommonType::Void: return QMetaType();
+ case QV4::CompiledData::CommonType::Var: return QMetaType::fromType<QList<QVariant>>();
+ case QV4::CompiledData::CommonType::Int: return QMetaType::fromType<QList<int>>();
+ case QV4::CompiledData::CommonType::Bool: return QMetaType::fromType<QList<bool>>();
+ case QV4::CompiledData::CommonType::Real: return QMetaType::fromType<QList<qreal>>();
+ case QV4::CompiledData::CommonType::String: return QMetaType::fromType<QList<QString>>();
+ case QV4::CompiledData::CommonType::Url: return QMetaType::fromType<QList<QUrl>>();
+ case QV4::CompiledData::CommonType::Time: return QMetaType::fromType<QList<QTime>>();
+ case QV4::CompiledData::CommonType::Date: return QMetaType::fromType<QList<QDate>>();
+ case QV4::CompiledData::CommonType::DateTime: return QMetaType::fromType<QList<QDateTime>>();
+#if QT_CONFIG(regularexpression)
+ case QV4::CompiledData::CommonType::RegExp: return QMetaType::fromType<QList<QRegularExpression>>();
+#else
+ case QV4::CompiledData::CommonType::RegExp: return QMetaType();
+#endif
+ case QV4::CompiledData::CommonType::Rect: return QMetaType::fromType<QList<QRectF>>();
+ case QV4::CompiledData::CommonType::Point: return QMetaType::fromType<QList<QPointF>>();
+ case QV4::CompiledData::CommonType::Size: return QMetaType::fromType<QList<QSizeF>>();
+ case QV4::CompiledData::CommonType::Invalid: break;
+ };
+ return QMetaType {};
+ }
+
+ static bool canCreateClassNameTypeByUrl(const QUrl &url);
+ static QByteArray createClassNameTypeByUrl(const QUrl &url);
- static int metaTypeForPropertyType(QV4::CompiledData::BuiltinType type);
+ static QByteArray createClassNameForInlineComponent(const QUrl &baseUrl, const QString &name);
+
+ struct IncrementalResult {
+ // valid if and only if an error occurred
+ QQmlError error;
+ // true if there was no error and there are still components left to process
+ bool canResume = false;
+ // the object index of the last processed (inline) component root.
+ int processedRoot = 0;
+ };
};
template <typename ObjectContainer>
class QQmlPropertyCacheCreator : public QQmlPropertyCacheCreatorBase
{
public:
- typedef typename ObjectContainer::CompiledObject CompiledObject;
+ using CompiledObject = typename ObjectContainer::CompiledObject;
+ using InlineComponent = typename std::remove_reference<decltype (*(std::declval<CompiledObject>().inlineComponentsBegin()))>::type;
QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches,
QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings,
QQmlEnginePrivate *enginePrivate,
- const ObjectContainer *objectContainer, const QQmlImports *imports);
-
- QQmlJS::DiagnosticMessage buildMetaObjects();
-
+ const ObjectContainer *objectContainer, const QQmlImports *imports,
+ const QByteArray &typeClassName);
+ ~QQmlPropertyCacheCreator() { propertyCaches->seal(); }
+
+
+ /*!
+ \internal
+ Creates the property cache for the CompiledObjects of objectContainer,
+ one (inline) root component at a time.
+
+ \note Later compiler passes might modify those property caches. Therefore,
+ the actual metaobjects are not created yet.
+ */
+ IncrementalResult buildMetaObjectsIncrementally();
+
+ /*!
+ \internal
+ Returns a valid error if the inline components of the objectContainer
+ form a cycle. Otherwise an invalid error is returned
+ */
+ QQmlError verifyNoICCycle();
+
+ enum class VMEMetaObjectIsRequired {
+ Maybe,
+ Always
+ };
protected:
- QQmlJS::DiagnosticMessage buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context);
- QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlJS::DiagnosticMessage *error) const;
- QQmlJS::DiagnosticMessage createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache);
+ QQmlError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired);
+ QQmlPropertyCache::ConstPtr propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const;
+ QQmlError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlPropertyCache::ConstPtr &baseTypeCache);
- int metaTypeForParameter(const QV4::CompiledData::ParameterType &param, QString *customTypeName = nullptr);
+ QMetaType metaTypeForParameter(const QV4::CompiledData::ParameterType &param, QString *customTypeName = nullptr);
QString stringAt(int index) const { return objectContainer->stringAt(index); }
@@ -126,31 +189,99 @@ protected:
const QQmlImports * const imports;
QQmlPropertyCacheVector *propertyCaches;
QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings;
+ QByteArray typeClassName; // not const as we temporarily chang it for inline components
+ unsigned int currentRoot; // set to objectID of inline component root when handling inline components
+
+ QQmlBindingInstantiationContext m_context;
+ std::vector<InlineComponent> allICs;
+ std::vector<icutils::Node> nodesSorted;
+ std::vector<icutils::Node>::reverse_iterator nodeIt = nodesSorted.rbegin();
+ bool hasCycle = false;
};
template <typename ObjectContainer>
inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches,
QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings,
QQmlEnginePrivate *enginePrivate,
- const ObjectContainer *objectContainer, const QQmlImports *imports)
+ const ObjectContainer *objectContainer, const QQmlImports *imports,
+ const QByteArray &typeClassName)
: enginePrivate(enginePrivate)
, objectContainer(objectContainer)
, imports(imports)
, propertyCaches(propertyCaches)
, pendingGroupPropertyBindings(pendingGroupPropertyBindings)
+ , typeClassName(typeClassName)
+ , currentRoot(-1)
+{
+ propertyCaches->resetAndResize(objectContainer->objectCount());
+
+ using namespace icutils;
+
+ // get a list of all inline components
+
+ for (int i=0; i != objectContainer->objectCount(); ++i) {
+ const CompiledObject *obj = objectContainer->objectAt(i);
+ for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
+ allICs.push_back(*it);
+ }
+ }
+
+ // create a graph on inline components referencing inline components
+ std::vector<icutils::Node> nodes;
+ nodes.resize(allICs.size());
+ std::iota(nodes.begin(), nodes.end(), 0);
+ AdjacencyList adjacencyList;
+ adjacencyList.resize(nodes.size());
+ fillAdjacencyListForInlineComponents(objectContainer, adjacencyList, nodes, allICs);
+
+ nodesSorted = topoSort(nodes, adjacencyList, hasCycle);
+ nodeIt = nodesSorted.rbegin();
+}
+
+template <typename ObjectContainer>
+inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::verifyNoICCycle()
{
- propertyCaches->resize(objectContainer->objectCount());
+ if (hasCycle) {
+ QQmlError diag;
+ diag.setDescription(QLatin1String("Inline components form a cycle!"));
+ return diag;
+ }
+ return {};
}
template <typename ObjectContainer>
-inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
+inline QQmlPropertyCacheCreatorBase::IncrementalResult
+QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectsIncrementally()
{
- QQmlBindingInstantiationContext context;
- return buildMetaObjectRecursively(/*root object*/0, context);
+ // needs to be checked with verifyNoICCycle before this function is called
+ Q_ASSERT(!hasCycle);
+
+ // create meta objects for inline components before compiling actual root component
+ if (nodeIt != nodesSorted.rend()) {
+ const auto &ic = allICs[nodeIt->index()];
+ QV4::ResolvedTypeReference *typeRef = objectContainer->resolvedType(ic.nameIndex);
+ Q_ASSERT(propertyCaches->at(ic.objectIndex).isNull());
+ Q_ASSERT(typeRef->typePropertyCache().isNull()); // not set yet
+
+ QByteArray icTypeName { objectContainer->stringAt(ic.nameIndex).toUtf8() };
+ QScopedValueRollback<QByteArray> nameChange {typeClassName, icTypeName};
+ QScopedValueRollback<unsigned int> rootChange {currentRoot, ic.objectIndex};
+ ++nodeIt;
+ QQmlError diag = buildMetaObjectRecursively(ic.objectIndex, m_context, VMEMetaObjectIsRequired::Always);
+ if (diag.isValid()) {
+ return {diag, false, 0};
+ }
+ typeRef->setTypePropertyCache(propertyCaches->at(ic.objectIndex));
+ Q_ASSERT(!typeRef->typePropertyCache().isNull());
+ return { QQmlError(), true, int(ic.objectIndex) };
+ }
+
+ auto diag = buildMetaObjectRecursively(/*root object*/0, m_context, VMEMetaObjectIsRequired::Maybe);
+ return {diag, false, 0};
}
template <typename ObjectContainer>
-inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context)
+inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired)
{
auto isAddressable = [](const QUrl &url) {
const QString fileName = url.fileName();
@@ -158,28 +289,32 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil
};
const CompiledObject *obj = objectContainer->objectAt(objectIndex);
- bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0
+ bool needVMEMetaObject = isVMERequired == VMEMetaObjectIsRequired::Always || obj->propertyCount() != 0 || obj->aliasCount() != 0
|| obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0
- || (((obj->flags & QV4::CompiledData::Object::IsComponent)
+ || ((obj->hasFlag(QV4::CompiledData::Object::IsComponent)
|| (objectIndex == 0 && isAddressable(objectContainer->url())))
- && !objectContainer->resolvedType(obj->inheritedTypeNameIndex)->isFullyDynamicType);
+ && !objectContainer->resolvedType(obj->inheritedTypeNameIndex)->isFullyDynamicType());
if (!needVMEMetaObject) {
auto binding = obj->bindingsBegin();
auto end = obj->bindingsEnd();
for ( ; binding != end; ++binding) {
- if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Object
+ && (binding->flags() & QV4::CompiledData::Binding::IsOnAssignment)) {
// If the on assignment is inside a group property, we need to distinguish between QObject based
// group properties and value type group properties. For the former the base type is derived from
// the property that references us, for the latter we only need a meta-object on the referencing object
// because interceptors can't go to the shared value type instances.
- if (context.instantiatingProperty && QQmlValueTypeFactory::isValueType(context.instantiatingProperty->propType())) {
+ if (context.instantiatingProperty && QQmlMetaType::isValueType(context.instantiatingProperty->propType())) {
if (!propertyCaches->needsVMEMetaObject(context.referencingObjectIndex)) {
const CompiledObject *obj = objectContainer->objectAt(context.referencingObjectIndex);
auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
- QQmlRefPointer<QQmlPropertyCache> baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- QQmlJS::DiagnosticMessage error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache);
+ QQmlPropertyCache::ConstPtr baseTypeCache = typeRef->createPropertyCache();
+ QQmlError error = baseTypeCache
+ ? createMetaObject(context.referencingObjectIndex, obj, baseTypeCache)
+ : qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr(
+ "Type cannot be used for 'on' assignment"));
if (error.isValid())
return error;
}
@@ -192,9 +327,9 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil
}
}
- QQmlRefPointer<QQmlPropertyCache> baseTypeCache;
+ QQmlPropertyCache::ConstPtr baseTypeCache;
{
- QQmlJS::DiagnosticMessage error;
+ QQmlError error;
baseTypeCache = propertyCacheForObject(obj, context, &error);
if (error.isValid())
return error;
@@ -202,7 +337,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil
if (baseTypeCache) {
if (needVMEMetaObject) {
- QQmlJS::DiagnosticMessage error = createMetaObject(objectIndex, obj, baseTypeCache);
+ QQmlError error = createMetaObject(objectIndex, obj, baseTypeCache);
if (error.isValid())
return error;
} else {
@@ -210,40 +345,51 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil
}
}
- if (QQmlPropertyCache *thisCache = propertyCaches->at(objectIndex)) {
- auto binding = obj->bindingsBegin();
- auto end = obj->bindingsEnd();
- for ( ; binding != end; ++binding)
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- QQmlBindingInstantiationContext context(objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
-
- // Binding to group property where we failed to look up the type of the
- // property? Possibly a group property that is an alias that's not resolved yet.
- // Let's attempt to resolve it after we're done with the aliases and fill in the
- // propertyCaches entry then.
- if (!context.resolveInstantiatingProperty())
- pendingGroupPropertyBindings->append(context);
-
- QQmlJS::DiagnosticMessage error = buildMetaObjectRecursively(binding->value.objectIndex, context);
- if (error.isValid())
- return error;
- }
+ QQmlPropertyCache::ConstPtr thisCache = propertyCaches->at(objectIndex);
+ auto binding = obj->bindingsBegin();
+ auto end = obj->bindingsEnd();
+ for (; binding != end; ++binding) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ // We can always resolve object, group, and attached properties.
+ break;
+ default:
+ // Everything else is of no interest here.
+ continue;
+ }
+
+ QQmlBindingInstantiationContext context(
+ objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
+
+ // Binding to group property where we failed to look up the type of the
+ // property? Possibly a group property that is an alias that's not resolved yet.
+ // Let's attempt to resolve it after we're done with the aliases and fill in the
+ // propertyCaches entry then.
+ if (!thisCache || !context.resolveInstantiatingProperty())
+ pendingGroupPropertyBindings->append(context);
+
+ QQmlError error = buildMetaObjectRecursively(
+ binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe);
+ if (error.isValid())
+ return error;
}
- QQmlJS::DiagnosticMessage noError;
+ QQmlError noError;
return noError;
}
template <typename ObjectContainer>
-inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlJS::DiagnosticMessage *error) const
+inline QQmlPropertyCache::ConstPtr QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const
{
if (context.instantiatingProperty) {
- return context.instantiatingPropertyCache(enginePrivate);
+ return context.instantiatingPropertyCache();
} else if (obj->inheritedTypeNameIndex != 0) {
auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
- if (typeRef->isFullyDynamicType) {
+ if (typeRef->isFullyDynamicType()) {
if (obj->propertyCount() > 0 || obj->aliasCount() > 0) {
*error = qQmlCompileError(obj->location, QQmlPropertyCacheCreatorBase::tr("Fully dynamic types cannot declare new properties."));
return nullptr;
@@ -258,70 +404,82 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine
}
}
- return typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- } else if (context.instantiatingBinding && context.instantiatingBinding->isAttachedProperty()) {
- auto *typeRef = objectContainer->resolvedType(
- context.instantiatingBinding->propertyNameIndex);
- Q_ASSERT(typeRef);
- QQmlType qmltype = typeRef->type;
- if (!qmltype.isValid()) {
- imports->resolveType(stringAt(context.instantiatingBinding->propertyNameIndex),
- &qmltype, nullptr, nullptr, nullptr);
- }
+ if (QQmlPropertyCache::ConstPtr propertyCache = typeRef->createPropertyCache())
+ return propertyCache;
+ *error = qQmlCompileError(
+ obj->location,
+ QQmlPropertyCacheCreatorBase::tr("Type '%1' cannot declare new members.")
+ .arg(stringAt(obj->inheritedTypeNameIndex)));
+ return nullptr;
+ } else if (const QV4::CompiledData::Binding *binding = context.instantiatingBinding) {
+ if (binding->isAttachedProperty()) {
+ auto *typeRef = objectContainer->resolvedType(
+ binding->propertyNameIndex);
+ Q_ASSERT(typeRef);
+ QQmlType qmltype = typeRef->type();
+ if (!qmltype.isValid()) {
+ imports->resolveType(
+ QQmlTypeLoader::get(enginePrivate), stringAt(binding->propertyNameIndex),
+ &qmltype, nullptr, nullptr);
+ }
- const QMetaObject *attachedMo = qmltype.attachedPropertiesType(enginePrivate);
- if (!attachedMo) {
- *error = qQmlCompileError(context.instantiatingBinding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object"));
- return nullptr;
+ const QMetaObject *attachedMo = qmltype.attachedPropertiesType(enginePrivate);
+ if (!attachedMo) {
+ *error = qQmlCompileError(binding->location, QQmlPropertyCacheCreatorBase::tr("Non-existent attached object"));
+ return nullptr;
+ }
+ return QQmlMetaType::propertyCache(attachedMo);
}
- return enginePrivate->cache(attachedMo);
}
return nullptr;
}
template <typename ObjectContainer>
-inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache)
+inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(
+ int objectIndex, const CompiledObject *obj,
+ const QQmlPropertyCache::ConstPtr &baseTypeCache)
{
- QQmlRefPointer<QQmlPropertyCache> cache;
- cache.adopt(baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(),
- obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
- obj->signalCount() + obj->propertyCount() + obj->aliasCount(), obj->enumCount()));
+ QQmlPropertyCache::Ptr cache = baseTypeCache->copyAndReserve(
+ obj->propertyCount() + obj->aliasCount(),
+ obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
+ obj->signalCount() + obj->propertyCount() + obj->aliasCount(),
+ obj->enumCount());
- propertyCaches->set(objectIndex, cache);
+ propertyCaches->setOwn(objectIndex, cache);
propertyCaches->setNeedsVMEMetaObject(objectIndex);
QByteArray newClassName;
- if (objectIndex == /*root object*/0) {
- const QString path = objectContainer->url().path();
- int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- if (lastSlash > -1) {
- const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5);
- if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
- newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
- QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
- }
+ if (objectIndex == /*root object*/0 || int(currentRoot) == objectIndex) {
+ newClassName = typeClassName;
}
if (newClassName.isEmpty()) {
- newClassName = QQmlMetaObject(baseTypeCache.data()).className();
+ newClassName = QQmlMetaObject(baseTypeCache).className();
newClassName.append("_QML_");
newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)));
}
cache->_dynamicClassName = newClassName;
- int varPropCount = 0;
+ using ListPropertyAssignBehavior = typename ObjectContainer::ListPropertyAssignBehavior;
+ switch (objectContainer->listPropertyAssignBehavior()) {
+ case ListPropertyAssignBehavior::ReplaceIfNotDefault:
+ cache->_listPropertyAssignBehavior = "ReplaceIfNotDefault";
+ break;
+ case ListPropertyAssignBehavior::Replace:
+ cache->_listPropertyAssignBehavior = "Replace";
+ break;
+ case ListPropertyAssignBehavior::Append:
+ break;
+ }
QQmlPropertyResolver resolver(baseTypeCache);
auto p = obj->propertiesBegin();
auto pend = obj->propertiesEnd();
for ( ; p != pend; ++p) {
- if (p->builtinType() == QV4::CompiledData::BuiltinType::Var)
- varPropCount++;
-
bool notInRevision = false;
- QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
+ const QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
if (d && d->isFinal())
return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
}
@@ -330,7 +488,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
auto aend = obj->aliasesEnd();
for ( ; a != aend; ++a) {
bool notInRevision = false;
- QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), &notInRevision);
+ const QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex()), &notInRevision);
if (d && d->isFinal())
return qQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
}
@@ -341,19 +499,32 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
// For property change signal override detection.
// We prepopulate a set of signal names which already exist in the object,
// and throw an error if there is a signal/method defined as an override.
- QSet<QString> seenSignals;
- seenSignals << QStringLiteral("destroyed") << QStringLiteral("parentChanged") << QStringLiteral("objectNameChanged");
- QQmlPropertyCache *parentCache = cache.data();
- while ((parentCache = parentCache->parent())) {
+ // TODO: Remove AllowOverride once we can. No override should be allowed.
+ enum class AllowOverride { No, Yes };
+ QHash<QString, AllowOverride> seenSignals {
+ { QStringLiteral("destroyed"), AllowOverride::No },
+ { QStringLiteral("parentChanged"), AllowOverride::No },
+ { QStringLiteral("objectNameChanged"), AllowOverride::No }
+ };
+ const QQmlPropertyCache *parentCache = cache.data();
+ while ((parentCache = parentCache->parent().data())) {
if (int pSigCount = parentCache->signalCount()) {
int pSigOffset = parentCache->signalOffset();
for (int i = pSigOffset; i < pSigCount; ++i) {
- QQmlPropertyData *currPSig = parentCache->signal(i);
+ const QQmlPropertyData *currPSig = parentCache->signal(i);
// XXX TODO: find a better way to get signal name from the property data :-/
for (QQmlPropertyCache::StringCache::ConstIterator iter = parentCache->stringCache.begin();
iter != parentCache->stringCache.end(); ++iter) {
if (currPSig == (*iter).second) {
- seenSignals.insert(iter.key());
+ if (currPSig->isOverridableSignal()) {
+ const qsizetype oldSize = seenSignals.size();
+ AllowOverride &entry = seenSignals[iter.key()];
+ if (seenSignals.size() != oldSize)
+ entry = AllowOverride::Yes;
+ } else {
+ seenSignals[iter.key()] = AllowOverride::No;
+ }
+
break;
}
}
@@ -367,8 +538,9 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
for ( ; p != pend; ++p) {
auto flags = QQmlPropertyData::defaultSignalFlags();
- QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
- seenSignals.insert(changedSigName);
+ const QString changedSigName =
+ QQmlSignalNames::propertyNameToChangedSignalName(stringAt(p->nameIndex));
+ seenSignals[changedSigName] = AllowOverride::No;
cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
}
@@ -378,8 +550,9 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
for ( ; a != aend; ++a) {
auto flags = QQmlPropertyData::defaultSignalFlags();
- QString changedSigName = stringAt(a->nameIndex) + QLatin1String("Changed");
- seenSignals.insert(changedSigName);
+ const QString changedSigName =
+ QQmlSignalNames::propertyNameToChangedSignalName(stringAt(a->nameIndex()));
+ seenSignals[changedSigName] = AllowOverride::No;
cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
}
@@ -407,10 +580,9 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
QList<QByteArray> names;
names.reserve(paramCount);
- QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0);
+ QVarLengthArray<QMetaType, 10> paramTypes(paramCount);
if (paramCount) {
- paramTypes[0] = paramCount;
int i = 0;
auto param = s->parametersBegin();
@@ -419,23 +591,39 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
names.append(stringAt(param->nameIndex).toUtf8());
QString customTypeName;
- auto type = metaTypeForParameter(param->type, &customTypeName);
- if (type == QMetaType::UnknownType)
+ QMetaType type = metaTypeForParameter(param->type, &customTypeName);
+ if (!type.isValid())
return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Invalid signal parameter type: %1").arg(customTypeName));
- paramTypes[i + 1] = type;
+ paramTypes[i] = type;
}
}
auto flags = QQmlPropertyData::defaultSignalFlags();
if (paramCount)
- flags.hasArguments = true;
+ flags.setHasArguments(true);
QString signalName = stringAt(s->nameIndex);
- if (seenSignals.contains(signalName))
- return qQmlCompileError(s->location, QQmlPropertyCacheCreatorBase::tr("Duplicate signal name: invalid override of property change signal or superclass signal"));
- seenSignals.insert(signalName);
-
+ const auto it = seenSignals.find(signalName);
+ if (it == seenSignals.end()) {
+ seenSignals[signalName] = AllowOverride::No;
+ } else {
+ // TODO: Remove the AllowOverride::Yes branch once we can.
+ QQmlError message = qQmlCompileError(
+ s->location,
+ QQmlPropertyCacheCreatorBase::tr(
+ "Duplicate signal name: "
+ "invalid override of property change signal or superclass signal"));
+ switch (*it) {
+ case AllowOverride::No:
+ return message;
+ case AllowOverride::Yes:
+ message.setUrl(objectContainer->url());
+ enginePrivate->warning(message);
+ *it = AllowOverride::No; // No further overriding allowed.
+ break;
+ }
+ }
cache->appendSignal(signalName, flags, effectiveMethodIndex++,
paramCount?paramTypes.constData():nullptr, names);
}
@@ -448,27 +636,42 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
auto flags = QQmlPropertyData::defaultSlotFlags();
const QString slotName = stringAt(function->nameIndex);
- if (seenSignals.contains(slotName))
- return qQmlCompileError(function->location, QQmlPropertyCacheCreatorBase::tr("Duplicate method name: invalid override of property change signal or superclass signal"));
+ const auto it = seenSignals.constFind(slotName);
+ if (it != seenSignals.constEnd()) {
+ // TODO: Remove the AllowOverride::Yes branch once we can.
+ QQmlError message = qQmlCompileError(
+ function->location,
+ QQmlPropertyCacheCreatorBase::tr(
+ "Duplicate method name: "
+ "invalid override of property change signal or superclass signal"));
+ switch (*it) {
+ case AllowOverride::No:
+ return message;
+ case AllowOverride::Yes:
+ message.setUrl(objectContainer->url());
+ enginePrivate->warning(message);
+ break;
+ }
+ }
// Note: we don't append slotName to the seenSignals list, since we don't
// protect against overriding change signals or methods with properties.
QList<QByteArray> parameterNames;
- QVector<int> parameterTypes;
+ QVector<QMetaType> parameterTypes;
auto formal = function->formalsBegin();
auto end = function->formalsEnd();
for ( ; formal != end; ++formal) {
- flags.hasArguments = true;
+ flags.setHasArguments(true);
parameterNames << stringAt(formal->nameIndex).toUtf8();
- int type = metaTypeForParameter(formal->type);
- if (type == QMetaType::UnknownType)
- type = QMetaType::QVariant;
+ QMetaType type = metaTypeForParameter(formal->type);
+ if (!type.isValid())
+ type = QMetaType::fromType<QVariant>();
parameterTypes << type;
}
- int returnType = metaTypeForParameter(function->returnType);
- if (returnType == QMetaType::UnknownType)
- returnType = QMetaType::QVariant;
+ QMetaType returnType = metaTypeForParameter(function->returnType);
+ if (!returnType.isValid())
+ returnType = QMetaType::fromType<QVariant>();
cache->appendMethod(slotName, flags, effectiveMethodIndex++, returnType, parameterNames, parameterTypes);
}
@@ -480,101 +683,140 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
p = obj->propertiesBegin();
pend = obj->propertiesEnd();
for ( ; p != pend; ++p, ++propertyIdx) {
- int propertyType = 0;
- int propertTypeMinorVersion = 0;
+ QMetaType propertyType;
+ QTypeRevision propertyTypeVersion = QTypeRevision::zero();
QQmlPropertyData::Flags propertyFlags;
- const QV4::CompiledData::BuiltinType type = p->builtinType();
-
- if (type == QV4::CompiledData::BuiltinType::Var)
- propertyFlags.type = QQmlPropertyData::Flags::VarPropertyType;
-
+ const QV4::CompiledData::CommonType type = p->commonType();
- if (type != QV4::CompiledData::BuiltinType::InvalidBuiltin) {
- propertyType = metaTypeForPropertyType(type);
+ if (p->isList())
+ propertyFlags.setType(QQmlPropertyData::Flags::QListType);
+ else if (type == QV4::CompiledData::CommonType::Var)
+ propertyFlags.setType(QQmlPropertyData::Flags::VarPropertyType);
- if (type == QV4::CompiledData::BuiltinType::Variant)
- propertyFlags.type = QQmlPropertyData::Flags::QVariantType;
+ if (type != QV4::CompiledData::CommonType::Invalid) {
+ propertyType = p->isList()
+ ? listTypeForPropertyType(type)
+ : metaTypeForPropertyType(type);
} else {
- Q_ASSERT(!p->isBuiltinType);
+ Q_ASSERT(!p->isCommonType());
QQmlType qmltype;
- if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr, nullptr)) {
+ bool selfReference = false;
+ if (!imports->resolveType(
+ QQmlTypeLoader::get(enginePrivate),
+ stringAt(p->commonTypeOrTypeNameIndex()), &qmltype, nullptr, nullptr,
+ nullptr, QQmlType::AnyRegistrationType, &selfReference)) {
return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
}
+ // inline components are not necessarily valid yet
Q_ASSERT(qmltype.isValid());
- if (qmltype.isComposite()) {
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
-
- auto compilationUnit = tdata->compilationUnit();
+ if (qmltype.isComposite() || qmltype.isInlineComponentType()) {
+ QQmlType compositeType;
+ if (qmltype.isInlineComponentType()) {
+ compositeType = qmltype;
+ Q_ASSERT(compositeType.isValid());
+ } else if (selfReference) {
+ compositeType = objectContainer->qmlTypeForComponent();
+ } else {
+ // compositeType may not be the same type as qmlType because multiple engines
+ // may load different types for the same document. Therefore we have to ask
+ // our engine's type loader here.
+ QQmlRefPointer<QQmlTypeData> tdata
+ = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+ compositeType = tdata->compilationUnit()->qmlTypeForComponent();
+ }
- if (p->isList) {
- propertyType = compilationUnit->listMetaTypeId;
+ if (p->isList()) {
+ propertyType = compositeType.qListTypeId();
} else {
- propertyType = compilationUnit->metaTypeId;
+ propertyType = compositeType.typeId();
}
} else {
- if (p->isList) {
+ if (p->isList())
propertyType = qmltype.qListTypeId();
- } else {
+ else
propertyType = qmltype.typeId();
- propertTypeMinorVersion = qmltype.minorVersion();
- }
+ propertyTypeVersion = qmltype.version();
}
- if (p->isList)
- propertyFlags.type = QQmlPropertyData::Flags::QListType;
- else
- propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType;
+ if (p->isList())
+ propertyFlags.setType(QQmlPropertyData::Flags::QListType);
+ else if (propertyType.flags().testFlag(QMetaType::PointerToQObject))
+ propertyFlags.setType(QQmlPropertyData::Flags::QObjectDerivedType);
}
- if (!p->isReadOnly && !p->isList)
- propertyFlags.isWritable = true;
+ if (!p->isReadOnly() && !propertyType.flags().testFlag(QMetaType::IsQmlList))
+ propertyFlags.setIsWritable(true);
QString propertyName = stringAt(p->nameIndex);
- if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
+ if (!obj->hasAliasAsDefaultProperty() && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
cache->_defaultPropertyName = propertyName;
cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- propertyType, propertTypeMinorVersion, effectiveSignalIndex);
+ propertyType, propertyTypeVersion, effectiveSignalIndex);
effectiveSignalIndex++;
}
- QQmlJS::DiagnosticMessage noError;
+ QQmlError noError;
return noError;
}
template <typename ObjectContainer>
-inline int QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(const QV4::CompiledData::ParameterType &param,
- QString *customTypeName)
+inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(
+ const QV4::CompiledData::ParameterType &param, QString *customTypeName)
{
- if (param.indexIsBuiltinType) {
+ const quint32 typeId = param.typeNameIndexOrCommonType();
+ if (param.indexIsCommonType()) {
// built-in type
- return metaTypeForPropertyType(static_cast<QV4::CompiledData::BuiltinType>(int(param.typeNameIndexOrBuiltinType)));
+ if (param.isList())
+ return listTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
+ return metaTypeForPropertyType(QV4::CompiledData::CommonType(typeId));
}
// lazily resolved type
- const QString typeName = stringAt(param.typeNameIndexOrBuiltinType);
+ const QString typeName = stringAt(param.typeNameIndexOrCommonType());
if (customTypeName)
*customTypeName = typeName;
QQmlType qmltype;
- if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr))
- return QMetaType::UnknownType;
-
- if (!qmltype.isComposite())
- return qmltype.typeId();
+ bool selfReference = false;
+ if (!imports->resolveType(
+ &enginePrivate->typeLoader, typeName, &qmltype, nullptr, nullptr, nullptr,
+ QQmlType::AnyRegistrationType, &selfReference))
+ return QMetaType();
+
+ if (!qmltype.isComposite()) {
+ const QMetaType typeId = param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
+ if (!typeId.isValid() && qmltype.isInlineComponentType()) {
+ const QQmlType qmlType = objectContainer->qmlTypeForComponent(qmltype.elementName());
+ return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
+ } else {
+ return typeId;
+ }
+ }
- QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
- Q_ASSERT(tdata);
- Q_ASSERT(tdata->isComplete());
+ if (selfReference) {
+ const QQmlType qmlType = objectContainer->qmlTypeForComponent();
+ return param.isList() ? qmlType.qListTypeId() : qmlType.typeId();
+ }
- auto compilationUnit = tdata->compilationUnit();
+ return param.isList() ? qmltype.qListTypeId() : qmltype.typeId();
+}
- return compilationUnit->metaTypeId;
+template <typename ObjectContainer, typename CompiledObject>
+int objectForId(const ObjectContainer *objectContainer, const CompiledObject &component, int id)
+{
+ for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
+ const int candidateIndex = component.namedObjectsInComponentTable()[i];
+ const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
+ if (candidate.objectId() == id)
+ return candidateIndex;
+ }
+ return -1;
}
template <typename ObjectContainer>
@@ -583,140 +825,49 @@ class QQmlPropertyCacheAliasCreator
public:
typedef typename ObjectContainer::CompiledObject CompiledObject;
- QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
-
- void appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv);
-
- QQmlJS::DiagnosticMessage appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv);
+ QQmlPropertyCacheAliasCreator(
+ QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer);
+ QQmlError appendAliasesToPropertyCache(
+ const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv);
private:
- void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex, QQmlEnginePrivate *enginePriv);
- QQmlJS::DiagnosticMessage propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv);
-
- void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const;
-
- int objectForId(const CompiledObject &component, int id) const;
+ QQmlError propertyDataForAlias(
+ const CompiledObject &component, const QV4::CompiledData::Alias &alias, QMetaType *type,
+ QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags,
+ QQmlEnginePrivate *enginePriv);
QQmlPropertyCacheVector *propertyCaches;
const ObjectContainer *objectContainer;
};
template <typename ObjectContainer>
-inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator(QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
+inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCreator(
+ QQmlPropertyCacheVector *propertyCaches, const ObjectContainer *objectContainer)
: propertyCaches(propertyCaches)
, objectContainer(objectContainer)
{
-
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv)
-{
- // skip the root object (index 0) as that one does not have a first object index originating
- // from a binding.
- for (int i = 1; i < objectContainer->objectCount(); ++i) {
- const CompiledObject &component = *objectContainer->objectAt(i);
- if (!(component.flags & QV4::CompiledData::Object::IsComponent))
- continue;
-
- const auto rootBinding = component.bindingsBegin();
- appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex, enginePriv);
- }
-
- const int rootObjectIndex = 0;
- appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex, enginePriv);
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex, QQmlEnginePrivate *enginePriv)
-{
- QVector<int> objectsWithAliases;
- collectObjectsWithAliasesRecursively(firstObjectIndex, &objectsWithAliases);
- if (objectsWithAliases.isEmpty())
- return;
-
- const auto allAliasTargetsExist = [this, &component](const CompiledObject &object) {
- auto alias = object.aliasesBegin();
- auto end = object.aliasesEnd();
- for ( ; alias != end; ++alias) {
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
-
- const int targetObjectIndex = objectForId(component, alias->targetObjectId);
- Q_ASSERT(targetObjectIndex >= 0);
-
- if (alias->aliasToLocalAlias)
- continue;
-
- if (alias->encodedMetaPropertyIndex == -1)
- continue;
-
- const QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
- Q_ASSERT(targetCache);
-
- int coreIndex = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex();
- QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
- if (!targetProperty)
- return false;
- }
- return true;
- };
-
- do {
- QVector<int> pendingObjects;
-
- for (int objectIndex: qAsConst(objectsWithAliases)) {
- const CompiledObject &object = *objectContainer->objectAt(objectIndex);
-
- if (allAliasTargetsExist(object)) {
- appendAliasesToPropertyCache(component, objectIndex, enginePriv);
- } else {
- pendingObjects.append(objectIndex);
- }
-
- }
- qSwap(objectsWithAliases, pendingObjects);
- } while (!objectsWithAliases.isEmpty());
-}
-
-template <typename ObjectContainer>
-inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const
-{
- const CompiledObject &object = *objectContainer->objectAt(objectIndex);
- if (object.aliasCount() > 0)
- objectsWithAliases->append(objectIndex);
-
- // Stop at Component boundary
- if (object.flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0)
- return;
-
- auto binding = object.bindingsBegin();
- auto end = object.bindingsEnd();
- for (; binding != end; ++binding) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object
- && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases);
- }
}
template <typename ObjectContainer>
-inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *minorVersion,
- QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv)
+inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(
+ const CompiledObject &component, const QV4::CompiledData::Alias &alias, QMetaType *type,
+ QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags,
+ QQmlEnginePrivate *enginePriv)
{
- *type = 0;
+ *type = QMetaType();
bool writable = false;
bool resettable = false;
+ bool bindable = false;
- propertyFlags->isAlias = true;
+ propertyFlags->setIsAlias(true);
- if (alias.aliasToLocalAlias) {
+ if (alias.isAliasToLocalAlias()) {
const QV4::CompiledData::Alias *lastAlias = &alias;
QVarLengthArray<const QV4::CompiledData::Alias *, 4> seenAliases({lastAlias});
do {
- const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId);
+ const int targetObjectIndex = objectForId(
+ objectContainer, component, lastAlias->targetObjectId());
Q_ASSERT(targetObjectIndex >= 0);
const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex);
Q_ASSERT(targetObject);
@@ -733,17 +884,18 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>:
seenAliases.append(targetAlias);
lastAlias = targetAlias;
- } while (lastAlias->aliasToLocalAlias);
+ } while (lastAlias->isAliasToLocalAlias());
- return propertyDataForAlias(component, *lastAlias, type, minorVersion, propertyFlags, enginePriv);
+ return propertyDataForAlias(
+ component, *lastAlias, type, version, propertyFlags, enginePriv);
}
- const int targetObjectIndex = objectForId(component, alias.targetObjectId);
+ const int targetObjectIndex = objectForId(objectContainer, component, alias.targetObjectId());
Q_ASSERT(targetObjectIndex >= 0);
const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
if (alias.encodedMetaPropertyIndex == -1) {
- Q_ASSERT(alias.flags & QV4::CompiledData::Alias::AliasPointsToPointerObject);
+ Q_ASSERT(alias.hasFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject));
auto *typeRef = objectContainer->resolvedType(targetObject.inheritedTypeNameIndex);
if (!typeRef) {
// Can be caused by the alias target not being a valid id or property. E.g.:
@@ -753,118 +905,135 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>:
QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
}
- if (typeRef->type.isValid())
- *type = typeRef->type.typeId();
- else
- *type = typeRef->compilationUnit->metaTypeId;
+ const auto referencedType = typeRef->type();
+ if (referencedType.isValid()) {
+ *type = referencedType.typeId();
+ if (!type->isValid() && referencedType.isInlineComponentType()) {
+ *type = objectContainer->qmlTypeForComponent(referencedType.elementName()).typeId();
+ Q_ASSERT(type->isValid());
+ }
+ } else {
+ *type = typeRef->compilationUnit()->metaType();
+ }
- *minorVersion = typeRef->minorVersion;
+ *version = typeRef->version();
- propertyFlags->type = QQmlPropertyData::Flags::QObjectDerivedType;
+ propertyFlags->setType(QQmlPropertyData::Flags::QObjectDerivedType);
} else {
int coreIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).coreIndex();
- int valueTypeIndex = QQmlPropertyIndex::fromEncoded(alias.encodedMetaPropertyIndex).valueTypeIndex();
+ int valueTypeIndex = QQmlPropertyIndex::fromEncoded(
+ alias.encodedMetaPropertyIndex).valueTypeIndex();
- QQmlPropertyCache *targetCache = propertyCaches->at(targetObjectIndex);
+ QQmlPropertyCache::ConstPtr targetCache = propertyCaches->at(targetObjectIndex);
Q_ASSERT(targetCache);
- QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
+ const QQmlPropertyData *targetProperty = targetCache->property(coreIndex);
Q_ASSERT(targetProperty);
+ const QMetaType targetPropType = targetProperty->propType();
+
+ const auto populateWithPropertyData = [&](const QQmlPropertyData *property) {
+ *type = property->propType();
+ writable = property->isWritable();
+ resettable = property->isResettable();
+ bindable = property->isBindable();
+
+ if (property->isVarProperty())
+ propertyFlags->setType(QQmlPropertyData::Flags::QVariantType);
+ else
+ propertyFlags->copyPropertyTypeFlags(property->flags());
+ };
+
// for deep aliases, valueTypeIndex is always set
- if (!QQmlValueTypeFactory::isValueType(targetProperty->propType()) && valueTypeIndex != -1) {
+ if (!QQmlMetaType::isValueType(targetPropType) && valueTypeIndex != -1) {
// deep alias property
- *type = targetProperty->propType();
- targetCache = enginePriv->propertyCacheForType(*type);
- Q_ASSERT(targetCache);
- targetProperty = targetCache->property(valueTypeIndex);
+ QQmlPropertyCache::ConstPtr typeCache
+ = QQmlMetaType::propertyCacheForType(targetPropType);
- *type = targetProperty->propType();
- writable = targetProperty->isWritable();
- resettable = targetProperty->isResettable();
+ if (!typeCache) {
+ // See if it's a half-resolved composite type
+ if (const QV4::ResolvedTypeReference *typeRef
+ = objectContainer->resolvedType(targetPropType)) {
+ typeCache = typeRef->typePropertyCache();
+ }
+ }
+ const QQmlPropertyData *typeProperty = typeCache
+ ? typeCache->property(valueTypeIndex)
+ : nullptr;
+ if (typeProperty == nullptr) {
+ return qQmlCompileError(
+ alias.referenceLocation,
+ QQmlPropertyCacheCreatorBase::tr("Invalid alias target"));
+ }
+ populateWithPropertyData(typeProperty);
} else {
// value type or primitive type or enum
- *type = targetProperty->propType();
-
- writable = targetProperty->isWritable();
- resettable = targetProperty->isResettable();
+ populateWithPropertyData(targetProperty);
if (valueTypeIndex != -1) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(*type);
- if (valueTypeMetaObject->property(valueTypeIndex).isEnumType())
- *type = QVariant::Int;
- else
- *type = valueTypeMetaObject->property(valueTypeIndex).userType();
- } else {
- if (targetProperty->isEnum()) {
- *type = QVariant::Int;
- } else {
- // Copy type flags
- propertyFlags->copyPropertyTypeFlags(targetProperty->flags());
-
- if (targetProperty->isVarProperty())
- propertyFlags->type = QQmlPropertyData::Flags::QVariantType;
- }
+ const QMetaObject *valueTypeMetaObject
+ = QQmlMetaType::metaObjectForValueType(*type);
+ const QMetaProperty valueTypeMetaProperty
+ = valueTypeMetaObject->property(valueTypeIndex);
+ *type = valueTypeMetaProperty.metaType();
+
+ // We can only write or reset the value type property if we can write
+ // the value type itself.
+ resettable = writable && valueTypeMetaProperty.isResettable();
+ writable = writable && valueTypeMetaProperty.isWritable();
+
+ bindable = valueTypeMetaProperty.isBindable();
}
}
}
- propertyFlags->isWritable = !(alias.flags & QV4::CompiledData::Alias::IsReadOnly) && writable;
- propertyFlags->isResettable = resettable;
- return QQmlJS::DiagnosticMessage();
+ propertyFlags->setIsWritable(
+ writable && !alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly));
+ propertyFlags->setIsResettable(resettable);
+ propertyFlags->setIsBindable(bindable);
+ return QQmlError();
}
template <typename ObjectContainer>
-inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(
+inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache(
const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv)
{
const CompiledObject &object = *objectContainer->objectAt(objectIndex);
if (!object.aliasCount())
- return QQmlJS::DiagnosticMessage();
+ return QQmlError();
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
+ QQmlPropertyCache::Ptr propertyCache = propertyCaches->ownAt(objectIndex);
Q_ASSERT(propertyCache);
- int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.count();
- int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
+ int effectiveSignalIndex = propertyCache->signalHandlerIndexCacheStart + propertyCache->propertyIndexCache.size();
+ int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.size();
int aliasIndex = 0;
auto alias = object.aliasesBegin();
auto end = object.aliasesEnd();
for ( ; alias != end; ++alias, ++aliasIndex) {
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+ Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved));
- int type = 0;
- int minorVersion = 0;
+ QMetaType type;
+ QTypeRevision version = QTypeRevision::zero();
QQmlPropertyData::Flags propertyFlags;
- QQmlJS::DiagnosticMessage error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags, enginePriv);
+ QQmlError error = propertyDataForAlias(component, *alias, &type, &version,
+ &propertyFlags, enginePriv);
if (error.isValid())
return error;
- const QString propertyName = objectContainer->stringAt(alias->nameIndex);
+ const QString propertyName = objectContainer->stringAt(alias->nameIndex());
- if (object.defaultPropertyIsAlias && aliasIndex == object.indexOfDefaultPropertyOrAlias)
+ if (object.hasAliasAsDefaultProperty() && aliasIndex == object.indexOfDefaultPropertyOrAlias)
propertyCache->_defaultPropertyName = propertyName;
propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
- type, minorVersion, effectiveSignalIndex++);
+ type, version, effectiveSignalIndex++);
}
- return QQmlJS::DiagnosticMessage();
-}
-
-template <typename ObjectContainer>
-inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const CompiledObject &component, int id) const
-{
- for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
- const int candidateIndex = component.namedObjectsInComponentTable()[i];
- const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
- if (candidate.id == id)
- return candidateIndex;
- }
- return -1;
+ return QQmlError();
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycachemethodarguments_p.h b/src/qml/qml/qqmlpropertycachemethodarguments_p.h
index 62f09bdfff..ab17c01379 100644
--- a/src/qml/qml/qqmlpropertycachemethodarguments_p.h
+++ b/src/qml/qml/qqmlpropertycachemethodarguments_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYCACHEMETODARGUMENTS_P_H
#define QQMLPROPERTYCACHEMETODARGUMENTS_P_H
@@ -53,6 +17,9 @@
#include <QtCore/qlist.h>
#include <QtCore/qbytearray.h>
+#include <QtCore/qtaggedpointer.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -61,15 +28,8 @@ class QQmlPropertyCacheMethodArguments
{
public:
QQmlPropertyCacheMethodArguments *next;
-
- //for signal handler rewrites
- QString *signalParameterStringForJS;
- int parameterError:1;
- int argumentsValid:1;
-
QList<QByteArray> *names;
-
- int arguments[1];
+ QMetaType types[1]; // First one is return type
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycachevector_p.h b/src/qml/qml/qqmlpropertycachevector_p.h
index 1dff7c61a6..1cee914220 100644
--- a/src/qml/qml/qqmlpropertycachevector_p.h
+++ b/src/qml/qml/qqmlpropertycachevector_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYCACHEVECTOR_P_H
#define QQMLPROPERTYCACHEVECTOR_P_H
@@ -51,52 +15,129 @@
// We mean it.
//
-#include <private/qflagpointer_p.h>
#include <private/qqmlpropertycache_p.h>
+#include <private/qbipointer_p.h>
+
+#include <QtCore/qtaggedpointer.h>
QT_BEGIN_NAMESPACE
class QQmlPropertyCacheVector
{
public:
- QQmlPropertyCacheVector() {}
- QQmlPropertyCacheVector(QQmlPropertyCacheVector &&other)
- : data(std::move(other.data)) {}
- QQmlPropertyCacheVector &operator=(QQmlPropertyCacheVector &&other) {
- QVector<QFlagPointer<QQmlPropertyCache>> moved(std::move(other.data));
- data.swap(moved);
- return *this;
- }
+ QQmlPropertyCacheVector() = default;
+ QQmlPropertyCacheVector(QQmlPropertyCacheVector &&) = default;
+ QQmlPropertyCacheVector &operator=(QQmlPropertyCacheVector &&) = default;
~QQmlPropertyCacheVector() { clear(); }
- void resize(int size) { return data.resize(size); }
- int count() const { return data.count(); }
+ void resize(int size)
+ {
+ Q_ASSERT(size >= data.size());
+ return data.resize(size);
+ }
+
+ int count() const {
+ // the property cache vector will never contain more thant INT_MAX many elements
+ return int(data.size());
+ }
void clear()
{
- for (int i = 0; i < data.count(); ++i) {
- if (QQmlPropertyCache *cache = data.at(i).data())
- cache->release();
- }
+ for (int i = 0; i < data.size(); ++i)
+ releaseElement(i);
data.clear();
}
- void append(QQmlPropertyCache *cache) { cache->addref(); data.append(cache); }
- QQmlPropertyCache *at(int index) const { return data.at(index).data(); }
- void set(int index, const QQmlRefPointer<QQmlPropertyCache> &replacement) {
- if (QQmlPropertyCache *oldCache = data.at(index).data()) {
- if (replacement.data() == oldCache)
+ void resetAndResize(int size)
+ {
+ for (int i = 0; i < data.size(); ++i) {
+ releaseElement(i);
+ data[i] = BiPointer();
+ }
+ data.resize(size);
+ }
+
+ void append(const QQmlPropertyCache::ConstPtr &cache) {
+ cache->addref();
+ data.append(BiPointer(cache.data()));
+ Q_ASSERT(data.last().isT1());
+ Q_ASSERT(data.size() <= std::numeric_limits<int>::max());
+ }
+
+ void appendOwn(const QQmlPropertyCache::Ptr &cache) {
+ cache->addref();
+ data.append(BiPointer(cache.data()));
+ Q_ASSERT(data.last().isT2());
+ Q_ASSERT(data.size() <= std::numeric_limits<int>::max());
+ }
+
+ QQmlPropertyCache::ConstPtr at(int index) const
+ {
+ const auto entry = data.at(index);
+ if (entry.isT2())
+ return entry.asT2();
+ return entry.asT1();
+ }
+
+ QQmlPropertyCache::Ptr ownAt(int index) const
+ {
+ const auto entry = data.at(index);
+ if (entry.isT2())
+ return entry.asT2();
+ return QQmlPropertyCache::Ptr();
+ }
+
+ void set(int index, const QQmlPropertyCache::ConstPtr &replacement) {
+ if (QQmlPropertyCache::ConstPtr oldCache = at(index)) {
+ // If it is our own, we keep it our own
+ if (replacement.data() == oldCache.data())
return;
oldCache->release();
}
data[index] = replacement.data();
replacement->addref();
+ Q_ASSERT(data[index].isT1());
+ }
+
+ void setOwn(int index, const QQmlPropertyCache::Ptr &replacement) {
+ if (QQmlPropertyCache::ConstPtr oldCache = at(index)) {
+ if (replacement.data() != oldCache.data()) {
+ oldCache->release();
+ replacement->addref();
+ }
+ } else {
+ replacement->addref();
+ }
+ data[index] = replacement.data();
+ Q_ASSERT(data[index].isT2());
}
void setNeedsVMEMetaObject(int index) { data[index].setFlag(); }
bool needsVMEMetaObject(int index) const { return data.at(index).flag(); }
+
+ void seal()
+ {
+ for (auto &entry: data) {
+ if (entry.isT2())
+ entry = static_cast<const QQmlPropertyCache *>(entry.asT2());
+ Q_ASSERT(entry.isT1());
+ }
+ }
+
private:
+ void releaseElement(int i)
+ {
+ const auto &cache = data.at(i);
+ if (cache.isT2()) {
+ if (QQmlPropertyCache *data = cache.asT2())
+ data->release();
+ } else if (const QQmlPropertyCache *data = cache.asT1()) {
+ data->release();
+ }
+ }
+
Q_DISABLE_COPY(QQmlPropertyCacheVector)
- QVector<QFlagPointer<QQmlPropertyCache>> data;
+ using BiPointer = QBiPointer<const QQmlPropertyCache, QQmlPropertyCache>;
+ QVector<BiPointer> data;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertydata_p.h b/src/qml/qml/qqmlpropertydata_p.h
index dec696226e..0fa7984f05 100644
--- a/src/qml/qml/qqmlpropertydata_p.h
+++ b/src/qml/qml/qqmlpropertydata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYDATA_P_H
#define QQMLPROPERTYDATA_P_H
@@ -52,6 +16,8 @@
//
#include <private/qobject_p.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qversionnumber.h>
QT_BEGIN_NAMESPACE
@@ -62,65 +28,161 @@ public:
enum WriteFlag {
BypassInterceptor = 0x01,
DontRemoveBinding = 0x02,
- RemoveBindingOnAliasWrite = 0x04
+ RemoveBindingOnAliasWrite = 0x04,
+ HasInternalIndex = 0x8,
};
Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction;
struct Flags {
- enum Types {
+ friend class QQmlPropertyData;
+ enum Type {
OtherType = 0,
FunctionType = 1, // Is an invokable
QObjectDerivedType = 2, // Property type is a QObject* derived type
EnumType = 3, // Property type is an enum
QListType = 4, // Property type is a QML list
- QmlBindingType = 5, // Property type is a QQmlBinding*
- QJSValueType = 6, // Property type is a QScriptValue
- // Gap, used to be V4HandleType
- VarPropertyType = 8, // Property type is a "var" property of VMEMO
- QVariantType = 9 // Property is a QVariant
+ VarPropertyType = 5, // Property type is a "var" property of VMEMO
+ QVariantType = 6, // Property is a QVariant
+ // One spot left for an extra type in the 3 bits used to store this.
};
+ private:
// The _otherBits (which "pad" the Flags struct to align it nicely) are used
// to store the relative property index. It will only get used when said index fits. See
// trySetStaticMetaCallFunction for details.
// (Note: this padding is done here, because certain compilers have surprising behavior
// when an enum is declared in-between two bit fields.)
- enum { BitsLeftInFlags = 10 };
+ enum { BitsLeftInFlags = 16 };
unsigned otherBits : BitsLeftInFlags; // align to 32 bits
- // Can apply to all properties, except IsFunction
- unsigned isConstant : 1; // Has CONST flag
- unsigned isWritable : 1; // Has WRITE function
- unsigned isResettable : 1; // Has RESET function
- unsigned isAlias : 1; // Is a QML alias to another property
- unsigned isFinal : 1; // Has FINAL flag
- unsigned isOverridden : 1; // Is overridden by a extension property
- unsigned isDirect : 1; // Exists on a C++ QMetaObject
-
- unsigned type : 4; // stores an entry of Types
-
- // Apply only to IsFunctions
- unsigned isVMEFunction : 1; // Function was added by QML
- unsigned hasArguments : 1; // Function takes arguments
- unsigned isSignal : 1; // Function is a signal
- unsigned isVMESignal : 1; // Signal was added by QML
- unsigned isV4Function : 1; // Function takes QQmlV4Function* args
- unsigned isSignalHandler : 1; // Function is a signal handler
- unsigned isOverload : 1; // Function is an overload of another function
- unsigned isCloned : 1; // The function was marked as cloned
- unsigned isConstructor : 1; // The function was marked is a constructor
+ // Members of the form aORb can only be a when type is not FunctionType, and only be
+ // b when type equals FunctionType. For that reason, the semantic meaning of the bit is
+ // overloaded, and the accessor functions are used to get the correct value
+ //
+ // Moreover, isSignalHandler, isOverridableSignal and isCloned make only sense
+ // for functions, too (and could at a later point be reused for flags that only make sense
+ // for non-functions)
+ //
+ // Lastly, isDirect and isOverridden apply to both functions and non-functions
+ unsigned isConst : 1; // Property: has CONST flag/Method: is const
+ unsigned isVMEFunction : 1; // Function was added by QML
+ unsigned isWritableORhasArguments : 1; // Has WRITE function OR Function takes arguments
+ unsigned isResettableORisSignal : 1; // Has RESET function OR Function is a signal
+ unsigned isAliasORisVMESignal : 1; // Is a QML alias to another property OR Signal was added by QML
+ unsigned isFinalORisV4Function : 1; // Has FINAL flag OR Function takes QQmlV4FunctionPtr args
+ unsigned isSignalHandler : 1; // Function is a signal handler
+
+ // TODO: Remove this once we can. Signals should not be overridable.
+ unsigned isOverridableSignal : 1; // Function is an overridable signal
+
+ unsigned isRequiredORisCloned : 1; // Has REQUIRED flag OR The function was marked as cloned
+ unsigned isConstructorORisBindable : 1; // The function was marked is a constructor OR property is backed by QProperty<T>
+ unsigned isOverridden : 1; // Is overridden by a extension property
+ unsigned hasMetaObject : 1;
+ unsigned type : 3; // stores an entry of Types
// Internal QQmlPropertyCache flags
- unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved
- unsigned overrideIndexIsProperty: 1;
+ unsigned overrideIndexIsProperty : 1;
+ public:
inline Flags();
inline bool operator==(const Flags &other) const;
inline void copyPropertyTypeFlags(Flags from);
+
+ void setIsConstant(bool b) {
+ isConst = b;
+ }
+
+ void setIsWritable(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isWritableORhasArguments = b;
+ }
+
+ void setIsResettable(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isResettableORisSignal = b;
+ }
+
+ void setIsAlias(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isAliasORisVMESignal = b;
+ }
+
+ void setIsFinal(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isFinalORisV4Function = b;
+ }
+
+ void setIsOverridden(bool b) {
+ isOverridden = b;
+ }
+
+ void setIsBindable(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isConstructorORisBindable = b;
+ }
+
+ void setIsRequired(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isRequiredORisCloned = b;
+ }
+
+ void setIsVMEFunction(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isVMEFunction = b;
+ }
+ void setHasArguments(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isWritableORhasArguments = b;
+ }
+ void setIsSignal(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isResettableORisSignal = b;
+ }
+ void setIsVMESignal(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isAliasORisVMESignal = b;
+ }
+
+ void setIsV4Function(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isFinalORisV4Function = b;
+ }
+
+ void setIsSignalHandler(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isSignalHandler = b;
+ }
+
+ // TODO: Remove this once we can. Signals should not be overridable.
+ void setIsOverridableSignal(bool b) {
+ Q_ASSERT(type == FunctionType);
+ Q_ASSERT(isResettableORisSignal);
+ isOverridableSignal = b;
+ }
+
+ void setIsCloned(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isRequiredORisCloned = b;
+ }
+
+ void setIsConstructor(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isConstructorORisBindable = b;
+ }
+
+ void setHasMetaObject(bool b) {
+ hasMetaObject = b;
+ }
+
+ void setType(Type newType) {
+ type = newType;
+ }
};
+
inline bool operator==(const QQmlPropertyData &) const;
Flags flags() const { return m_flags; }
@@ -133,45 +195,43 @@ public:
bool isValid() const { return coreIndex() != -1; }
- bool isConstant() const { return m_flags.isConstant; }
- bool isWritable() const { return m_flags.isWritable; }
- void setWritable(bool onoff) { m_flags.isWritable = onoff; }
- bool isResettable() const { return m_flags.isResettable; }
- bool isAlias() const { return m_flags.isAlias; }
- bool isFinal() const { return m_flags.isFinal; }
+ bool isConstant() const { return m_flags.isConst; }
+ bool isWritable() const { return !isFunction() && m_flags.isWritableORhasArguments; }
+ void setWritable(bool onoff) { Q_ASSERT(!isFunction()); m_flags.isWritableORhasArguments = onoff; }
+ bool isResettable() const { return !isFunction() && m_flags.isResettableORisSignal; }
+ bool isAlias() const { return !isFunction() && m_flags.isAliasORisVMESignal; }
+ bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; }
bool isOverridden() const { return m_flags.isOverridden; }
- bool isDirect() const { return m_flags.isDirect; }
+ bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; }
bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
bool isFunction() const { return m_flags.type == Flags::FunctionType; }
bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
bool isEnum() const { return m_flags.type == Flags::EnumType; }
bool isQList() const { return m_flags.type == Flags::QListType; }
- bool isQmlBinding() const { return m_flags.type == Flags::QmlBindingType; }
- bool isQJSValue() const { return m_flags.type == Flags::QJSValueType; }
bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; }
bool isQVariant() const { return m_flags.type == Flags::QVariantType; }
- bool isVMEFunction() const { return m_flags.isVMEFunction; }
- bool hasArguments() const { return m_flags.hasArguments; }
- bool isSignal() const { return m_flags.isSignal; }
- bool isVMESignal() const { return m_flags.isVMESignal; }
- bool isV4Function() const { return m_flags.isV4Function; }
+ bool isVMEFunction() const { return isFunction() && m_flags.isVMEFunction; }
+ bool hasArguments() const { return isFunction() && m_flags.isWritableORhasArguments; }
+ bool isSignal() const { return isFunction() && m_flags.isResettableORisSignal; }
+ bool isVMESignal() const { return isFunction() && m_flags.isAliasORisVMESignal; }
+ bool isV4Function() const { return isFunction() && m_flags.isFinalORisV4Function; }
bool isSignalHandler() const { return m_flags.isSignalHandler; }
- bool isOverload() const { return m_flags.isOverload; }
- void setOverload(bool onoff) { m_flags.isOverload = onoff; }
- bool isCloned() const { return m_flags.isCloned; }
- bool isConstructor() const { return m_flags.isConstructor; }
+ bool hasMetaObject() const { return m_flags.hasMetaObject; }
- bool hasOverride() const { return overrideIndex() >= 0; }
- bool hasRevision() const { return revision() != 0; }
+ // TODO: Remove this once we can. Signals should not be overridable.
+ bool isOverridableSignal() const { return m_flags.isOverridableSignal; }
+
+ bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; }
+ bool isConstructor() const { return isFunction() && m_flags.isConstructorORisBindable; }
+ bool isBindable() const { return !isFunction() && m_flags.isConstructorORisBindable; }
- bool isFullyResolved() const { return !m_flags.notFullyResolved; }
+ bool hasOverride() const { return overrideIndex() >= 0; }
+ bool hasRevision() const { return revision() != QTypeRevision::zero(); }
- int propType() const { Q_ASSERT(isFullyResolved()); return m_propType; }
- void setPropType(int pt)
+ QMetaType propType() const { return m_propType; }
+ void setPropType(QMetaType pt)
{
- Q_ASSERT(pt >= 0);
- Q_ASSERT(pt <= std::numeric_limits<qint16>::max());
- m_propType = quint16(pt);
+ m_propType = pt;
}
int notifyIndex() const { return m_notifyIndex; }
@@ -201,12 +261,8 @@ public:
m_coreIndex = qint16(idx);
}
- quint8 revision() const { return m_revision; }
- void setRevision(quint8 rev)
- {
- Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
- m_revision = quint8(rev);
- }
+ QTypeRevision revision() const { return m_revision; }
+ void setRevision(QTypeRevision revision) { m_revision = revision; }
/* If a property is a C++ type, then we store the minor
* version of this type.
@@ -226,15 +282,39 @@ public:
*
*/
- quint8 typeMinorVersion() const { return m_typeMinorVersion; }
- void setTypeMinorVersion(quint8 rev)
+ QTypeRevision typeVersion() const { return m_typeVersion; }
+ void setTypeVersion(QTypeRevision typeVersion) { m_typeVersion = typeVersion; }
+
+ QQmlPropertyCacheMethodArguments *arguments() const
+ {
+ Q_ASSERT(!hasMetaObject());
+ return m_arguments;
+ }
+ void setArguments(QQmlPropertyCacheMethodArguments *args)
{
- Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
- m_typeMinorVersion = quint8(rev);
+ Q_ASSERT(!hasMetaObject());
+ m_arguments = args;
}
- QQmlPropertyCacheMethodArguments *arguments() const { return m_arguments; }
- void setArguments(QQmlPropertyCacheMethodArguments *args) { m_arguments = args; }
+ const QMetaObject *metaObject() const
+ {
+ Q_ASSERT(hasMetaObject());
+ return m_metaObject;
+ }
+
+ void setMetaObject(const QMetaObject *metaObject)
+ {
+ Q_ASSERT(!hasArguments() || !m_arguments);
+ m_flags.setHasMetaObject(true);
+ m_metaObject = metaObject;
+ }
+
+ QMetaMethod metaMethod() const
+ {
+ Q_ASSERT(hasMetaObject());
+ Q_ASSERT(isFunction());
+ return m_metaObject->method(m_coreIndex);
+ }
int metaObjectOffset() const { return m_metaObjectOffset; }
void setMetaObjectOffset(int off)
@@ -244,9 +324,10 @@ public:
m_metaObjectOffset = qint16(off);
}
- StaticMetaCallFunction staticMetaCallFunction() const { return m_staticMetaCallFunction; }
+ StaticMetaCallFunction staticMetaCallFunction() const { Q_ASSERT(!isFunction()); return m_staticMetaCallFunction; }
void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
{
+ Q_ASSERT(!isFunction());
if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
m_flags.otherBits = relativePropertyIndex;
m_staticMetaCallFunction = f;
@@ -260,7 +341,7 @@ public:
QString name(QObject *) const;
QString name(const QMetaObject *) const;
- void markAsOverrideOf(QQmlPropertyData *predecessor);
+ bool markAsOverrideOf(QQmlPropertyData *predecessor);
inline void readProperty(QObject *target, void *property) const
{
@@ -268,14 +349,23 @@ public:
readPropertyWithArgs(target, args);
}
- inline void readPropertyWithArgs(QObject *target, void *args[]) const
+ // This is the same as QMetaObject::metacall(), but inlined here to avoid a function call.
+ // And we ignore the return value.
+ template<QMetaObject::Call call>
+ void doMetacall(QObject *object, int idx, void **argv) const
+ {
+ if (QDynamicMetaObjectData *dynamicMetaObject = QObjectPrivate::get(object)->metaObject)
+ dynamicMetaObject->metaCall(object, call, idx, argv);
+ else
+ object->qt_metacall(call, idx, argv);
+ }
+
+ void readPropertyWithArgs(QObject *target, void *args[]) const
{
if (hasStaticMetaCallFunction())
staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
- else if (isDirect())
- target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args);
else
- QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args);
+ doMetacall<QMetaObject::ReadProperty>(target, coreIndex(), args);
}
bool writeProperty(QObject *target, void *value, WriteFlags flags) const
@@ -284,51 +374,60 @@ public:
void *argv[] = { value, nullptr, &status, &flags };
if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
- else if (flags.testFlag(BypassInterceptor) && isDirect())
- target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv);
else
- QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv);
+ doMetacall<QMetaObject::WriteProperty>(target, coreIndex(), argv);
+ return true;
+ }
+
+ bool resetProperty(QObject *target, WriteFlags flags) const
+ {
+ if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
+ staticMetaCallFunction()(target, QMetaObject::ResetProperty, relativePropertyIndex(), nullptr);
+ else
+ doMetacall<QMetaObject::ResetProperty>(target, coreIndex(), nullptr);
return true;
}
static Flags defaultSignalFlags()
{
Flags f;
- f.isSignal = true;
- f.type = Flags::FunctionType;
- f.isVMESignal = true;
+ f.setType(Flags::FunctionType);
+ f.setIsSignal(true);
+ f.setIsVMESignal(true);
return f;
}
static Flags defaultSlotFlags()
{
Flags f;
- f.type = Flags::FunctionType;
- f.isVMEFunction = true;
+ f.setType(Flags::FunctionType);
+ f.setIsVMEFunction(true);
return f;
}
private:
friend class QQmlPropertyCache;
- void lazyLoad(const QMetaProperty &);
- void lazyLoad(const QMetaMethod &);
- bool notFullyResolved() const { return m_flags.notFullyResolved; }
Flags m_flags;
qint16 m_coreIndex = -1;
- quint16 m_propType = 0;
// The notify index is in the range returned by QObjectPrivate::signalIndex().
// This is different from QMetaMethod::methodIndex().
qint16 m_notifyIndex = -1;
qint16 m_overrideIndex = -1;
- quint8 m_revision = 0;
- quint8 m_typeMinorVersion = 0;
qint16 m_metaObjectOffset = -1;
- QQmlPropertyCacheMethodArguments *m_arguments = nullptr;
- StaticMetaCallFunction m_staticMetaCallFunction = nullptr;
+ QTypeRevision m_revision = QTypeRevision::zero();
+ QTypeRevision m_typeVersion = QTypeRevision::zero();
+
+ QMetaType m_propType = {};
+
+ union {
+ QQmlPropertyCacheMethodArguments *m_arguments = nullptr;
+ StaticMetaCallFunction m_staticMetaCallFunction;
+ const QMetaObject *m_metaObject;
+ };
};
#if QT_POINTER_SIZE == 4
@@ -337,6 +436,8 @@ private:
Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 32);
#endif
+static_assert(std::is_trivially_copyable<QQmlPropertyData>::value);
+
bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
{
return flags() == other.flags() &&
@@ -348,46 +449,37 @@ bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
QQmlPropertyData::Flags::Flags()
: otherBits(0)
- , isConstant(false)
- , isWritable(false)
- , isResettable(false)
- , isAlias(false)
- , isFinal(false)
- , isOverridden(false)
- , isDirect(false)
- , type(OtherType)
+ , isConst(false)
, isVMEFunction(false)
- , hasArguments(false)
- , isSignal(false)
- , isVMESignal(false)
- , isV4Function(false)
+ , isWritableORhasArguments(false)
+ , isResettableORisSignal(false)
+ , isAliasORisVMESignal(false)
+ , isFinalORisV4Function(false)
, isSignalHandler(false)
- , isOverload(false)
- , isCloned(false)
- , isConstructor(false)
- , notFullyResolved(false)
+ , isOverridableSignal(false)
+ , isRequiredORisCloned(false)
+ , isConstructorORisBindable(false)
+ , isOverridden(false)
+ , hasMetaObject(false)
+ , type(OtherType)
, overrideIndexIsProperty(false)
-{}
+{
+}
bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) const
{
- return isConstant == other.isConstant &&
- isWritable == other.isWritable &&
- isResettable == other.isResettable &&
- isAlias == other.isAlias &&
- isFinal == other.isFinal &&
- isOverridden == other.isOverridden &&
- type == other.type &&
+ return isConst == other.isConst &&
isVMEFunction == other.isVMEFunction &&
- hasArguments == other.hasArguments &&
- isSignal == other.isSignal &&
- isVMESignal == other.isVMESignal &&
- isV4Function == other.isV4Function &&
+ isWritableORhasArguments == other.isWritableORhasArguments &&
+ isResettableORisSignal == other.isResettableORisSignal &&
+ isAliasORisVMESignal == other.isAliasORisVMESignal &&
+ isFinalORisV4Function == other.isFinalORisV4Function &&
+ isOverridden == other.isOverridden &&
isSignalHandler == other.isSignalHandler &&
- isOverload == other.isOverload &&
- isCloned == other.isCloned &&
- isConstructor == other.isConstructor &&
- notFullyResolved == other.notFullyResolved &&
+ isRequiredORisCloned == other.isRequiredORisCloned &&
+ hasMetaObject == other.hasMetaObject &&
+ type == other.type &&
+ isConstructorORisBindable == other.isConstructorORisBindable &&
overrideIndexIsProperty == other.overrideIndexIsProperty;
}
@@ -397,8 +489,6 @@ void QQmlPropertyData::Flags::copyPropertyTypeFlags(QQmlPropertyData::Flags from
case QObjectDerivedType:
case EnumType:
case QListType:
- case QmlBindingType:
- case QJSValueType:
case QVariantType:
type = from.type;
}
diff --git a/src/qml/qml/qqmlpropertyindex_p.h b/src/qml/qml/qqmlpropertyindex_p.h
index ebc1828efb..ca63cbf881 100644
--- a/src/qml/qml/qqmlpropertyindex_p.h
+++ b/src/qml/qml/qqmlpropertyindex_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYINDEX_P_H
#define QQMLPROPERTYINDEX_P_H
diff --git a/src/qml/qml/qqmlpropertyresolver.cpp b/src/qml/qml/qqmlpropertyresolver.cpp
index 90eaca0b90..0217f7b7b5 100644
--- a/src/qml/qml/qqmlpropertyresolver.cpp
+++ b/src/qml/qml/qqmlpropertyresolver.cpp
@@ -1,52 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertyresolver_p.h"
+#include <private/qqmlcontextdata_p.h>
+#include <private/qqmlsignalnames_p.h>
QT_BEGIN_NAMESPACE
-QQmlPropertyData *QQmlPropertyResolver::property(const QString &name, bool *notInRevision,
+const QQmlPropertyData *QQmlPropertyResolver::property(const QString &name, bool *notInRevision,
RevisionCheck check) const
{
if (notInRevision) *notInRevision = false;
- QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
+ const QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
// Find the first property
while (d && d->isFunction())
@@ -61,11 +27,11 @@ QQmlPropertyData *QQmlPropertyResolver::property(const QString &name, bool *notI
}
-QQmlPropertyData *QQmlPropertyResolver::signal(const QString &name, bool *notInRevision) const
+const QQmlPropertyData *QQmlPropertyResolver::signal(const QString &name, bool *notInRevision) const
{
if (notInRevision) *notInRevision = false;
- QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
+ const QQmlPropertyData *d = cache->property(name, nullptr, nullptr);
if (notInRevision) *notInRevision = false;
while (d && !(d->isFunction()))
@@ -78,10 +44,8 @@ QQmlPropertyData *QQmlPropertyResolver::signal(const QString &name, bool *notInR
return d;
}
- if (name.endsWith(QLatin1String("Changed"))) {
- QString propName = name.mid(0, name.length() - static_cast<int>(strlen("Changed")));
-
- d = property(propName, notInRevision);
+ if (auto propName = QQmlSignalNames::changedSignalNameToPropertyName(name)) {
+ d = property(*propName, notInRevision);
if (d)
return cache->signal(d->notifyIndex());
}
diff --git a/src/qml/qml/qqmlpropertyresolver_p.h b/src/qml/qml/qqmlpropertyresolver_p.h
index df857f242e..4c9ae4a8af 100644
--- a/src/qml/qml/qqmlpropertyresolver_p.h
+++ b/src/qml/qml/qqmlpropertyresolver_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYRESOLVER_P_H
#define QQMLPROPERTYRESOLVER_P_H
@@ -59,11 +23,11 @@ QT_BEGIN_NAMESPACE
struct Q_QML_EXPORT QQmlPropertyResolver
{
- QQmlPropertyResolver(const QQmlRefPointer<QQmlPropertyCache> &cache)
+ QQmlPropertyResolver(const QQmlPropertyCache::ConstPtr &cache)
: cache(cache)
{}
- QQmlPropertyData *property(int index) const
+ const QQmlPropertyData *property(int index) const
{
return cache->property(index);
}
@@ -73,13 +37,13 @@ struct Q_QML_EXPORT QQmlPropertyResolver
IgnoreRevision
};
- QQmlPropertyData *property(const QString &name, bool *notInRevision = nullptr,
+ const QQmlPropertyData *property(const QString &name, bool *notInRevision = nullptr,
RevisionCheck check = CheckRevision) const;
// This code must match the semantics of QQmlPropertyPrivate::findSignalByName
- QQmlPropertyData *signal(const QString &name, bool *notInRevision) const;
+ const QQmlPropertyData *signal(const QString &name, bool *notInRevision) const;
- QQmlRefPointer<QQmlPropertyCache> cache;
+ QQmlPropertyCache::ConstPtr cache;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertytopropertybinding.cpp b/src/qml/qml/qqmlpropertytopropertybinding.cpp
new file mode 100644
index 0000000000..ec77e8c97a
--- /dev/null
+++ b/src/qml/qml/qqmlpropertytopropertybinding.cpp
@@ -0,0 +1,128 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmlpropertytopropertybinding_p.h"
+#include <private/qqmlvmemetaobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ * \internal
+ * \class QQmlPropertyToPropertyBinding
+ *
+ * This class can be used to create a direct binding from a source property to
+ * a target property, without going through QQmlJavaScriptExpression and
+ * QV4::Function. In particular you don't need a compilation unit or byte code
+ * to set this up.
+ */
+
+QQmlPropertyToPropertyBinding::QQmlPropertyToPropertyBinding(
+ QQmlEngine *engine, QObject *sourceObject, int sourcePropertyIndex,
+ QObject *targetObject, int targetPropertyIndex)
+ : QQmlNotifierEndpoint(QQmlPropertyGuard)
+ , m_engine(engine)
+ , m_sourceObject(sourceObject)
+ , m_sourcePropertyIndex(sourcePropertyIndex)
+{
+ setTarget(targetObject, targetPropertyIndex, false, -1);
+}
+
+QQmlAbstractBinding::Kind QQmlPropertyToPropertyBinding::kind() const
+{
+ return PropertyToPropertyBinding;
+}
+
+void QQmlPropertyToPropertyBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
+{
+ const bool wasEnabled = enabledFlag();
+ setEnabledFlag(e);
+ updateCanUseAccessor();
+ if (e && !wasEnabled)
+ update(flags);
+}
+
+void QQmlPropertyToPropertyBinding::captureProperty(
+ const QMetaObject *sourceMetaObject, int notifyIndex,
+ bool isSourceBindable, bool isTargetBindable)
+{
+ if (isSourceBindable) {
+ // if the property is a QPropery, and we're binding to a QProperty
+ // the automatic capturing process already takes care of everything
+ if (isTargetBindable)
+ return;
+
+ // We have already captured.
+ if (observer)
+ return;
+
+ observer = std::make_unique<Observer>(this);
+ QUntypedBindable bindable;
+ void *argv[] = { &bindable };
+ sourceMetaObject->metacall(
+ m_sourceObject, QMetaObject::BindableProperty, m_sourcePropertyIndex, argv);
+ bindable.observe(observer.get());
+ return;
+ }
+
+ // We cannot capture non-bindable properties without signals
+ if (notifyIndex == -1)
+ return;
+
+ if (isConnected(m_sourceObject, notifyIndex))
+ cancelNotify();
+ else
+ connect(m_sourceObject, notifyIndex, m_engine, true);
+}
+
+void QQmlPropertyToPropertyBinding::update(QQmlPropertyData::WriteFlags flags)
+{
+ if (!enabledFlag())
+ return;
+
+ // Check that the target has not been deleted
+ QObject *target = targetObject();
+ if (QQmlData::wasDeleted(target))
+ return;
+
+ const QQmlPropertyData *d = nullptr;
+ QQmlPropertyData vtd;
+ getPropertyData(&d, &vtd);
+ Q_ASSERT(d);
+
+ // Check for a binding update loop
+ if (Q_UNLIKELY(updatingFlag())) {
+ QQmlAbstractBinding::printBindingLoopError(
+ QQmlPropertyPrivate::restore(target, *d, &vtd, nullptr));
+ return;
+ }
+
+ setUpdatingFlag(true);
+
+ if (canUseAccessor())
+ flags.setFlag(QQmlPropertyData::BypassInterceptor);
+
+ const QMetaObject *sourceMetaObject = m_sourceObject->metaObject();
+ const QMetaProperty property = sourceMetaObject->property(m_sourcePropertyIndex);
+ if (!property.isConstant()) {
+ captureProperty(sourceMetaObject, QMetaObjectPrivate::signalIndex(property.notifySignal()),
+ property.isBindable(), !vtd.isValid() && d->isBindable());
+ }
+
+ QQmlPropertyPrivate::writeValueProperty(
+ target, *d, vtd, property.read(m_sourceObject), {}, flags);
+
+ setUpdatingFlag(false);
+}
+
+void QQmlPropertyGuard_callback(QQmlNotifierEndpoint *e, void **)
+{
+ static_cast<QQmlPropertyToPropertyBinding *>(e)->update();
+}
+
+void QQmlPropertyToPropertyBinding::Observer::trigger(
+ QPropertyObserver *observer, QUntypedPropertyData *)
+{
+ static_cast<Observer *>(observer)->binding->update();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertytopropertybinding_p.h b/src/qml/qml/qqmlpropertytopropertybinding_p.h
new file mode 100644
index 0000000000..d741c5a740
--- /dev/null
+++ b/src/qml/qml/qqmlpropertytopropertybinding_p.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLPROPERTYTOPROPERTYBINDINDING_P_H
+#define QQMLPROPERTYTOPROPERTYBINDINDING_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmlabstractbinding_p.h>
+#include <private/qqmlnotifier_p.h>
+#include <QtCore/qproperty.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_EXPORT QQmlPropertyToPropertyBinding
+ : public QQmlAbstractBinding, public QQmlNotifierEndpoint
+{
+public:
+ QQmlPropertyToPropertyBinding(
+ QQmlEngine *engine, QObject *sourceObject, int sourcePropertyIndex,
+ QObject *targetObject, int targetPropertyIndex);
+
+ Kind kind() const final;
+ void setEnabled(bool e, QQmlPropertyData::WriteFlags flags) final;
+
+ void update(QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding);
+
+private:
+ static void trigger(QPropertyObserver *, QUntypedPropertyData *);
+
+ void captureProperty(
+ const QMetaObject *sourceMetaObject, int notifyIndex,
+ bool isSourceBindable, bool isTargetBindable);
+
+ struct Observer : QPropertyObserver {
+ static void trigger(QPropertyObserver *observer, QUntypedPropertyData *);
+ Observer(QQmlPropertyToPropertyBinding *binding)
+ : QPropertyObserver(trigger)
+ , binding(binding)
+ {
+ }
+ QQmlPropertyToPropertyBinding *binding = nullptr;
+ };
+
+ std::unique_ptr<Observer> observer;
+ QQmlEngine *m_engine = nullptr;
+ QObject *m_sourceObject = nullptr;
+ int m_sourcePropertyIndex = -1;
+};
+
+void QQmlPropertyGuard_callback(QQmlNotifierEndpoint *e, void **);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index d7361ea2c6..ff22c3043a 100644
--- a/src/qml/qml/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -1,57 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertyvalidator_p.h"
#include <private/qqmlcustomparser_p.h>
+#include <private/qqmlglobal_p.h>
#include <private/qqmlirbuilder_p.h>
-#include <private/qqmlstringconverters_p.h>
#include <private/qqmlpropertycachecreator_p.h>
#include <private/qqmlpropertyresolver_p.h>
+#include <private/qqmlstringconverters_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <QtCore/qdatetime.h>
QT_BEGIN_NAMESPACE
-static bool isPrimitiveType(int typeId)
+static bool isPrimitiveType(QMetaType metaType)
{
- switch (typeId) {
+ switch (metaType.id()) {
#define HANDLE_PRIMITIVE(Type, id, T) \
case QMetaType::Type:
QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(HANDLE_PRIMITIVE);
@@ -62,7 +28,8 @@ QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(HANDLE_PRIMITIVE);
}
}
-QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
+QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports *imports,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit)
: enginePrivate(enginePrivate)
, compilationUnit(compilationUnit)
, imports(imports)
@@ -73,7 +40,7 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, c
bindingPropertyDataPerObject->resize(compilationUnit->objectCount());
}
-QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validate()
+QVector<QQmlError> QQmlPropertyValidator::validate()
{
return validateObject(/*root object*/0, /*instantiatingBinding*/nullptr);
}
@@ -96,26 +63,39 @@ struct BindingFinder
}
};
-QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
+QVector<QQmlError> QQmlPropertyValidator::validateObject(
int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
{
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(objectIndex);
+ for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
+ const auto errors = validateObject(it->objectIndex, /* instantiatingBinding*/ nullptr);
+ if (!errors.isEmpty())
+ return errors;
+ }
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ if (obj->hasFlag(QV4::CompiledData::Object::IsComponent)
+ && !obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot)) {
Q_ASSERT(obj->nBindings == 1);
const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ Q_ASSERT(componentBinding->type() == QV4::CompiledData::Binding::Type_Object);
return validateObject(componentBinding->value.objectIndex, componentBinding);
}
- QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex);
+ QQmlPropertyCache::ConstPtr propertyCache = propertyCaches.at(objectIndex);
if (!propertyCache)
- return QVector<QQmlJS::DiagnosticMessage>();
+ return QVector<QQmlError>();
QQmlCustomParser *customParser = nullptr;
if (auto typeRef = resolvedType(obj->inheritedTypeNameIndex)) {
- if (typeRef->type.isValid())
- customParser = typeRef->type.customParser();
+
+ // This binding instantiates a separate object. The separate object can have an ID and its
+ // own group properties even if it's then assigned to a value type, for example a 'var', or
+ // anything with an invokable ctor taking a QObject*.
+ populatingValueTypeGroupProperty = false;
+
+ const auto type = typeRef->type();
+ if (type.isValid())
+ customParser = type.customParser();
}
QList<const QV4::CompiledData::Binding*> customBindings;
@@ -128,7 +108,7 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
if (!binding->isGroupProperty())
continue;
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment))
continue;
if (populatingValueTypeGroupProperty) {
@@ -142,9 +122,9 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
QQmlPropertyResolver propertyResolver(propertyCache);
QString defaultPropertyName;
- QQmlPropertyData *defaultProperty = nullptr;
+ const QQmlPropertyData *defaultProperty = nullptr;
if (obj->indexOfDefaultPropertyOrAlias != -1) {
- QQmlPropertyCache *cache = propertyCache->parent();
+ const QQmlPropertyCache *cache = propertyCache->parent().data();
defaultPropertyName = cache->defaultPropertyName();
defaultProperty = cache->defaultProperty();
} else {
@@ -152,19 +132,21 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
defaultProperty = propertyCache->defaultProperty();
}
- QV4::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
+ QV4::CompiledData::BindingPropertyData collectedBindingPropertyData(obj->nBindings);
binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
QString name = stringAt(binding->propertyNameIndex);
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
customBindings << binding;
continue;
}
- } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
+ } else if (QQmlSignalNames::isHandlerName(name)
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
customBindings << binding;
continue;
@@ -172,13 +154,14 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
}
bool bindingToDefaultProperty = false;
- bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty;
+ bool isGroupProperty = instantiatingBinding
+ && instantiatingBinding->type() == QV4::CompiledData::Binding::Type_GroupProperty;
bool notInRevision = false;
- QQmlPropertyData *pd = nullptr;
+ const QQmlPropertyData *pd = nullptr;
if (!name.isEmpty()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
pd = propertyResolver.signal(name, &notInRevision);
} else {
pd = propertyResolver.property(name, &notInRevision,
@@ -187,9 +170,16 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
if (notInRevision) {
QString typeName = stringAt(obj->inheritedTypeNameIndex);
- auto *objectType = resolvedType(obj->inheritedTypeNameIndex);
- if (objectType && objectType->type.isValid()) {
- return recordError(binding->location, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType->type.module()).arg(objectType->majorVersion).arg(objectType->minorVersion));
+ if (auto *objectType = resolvedType(obj->inheritedTypeNameIndex)) {
+ const auto type = objectType->type();
+ if (type.isValid()) {
+ const auto version = objectType->version();
+ return recordError(binding->location,
+ tr("\"%1.%2\" is not available in %3 %4.%5.")
+ .arg(typeName).arg(name).arg(type.module())
+ .arg(version.majorVersion())
+ .arg(version.minorVersion()));
+ }
} else {
return recordError(binding->location, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name));
}
@@ -209,18 +199,21 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
if (name.constData()->isUpper() && !binding->isAttachedProperty()) {
QQmlType type;
QQmlImportNamespace *typeNamespace = nullptr;
- imports.resolveType(stringAt(binding->propertyNameIndex), &type, nullptr, nullptr, &typeNamespace);
+ imports->resolveType(
+ QQmlTypeLoader::get(enginePrivate), stringAt(binding->propertyNameIndex),
+ &type, nullptr, &typeNamespace);
if (typeNamespace)
return recordError(binding->location, tr("Invalid use of namespace"));
return recordError(binding->location, tr("Invalid attached object assignment"));
}
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
+ if (bindingType >= QV4::CompiledData::Binding::Type_Object
+ && (pd || binding->isAttachedProperty() || binding->isGroupProperty())) {
const bool populatingValueTypeGroupProperty
= pd
- && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType())
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment);
- const QVector<QQmlJS::DiagnosticMessage> subObjectValidatorErrors
+ && QQmlMetaType::metaObjectForValueType(pd->propType())
+ && !binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment);
+ const QVector<QQmlError> subObjectValidatorErrors
= validateObject(binding->value.objectIndex, binding,
populatingValueTypeGroupProperty);
if (!subObjectValidatorErrors.isEmpty())
@@ -228,15 +221,25 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
}
// Signal handlers were resolved and checked earlier in the signal handler conversion pass.
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ if (binding->flags() & (QV4::CompiledData::Binding::IsSignalHandlerExpression
+ | QV4::CompiledData::Binding::IsSignalHandlerObject
+ | QV4::CompiledData::Binding::IsPropertyObserver)) {
continue;
+ }
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
- if (instantiatingBinding && (instantiatingBinding->isAttachedProperty() || instantiatingBinding->isGroupProperty())) {
- return recordError(binding->location, tr("Attached properties cannot be used here"));
+ if ((pd && bindingType == QV4::CompiledData::Binding::Type_AttachedProperty)
+ || (!pd && bindingType == QV4::CompiledData::Binding::Type_GroupProperty)) {
+ if (instantiatingBinding && (instantiatingBinding->isAttachedProperty()
+ || instantiatingBinding->isGroupProperty())) {
+ return recordError(
+ binding->location, tr("%1 properties cannot be used here")
+ .arg(bindingType == QV4::CompiledData::Binding::Type_AttachedProperty
+ ? QStringLiteral("Attached")
+ : QStringLiteral("Group")));
}
continue;
+ } else if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ continue;
}
if (pd) {
@@ -246,17 +249,17 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
if (!pd->isWritable()
&& !pd->isQList()
&& !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
+ && !(bindingFlags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
) {
- if (assigningToGroupProperty && binding->type < QV4::CompiledData::Binding::Type_Object)
+ if (assigningToGroupProperty && bindingType < QV4::CompiledData::Binding::Type_Object)
return recordError(binding->valueLocation, tr("Cannot assign a value directly to a grouped property"));
return recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
}
- if (!pd->isQList() && (binding->flags & QV4::CompiledData::Binding::IsListItem)) {
+ if (!pd->isQList() && (bindingFlags & QV4::CompiledData::Binding::IsListItem)) {
QString error;
- if (pd->propType() == qMetaTypeId<QQmlScriptString>())
+ if (pd->propType() == QMetaType::fromType<QQmlScriptString>())
error = tr( "Cannot assign multiple values to a script property");
else
error = tr( "Cannot assign multiple values to a singular property");
@@ -265,28 +268,28 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
if (!bindingToDefaultProperty
&& !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment)
&& assigningToGroupProperty) {
QV4::CompiledData::Location loc = binding->valueLocation;
if (loc < (*assignedGroupProperty)->valueLocation)
loc = (*assignedGroupProperty)->valueLocation;
- if (pd && QQmlValueTypeFactory::isValueType(pd->propType()))
+ if (pd && QQmlMetaType::isValueType(pd->propType()))
return recordError(loc, tr("Property has already been assigned a value"));
return recordError(loc, tr("Cannot assign a value directly to a grouped property"));
}
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
- QQmlJS::DiagnosticMessage bindingError = validateLiteralBinding(propertyCache, pd, binding);
+ if (bindingType < QV4::CompiledData::Binding::Type_Script) {
+ QQmlError bindingError = validateLiteralBinding(propertyCache, pd, binding);
if (bindingError.isValid())
return recordError(bindingError);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- QQmlJS::DiagnosticMessage bindingError = validateObjectBinding(pd, name, binding);
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Object) {
+ QQmlError bindingError = validateObjectBinding(pd, name, binding);
if (bindingError.isValid())
return recordError(bindingError);
} else if (binding->isGroupProperty()) {
- if (QQmlValueTypeFactory::isValueType(pd->propType())) {
- if (QQmlValueTypeFactory::metaObjectForMetaType(pd->propType())) {
+ if (QQmlMetaType::isValueType(pd->propType())) {
+ if (QQmlMetaType::metaObjectForValueType(pd->propType())) {
if (!pd->isWritable()) {
return recordError(binding->location, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
}
@@ -294,22 +297,30 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
return recordError(binding->location, tr("Invalid grouped property access"));
}
} else {
- const int typeId = pd->propType();
- if (isPrimitiveType(typeId)) {
+ const QMetaType type = pd->propType();
+ if (isPrimitiveType(type)) {
return recordError(
binding->location,
tr("Invalid grouped property access: Property \"%1\" with primitive type \"%2\".")
- .arg(name)
- .arg(QString::fromLatin1(QMetaType::typeName(typeId)))
+ .arg(name, QString::fromUtf8(type.name()))
);
}
- if (!enginePrivate->propertyCacheForType(typeId)) {
- return recordError(binding->location,
- tr("Invalid grouped property access: Property \"%1\" with type \"%2\", which is not a value type")
- .arg(name)
- .arg(QString::fromLatin1(QMetaType::typeName(typeId)))
- );
+ if (!QQmlMetaType::propertyCacheForType(type)) {
+ auto mo = type.metaObject();
+ if (!mo) {
+ return recordError(binding->location,
+ tr("Invalid grouped property access: Property \"%1\" with type \"%2\", which is neither a value nor an object type")
+ .arg(name, QString::fromUtf8(type.name()))
+ );
+ }
+ if (QMetaObjectPrivate::get(mo)->flags & DynamicMetaObject) {
+ return recordError(binding->location,
+ tr("Unsupported grouped property access: Property \"%1\" with type \"%2\" has a dynamic meta-object.")
+ .arg(name, QString::fromUtf8(type.name()))
+ );
+ }
+ // fall through, this is okay
}
}
}
@@ -338,32 +349,42 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
customParser->clearErrors();
customParser->validator = this;
customParser->engine = enginePrivate;
- customParser->imports = &imports;
- customParser->verifyBindings(compilationUnit, customBindings);
+ customParser->imports = imports;
+ customParser->verifyBindings(
+ enginePrivate->v4engine()->executableCompilationUnit(
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit>(compilationUnit)),
+ customBindings);
customParser->validator = nullptr;
customParser->engine = nullptr;
customParser->imports = (QQmlImports*)nullptr;
- QVector<QQmlJS::DiagnosticMessage> parserErrors = customParser->errors();
+ QVector<QQmlError> parserErrors = customParser->errors();
if (!parserErrors.isEmpty())
return parserErrors;
}
(*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData;
- QVector<QQmlJS::DiagnosticMessage> noError;
+ QVector<QQmlError> noError;
return noError;
}
-QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const
+QQmlError QQmlPropertyValidator::validateLiteralBinding(
+ const QQmlPropertyCache::ConstPtr &propertyCache, const QQmlPropertyData *property,
+ const QV4::CompiledData::Binding *binding) const
{
if (property->isQList()) {
return qQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists"));
}
- QQmlJS::DiagnosticMessage noError;
+ QQmlError noError;
if (property->isEnum()) {
- if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum))
+ return noError;
+
+ // TODO: For historical reasons you can assign any number to an enum property alias
+ // This can be fixed with an opt-out mechanism, for example a pragma.
+ if (property->isAlias() && binding->isNumberBinding())
return noError;
QString value = compilationUnit->bindingValueAsString(binding);
@@ -381,49 +402,43 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlProp
}
auto warnOrError = [&](const QString &error) {
- if (binding->type == QV4::CompiledData::Binding::Type_Null) {
- QQmlError warning;
- warning.setUrl(compilationUnit->url());
- warning.setLine(binding->valueLocation.line);
- warning.setColumn(binding->valueLocation.column);
- warning.setDescription(error + tr(" - Assigning null to incompatible properties in QML "
- "is deprecated. This will become a compile error in "
- "future versions of Qt."));
- enginePrivate->warning(warning);
- return noError;
- }
return qQmlCompileError(binding->valueLocation, error);
};
- switch (property->propType()) {
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ const auto isStringBinding = [&]() -> bool {
+ // validateLiteralBinding is not supposed to be used on scripts
+ Q_ASSERT(bindingType != QV4::CompiledData::Binding::Type_Script);
+ return bindingType == QV4::CompiledData::Binding::Type_String;
+ };
+
+ switch (property->propType().id()) {
case QMetaType::QVariant:
break;
- case QVariant::String: {
+ case QMetaType::QString: {
if (!binding->evaluatesToString()) {
return warnOrError(tr("Invalid property assignment: string expected"));
}
}
break;
- case QVariant::StringList: {
+ case QMetaType::QStringList: {
if (!binding->evaluatesToString()) {
return warnOrError(tr("Invalid property assignment: string or string list expected"));
}
}
break;
- case QVariant::ByteArray: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ case QMetaType::QByteArray: {
+ if (bindingType != QV4::CompiledData::Binding::Type_String)
return warnOrError(tr("Invalid property assignment: byte array expected"));
- }
}
break;
- case QVariant::Url: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ case QMetaType::QUrl: {
+ if (bindingType != QV4::CompiledData::Binding::Type_String)
return warnOrError(tr("Invalid property assignment: url expected"));
- }
}
break;
- case QVariant::UInt: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ case QMetaType::UInt: {
+ if (bindingType == QV4::CompiledData::Binding::Type_Number) {
double d = compilationUnit->bindingValueAsNumber(binding);
if (double(uint(d)) == d)
return noError;
@@ -431,8 +446,8 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlProp
return warnOrError(tr("Invalid property assignment: unsigned int expected"));
}
break;
- case QVariant::Int: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ case QMetaType::Int: {
+ if (bindingType == QV4::CompiledData::Binding::Type_Number) {
double d = compilationUnit->bindingValueAsNumber(binding);
if (double(int(d)) == d)
return noError;
@@ -441,162 +456,148 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlProp
}
break;
case QMetaType::Float: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number expected"));
}
}
break;
- case QVariant::Double: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ case QMetaType::Double: {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number expected"));
}
}
break;
- case QVariant::Color: {
+ case QMetaType::QColor: {
bool ok = false;
- QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: color expected"));
}
}
break;
#if QT_CONFIG(datestring)
- case QVariant::Date: {
+ case QMetaType::QDate: {
bool ok = false;
- QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: date expected"));
}
}
break;
- case QVariant::Time: {
+ case QMetaType::QTime: {
bool ok = false;
- QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: time expected"));
}
}
break;
- case QVariant::DateTime: {
+ case QMetaType::QDateTime: {
bool ok = false;
- QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: datetime expected"));
}
}
break;
#endif // datestring
- case QVariant::Point: {
+ case QMetaType::QPoint: {
bool ok = false;
- QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: point expected"));
}
}
break;
- case QVariant::PointF: {
+ case QMetaType::QPointF: {
bool ok = false;
- QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: point expected"));
}
}
break;
- case QVariant::Size: {
+ case QMetaType::QSize: {
bool ok = false;
- QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: size expected"));
}
}
break;
- case QVariant::SizeF: {
+ case QMetaType::QSizeF: {
bool ok = false;
- QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: size expected"));
}
}
break;
- case QVariant::Rect: {
+ case QMetaType::QRect: {
bool ok = false;
- QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: rect expected"));
}
}
break;
- case QVariant::RectF: {
+ case QMetaType::QRectF: {
bool ok = false;
- QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
+ if (isStringBinding())
+ QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok);
if (!ok) {
return warnOrError(tr("Invalid property assignment: point expected"));
}
}
break;
- case QVariant::Bool: {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ case QMetaType::Bool: {
+ if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
return warnOrError(tr("Invalid property assignment: boolean expected"));
}
}
break;
- case QVariant::Vector2D: {
- struct {
- float xp;
- float yp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: 2D vector expected"));
- }
- }
- break;
- case QVariant::Vector3D: {
- struct {
- float xp;
- float yp;
- float zy;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: 3D vector expected"));
- }
- }
- break;
- case QVariant::Vector4D: {
- struct {
- float xp;
- float yp;
- float zy;
- float wp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: 4D vector expected"));
- }
- }
- break;
- case QVariant::Quaternion: {
- struct {
- float wp;
- float xp;
- float yp;
- float zp;
- } vec;
- if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) {
- return warnOrError(tr("Invalid property assignment: quaternion expected"));
+ case QMetaType::QVector2D:
+ case QMetaType::QVector3D:
+ case QMetaType::QVector4D:
+ case QMetaType::QQuaternion: {
+ auto typeName = [&]() {
+ switch (property->propType().id()) {
+ case QMetaType::QVector2D: return QStringLiteral("2D vector");
+ case QMetaType::QVector3D: return QStringLiteral("3D vector");
+ case QMetaType::QVector4D: return QStringLiteral("4D vector");
+ case QMetaType::QQuaternion: return QStringLiteral("quaternion");
+ default: return QString();
+ }
+ };
+ const QVariant result = QQmlValueTypeProvider::createValueType(
+ compilationUnit->bindingValueAsString(binding),
+ property->propType());
+ if (!result.isValid()) {
+ return warnOrError(tr("Invalid property assignment: %1 expected")
+ .arg(typeName()));
}
}
break;
- case QVariant::RegExp:
- case QVariant::RegularExpression:
+ case QMetaType::QRegularExpression:
return warnOrError(tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
default: {
// generate single literal value assignment to a list property if required
- if (property->propType() == qMetaTypeId<QList<qreal> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (property->propType() == QMetaType::fromType<QList<qreal> >()) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number or array of numbers expected"));
}
break;
- } else if (property->propType() == qMetaTypeId<QList<int> >()) {
- bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number);
+ } else if (property->propType() == QMetaType::fromType<QList<int> >()) {
+ bool ok = (bindingType == QV4::CompiledData::Binding::Type_Number);
if (ok) {
double n = compilationUnit->bindingValueAsNumber(binding);
if (double(int(n)) != n)
@@ -605,35 +606,33 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlProp
if (!ok)
return warnOrError(tr("Invalid property assignment: int or array of ints expected"));
break;
- } else if (property->propType() == qMetaTypeId<QList<bool> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ } else if (property->propType() == QMetaType::fromType<QList<bool> >()) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
return warnOrError(tr("Invalid property assignment: bool or array of bools expected"));
}
break;
- } else if (property->propType() == qMetaTypeId<QList<QUrl> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ } else if (property->propType() == QMetaType::fromType<QList<QUrl> >()) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String) {
return warnOrError(tr("Invalid property assignment: url or array of urls expected"));
}
break;
- } else if (property->propType() == qMetaTypeId<QList<QString> >()) {
+ } else if (property->propType() == QMetaType::fromType<QList<QString> >()) {
if (!binding->evaluatesToString()) {
return warnOrError(tr("Invalid property assignment: string or array of strings expected"));
}
break;
- } else if (property->propType() == qMetaTypeId<QJSValue>()) {
+ } else if (property->propType() == QMetaType::fromType<QJSValue>()) {
break;
- } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
+ } else if (property->propType() == QMetaType::fromType<QQmlScriptString>()) {
break;
} else if (property->isQObject()
- && binding->type == QV4::CompiledData::Binding::Type_Null) {
+ && bindingType == QV4::CompiledData::Binding::Type_Null) {
+ break;
+ } else if (QQmlMetaType::qmlType(property->propType()).canConstructValueType()) {
break;
}
- // otherwise, try a custom type assignment
- QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType());
- if (!converter) {
- return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType()))));
- }
+ return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QLatin1StringView(property->propType().name())));
}
break;
}
@@ -644,9 +643,22 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlProp
Returns true if from can be assigned to a (QObject) property of type
to.
*/
-bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const
+bool QQmlPropertyValidator::canCoerce(QMetaType to, QQmlPropertyCache::ConstPtr fromMo) const
{
- QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to);
+ QQmlPropertyCache::ConstPtr toMo = QQmlMetaType::rawPropertyCacheForType(to);
+
+ if (toMo.isNull()) {
+ // if we have an inline component from the current file,
+ // it is not properly registered at this point, as registration
+ // only occurs after the whole file has been validated
+ // Therefore we need to check the ICs here
+ for (const auto& icDatum : compilationUnit->inlineComponentData) {
+ if (icDatum.qmlType.typeId() == to) {
+ toMo = compilationUnit->propertyCaches.at(icDatum.objectIndex);
+ break;
+ }
+ }
+ }
while (fromMo) {
if (fromMo == toMo)
@@ -656,40 +668,39 @@ bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const
return false;
}
-QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const
+QVector<QQmlError> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const
{
- QVector<QQmlJS::DiagnosticMessage> errors;
+ QVector<QQmlError> errors;
errors.append(qQmlCompileError(location, description));
return errors;
}
-QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::recordError(const QQmlJS::DiagnosticMessage &error) const
+QVector<QQmlError> QQmlPropertyValidator::recordError(const QQmlError &error) const
{
- QVector<QQmlJS::DiagnosticMessage> errors;
+ QVector<QQmlError> errors;
errors.append(error);
return errors;
}
-QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
+QQmlError QQmlPropertyValidator::validateObjectBinding(const QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const
{
- QQmlJS::DiagnosticMessage noError;
+ QQmlError noError;
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object);
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) {
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Object);
bool isValueSource = false;
bool isPropertyInterceptor = false;
const QV4::CompiledData::Object *targetObject = compilationUnit->objectAt(binding->value.objectIndex);
if (auto *typeRef = resolvedType(targetObject->inheritedTypeNameIndex)) {
- QQmlRefPointer<QQmlPropertyCache> cache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate));
- const QMetaObject *mo = cache->firstCppMetaObject();
+ QQmlPropertyCache::ConstPtr cache = typeRef->createPropertyCache();
+ const QMetaObject *mo = cache ? cache->firstCppMetaObject() : nullptr;
QQmlType qmlType;
while (mo && !qmlType.isValid()) {
qmlType = QQmlMetaType::qmlType(mo);
mo = mo->superClass();
}
- Q_ASSERT(qmlType.isValid());
isValueSource = qmlType.propertyValueSourceCast() != -1;
isPropertyInterceptor = qmlType.propertyValueInterceptorCast() != -1;
@@ -702,7 +713,7 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
return noError;
}
- const int propType = property->propType();
+ const QMetaType propType = property->propType();
const auto rhsType = [&]() {
return stringAt(compilationUnit->objectAt(binding->value.objectIndex)
->inheritedTypeNameIndex);
@@ -712,43 +723,59 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
// Can only check at instantiation time if the created sub-object successfully casts to the
// target interface.
return noError;
- } else if (propType == QMetaType::QVariant || propType == qMetaTypeId<QJSValue>()) {
+ } else if (propType == QMetaType::fromType<QVariant>()
+ || propType == QMetaType::fromType<QJSValue>()) {
// We can convert everything to QVariant :)
return noError;
} else if (property->isQList()) {
- const int listType = enginePrivate->listType(propType);
+ const QMetaType listType = QQmlMetaType::listValueType(property->propType());
if (!QQmlMetaType::isInterface(listType)) {
- QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex);
+ QQmlPropertyCache::ConstPtr source = propertyCaches.at(binding->value.objectIndex);
if (!canCoerce(listType, source)) {
return qQmlCompileError(binding->valueLocation, tr("Cannot assign object to list property \"%1\"").arg(propertyName));
}
}
return noError;
- } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
+ } else if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject)
+ && property->isFunction()) {
return noError;
} else if (isPrimitiveType(propType)) {
- auto typeName = QString::fromUtf8(QMetaType::typeName(propType));
- return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting \"%3\"")
+ auto typeName = QString::fromUtf8(QMetaType(propType).name());
+ return qQmlCompileError(binding->location, tr("Cannot assign value of type \"%1\" to property \"%2\", expecting \"%3\"")
.arg(rhsType())
.arg(propertyName)
.arg(typeName));
- } else if (QQmlValueTypeFactory::isValueType(propType)) {
- return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object")
- .arg(rhsType()).arg(propertyName));
- } else if (propType == qMetaTypeId<QQmlScriptString>()) {
+ } else if (propType == QMetaType::fromType<QQmlScriptString>()) {
return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
+ } else if (QQmlMetaType::isValueType(property->propType())) {
+ return qQmlCompileError(binding->location, tr("Cannot assign value of type \"%1\" to property \"%2\", expecting an object")
+ .arg(rhsType()).arg(propertyName));
} else {
// We want to use the raw metaObject here as the raw metaobject is the
// actual property type before we applied any extensions that might
// effect the properties on the type, but don't effect assignability
- // Using -1 for the minor version ensures that we get the raw metaObject.
- QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(propType, -1);
+ // Not passing a version ensures that we get the raw metaObject.
+ QQmlPropertyCache::ConstPtr propertyMetaObject
+ = QQmlMetaType::rawPropertyCacheForType(propType);
+ if (!propertyMetaObject) {
+ // if we have an inline component from the current file,
+ // it is not properly registered at this point, as registration
+ // only occurs after the whole file has been validated
+ // Therefore we need to check the ICs here
+ for (const auto& icDatum: compilationUnit->inlineComponentData) {
+ if (icDatum.qmlType.typeId() == property->propType()) {
+ propertyMetaObject
+ = compilationUnit->propertyCaches.at(icDatum.objectIndex);
+ break;
+ }
+ }
+ }
if (propertyMetaObject) {
// Will be true if the assigned type inherits propertyMetaObject
// Determine isAssignable value
bool isAssignable = false;
- QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex);
+ QQmlPropertyCache::ConstPtr c = propertyCaches.at(binding->value.objectIndex);
while (c && !isAssignable) {
isAssignable |= c == propertyMetaObject;
c = c->parent();
@@ -756,11 +783,11 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
if (!isAssignable) {
return qQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.")
- .arg(rhsType()).arg(QLatin1String(QMetaType::typeName(propType))));
+ .arg(rhsType()).arg(QLatin1String(property->propType().name())));
}
} else {
return qQmlCompileError(binding->valueLocation, tr("Cannot assign to property of unknown type \"%1\".")
- .arg(QLatin1String(QMetaType::typeName(propType))));
+ .arg(QLatin1String(property->propType().name())));
}
}
diff --git a/src/qml/qml/qqmlpropertyvalidator_p.h b/src/qml/qml/qqmlpropertyvalidator_p.h
index 74a1281927..75787fcf68 100644
--- a/src/qml/qml/qqmlpropertyvalidator_p.h
+++ b/src/qml/qml/qqmlpropertyvalidator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYVALIDATOR_P_H
#define QQMLPROPERTYVALIDATOR_P_H
@@ -64,27 +28,31 @@ class QQmlPropertyValidator
{
Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator)
public:
- QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit);
+ QQmlPropertyValidator(
+ QQmlEnginePrivate *enginePrivate, const QQmlImports *imports,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
- QVector<QQmlJS::DiagnosticMessage> validate();
+ QVector<QQmlError> validate();
+
+ QQmlPropertyCache::ConstPtr rootPropertyCache() const { return propertyCaches.at(0); }
+ QUrl documentSourceUrl() const { return compilationUnit->url(); }
private:
- QVector<QQmlJS::DiagnosticMessage> validateObject(
+ QVector<QQmlError> validateObject(
int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding,
bool populatingValueTypeGroupProperty = false) const;
- QQmlJS::DiagnosticMessage validateLiteralBinding(
- QQmlPropertyCache *propertyCache, QQmlPropertyData *property,
+ QQmlError validateLiteralBinding(
+ const QQmlPropertyCache::ConstPtr &propertyCache, const QQmlPropertyData *property,
const QV4::CompiledData::Binding *binding) const;
- QQmlJS::DiagnosticMessage validateObjectBinding(
- QQmlPropertyData *property, const QString &propertyName,
+ QQmlError validateObjectBinding(
+ const QQmlPropertyData *property, const QString &propertyName,
const QV4::CompiledData::Binding *binding) const;
- bool canCoerce(int to, QQmlPropertyCache *fromMo) const;
+ bool canCoerce(QMetaType to, QQmlPropertyCache::ConstPtr fromMo) const;
- Q_REQUIRED_RESULT QVector<QQmlJS::DiagnosticMessage> recordError(
+ Q_REQUIRED_RESULT QVector<QQmlError> recordError(
const QV4::CompiledData::Location &location, const QString &description) const;
- Q_REQUIRED_RESULT QVector<QQmlJS::DiagnosticMessage> recordError(
- const QQmlJS::DiagnosticMessage &error) const;
+ Q_REQUIRED_RESULT QVector<QQmlError> recordError(const QQmlError &error) const;
QString stringAt(int index) const { return compilationUnit->stringAt(index); }
QV4::ResolvedTypeReference *resolvedType(int id) const
{
@@ -92,12 +60,12 @@ private:
}
QQmlEnginePrivate *enginePrivate;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
- const QQmlImports &imports;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+ const QQmlImports *imports;
const QV4::CompiledData::Unit *qmlUnit;
const QQmlPropertyCacheVector &propertyCaches;
- QVector<QV4::BindingPropertyData> * const bindingPropertyDataPerObject;
+ QVector<QV4::CompiledData::BindingPropertyData> * const bindingPropertyDataPerObject;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertyvalueinterceptor.cpp b/src/qml/qml/qqmlpropertyvalueinterceptor.cpp
index 603245f29d..17d43a1271 100644
--- a/src/qml/qml/qqmlpropertyvalueinterceptor.cpp
+++ b/src/qml/qml/qqmlpropertyvalueinterceptor.cpp
@@ -1,46 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertyvalueinterceptor_p.h"
-#include "qqml.h"
-
QT_BEGIN_NAMESPACE
/*!
@@ -64,6 +26,21 @@ QQmlPropertyValueInterceptor::~QQmlPropertyValueInterceptor()
}
/*!
+ \internal
+ Called when a BindableProperty metacall gets intercepted. The default implementation does nothing
+ and simply returns false.
+ A subclass which can properly intercept the metacall should return true after doing its work.
+ \a bindable is the pointer to the QUntypedBindable passed through the metacall
+ \a target is the QUntypedBindable of the intercepted property
+*/
+bool QQmlPropertyValueInterceptor::bindable(QUntypedBindable *bindable, QUntypedBindable target)
+{
+ Q_UNUSED(bindable);
+ Q_UNUSED(target)
+ return false;
+}
+
+/*!
\fn void QQmlPropertyValueInterceptor::setTarget(const QQmlProperty &property)
Set the target \a property for the value interceptor. This method will
be called by the QML engine when assigning a value interceptor.
diff --git a/src/qml/qml/qqmlpropertyvalueinterceptor_p.h b/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
index a3d6b0c8c7..9d1b0606cd 100644
--- a/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
+++ b/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYVALUEINTERCEPTOR_P_H
#define QQMLPROPERTYVALUEINTERCEPTOR_P_H
@@ -54,17 +18,19 @@
#include <private/qtqmlglobal_p.h>
#include <private/qqmlpropertyindex_p.h>
#include <QtCore/qobject.h>
+#include <QtCore/qproperty.h>
QT_BEGIN_NAMESPACE
class QQmlProperty;
-class Q_QML_PRIVATE_EXPORT QQmlPropertyValueInterceptor
+class Q_QML_EXPORT QQmlPropertyValueInterceptor
{
public:
QQmlPropertyValueInterceptor();
virtual ~QQmlPropertyValueInterceptor();
virtual void setTarget(const QQmlProperty &property) = 0;
virtual void write(const QVariant &value) = 0;
+ virtual bool bindable(QUntypedBindable *bindable, QUntypedBindable target);
private:
friend class QQmlInterceptorMetaObject;
diff --git a/src/qml/qml/qqmlpropertyvaluesource.cpp b/src/qml/qml/qqmlpropertyvaluesource.cpp
index 0aad41ebf1..558b36de09 100644
--- a/src/qml/qml/qqmlpropertyvaluesource.cpp
+++ b/src/qml/qml/qqmlpropertyvaluesource.cpp
@@ -1,46 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertyvaluesource.h"
-#include "qqml.h"
-
QT_BEGIN_NAMESPACE
/*!
diff --git a/src/qml/qml/qqmlpropertyvaluesource.h b/src/qml/qml/qqmlpropertyvaluesource.h
index 282a1021d6..9a39728220 100644
--- a/src/qml/qml/qqmlpropertyvaluesource.h
+++ b/src/qml/qml/qqmlpropertyvaluesource.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYVALUESOURCE_H
#define QQMLPROPERTYVALUESOURCE_H
diff --git a/src/qml/qml/qqmlproxymetaobject.cpp b/src/qml/qml/qqmlproxymetaobject.cpp
index e1500f70fb..6ec4009c37 100644
--- a/src/qml/qml/qqmlproxymetaobject.cpp
+++ b/src/qml/qml/qqmlproxymetaobject.cpp
@@ -1,55 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlproxymetaobject_p.h"
#include "qqmlproperty_p.h"
QT_BEGIN_NAMESPACE
-QQmlProxyMetaObject::QQmlProxyMetaObject(QObject *obj, QList<ProxyData> *mList)
-: metaObjects(mList), proxies(nullptr), parent(nullptr), object(obj)
+QQmlProxyMetaObject::QQmlProxyMetaObject(QObject *obj, const QList<ProxyData> *mList)
+ : metaObjects(mList), proxies(nullptr), parent(nullptr), object(obj)
{
- *static_cast<QMetaObject *>(this) = *metaObjects->constFirst().metaObject;
+ metaObject = metaObjects->constFirst().metaObject;
QObjectPrivate *op = QObjectPrivate::get(obj);
if (op->metaObject)
- parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
+ parent = op->metaObject;
op->metaObject = this;
}
@@ -65,54 +29,96 @@ QQmlProxyMetaObject::~QQmlProxyMetaObject()
proxies = nullptr;
}
+QObject *QQmlProxyMetaObject::getProxy(int index)
+{
+ if (!proxies) {
+ proxies = new QObject *[metaObjects->size()];
+ ::memset(proxies, 0, sizeof(QObject *) * metaObjects->size());
+ }
+
+ if (!proxies[index]) {
+ const ProxyData &data = metaObjects->at(index);
+ if (!data.createFunc)
+ return nullptr;
+
+ QObject *proxy = data.createFunc(object);
+ const QMetaObject *metaObject = proxy->metaObject();
+ proxies[index] = proxy;
+
+ int localOffset = data.metaObject->methodOffset();
+ int methodOffset = metaObject->methodOffset();
+ int methods = metaObject->methodCount() - methodOffset;
+
+ // ### - Can this be done more optimally?
+ for (int jj = 0; jj < methods; ++jj) {
+ QMetaMethod method =
+ metaObject->method(jj + methodOffset);
+ if (method.methodType() == QMetaMethod::Signal)
+ QQmlPropertyPrivate::connect(proxy, methodOffset + jj, object, localOffset + jj);
+ }
+ }
+
+ return proxies[index];
+}
+
int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void **a)
{
Q_ASSERT(object == o);
- if ((c == QMetaObject::ReadProperty ||
- c == QMetaObject::WriteProperty) &&
- id >= metaObjects->constLast().propertyOffset) {
-
- for (int ii = 0; ii < metaObjects->count(); ++ii) {
- const ProxyData &data = metaObjects->at(ii);
- if (id >= data.propertyOffset) {
- if (!proxies) {
- proxies = new QObject*[metaObjects->count()];
- ::memset(proxies, 0,
- sizeof(QObject *) * metaObjects->count());
- }
-
- if (!proxies[ii]) {
- QObject *proxy = data.createFunc(object);
- const QMetaObject *metaObject = proxy->metaObject();
- proxies[ii] = proxy;
-
- int localOffset = data.metaObject->methodOffset();
- int methodOffset = metaObject->methodOffset();
- int methods = metaObject->methodCount() - methodOffset;
-
- // ### - Can this be done more optimally?
- for (int jj = 0; jj < methods; ++jj) {
- QMetaMethod method =
- metaObject->method(jj + methodOffset);
- if (method.methodType() == QMetaMethod::Signal)
- QQmlPropertyPrivate::connect(proxy, methodOffset + jj, object, localOffset + jj);
- }
- }
-
- int proxyOffset = proxies[ii]->metaObject()->propertyOffset();
- int proxyId = id - data.propertyOffset + proxyOffset;
-
- return proxies[ii]->qt_metacall(c, proxyId, a);
- }
+ switch (c) {
+ case QMetaObject::ReadProperty:
+ case QMetaObject::WriteProperty: {
+ if (id < metaObjects->constLast().propertyOffset)
+ break;
+
+ for (int ii = 0; ii < metaObjects->size(); ++ii) {
+ const int globalPropertyOffset = metaObjects->at(ii).propertyOffset;
+ if (id < globalPropertyOffset)
+ continue;
+
+ QObject *proxy = getProxy(ii);
+ Q_ASSERT(proxy);
+ const int localProxyOffset = proxy->metaObject()->propertyOffset();
+ const int localProxyId = id - globalPropertyOffset + localProxyOffset;
+ return proxy->qt_metacall(c, localProxyId, a);
}
- } else if (c == QMetaObject::InvokeMetaMethod &&
- id >= metaObjects->constLast().methodOffset) {
+ break;
+ }
+ case QMetaObject::InvokeMetaMethod: {
+ if (id < metaObjects->constLast().methodOffset)
+ break;
+
QMetaMethod m = object->metaObject()->method(id);
if (m.methodType() == QMetaMethod::Signal) {
QMetaObject::activate(object, id, a);
return -1;
}
+
+ for (int ii = 0; ii < metaObjects->size(); ++ii) {
+ const int globalMethodOffset = metaObjects->at(ii).methodOffset;
+ if (id < globalMethodOffset)
+ continue;
+
+ QObject *proxy = getProxy(ii);
+ Q_ASSERT(proxy);
+ const int localMethodOffset = proxy->metaObject()->methodOffset();
+ const int localMethodId = id - globalMethodOffset + localMethodOffset;
+ return proxy->qt_metacall(c, localMethodId, a);
+ }
+
+ break;
+ }
+ case QMetaObject::CustomCall: {
+ if ((id & ~MaxExtensionCount) != ExtensionObjectId)
+ break;
+ int index = id & MaxExtensionCount;
+ if (qsizetype(index) >= metaObjects->size())
+ break;
+ a[0] = getProxy(index);
+ return id;
+ }
+ default:
+ break;
}
if (parent)
@@ -121,4 +127,17 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void
return object->qt_metacall(c, id, a);
}
+QMetaObject *QQmlProxyMetaObject::toDynamicMetaObject(QObject *)
+{
+ return metaObject;
+}
+
+void QQmlProxyMetaObject::objectDestroyed(QObject *object)
+{
+ if (parent)
+ parent->objectDestroyed(object);
+ else
+ QDynamicMetaObjectData::objectDestroyed(object);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlproxymetaobject_p.h b/src/qml/qml/qqmlproxymetaobject_p.h
index 2b7a980361..18cf2d4bac 100644
--- a/src/qml/qml/qqmlproxymetaobject_p.h
+++ b/src/qml/qml/qqmlproxymetaobject_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROXYMETAOBJECT_P_H
#define QQMLPROXYMETAOBJECT_P_H
@@ -51,8 +15,8 @@
// We mean it.
//
+#include <private/qtqmlglobal_p.h>
#include <private/qmetaobjectbuilder_p.h>
-#include "qqml.h"
#include <QtCore/QMetaObject>
#include <QtCore/QObject>
@@ -61,8 +25,7 @@
QT_BEGIN_NAMESPACE
-
-class QQmlProxyMetaObject : public QAbstractDynamicMetaObject
+class Q_QML_EXPORT QQmlProxyMetaObject : public QDynamicMetaObjectData
{
public:
struct ProxyData {
@@ -73,18 +36,39 @@ public:
int methodOffset;
};
- QQmlProxyMetaObject(QObject *, QList<ProxyData> *);
+ QQmlProxyMetaObject(QObject *, const QList<ProxyData> *);
~QQmlProxyMetaObject();
+ static constexpr int extensionObjectId(int id) noexcept
+ {
+ Q_ASSERT(id >= 0);
+ Q_ASSERT(id <= MaxExtensionCount); // MaxExtensionCount is a valid index
+ return ExtensionObjectId | id;
+ }
+
protected:
int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override;
+ QMetaObject *toDynamicMetaObject(QObject *) override;
+ void objectDestroyed(QObject *object) override;
private:
- QList<ProxyData> *metaObjects;
+ QObject *getProxy(int index);
+
+ const QList<ProxyData> *metaObjects;
QObject **proxies;
- QAbstractDynamicMetaObject *parent;
+ QDynamicMetaObjectData *parent;
+ QMetaObject *metaObject;
QObject *object;
+
+ // ExtensionObjectId acts as a flag for whether we should interpret a
+ // QMetaObject::CustomCall as a call to fetch the extension object (see
+ // QQmlProxyMetaObject::metaCall()). MaxExtensionCount is a limit on how
+ // many extensions we can query via such mechanism
+ enum : int {
+ MaxExtensionCount = 127, // magic number so that low bits are all '1'
+ ExtensionObjectId = ~MaxExtensionCount,
+ };
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlregistration.h b/src/qml/qml/qqmlregistration.h
new file mode 100644
index 0000000000..562a79eaf1
--- /dev/null
+++ b/src/qml/qml/qqmlregistration.h
@@ -0,0 +1,15 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLREGISTRATION_H
+#define QQMLREGISTRATION_H
+
+#include <QtCore/qglobal.h>
+#include <QtQmlIntegration/qqmlintegration.h>
+
+// satisfy configure, which warns about public headers not using those
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
+
+#endif // QQMLREGISTRATION_H
diff --git a/src/qml/qml/qqmlscriptblob.cpp b/src/qml/qml/qqmlscriptblob.cpp
index 6ac30d3ab5..fa9a41e801 100644
--- a/src/qml/qml/qqmlscriptblob.cpp
+++ b/src/qml/qml/qqmlscriptblob.cpp
@@ -1,46 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmlengine_p.h>
#include <private/qqmlirbuilder_p.h>
#include <private/qqmlscriptblob_p.h>
#include <private/qqmlscriptdata_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qqmlcontextdata_p.h>
#include <private/qv4runtimecodegen_p.h>
#include <private/qv4script_p.h>
@@ -66,14 +32,18 @@ QQmlRefPointer<QQmlScriptData> QQmlScriptBlob::scriptData() const
return m_scriptData;
}
+bool QQmlScriptBlob::isNative() const
+{
+ return m_scriptData && !m_scriptData->m_value.isEmpty();
+}
+
void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
{
- if (!diskCacheDisabled() || diskCacheForced()) {
- QQmlRefPointer<QV4::ExecutableCompilationUnit> unit
- = QV4::ExecutableCompilationUnit::create();
+ if (readCacheFile()) {
+ auto unit = QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>();
QString error;
if (unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
- initializeFromCompilationUnit(unit);
+ initializeFromCompilationUnit(std::move(unit));
return;
} else {
qCDebug(DBG_DISK_CACHE()) << "Error loading" << urlString() << "from disk cache:" << error;
@@ -95,7 +65,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
return;
}
- QV4::CompiledData::CompilationUnit unit;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit;
if (m_isModule) {
QList<QQmlJS::DiagnosticMessage> diagnostics;
@@ -130,28 +100,26 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data)
unit = std::move(irUnit.javaScriptCompilationUnit);
}
- auto executableUnit = QV4::ExecutableCompilationUnit::create(std::move(unit));
-
- if ((!diskCacheDisabled() || diskCacheForced()) && !isDebugging()) {
+ if (writeCacheFile()) {
QString errorString;
- if (executableUnit->saveToDisk(url(), &errorString)) {
+ if (unit->saveToDisk(url(), &errorString)) {
QString error;
- if (!executableUnit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
+ if (!unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) {
// ignore error, keep using the in-memory compilation unit.
}
} else {
qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of"
- << executableUnit->fileName() << "to disk:" << errorString;
+ << unit->fileName() << "to disk:" << errorString;
}
}
- initializeFromCompilationUnit(executableUnit);
+ initializeFromCompilationUnit(std::move(unit));
}
-void QQmlScriptBlob::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
+void QQmlScriptBlob::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *cachedUnit)
{
- initializeFromCompilationUnit(QV4::ExecutableCompilationUnit::create(
- QV4::CompiledData::CompilationUnit(unit, urlString(), finalUrlString())));
+ initializeFromCompilationUnit(QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>(
+ cachedUnit->qmlData, cachedUnit->aotCompiledFunctions, urlString(), finalUrlString()));
}
void QQmlScriptBlob::done()
@@ -160,15 +128,15 @@ void QQmlScriptBlob::done()
return;
// Check all script dependencies for errors
- for (int ii = 0; ii < m_scripts.count(); ++ii) {
+ for (int ii = 0; ii < m_scripts.size(); ++ii) {
const ScriptReference &script = m_scripts.at(ii);
Q_ASSERT(script.script->isCompleteOrError());
if (script.script->isError()) {
QList<QQmlError> errors = script.script->errors();
QQmlError error;
error.setUrl(url());
- error.setLine(script.location.line);
- error.setColumn(script.location.column);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column()));
error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
errors.prepend(error);
setError(errors);
@@ -181,7 +149,7 @@ void QQmlScriptBlob::done()
QSet<QString> ns;
- for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
+ for (int scriptIndex = 0; scriptIndex < m_scripts.size(); ++scriptIndex) {
const ScriptReference &script = m_scripts.at(scriptIndex);
m_scriptData->scripts.append(script.script);
@@ -195,7 +163,7 @@ void QQmlScriptBlob::done()
m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
}
- m_importCache.populateCache(m_scriptData->typeNameCache.data());
+ m_importCache->populateCache(m_scriptData->typeNameCache.data());
}
m_scripts.clear();
}
@@ -216,28 +184,29 @@ void QQmlScriptBlob::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob,
m_scripts << ref;
}
-void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit)
+void QQmlScriptBlob::initializeFromCompilationUnit(
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> &&unit)
{
Q_ASSERT(!m_scriptData);
+ Q_ASSERT(unit);
+
m_scriptData.adopt(new QQmlScriptData());
m_scriptData->url = finalUrl();
m_scriptData->urlString = finalUrlString();
m_scriptData->m_precompiledScript = unit;
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
-
- QQmlRefPointer<QV4::ExecutableCompilationUnit> script = m_scriptData->m_precompiledScript;
+ m_importCache->setBaseUrl(finalUrl(), finalUrlString());
if (!m_isModule) {
QList<QQmlError> errors;
- for (quint32 i = 0, count = script->importCount(); i < count; ++i) {
- const QV4::CompiledData::Import *import = script->importAt(i);
- if (!addImport(import, &errors)) {
+ for (quint32 i = 0, count = unit->importCount(); i < count; ++i) {
+ const QV4::CompiledData::Import *import = unit->importAt(i);
+ if (!addImport(import, {}, &errors)) {
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
+ error.setUrl(m_importCache->baseUrl());
+ error.setLine(import->location.line());
+ error.setColumn(import->location.column());
errors.prepend(error); // put it back on the list after filling out information.
setError(errors);
return;
@@ -245,19 +214,42 @@ void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::Exe
}
}
- auto *v4 = QQmlEnginePrivate::getV4Engine(typeLoader()->engine());
-
- v4->injectModule(unit);
+ const QStringList moduleRequests = unit->moduleRequests();
+ for (const QString &request: moduleRequests) {
+ const QUrl relativeRequest = QUrl(request);
+ if (m_typeLoader->injectedScript(relativeRequest))
+ continue;
- for (const QString &request: unit->moduleRequests()) {
- if (v4->moduleForUrl(QUrl(request), unit.data()))
+ const QUrl absoluteRequest = unit->finalUrl().resolved(relativeRequest);
+ QQmlRefPointer<QQmlScriptBlob> absoluteBlob = typeLoader()->getScript(absoluteRequest);
+ if (absoluteBlob->m_scriptData && absoluteBlob->m_scriptData->m_precompiledScript)
continue;
- const QUrl absoluteRequest = unit->finalUrl().resolved(QUrl(request));
- QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(absoluteRequest);
- addDependency(blob.data());
- scriptImported(blob, /* ### */QV4::CompiledData::Location(), /*qualifier*/QString(), /*namespace*/QString());
+ addDependency(absoluteBlob.data());
+ scriptImported(
+ absoluteBlob, /* ### */QV4::CompiledData::Location(), /*qualifier*/QString(),
+ /*namespace*/QString());
}
}
+
+/*!
+ \internal
+
+ This initializes a dummy script blob from a "native" ECMAScript module.
+ Native modules are just JavaScript values, possibly objects with members.
+
+ \sa QJSEngine::registerModule()
+ */
+void QQmlScriptBlob::initializeFromNative(const QV4::Value &value)
+{
+ Q_ASSERT(!m_scriptData);
+ m_scriptData.adopt(new QQmlScriptData());
+ m_scriptData->url = finalUrl();
+ m_scriptData->urlString = finalUrlString();
+ m_scriptData->m_loaded = true;
+ m_scriptData->m_value.set(QQmlEnginePrivate::getV4Engine(typeLoader()->engine()), value);
+ m_importCache->setBaseUrl(finalUrl(), finalUrlString());
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscriptblob_p.h b/src/qml/qml/qqmlscriptblob_p.h
index 10c0437e7b..59f969859b 100644
--- a/src/qml/qml/qqmlscriptblob_p.h
+++ b/src/qml/qml/qqmlscriptblob_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLSCRIPTBLOB_P_H
#define QQMLSCRIPTBLOB_P_H
@@ -75,17 +39,19 @@ public:
};
QQmlRefPointer<QQmlScriptData> scriptData() const;
+ bool isNative() const;
protected:
void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
+ void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) override;
void done() override;
QString stringAt(int index) const override;
private:
void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
- void initializeFromCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit);
+ void initializeFromCompilationUnit(QQmlRefPointer<QV4::CompiledData::CompilationUnit> &&cu);
+ void initializeFromNative(const QV4::Value &value);
QList<ScriptReference> m_scripts;
QQmlRefPointer<QQmlScriptData> m_scriptData;
diff --git a/src/qml/qml/qqmlscriptdata.cpp b/src/qml/qml/qqmlscriptdata.cpp
index ae268ca904..9337f25c6e 100644
--- a/src/qml/qml/qqmlscriptdata.cpp
+++ b/src/qml/qml/qqmlscriptdata.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmlscriptdata_p.h>
#include <private/qqmlcontext_p.h>
@@ -49,84 +13,81 @@
QT_BEGIN_NAMESPACE
-QQmlScriptData::QQmlScriptData()
- : typeNameCache(nullptr)
- , m_loaded(false)
+QQmlRefPointer<QQmlContextData> QQmlScriptData::qmlContextDataForContext(
+ const QQmlRefPointer<QQmlContextData> &parentQmlContextData)
{
-}
-
-QQmlContextData *QQmlScriptData::qmlContextDataForContext(QQmlContextData *parentQmlContextData)
-{
- Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
+ Q_ASSERT(parentQmlContextData && parentQmlContextData->engine());
- if (m_precompiledScript->isESModule())
+ if (!m_precompiledScript || m_precompiledScript->isESModule())
return nullptr;
- auto qmlContextData = new QQmlContextData();
+ QQmlRefPointer<QQmlContextData> qmlContextData = m_precompiledScript->isSharedLibrary()
+ ? QQmlContextData::createRefCounted(QQmlRefPointer<QQmlContextData>())
+ : QQmlContextData::createRefCounted(parentQmlContextData);
- qmlContextData->isInternal = true;
- qmlContextData->isJSContext = true;
+ qmlContextData->setInternal(true);
+ qmlContextData->setJSContext(true);
if (m_precompiledScript->isSharedLibrary())
- qmlContextData->isPragmaLibraryContext = true;
+ qmlContextData->setPragmaLibraryContext(true);
else
- qmlContextData->isPragmaLibraryContext = parentQmlContextData->isPragmaLibraryContext;
- qmlContextData->baseUrl = url;
- qmlContextData->baseUrlString = urlString;
+ qmlContextData->setPragmaLibraryContext(parentQmlContextData->isPragmaLibraryContext());
+ qmlContextData->setBaseUrl(url);
+ qmlContextData->setBaseUrlString(urlString);
// For backward compatibility, if there are no imports, we need to use the
// imports from the parent context. See QTBUG-17518.
if (!typeNameCache->isEmpty()) {
- qmlContextData->imports = typeNameCache;
+ qmlContextData->setImports(typeNameCache);
} else if (!m_precompiledScript->isSharedLibrary()) {
- qmlContextData->imports = parentQmlContextData->imports;
- qmlContextData->importedScripts = parentQmlContextData->importedScripts;
+ qmlContextData->setImports(parentQmlContextData->imports());
+ qmlContextData->setImportedScripts(parentQmlContextData->importedScripts());
}
- if (!m_precompiledScript->isSharedLibrary()) {
- qmlContextData->setParent(parentQmlContextData);
- } else {
- qmlContextData->engine = parentQmlContextData->engine; // Fix for QTBUG-21620
- }
+ if (m_precompiledScript->isSharedLibrary())
+ qmlContextData->setEngine(parentQmlContextData->engine()); // Fix for QTBUG-21620
- QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
+ QV4::ExecutionEngine *v4 = parentQmlContextData->engine()->handle();
QV4::Scope scope(v4);
QV4::ScopedObject scriptsArray(scope);
- if (qmlContextData->importedScripts.isNullOrUndefined()) {
- scriptsArray = v4->newArrayObject(scripts.count());
- qmlContextData->importedScripts.set(v4, scriptsArray);
+ if (qmlContextData->importedScripts().isNullOrUndefined()) {
+ scriptsArray = v4->newArrayObject(scripts.size());
+ qmlContextData->setImportedScripts(
+ QV4::PersistentValue(v4, scriptsArray.asReturnedValue()));
} else {
- scriptsArray = qmlContextData->importedScripts.valueRef();
+ scriptsArray = qmlContextData->importedScripts().valueRef();
}
QV4::ScopedValue v(scope);
- for (int ii = 0; ii < scripts.count(); ++ii)
- scriptsArray->put(ii, (v = scripts.at(ii)->scriptData()->scriptValueForContext(qmlContextData)));
+ for (int ii = 0; ii < scripts.size(); ++ii) {
+ v = scripts.at(ii)->scriptData()->scriptValueForContext(qmlContextData);
+ scriptsArray->put(ii, v);
+ }
return qmlContextData;
}
-QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parentQmlContextData)
+QV4::ReturnedValue QQmlScriptData::scriptValueForContext(
+ const QQmlRefPointer<QQmlContextData> &parentQmlContextData)
{
if (m_loaded)
return m_value.value();
- Q_ASSERT(parentQmlContextData && parentQmlContextData->engine);
- QV4::ExecutionEngine *v4 = parentQmlContextData->engine->handle();
+ Q_ASSERT(parentQmlContextData && parentQmlContextData->engine());
+ QV4::ExecutionEngine *v4 = parentQmlContextData->engine()->handle();
QV4::Scope scope(v4);
- if (!hasEngine()) {
- addToEngine(parentQmlContextData->engine);
- addref();
+ QV4::Scoped<QV4::QmlContext> qmlExecutionContext(scope);
+ if (auto qmlContextData = qmlContextDataForContext(parentQmlContextData)) {
+ qmlExecutionContext = QV4::QmlContext::create(v4->rootContext(), std::move(qmlContextData),
+ /* scopeObject: */ nullptr);
}
- QQmlContextDataRef qmlContextData = qmlContextDataForContext(parentQmlContextData);
- QV4::Scoped<QV4::QmlContext> qmlExecutionContext(scope);
- if (qmlContextData)
- qmlExecutionContext =
- QV4::QmlContext::create(v4->rootContext(), qmlContextData, /* scopeObject: */ nullptr);
+ QV4::Scoped<QV4::Module> module(
+ scope,
+ v4->executableCompilationUnit(QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
+ m_precompiledScript))->instantiate());
- QV4::Scoped<QV4::Module> module(scope, m_precompiledScript->instantiate(v4));
if (module) {
- if (qmlContextData) {
+ if (qmlExecutionContext) {
module->d()->scope->outer.set(v4, qmlExecutionContext->d());
qmlExecutionContext->d()->qml()->module.set(v4, module->d());
}
@@ -141,7 +102,7 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
}
QV4::ScopedValue value(scope);
- if (qmlContextData)
+ if (qmlExecutionContext)
value = qmlExecutionContext->d()->qml();
else if (module)
value = module->d();
@@ -154,13 +115,4 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
return value->asReturnedValue();
}
-void QQmlScriptData::clear()
-{
- typeNameCache = nullptr;
- scripts.clear();
-
- // An addref() was made when the QQmlCleanup was added to the engine.
- release();
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscriptdata_p.h b/src/qml/qml/qqmlscriptdata_p.h
index 80b65b699c..ad5ffb3d07 100644
--- a/src/qml/qml/qqmlscriptdata_p.h
+++ b/src/qml/qml/qqmlscriptdata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLSCRIPTDATA_P_H
#define QQMLSCRIPTDATA_P_H
@@ -52,11 +16,10 @@
//
#include <private/qqmlrefcount_p.h>
-#include <private/qqmlcleanup_p.h>
#include <private/qqmlscriptblob_p.h>
#include <private/qv4value_p.h>
#include <private/qv4persistent_p.h>
-#include <private/qv4executablecompilationunit_p.h>
+#include <private/qv4compileddata_p.h>
#include <QtCore/qurl.h>
@@ -65,19 +28,12 @@ QT_BEGIN_NAMESPACE
class QQmlTypeNameCache;
class QQmlContextData;
-// QQmlScriptData instances are created, uninitialized, by the loader in the
-// load thread. The first time they are used by the VME, they are initialized which
-// creates their v8 objects and they are referenced and added to the engine's cleanup
-// list. During QQmlCleanup::clear() all v8 resources are destroyed, and the
-// reference that was created is released but final deletion only occurs once all the
-// references as released. This is all intended to ensure that the v8 resources are
-// only created and destroyed in the main thread :)
-class Q_AUTOTEST_EXPORT QQmlScriptData : public QQmlCleanup, public QQmlRefCount
+class Q_AUTOTEST_EXPORT QQmlScriptData final : public QQmlRefCounted<QQmlScriptData>
{
private:
friend class QQmlTypeLoader;
- QQmlScriptData();
+ QQmlScriptData() = default;
public:
QUrl url;
@@ -85,21 +41,21 @@ public:
QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QVector<QQmlRefPointer<QQmlScriptBlob>> scripts;
- QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
+ QV4::ReturnedValue scriptValueForContext(const QQmlRefPointer<QQmlContextData> &parentCtxt);
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() const { return m_precompiledScript; }
-
-protected:
- void clear() override; // From QQmlCleanup
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit() const
+ {
+ return m_precompiledScript;
+ }
private:
friend class QQmlScriptBlob;
- void initialize(QQmlEngine *);
- QQmlContextData *qmlContextDataForContext(QQmlContextData *parentQmlContextData);
+ QQmlRefPointer<QQmlContextData> qmlContextDataForContext(
+ const QQmlRefPointer<QQmlContextData> &parentQmlContextData);
- bool m_loaded;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> m_precompiledScript;
+ bool m_loaded = false;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_precompiledScript;
QV4::PersistentValue m_value;
};
diff --git a/src/qml/qml/qqmlscriptstring.cpp b/src/qml/qml/qqmlscriptstring.cpp
index 3230e69b6d..9f47841031 100644
--- a/src/qml/qml/qqmlscriptstring.cpp
+++ b/src/qml/qml/qqmlscriptstring.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlscriptstring.h"
#include "qqmlscriptstring_p.h"
@@ -80,7 +44,7 @@ const QQmlScriptStringPrivate* QQmlScriptStringPrivate::get(const QQmlScriptStri
Constructs an empty instance.
*/
QQmlScriptString::QQmlScriptString()
-: d(new QQmlScriptStringPrivate)
+: d()
{
}
@@ -128,6 +92,8 @@ bool QQmlScriptString::operator==(const QQmlScriptString &other) const
{
if (d == other.d)
return true;
+ if (!d || !other.d)
+ return false;
if (d->isNumberLiteral || other.d->isNumberLiteral)
return d->isNumberLiteral && other.d->isNumberLiteral && d->numberValue == other.d->numberValue;
@@ -162,6 +128,8 @@ Returns whether the QQmlScriptString is empty.
*/
bool QQmlScriptString::isEmpty() const
{
+ if (!d)
+ return true;
if (!d->script.isEmpty())
return false;
return d->bindingId == -1;
@@ -172,7 +140,7 @@ Returns whether the content of the QQmlScriptString is the \c undefined literal.
*/
bool QQmlScriptString::isUndefinedLiteral() const
{
- return d->script == QLatin1String("undefined");
+ return d && d->script == QLatin1String("undefined");
}
/*!
@@ -180,7 +148,7 @@ Returns whether the content of the QQmlScriptString is the \c null literal.
*/
bool QQmlScriptString::isNullLiteral() const
{
- return d->script == QLatin1String("null");
+ return d && d->script == QLatin1String("null");
}
/*!
@@ -189,8 +157,8 @@ Otherwise returns a null QString.
*/
QString QQmlScriptString::stringLiteral() const
{
- if (d->isStringLiteral)
- return d->script.mid(1, d->script.length()-2);
+ if (d && d->isStringLiteral)
+ return d->script.mid(1, d->script.size()-2);
return QString();
}
@@ -201,8 +169,8 @@ sets \a ok to true. Otherwise returns 0.0 and sets \a ok to false.
qreal QQmlScriptString::numberLiteral(bool *ok) const
{
if (ok)
- *ok = d->isNumberLiteral;
- return d->isNumberLiteral ? d->numberValue : 0.;
+ *ok = d && d->isNumberLiteral;
+ return (d && d->isNumberLiteral) ? d->numberValue : 0.;
}
/*!
@@ -211,8 +179,8 @@ sets \a ok to true. Otherwise returns false and sets \a ok to false.
*/
bool QQmlScriptString::booleanLiteral(bool *ok) const
{
- bool isTrue = d->script == QLatin1String("true");
- bool isFalse = !isTrue && d->script == QLatin1String("false");
+ bool isTrue = d && d->script == QLatin1String("true");
+ bool isFalse = !isTrue && d && d->script == QLatin1String("false");
if (ok)
*ok = isTrue || isFalse;
return isTrue ? true : false;
@@ -220,3 +188,5 @@ bool QQmlScriptString::booleanLiteral(bool *ok) const
QT_END_NAMESPACE
+#include "moc_qqmlscriptstring.cpp"
+
diff --git a/src/qml/qml/qqmlscriptstring.h b/src/qml/qml/qqmlscriptstring.h
index 1f30c5a046..debc3d16c1 100644
--- a/src/qml/qml/qqmlscriptstring.h
+++ b/src/qml/qml/qqmlscriptstring.h
@@ -1,46 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLSCRIPTSTRING_H
#define QQMLSCRIPTSTRING_H
#include <QtQml/qtqmlglobal.h>
+#include <QtQml/qqml.h>
#include <QtCore/qstring.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qmetatype.h>
@@ -57,6 +22,7 @@ namespace QV4 {
}
class Q_QML_EXPORT QQmlScriptString
{
+ Q_GADGET
public:
QQmlScriptString();
QQmlScriptString(const QQmlScriptString &);
@@ -83,6 +49,7 @@ private:
friend class QQmlScriptStringPrivate;
friend class QQmlExpression;
friend class QQmlBinding;
+ friend class QQmlPropertyBinding;
friend struct QV4::QObjectWrapper;
};
diff --git a/src/qml/qml/qqmlscriptstring_p.h b/src/qml/qml/qqmlscriptstring_p.h
index fd8ccd5d53..a1b078ee8e 100644
--- a/src/qml/qml/qqmlscriptstring_p.h
+++ b/src/qml/qml/qqmlscriptstring_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLSCRIPTSTRING_P_H
#define QQMLSCRIPTSTRING_P_H
@@ -53,6 +17,7 @@
#include "qqmlscriptstring.h"
#include <QtQml/qqmlcontext.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlsourcecoordinate_p.h b/src/qml/qml/qqmlsourcecoordinate_p.h
index 55e11fd147..f7474f4d9b 100644
--- a/src/qml/qml/qqmlsourcecoordinate_p.h
+++ b/src/qml/qml/qqmlsourcecoordinate_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLSOURCECOORDINATE_P_H
#define QQMLSOURCECOORDINATE_P_H
@@ -51,7 +15,7 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
#include <limits>
diff --git a/src/qml/qml/qqmlstaticmetaobject.cpp b/src/qml/qml/qqmlstaticmetaobject.cpp
deleted file mode 100644
index 218d0134fd..0000000000
--- a/src/qml/qml/qqmlstaticmetaobject.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlstaticmetaobject_p.h"
-
-QT_BEGIN_NAMESPACE
-
-int *QQmlStaticMetaObject::constructorParameterTypes(int index, ArgTypeStorage *dummy,
- QByteArray *unknownTypeError) const
-{
- QMetaMethod m = _m.asT2()->constructor(index);
- return methodParameterTypes(m, dummy, unknownTypeError);
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlstaticmetaobject_p.h b/src/qml/qml/qqmlstaticmetaobject_p.h
deleted file mode 100644
index e1ca496080..0000000000
--- a/src/qml/qml/qqmlstaticmetaobject_p.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLSTATICMETAOBJECT_P_H
-#define QQMLSTATICMETAOBJECT_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qqmlobjectorgadget_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlStaticMetaObject : public QQmlObjectOrGadget {
-public:
- QQmlStaticMetaObject(const QMetaObject* metaObject)
- : QQmlObjectOrGadget(metaObject)
- {}
- int *constructorParameterTypes(int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLSTATICMETAOBJECT_P_H
diff --git a/src/qml/qml/qqmlstringconverters.cpp b/src/qml/qml/qqmlstringconverters.cpp
index e53f90b45b..a1f8cce67c 100644
--- a/src/qml/qml/qqmlstringconverters.cpp
+++ b/src/qml/qml/qqmlstringconverters.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlstringconverters_p.h"
#include <private/qqmlglobal_p.h>
@@ -48,25 +12,9 @@
QT_BEGIN_NAMESPACE
-QVariant QQmlStringConverters::variantFromString(const QString &s)
+QVariant QQmlStringConverters::variantFromString(const QString &s, QMetaType preferredType, bool *ok)
{
- if (s.isEmpty())
- return QVariant(s);
-
- bool ok = false;
- QRectF r = rectFFromString(s, &ok);
- if (ok) return QVariant(r);
- QPointF p = pointFFromString(s, &ok);
- if (ok) return QVariant(p);
- QSizeF sz = sizeFFromString(s, &ok);
- if (ok) return QVariant(sz);
-
- return QQml_valueTypeProvider()->createVariantFromString(s);
-}
-
-QVariant QQmlStringConverters::variantFromString(const QString &s, int preferredType, bool *ok)
-{
- switch (preferredType) {
+ switch (preferredType.id()) {
case QMetaType::Int:
return QVariant(int(qRound(s.toDouble(ok))));
case QMetaType::UInt:
@@ -91,8 +39,17 @@ QVariant QQmlStringConverters::variantFromString(const QString &s, int preferred
return QVariant::fromValue(rectFFromString(s, ok));
case QMetaType::QRect:
return QVariant::fromValue(rectFFromString(s, ok).toRect());
- default:
- return QQml_valueTypeProvider()->createVariantFromString(preferredType, s, ok);
+ default: {
+ const QVariant ret = QQmlValueTypeProvider::createValueType(s, preferredType);
+ if (ret.isValid()) {
+ if (ok)
+ *ok = true;
+ return ret;
+ }
+ if (ok)
+ *ok = false;
+ return QVariant();
+ }
}
}
@@ -125,9 +82,6 @@ QDateTime QQmlStringConverters::dateTimeFromString(const QString &s, bool *ok)
{
QDateTime d = QDateTime::fromString(s, Qt::ISODate);
if (ok) *ok = d.isValid();
- // V8 never parses a date string as local time. For consistency do the same here.
- if (d.timeSpec() == Qt::LocalTime)
- d.setTimeSpec(Qt::UTC);
return d;
}
#endif // datestring
@@ -135,168 +89,19 @@ QDateTime QQmlStringConverters::dateTimeFromString(const QString &s, bool *ok)
//expects input of "x,y"
QPointF QQmlStringConverters::pointFFromString(const QString &s, bool *ok)
{
- if (s.count(QLatin1Char(',')) != 1) {
- if (ok)
- *ok = false;
- return QPointF();
- }
-
- bool xGood, yGood;
- int index = s.indexOf(QLatin1Char(','));
- qreal xCoord = s.leftRef(index).toDouble(&xGood);
- qreal yCoord = s.midRef(index+1).toDouble(&yGood);
- if (!xGood || !yGood) {
- if (ok)
- *ok = false;
- return QPointF();
- }
-
- if (ok)
- *ok = true;
- return QPointF(xCoord, yCoord);
+ return valueTypeFromNumberString<QPointF, 2, u','>(s, ok);
}
//expects input of "widthxheight"
QSizeF QQmlStringConverters::sizeFFromString(const QString &s, bool *ok)
{
- if (s.count(QLatin1Char('x')) != 1) {
- if (ok)
- *ok = false;
- return QSizeF();
- }
-
- bool wGood, hGood;
- int index = s.indexOf(QLatin1Char('x'));
- qreal width = s.leftRef(index).toDouble(&wGood);
- qreal height = s.midRef(index+1).toDouble(&hGood);
- if (!wGood || !hGood) {
- if (ok)
- *ok = false;
- return QSizeF();
- }
-
- if (ok)
- *ok = true;
- return QSizeF(width, height);
+ return valueTypeFromNumberString<QSizeF, 2, u'x'>(s, ok);
}
//expects input of "x,y,widthxheight" //### use space instead of second comma?
QRectF QQmlStringConverters::rectFFromString(const QString &s, bool *ok)
{
- if (s.count(QLatin1Char(',')) != 2 || s.count(QLatin1Char('x')) != 1) {
- if (ok)
- *ok = false;
- return QRectF();
- }
-
- bool xGood, yGood, wGood, hGood;
- int index = s.indexOf(QLatin1Char(','));
- qreal x = s.leftRef(index).toDouble(&xGood);
- int index2 = s.indexOf(QLatin1Char(','), index+1);
- qreal y = s.midRef(index+1, index2-index-1).toDouble(&yGood);
- index = s.indexOf(QLatin1Char('x'), index2+1);
- qreal width = s.midRef(index2+1, index-index2-1).toDouble(&wGood);
- qreal height = s.midRef(index+1).toDouble(&hGood);
- if (!xGood || !yGood || !wGood || !hGood) {
- if (ok)
- *ok = false;
- return QRectF();
- }
-
- if (ok)
- *ok = true;
- return QRectF(x, y, width, height);
-}
-
-bool QQmlStringConverters::createFromString(int type, const QString &s, void *data, size_t n)
-{
- Q_ASSERT(data);
-
- bool ok = false;
-
- switch (type) {
- case QMetaType::Int:
- {
- Q_ASSERT(n >= sizeof(int));
- int *p = reinterpret_cast<int *>(data);
- *p = int(qRound(s.toDouble(&ok)));
- return ok;
- }
- case QMetaType::UInt:
- {
- Q_ASSERT(n >= sizeof(uint));
- uint *p = reinterpret_cast<uint *>(data);
- *p = uint(qRound(s.toDouble(&ok)));
- return ok;
- }
-#if QT_CONFIG(datestring)
- case QMetaType::QDate:
- {
- Q_ASSERT(n >= sizeof(QDate));
- QDate *p = reinterpret_cast<QDate *>(data);
- *p = dateFromString(s, &ok);
- return ok;
- }
- case QMetaType::QTime:
- {
- Q_ASSERT(n >= sizeof(QTime));
- QTime *p = reinterpret_cast<QTime *>(data);
- *p = timeFromString(s, &ok);
- return ok;
- }
- case QMetaType::QDateTime:
- {
- Q_ASSERT(n >= sizeof(QDateTime));
- QDateTime *p = reinterpret_cast<QDateTime *>(data);
- *p = dateTimeFromString(s, &ok);
- return ok;
- }
-#endif // datestring
- case QMetaType::QPointF:
- {
- Q_ASSERT(n >= sizeof(QPointF));
- QPointF *p = reinterpret_cast<QPointF *>(data);
- *p = pointFFromString(s, &ok);
- return ok;
- }
- case QMetaType::QPoint:
- {
- Q_ASSERT(n >= sizeof(QPoint));
- QPoint *p = reinterpret_cast<QPoint *>(data);
- *p = pointFFromString(s, &ok).toPoint();
- return ok;
- }
- case QMetaType::QSizeF:
- {
- Q_ASSERT(n >= sizeof(QSizeF));
- QSizeF *p = reinterpret_cast<QSizeF *>(data);
- *p = sizeFFromString(s, &ok);
- return ok;
- }
- case QMetaType::QSize:
- {
- Q_ASSERT(n >= sizeof(QSize));
- QSize *p = reinterpret_cast<QSize *>(data);
- *p = sizeFFromString(s, &ok).toSize();
- return ok;
- }
- case QMetaType::QRectF:
- {
- Q_ASSERT(n >= sizeof(QRectF));
- QRectF *p = reinterpret_cast<QRectF *>(data);
- *p = rectFFromString(s, &ok);
- return ok;
- }
- case QMetaType::QRect:
- {
- Q_ASSERT(n >= sizeof(QRect));
- QRect *p = reinterpret_cast<QRect *>(data);
- *p = rectFFromString(s, &ok).toRect();
- return ok;
- }
- default:
- return QQml_valueTypeProvider()->createValueFromString(type, s, data, n);
- }
+ return valueTypeFromNumberString<QRectF, 4, u',', u',', u'x'>(s, ok);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlstringconverters_p.h b/src/qml/qml/qqmlstringconverters_p.h
index 215f0c0aaf..0d220b11fc 100644
--- a/src/qml/qml/qqmlstringconverters_p.h
+++ b/src/qml/qml/qqmlstringconverters_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLSTRINGCONVERTERS_P_H
#define QQMLSTRINGCONVERTERS_P_H
@@ -66,22 +30,92 @@ class QByteArray;
namespace QQmlStringConverters
{
- Q_QML_PRIVATE_EXPORT QVariant variantFromString(const QString &);
- Q_QML_PRIVATE_EXPORT QVariant variantFromString(const QString &, int preferredType, bool *ok = nullptr);
+ Q_QML_EXPORT QVariant variantFromString(const QString &, QMetaType preferredType, bool *ok = nullptr);
- Q_QML_PRIVATE_EXPORT QVariant colorFromString(const QString &, bool *ok = nullptr);
- Q_QML_PRIVATE_EXPORT unsigned rgbaFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QVariant colorFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT unsigned rgbaFromString(const QString &, bool *ok = nullptr);
#if QT_CONFIG(datestring)
- Q_QML_PRIVATE_EXPORT QDate dateFromString(const QString &, bool *ok = nullptr);
- Q_QML_PRIVATE_EXPORT QTime timeFromString(const QString &, bool *ok = nullptr);
- Q_QML_PRIVATE_EXPORT QDateTime dateTimeFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QDate dateFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QTime timeFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QDateTime dateTimeFromString(const QString &, bool *ok = nullptr);
#endif
- Q_QML_PRIVATE_EXPORT QPointF pointFFromString(const QString &, bool *ok = nullptr);
- Q_QML_PRIVATE_EXPORT QSizeF sizeFFromString(const QString &, bool *ok = nullptr);
- Q_QML_PRIVATE_EXPORT QRectF rectFFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QPointF pointFFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QSizeF sizeFFromString(const QString &, bool *ok = nullptr);
+ Q_QML_EXPORT QRectF rectFFromString(const QString &, bool *ok = nullptr);
- Q_QML_PRIVATE_EXPORT bool createFromString(int, const QString &, void *, size_t);
+ // checks if the string contains a list of doubles separated by separators, like "double1
+ // separators1 double2 separators2 ..." for example.
+ template<int NumParams, char16_t... separators>
+ bool isValidNumberString(const QString &s, std::array<double, NumParams> *numbers = nullptr)
+ {
+ Q_STATIC_ASSERT_X(
+ NumParams == 2 || NumParams == 3 || NumParams == 4 || NumParams == 16,
+ "Unsupported number of params; add an additional case below if necessary.");
+ constexpr std::array<char16_t, NumParams - 1> separatorArray{ separators... };
+ // complain about missing separators when first or last entry is initialized with 0
+ Q_STATIC_ASSERT_X(separatorArray[0] != 0,
+ "Did not specify any separators for isValidNumberString.");
+ Q_STATIC_ASSERT_X(separatorArray[NumParams - 2] != 0,
+ "Did not specify enough separators for isValidNumberString.");
+
+ bool floatOk = true;
+ QStringView view(s);
+ for (qsizetype i = 0; i < NumParams - 1; ++i) {
+ const qsizetype commaIndex = view.indexOf(separatorArray[i]);
+ if (commaIndex == -1)
+ return false;
+ const auto current = view.first(commaIndex).toDouble(&floatOk);
+ if (!floatOk)
+ return false;
+ if (numbers)
+ (*numbers)[i] = current;
+
+ view = view.sliced(commaIndex + 1);
+ }
+ const auto current = view.toDouble(&floatOk);
+ if (!floatOk)
+ return false;
+ if (numbers)
+ (*numbers)[NumParams - 1] = current;
+
+ return true;
+ }
+
+ // Constructs a value type T from the given string that contains NumParams double values
+ // separated by separators, like "double1 separators1 double2 separators2 ..." for example.
+ template<typename T, int NumParams, char16_t... separators>
+ T valueTypeFromNumberString(const QString &s, bool *ok = nullptr)
+ {
+ Q_STATIC_ASSERT_X(
+ NumParams == 2 || NumParams == 3 || NumParams == 4 || NumParams == 16,
+ "Unsupported number of params; add an additional case below if necessary.");
+
+ std::array<double, NumParams> parameters;
+ if (!isValidNumberString<NumParams, separators...>(s, &parameters)) {
+ if (ok)
+ *ok = false;
+ return T{};
+ }
+
+ if (ok)
+ *ok = true;
+
+ if constexpr (NumParams == 2) {
+ return T(parameters[0], parameters[1]);
+ } else if constexpr (NumParams == 3) {
+ return T(parameters[0], parameters[1], parameters[2]);
+ } else if constexpr (NumParams == 4) {
+ return T(parameters[0], parameters[1], parameters[2], parameters[3]);
+ } else if constexpr (NumParams == 16) {
+ return T(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4],
+ parameters[5], parameters[6], parameters[7], parameters[8], parameters[9],
+ parameters[10], parameters[11], parameters[12], parameters[13], parameters[14],
+ parameters[15]);
+ }
+
+ Q_UNREACHABLE_RETURN(T{});
+ }
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp
index 874bcd4bca..533c3909ba 100644
--- a/src/qml/qml/qqmltype.cpp
+++ b/src/qml/qml/qqmltype.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmltype_p_p.h"
@@ -53,36 +17,44 @@
QT_BEGIN_NAMESPACE
QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
- : regType(type), iid(nullptr), typeId(0), listId(0), revision(0),
- containsRevisionedAttributes(false), baseMetaObject(nullptr),
- index(-1), isSetup(false), isEnumFromCacheSetup(false), isEnumFromBaseSetup(false),
- haveSuperType(false)
+ : regType(type)
{
switch (type) {
case QQmlType::CppType:
- extraData.cd = new QQmlCppTypeData;
- extraData.cd->allocationSize = 0;
- extraData.cd->newFunc = nullptr;
- extraData.cd->parserStatusCast = -1;
- extraData.cd->extFunc = nullptr;
- extraData.cd->extMetaObject = nullptr;
- extraData.cd->customParser = nullptr;
- extraData.cd->attachedPropertiesFunc = nullptr;
- extraData.cd->attachedPropertiesType = nullptr;
- extraData.cd->propertyValueSourceCast = -1;
- extraData.cd->propertyValueInterceptorCast = -1;
- extraData.cd->registerEnumClassesUnscoped = true;
+ extraData.cppTypeData = new QQmlCppTypeData;
+ extraData.cppTypeData->allocationSize = 0;
+ extraData.cppTypeData->newFunc = nullptr;
+ extraData.cppTypeData->createValueTypeFunc = nullptr;
+ extraData.cppTypeData->parserStatusCast = -1;
+ extraData.cppTypeData->extFunc = nullptr;
+ extraData.cppTypeData->extMetaObject = nullptr;
+ extraData.cppTypeData->customParser = nullptr;
+ extraData.cppTypeData->attachedPropertiesFunc = nullptr;
+ extraData.cppTypeData->attachedPropertiesType = nullptr;
+ extraData.cppTypeData->propertyValueSourceCast = -1;
+ extraData.cppTypeData->propertyValueInterceptorCast = -1;
+ extraData.cppTypeData->finalizerCast = -1;
+ extraData.cppTypeData->registerEnumClassesUnscoped = true;
+ extraData.cppTypeData->registerEnumsFromRelatedTypes = true;
break;
case QQmlType::SingletonType:
case QQmlType::CompositeSingletonType:
- extraData.sd = new QQmlSingletonTypeData;
- extraData.sd->singletonInstanceInfo = nullptr;
+ extraData.singletonTypeData = new QQmlSingletonTypeData;
+ extraData.singletonTypeData->singletonInstanceInfo = nullptr;
+ extraData.singletonTypeData->extFunc = nullptr;
+ extraData.singletonTypeData->extMetaObject = nullptr;
break;
case QQmlType::InterfaceType:
- extraData.cd = nullptr;
+ extraData.interfaceTypeData = nullptr;
break;
case QQmlType::CompositeType:
- extraData.fd = new QQmlCompositeTypeData;
+ new (&extraData.compositeTypeData) QUrl();
+ break;
+ case QQmlType::InlineComponentType:
+ new (&extraData.inlineComponentTypeData) QUrl();
+ break;
+ case QQmlType::SequentialContainerType:
+ new (&extraData.sequentialContainerTypeData) QMetaSequence();
break;
default: qFatal("QQmlTypePrivate Internal Error.");
}
@@ -90,21 +62,32 @@ QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
QQmlTypePrivate::~QQmlTypePrivate()
{
- qDeleteAll(scopedEnums);
- for (const auto &metaObject : metaObjects)
- free(metaObject.metaObject);
+ delete enums.fetchAndStoreAcquire(nullptr);
+ delete proxyMetaObjects.fetchAndStoreAcquire(nullptr);
+
+ if (const QtPrivate::QMetaTypeInterface *iface = typeId.iface()) {
+ if (iface->metaObjectFn == &dynamicQmlMetaObject)
+ QQmlMetaType::unregisterInternalCompositeType(typeId, listId);
+ }
+
switch (regType) {
case QQmlType::CppType:
- delete extraData.cd->customParser;
- delete extraData.cd;
+ delete extraData.cppTypeData->customParser;
+ delete extraData.cppTypeData;
break;
case QQmlType::SingletonType:
case QQmlType::CompositeSingletonType:
- delete extraData.sd->singletonInstanceInfo;
- delete extraData.sd;
+ extraData.singletonTypeData->singletonInstanceInfo.reset();
+ delete extraData.singletonTypeData;
break;
case QQmlType::CompositeType:
- delete extraData.fd;
+ extraData.compositeTypeData.~QUrl();
+ break;
+ case QQmlType::InlineComponentType:
+ extraData.inlineComponentTypeData.~QUrl();
+ break;
+ case QQmlType::SequentialContainerType:
+ extraData.sequentialContainerTypeData.~QMetaSequence();
break;
default: //Also InterfaceType, because it has no extra data
break;
@@ -126,34 +109,33 @@ QHashedString QQmlType::module() const
return d->module;
}
-int QQmlType::majorVersion() const
+QTypeRevision QQmlType::version() const
{
if (!d)
- return -1;
- return d->version_maj;
+ return QTypeRevision();
+ return d->version;
}
-int QQmlType::minorVersion() const
+bool QQmlType::availableInVersion(QTypeRevision version) const
{
if (!d)
- return -1;
- return d->version_min;
-}
+ return false;
-bool QQmlType::availableInVersion(int vmajor, int vminor) const
-{
- Q_ASSERT(vmajor >= 0 && vminor >= 0);
- if (!d)
+ if (!version.hasMajorVersion())
+ return true;
+
+ if (version.majorVersion() != d->version.majorVersion())
return false;
- return vmajor == d->version_maj && vminor >= d->version_min;
+
+ return !version.hasMinorVersion() || version.minorVersion() >= d->version.minorVersion();
}
-bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const
+bool QQmlType::availableInVersion(const QHashedStringRef &module, QTypeRevision version) const
{
- Q_ASSERT(vmajor >= 0 && vminor >= 0);
- if (!d)
+ if (!d || module != d->module)
return false;
- return module == d->module && vmajor == d->version_maj && vminor >= d->version_min;
+
+ return availableInVersion(version);
}
QQmlType QQmlTypePrivate::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
@@ -164,12 +146,13 @@ QQmlType QQmlTypePrivate::resolveCompositeBaseType(QQmlEnginePrivate *engine) co
QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()));
if (td.isNull() || !td->isComplete())
return QQmlType();
- QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit();
+ QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit();
const QMetaObject *mo = compilationUnit->rootPropertyCache()->firstCppMetaObject();
return QQmlMetaType::qmlType(mo);
}
-QQmlPropertyCache *QQmlTypePrivate::compositePropertyCache(QQmlEnginePrivate *engine) const
+QQmlPropertyCache::ConstPtr QQmlTypePrivate::compositePropertyCache(
+ QQmlEnginePrivate *engine) const
{
// similar logic to resolveCompositeBaseType
Q_ASSERT(isComposite());
@@ -178,69 +161,72 @@ QQmlPropertyCache *QQmlTypePrivate::compositePropertyCache(QQmlEnginePrivate *en
QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()));
if (td.isNull() || !td->isComplete())
return nullptr;
- QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit();
- return compilationUnit->rootPropertyCache().data();
+ QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit();
+ return compilationUnit->rootPropertyCache();
}
static bool isPropertyRevisioned(const QMetaObject *mo, int index)
{
- int i = index;
- i -= mo->propertyOffset();
- if (i < 0 && mo->d.superdata)
- return isPropertyRevisioned(mo->d.superdata, index);
-
- const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate*>(mo->d.data);
- if (i >= 0 && i < mop->propertyCount) {
- int handle = mop->propertyData + 3*i;
- int flags = mo->d.data[handle + 2];
-
- return (flags & Revisioned);
- }
-
- return false;
+ return mo->property(index).revision();
}
-void QQmlTypePrivate::init() const
+const QQmlTypePrivate::ProxyMetaObjects *QQmlTypePrivate::init() const
{
- if (isSetup)
- return;
+ if (const ProxyMetaObjects *result = proxyMetaObjects.loadRelaxed())
+ return result;
- QMutexLocker lock(QQmlMetaType::typeRegistrationLock());
- if (isSetup)
- return;
+ ProxyMetaObjects *proxies = new ProxyMetaObjects;
+ auto finalize = [this, proxies]() -> const ProxyMetaObjects *{
+ const ProxyMetaObjects *concurrentModification;
+ if (proxyMetaObjects.testAndSetOrdered(nullptr, proxies, concurrentModification))
+ return proxies;
+
+ delete proxies;
+ return concurrentModification;
+ };
const QMetaObject *mo = baseMetaObject;
if (!mo) {
// version 0 singleton type without metaobject information
- return;
+ return finalize();
}
- if (regType == QQmlType::CppType) {
- // Setup extended meta object
+ QList<QQmlProxyMetaObject::ProxyData> metaObjects;
+
+ auto setupExtendedMetaObject = [&](const QMetaObject *extMetaObject,
+ QObject *(*extFunc)(QObject *)) {
+ if (!extMetaObject)
+ return;
+
// XXX - very inefficient
- if (extraData.cd->extFunc) {
- QMetaObjectBuilder builder;
- QQmlMetaType::clone(builder, extraData.cd->extMetaObject, extraData.cd->extMetaObject,
- extraData.cd->extMetaObject);
- builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
- QMetaObject *mmo = builder.toMetaObject();
- mmo->d.superdata = mo;
- QQmlProxyMetaObject::ProxyData data = { mmo, extraData.cd->extFunc, 0, 0 };
- metaObjects << data;
- }
- }
+ QMetaObjectBuilder builder;
+ QQmlMetaType::clone(builder, extMetaObject, extMetaObject, extMetaObject,
+ extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly);
+ QMetaObject *mmo = builder.toMetaObject();
+ mmo->d.superdata = mo;
+ QQmlProxyMetaObject::ProxyData data = { mmo, extFunc, 0, 0 };
+ metaObjects << data;
+ QQmlMetaType::registerMetaObjectForType(mmo, const_cast<QQmlTypePrivate *>(this));
+ };
+
+ if (regType == QQmlType::SingletonType)
+ setupExtendedMetaObject(extraData.singletonTypeData->extMetaObject, extraData.singletonTypeData->extFunc);
+ else if (regType == QQmlType::CppType)
+ setupExtendedMetaObject(extraData.cppTypeData->extMetaObject, extraData.cppTypeData->extFunc);
metaObjects.append(QQmlMetaType::proxyData(
mo, baseMetaObject, metaObjects.isEmpty() ? nullptr
: metaObjects.constLast().metaObject));
- for (int ii = 0; ii < metaObjects.count(); ++ii) {
+ for (int ii = 0; ii < metaObjects.size(); ++ii) {
metaObjects[ii].propertyOffset =
metaObjects.at(ii).metaObject->propertyOffset();
metaObjects[ii].methodOffset =
metaObjects.at(ii).metaObject->methodOffset();
}
+ bool containsRevisionedAttributes = false;
+
// Check for revisioned details
{
const QMetaObject *mo = nullptr;
@@ -260,52 +246,75 @@ void QQmlTypePrivate::init() const
}
}
- isSetup = true;
- lock.unlock();
+ proxies->data = std::move(metaObjects);
+ proxies->containsRevisionedAttributes = containsRevisionedAttributes;
+
+ return finalize();
}
-void QQmlTypePrivate::initEnums(QQmlEnginePrivate *engine) const
+const QQmlTypePrivate::Enums *QQmlTypePrivate::initEnums(QQmlEnginePrivate *engine) const
{
- const QQmlPropertyCache *cache = (!isEnumFromCacheSetup && isComposite())
- ? compositePropertyCache(engine)
- : nullptr;
+ if (const Enums *result = enums.loadRelaxed())
+ return result;
- const QMetaObject *metaObject = !isEnumFromCacheSetup
- ? baseMetaObject // beware: It could be a singleton type without metaobject
- : nullptr;
+ QQmlPropertyCache::ConstPtr cache;
+ if (isComposite()) {
+ cache = compositePropertyCache(engine);
+ if (!cache)
+ return nullptr; // Composite type not ready, yet.
+ }
- if (!cache && !metaObject)
- return;
+ Enums *newEnums = new Enums;
- init();
+ // beware: It could be a singleton type without metaobject
- QMutexLocker lock(QQmlMetaType::typeRegistrationLock());
+ if (cache)
+ insertEnumsFromPropertyCache(newEnums, cache);
- if (cache) {
- insertEnumsFromPropertyCache(cache);
- isEnumFromCacheSetup = true;
+ if (baseMetaObject) {
+ // init() can add to the metaObjects list. Therefore, check proxies->data only below
+ const ProxyMetaObjects *proxies = init();
+ insertEnums(
+ newEnums,
+ proxies->data.isEmpty() ? baseMetaObject : proxies->data.constFirst().metaObject);
}
- if (metaObject) {
- insertEnums(metaObject);
- isEnumFromBaseSetup = true;
- }
+ const Enums *concurrentModification;
+ if (enums.testAndSetOrdered(nullptr, newEnums, concurrentModification))
+ return newEnums;
+
+ delete newEnums;
+ return concurrentModification;
}
-void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
+void QQmlTypePrivate::insertEnums(Enums *enums, const QMetaObject *metaObject) const
{
// Add any enum values defined by 'related' classes
- if (metaObject->d.relatedMetaObjects) {
- const auto *related = metaObject->d.relatedMetaObjects;
- if (related) {
- while (*related)
- insertEnums(*related++);
+ if (regType != QQmlType::CppType || extraData.cppTypeData->registerEnumsFromRelatedTypes) {
+ if (const auto *related = metaObject->d.relatedMetaObjects) {
+ while (const QMetaObject *relatedMetaObject = *related) {
+ insertEnums(enums, relatedMetaObject);
+ ++related;
+ }
}
}
QSet<QString> localEnums;
const QMetaObject *localMetaObject = nullptr;
+ // ### TODO (QTBUG-123294): track this at instance creation time
+ auto shouldSingletonAlsoRegisterUnscoped = [&](){
+ Q_ASSERT(regType == QQmlType::SingletonType);
+ if (!baseMetaObject)
+ return true;
+ int idx = baseMetaObject->indexOfClassInfo("RegisterEnumClassesUnscoped");
+ if (idx == -1)
+ return true;
+ if (qstrcmp(baseMetaObject->classInfo(idx).value(), "false") == 0)
+ return false;
+ return true;
+ };
+
// Add any enum values defined by this class, overwriting any inherited values
for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
QMetaEnum e = metaObject->enumerator(ii);
@@ -322,29 +331,33 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
localEnums.clear();
localMetaObject = e.enclosingMetaObject();
}
+ const bool shouldRegisterUnscoped = !isScoped
+ || (regType == QQmlType::CppType && extraData.cppTypeData->registerEnumClassesUnscoped)
+ || (regType == QQmlType::SingletonType && shouldSingletonAlsoRegisterUnscoped())
+ ;
for (int jj = 0; jj < e.keyCount(); ++jj) {
const QString key = QString::fromUtf8(e.key(jj));
const int value = e.value(jj);
- if (!isScoped || (regType == QQmlType::CppType && extraData.cd->registerEnumClassesUnscoped)) {
+ if (shouldRegisterUnscoped) {
if (localEnums.contains(key)) {
- auto existingEntry = enums.find(key);
- if (existingEntry != enums.end() && existingEntry.value() != value) {
+ auto existingEntry = enums->enums.find(key);
+ if (existingEntry != enums->enums.end() && existingEntry.value() != value) {
qWarning("Previously registered enum will be overwritten due to name clash: %s.%s", metaObject->className(), key.toUtf8().constData());
createEnumConflictReport(metaObject, key);
}
} else {
localEnums.insert(key);
}
- enums.insert(key, value);
+ enums->enums.insert(key, value);
}
if (isScoped)
scoped->insert(key, value);
}
if (isScoped) {
- scopedEnums << scoped;
- scopedEnumIndex.insert(QString::fromUtf8(e.name()), scopedEnums.count()-1);
+ enums->scopedEnums << scoped;
+ enums->scopedEnumIndex.insert(QString::fromUtf8(e.name()), enums->scopedEnums.size()-1);
}
}
}
@@ -395,35 +408,37 @@ void QQmlTypePrivate::createEnumConflictReport(const QMetaObject *metaObject, co
qWarning().noquote() << QLatin1String("Possible conflicting items:");
// find items with conflicting key
- for (const auto &i : qAsConst(enumInfoList)) {
+ for (const auto &i : std::as_const(enumInfoList)) {
if (i.enumKey == conflictingKey)
qWarning().noquote().nospace() << " " << i.metaObjectName << "." << i.enumName << "." << i.enumKey << " from scope "
<< i.metaEnumScope << " injected by " << i.path.join(QLatin1String("->"));
}
}
-void QQmlTypePrivate::insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const
+void QQmlTypePrivate::insertEnumsFromPropertyCache(
+ Enums *enums, const QQmlPropertyCache::ConstPtr &cache) const
{
const QMetaObject *cppMetaObject = cache->firstCppMetaObject();
- while (cache && cache->metaObject() != cppMetaObject) {
+ for (const QQmlPropertyCache *currentCache = cache.data();
+ currentCache && currentCache->metaObject() != cppMetaObject;
+ currentCache = currentCache->parent().data()) {
- int count = cache->qmlEnumCount();
+ int count = currentCache->qmlEnumCount();
for (int ii = 0; ii < count; ++ii) {
QStringHash<int> *scoped = new QStringHash<int>();
- QQmlEnumData *enumData = cache->qmlEnum(ii);
+ QQmlEnumData *enumData = currentCache->qmlEnum(ii);
- for (int jj = 0; jj < enumData->values.count(); ++jj) {
+ for (int jj = 0; jj < enumData->values.size(); ++jj) {
const QQmlEnumValue &value = enumData->values.at(jj);
- enums.insert(value.namedValue, value.value);
+ enums->enums.insert(value.namedValue, value.value);
scoped->insert(value.namedValue, value.value);
}
- scopedEnums << scoped;
- scopedEnumIndex.insert(enumData->name, scopedEnums.count()-1);
+ enums->scopedEnums << scoped;
+ enums->scopedEnumIndex.insert(enumData->name, enums->scopedEnums.size()-1);
}
- cache = cache->parent();
}
- insertEnums(cppMetaObject);
+ insertEnums(enums, cppMetaObject);
}
void QQmlTypePrivate::setName(const QString &uri, const QString &element)
@@ -437,7 +452,7 @@ QByteArray QQmlType::typeName() const
{
if (d) {
if (d->regType == SingletonType || d->regType == CompositeSingletonType)
- return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8();
+ return d->extraData.singletonTypeData->singletonInstanceInfo->typeName;
else if (d->baseMetaObject)
return d->baseMetaObject->className();
}
@@ -458,46 +473,68 @@ QString QQmlType::qmlTypeName() const
return d->name;
}
+/*!
+ \internal
+ Allocates and initializes an object if the type is creatable.
+ Returns a pointer to the object, or nullptr if the type was
+ not creatable.
+ */
QObject *QQmlType::create() const
{
- if (!d || !isCreatable())
- return nullptr;
-
- d->init();
-
- QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize);
- d->extraData.cd->newFunc(rv);
+ void *unused;
+ return create(&unused, 0);
+}
- if (rv && !d->metaObjects.isEmpty())
- (void)new QQmlProxyMetaObject(rv, &d->metaObjects);
+/*!
+ \internal
+ \brief Like create without arguments, but allocates some extra space after the object.
+ \param memory An out-only argument. *memory will point to the start of the additionally
+ allocated memory.
+ \param additionalMemory The amount of extra memory in bytes that shoudld be allocated.
- return rv;
-}
+ \note This function is used to allocate the QQmlData next to the object in the
+ QQmlObjectCreator.
-void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) const
+ \overload
+ */
+QObject *QQmlType::create(void **memory, size_t additionalMemory) const
{
if (!d || !isCreatable())
- return;
-
- d->init();
+ return nullptr;
- QObject *rv = (QObject *)operator new(d->extraData.cd->allocationSize + additionalMemory);
- d->extraData.cd->newFunc(rv);
+ QObject *rv = (QObject *)operator new(d->extraData.cppTypeData->allocationSize + additionalMemory);
+ d->extraData.cppTypeData->newFunc(rv, d->extraData.cppTypeData->userdata);
- if (rv && !d->metaObjects.isEmpty())
- (void)new QQmlProxyMetaObject(rv, &d->metaObjects);
+ createProxy(rv);
+ *memory = ((char *)rv) + d->extraData.cppTypeData->allocationSize;
+ return rv;
+}
- *out = rv;
- *memory = ((char *)rv) + d->extraData.cd->allocationSize;
+/*!
+ \internal
+ Like create, but also allocates memory behind the object, constructs a QQmlData there
+ and lets the objects declarativeData point to the newly created QQmlData.
+ */
+QObject *QQmlType::createWithQQmlData() const
+{
+ void *ddataMemory = nullptr;
+ auto instance = create(&ddataMemory, sizeof(QQmlData));
+ if (!instance)
+ return nullptr;
+ QObjectPrivate* p = QObjectPrivate::get(instance);
+ Q_ASSERT(!p->isDeletingChildren);
+ if (!p->declarativeData)
+ p->declarativeData = new (ddataMemory) QQmlData(QQmlData::DoesNotOwnMemory);
+ return instance;
}
-QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const
+QQmlType::SingletonInstanceInfo::ConstPtr QQmlType::singletonInstanceInfo() const
{
if (!d)
- return nullptr;
+ return {};
if (d->regType != SingletonType && d->regType != CompositeSingletonType)
- return nullptr;
- return d->extraData.sd->singletonInstanceInfo;
+ return {};
+ return d->extraData.singletonTypeData->singletonInstanceInfo;
}
QQmlCustomParser *QQmlType::customParser() const
@@ -506,42 +543,82 @@ QQmlCustomParser *QQmlType::customParser() const
return nullptr;
if (d->regType != CppType)
return nullptr;
- return d->extraData.cd->customParser;
+ return d->extraData.cppTypeData->customParser;
+}
+
+QQmlType::CreateValueTypeFunc QQmlType::createValueTypeFunction() const
+{
+ if (!d || d->regType != CppType)
+ return nullptr;
+ return d->extraData.cppTypeData->createValueTypeFunc;
+}
+
+bool QQmlType::canConstructValueType() const
+{
+ if (!d || d->regType != CppType)
+ return false;
+ return d->extraData.cppTypeData->constructValueType;
+}
+
+bool QQmlType::canPopulateValueType() const
+{
+ if (!d || d->regType != CppType)
+ return false;
+ return d->extraData.cppTypeData->populateValueType;
}
QQmlType::CreateFunc QQmlType::createFunction() const
{
if (!d || d->regType != CppType)
return nullptr;
- return d->extraData.cd->newFunc;
+ return d->extraData.cppTypeData->newFunc;
}
QString QQmlType::noCreationReason() const
{
if (!d || d->regType != CppType)
return QString();
- return d->extraData.cd->noCreationReason;
+ return d->extraData.cppTypeData->noCreationReason;
}
bool QQmlType::isCreatable() const
{
- return d && d->regType == CppType && d->extraData.cd->newFunc;
+ return d && d->regType == CppType && d->extraData.cppTypeData->newFunc;
}
QQmlType::ExtensionFunc QQmlType::extensionFunction() const
{
- if (!d || d->regType != CppType)
+ if (!d)
return nullptr;
- return d->extraData.cd->extFunc;
+
+ switch (d->regType) {
+ case CppType:
+ return d->extraData.cppTypeData->extFunc;
+ case SingletonType:
+ return d->extraData.singletonTypeData->extFunc;
+ default:
+ return nullptr;
+ }
}
-bool QQmlType::isExtendedType() const
+const QMetaObject *QQmlType::extensionMetaObject() const
{
if (!d)
- return false;
- d->init();
+ return nullptr;
- return !d->metaObjects.isEmpty();
+ switch (d->regType) {
+ case CppType:
+ return d->extraData.cppTypeData->extMetaObject;
+ case SingletonType:
+ return d->extraData.singletonTypeData->extMetaObject;
+ default:
+ return nullptr;
+ }
+}
+
+bool QQmlType::isExtendedType() const
+{
+ return d && !d->init()->data.isEmpty();
}
bool QQmlType::isSingleton() const
@@ -561,40 +638,57 @@ bool QQmlType::isComposite() const
bool QQmlType::isCompositeSingleton() const
{
- return d && d->regType == CompositeSingletonType;
+ // if the outer type is a composite singleton, d->regType will indicate that even for
+ // the inline component type
+ // however, inline components can -at least for now- never be singletons
+ // so we just do one additional check
+ return d && d->regType == CompositeSingletonType && !isInlineComponentType();
}
bool QQmlType::isQObjectSingleton() const
{
- return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->qobjectCallback;
+ return d && d->regType == SingletonType && d->extraData.singletonTypeData->singletonInstanceInfo->qobjectCallback;
}
bool QQmlType::isQJSValueSingleton() const
{
- return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->scriptCallback;
+ return d && d->regType == SingletonType && d->extraData.singletonTypeData->singletonInstanceInfo->scriptCallback;
}
-int QQmlType::typeId() const
+bool QQmlType::isSequentialContainer() const
{
- return d ? d->typeId : -1;
+ return d && d->regType == SequentialContainerType;
}
-int QQmlType::qListTypeId() const
+bool QQmlType::isValueType() const
{
- return d ? d->listId : -1;
+ return d && d->isValueType();
}
-const QMetaObject *QQmlType::metaObject() const
+QMetaType QQmlType::typeId() const
{
- if (!d)
- return nullptr;
- d->init();
+ return d ? d->typeId : QMetaType{};
+}
- if (d->metaObjects.isEmpty())
- return d->baseMetaObject;
- else
- return d->metaObjects.constFirst().metaObject;
+QMetaType QQmlType::qListTypeId() const
+{
+ return d ? d->listId : QMetaType{};
+}
+
+QMetaSequence QQmlType::listMetaSequence() const
+{
+ return isSequentialContainer() ? d->extraData.sequentialContainerTypeData : QMetaSequence();
+}
+
+const QMetaObject *QQmlType::metaObject() const
+{
+ return d ? d->metaObject() : nullptr;
+}
+const QMetaObject *QQmlType::metaObjectForValueType() const
+{
+ Q_ASSERT(d);
+ return d->metaObjectForValueType();
}
const QMetaObject *QQmlType::baseMetaObject() const
@@ -604,90 +698,61 @@ const QMetaObject *QQmlType::baseMetaObject() const
bool QQmlType::containsRevisionedAttributes() const
{
- if (!d)
- return false;
- d->init();
-
- return d->containsRevisionedAttributes;
+ return d && d->init()->containsRevisionedAttributes;
}
-int QQmlType::metaObjectRevision() const
+QTypeRevision QQmlType::metaObjectRevision() const
{
- return d ? d->revision : -1;
+ return d ? d->revision : QTypeRevision();
}
QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivate *engine) const
{
- if (!d)
- return nullptr;
- if (d->regType == CppType)
- return d->extraData.cd->attachedPropertiesFunc;
-
- QQmlType base;
- if (d->regType == CompositeType)
- base = d->resolveCompositeBaseType(engine);
- return base.attachedPropertiesFunction(engine);
+ if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(engine) : nullptr)
+ return base->extraData.cppTypeData->attachedPropertiesFunc;
+ return nullptr;
}
const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) const
{
- if (!d)
- return nullptr;
- if (d->regType == CppType)
- return d->extraData.cd->attachedPropertiesType;
-
- QQmlType base;
- if (d->regType == CompositeType)
- base = d->resolveCompositeBaseType(engine);
- return base.attachedPropertiesType(engine);
+ if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(engine) : nullptr)
+ return base->extraData.cppTypeData->attachedPropertiesType;
+ return nullptr;
}
-#if QT_DEPRECATED_SINCE(5, 14)
-/*
-This is the id passed to qmlAttachedPropertiesById(). This is different from the index
-for the case that a single class is registered under two or more names (eg. Item in
-Qt 4.7 and QtQuick 1.0).
-*/
-int QQmlType::attachedPropertiesId(QQmlEnginePrivate *engine) const
+int QQmlType::parserStatusCast() const
{
- if (!d)
+ if (!d || d->regType != CppType)
return -1;
- if (d->regType == CppType)
- return d->extraData.cd->attachedPropertiesType ? d->index : -1;
-
- QQmlType base;
- if (d->regType == CompositeType)
- base = d->resolveCompositeBaseType(engine);
- return base.attachedPropertiesId(engine);
+ return d->extraData.cppTypeData->parserStatusCast;
}
-#endif
-int QQmlType::parserStatusCast() const
+int QQmlType::propertyValueSourceCast() const
{
if (!d || d->regType != CppType)
return -1;
- return d->extraData.cd->parserStatusCast;
+ return d->extraData.cppTypeData->propertyValueSourceCast;
}
-int QQmlType::propertyValueSourceCast() const
+int QQmlType::propertyValueInterceptorCast() const
{
if (!d || d->regType != CppType)
return -1;
- return d->extraData.cd->propertyValueSourceCast;
+ return d->extraData.cppTypeData->propertyValueInterceptorCast;
}
-int QQmlType::propertyValueInterceptorCast() const
+int QQmlType::finalizerCast() const
{
if (!d || d->regType != CppType)
return -1;
- return d->extraData.cd->propertyValueInterceptorCast;
+ return d->extraData.cppTypeData->finalizerCast;
}
const char *QQmlType::interfaceIId() const
{
if (!d || d->regType != InterfaceType)
return nullptr;
- return d->iid;
+ return d->extraData.interfaceTypeData;
}
int QQmlType::index() const
@@ -695,6 +760,10 @@ int QQmlType::index() const
return d ? d->index : -1;
}
+bool QQmlType::isInlineComponentType() const {
+ return d ? d->regType == QQmlType::InlineComponentType : false;
+}
+
QUrl QQmlType::sourceUrl() const
{
return d ? d->sourceUrl() : QUrl();
@@ -702,165 +771,42 @@ QUrl QQmlType::sourceUrl() const
int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, bool *ok) const
{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->enums.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::enumValue(d, engine, name, ok);
}
int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name, bool *ok) const
{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->enums.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::enumValue(d, engine, name, ok);
}
int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->enums.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::enumValue(d, engine, name, ok);
}
int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->scopedEnumIndex.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::scopedEnumIndex(d, engine, name, ok);
}
int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const
{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->scopedEnumIndex.value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::scopedEnumIndex(d, engine, name, ok);
}
int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const
{
- Q_UNUSED(engine)
- Q_ASSERT(ok);
- *ok = true;
-
- if (d) {
- Q_ASSERT(index > -1 && index < d->scopedEnums.count());
- int *rv = d->scopedEnums.at(index)->value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::scopedEnumValue(d, engine, index, name, ok);
}
int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const
{
- Q_UNUSED(engine)
- Q_ASSERT(ok);
- *ok = true;
-
- if (d) {
- Q_ASSERT(index > -1 && index < d->scopedEnums.count());
- int *rv = d->scopedEnums.at(index)->value(name);
- if (rv)
- return *rv;
- }
-
- *ok = false;
- return -1;
-}
-
-int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedEnumName, const QByteArray &name, bool *ok) const
-{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->scopedEnumIndex.value(QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.length()));
- if (rv) {
- int index = *rv;
- Q_ASSERT(index > -1 && index < d->scopedEnums.count());
- rv = d->scopedEnums.at(index)->value(QHashedCStringRef(name.constData(), name.length()));
- if (rv)
- return *rv;
- }
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::scopedEnumValue(d, engine, index, name, ok);
}
-int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedEnumName, const QStringRef &name, bool *ok) const
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QHashedStringRef &scopedEnumName, const QHashedStringRef &name, bool *ok) const
{
- Q_ASSERT(ok);
- if (d) {
- *ok = true;
-
- d->initEnums(engine);
-
- int *rv = d->scopedEnumIndex.value(QHashedStringRef(scopedEnumName));
- if (rv) {
- int index = *rv;
- Q_ASSERT(index > -1 && index < d->scopedEnums.count());
- rv = d->scopedEnums.at(index)->value(QHashedStringRef(name));
- if (rv)
- return *rv;
- }
- }
-
- *ok = false;
- return -1;
+ return QQmlTypePrivate::scopedEnumValue(d, engine, scopedEnumName, name, ok);
}
void QQmlType::refHandle(const QQmlTypePrivate *priv)
@@ -882,4 +828,11 @@ int QQmlType::refCount(const QQmlTypePrivate *priv)
return -1;
}
+void QQmlType::createProxy(QObject *instance) const
+{
+ const QQmlTypePrivate::ProxyMetaObjects *proxies = d->init();
+ if (!proxies->data.isEmpty())
+ (void)new QQmlProxyMetaObject(instance, &proxies->data);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h
index ec27b38a73..622e91a4b2 100644
--- a/src/qml/qml/qqmltype_p.h
+++ b/src/qml/qml/qqmltype_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPE_P_H
#define QQMLTYPE_P_H
@@ -60,6 +24,7 @@
#include <QtQml/qjsvalue.h>
#include <QtCore/qobject.h>
+#include <QtCore/qversionnumber.h>
QT_BEGIN_NAMESPACE
@@ -75,7 +40,7 @@ namespace QV4 {
struct String;
}
-class Q_QML_PRIVATE_EXPORT QQmlType
+class Q_QML_EXPORT QQmlType
{
public:
QQmlType();
@@ -86,10 +51,6 @@ public:
explicit QQmlType(const QQmlTypePrivate *priv);
~QQmlType();
- bool operator ==(const QQmlType &other) const {
- return d.data() == other.d.data();
- }
-
bool isValid() const { return !d.isNull(); }
QByteArray typeName() const;
@@ -97,22 +58,30 @@ public:
QString elementName() const;
QHashedString module() const;
- int majorVersion() const;
- int minorVersion() const;
+ QTypeRevision version() const;
+
+ bool availableInVersion(QTypeRevision version) const;
+ bool availableInVersion(const QHashedStringRef &module, QTypeRevision version) const;
- bool availableInVersion(int vmajor, int vminor) const;
- bool availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const;
+ typedef QVariant (*CreateValueTypeFunc)(const QJSValue &);
+ CreateValueTypeFunc createValueTypeFunction() const;
+
+ bool canConstructValueType() const;
+ bool canPopulateValueType() const;
QObject *create() const;
- void create(QObject **, void **, size_t) const;
+ QObject *create(void **, size_t) const;
+ QObject *createWithQQmlData() const;
- typedef void (*CreateFunc)(void *);
+ typedef void (*CreateFunc)(void *, void *);
CreateFunc createFunction() const;
+
QQmlCustomParser *customParser() const;
bool isCreatable() const;
typedef QObject *(*ExtensionFunc)(QObject *);
ExtensionFunc extensionFunction() const;
+ const QMetaObject *extensionMetaObject() const;
bool isExtendedType() const;
QString noCreationReason() const;
@@ -122,37 +91,53 @@ public:
bool isCompositeSingleton() const;
bool isQObjectSingleton() const;
bool isQJSValueSingleton() const;
+ bool isSequentialContainer() const;
+ bool isValueType() const;
- int typeId() const;
- int qListTypeId() const;
+ QMetaType typeId() const;
+ QMetaType qListTypeId() const;
+ QMetaSequence listMetaSequence() const;
const QMetaObject *metaObject() const;
+
+ // Precondition: The type is actually a value type!
+ const QMetaObject *metaObjectForValueType() const;
+
const QMetaObject *baseMetaObject() const;
- int metaObjectRevision() const;
+ QTypeRevision metaObjectRevision() const;
bool containsRevisionedAttributes() const;
QQmlAttachedPropertiesFunc attachedPropertiesFunction(QQmlEnginePrivate *engine) const;
const QMetaObject *attachedPropertiesType(QQmlEnginePrivate *engine) const;
-#if QT_DEPRECATED_SINCE(5, 14)
- QT_DEPRECATED int attachedPropertiesId(QQmlEnginePrivate *engine) const;
-#endif
int parserStatusCast() const;
const char *interfaceIId() const;
int propertyValueSourceCast() const;
int propertyValueInterceptorCast() const;
+ int finalizerCast() const;
int index() const;
- struct Q_QML_PRIVATE_EXPORT SingletonInstanceInfo
+ bool isInlineComponentType() const;
+
+ struct Q_QML_EXPORT SingletonInstanceInfo final
+ : public QQmlRefCounted<SingletonInstanceInfo>
{
- QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *) = nullptr;
+ using Ptr = QQmlRefPointer<SingletonInstanceInfo>;
+ using ConstPtr = QQmlRefPointer<const SingletonInstanceInfo>;
+
+ static Ptr create() { return Ptr(new SingletonInstanceInfo, Ptr::Adopt); }
+
+ std::function<QJSValue(QQmlEngine *, QJSEngine *)> scriptCallback = {};
std::function<QObject *(QQmlEngine *, QJSEngine *)> qobjectCallback = {};
- const QMetaObject *instanceMetaObject = nullptr;
- QString typeName;
+ QByteArray typeName;
QUrl url; // used by composite singletons
+
+ private:
+ Q_DISABLE_COPY_MOVE(SingletonInstanceInfo)
+ SingletonInstanceInfo() = default;
};
- SingletonInstanceInfo *singletonInstanceInfo() const;
+ SingletonInstanceInfo::ConstPtr singletonInstanceInfo() const;
QUrl sourceUrl() const;
@@ -164,8 +149,7 @@ public:
int scopedEnumIndex(QQmlEnginePrivate *engine, const QString &, bool *ok) const;
int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *, bool *ok) const;
int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &, bool *ok) const;
- int scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &, const QByteArray &, bool *ok) const;
- int scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &, const QStringRef &, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, const QHashedStringRef &, const QHashedStringRef &, bool *ok) const;
const QQmlTypePrivate *priv() const { return d.data(); }
static void refHandle(const QQmlTypePrivate *priv);
@@ -178,15 +162,29 @@ public:
InterfaceType = 2,
CompositeType = 3,
CompositeSingletonType = 4,
+ InlineComponentType = 5,
+ SequentialContainerType = 6,
AnyRegistrationType = 255
};
+ void createProxy(QObject *instance) const;
+
private:
- friend uint qHash(const QQmlType &t, uint seed);
+ friend class QQmlTypePrivate;
+ friend size_t qHash(const QQmlType &t, size_t seed);
+ friend bool operator==(const QQmlType &a, const QQmlType &b) noexcept
+ {
+ return a.d.data() == b.d.data();
+ }
+ friend bool operator!=(const QQmlType &a, const QQmlType &b) noexcept
+ {
+ return !(a == b);
+ }
+
QQmlRefPointer<const QQmlTypePrivate> d;
};
-inline uint qHash(const QQmlType &t, uint seed = 0)
+inline size_t qHash(const QQmlType &t, size_t seed = 0)
{
return qHash(reinterpret_cast<quintptr>(t.d.data()), seed);
}
diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h
index 6a2d961de8..2bf83ddb8b 100644
--- a/src/qml/qml/qqmltype_p_p.h
+++ b/src/qml/qml/qqmltype_p_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPE_P_P_H
#define QQMLTYPE_P_P_H
@@ -56,47 +20,90 @@
#include <private/qqmlproxymetaobject_p.h>
#include <private/qqmlrefcount_p.h>
#include <private/qqmlpropertycache_p.h>
+#include <private/qqmlmetatype_p.h>
+#include <private/qqmltypeloader_p.h>
+#include <private/qv4executablecompilationunit_p.h>
+#include <private/qv4engine_p.h>
+
+#include <QAtomicInteger>
QT_BEGIN_NAMESPACE
-class QQmlTypePrivate : public QQmlRefCount
+class QQmlTypePrivate final : public QQmlRefCounted<QQmlTypePrivate>
{
Q_DISABLE_COPY_MOVE(QQmlTypePrivate)
public:
+ struct ProxyMetaObjects
+ {
+ ~ProxyMetaObjects()
+ {
+ for (const QQmlProxyMetaObject::ProxyData &metaObject : data)
+ free(metaObject.metaObject);
+ }
+
+ QList<QQmlProxyMetaObject::ProxyData> data;
+ bool containsRevisionedAttributes = false;
+ };
+
+ struct Enums
+ {
+ ~Enums() { qDeleteAll(scopedEnums); }
+
+ QStringHash<int> enums;
+ QStringHash<int> scopedEnumIndex; // maps from enum name to index in scopedEnums
+ QList<QStringHash<int> *> scopedEnums;
+ };
+
QQmlTypePrivate(QQmlType::RegistrationType type);
- void init() const;
- void initEnums(QQmlEnginePrivate *engine) const;
- void insertEnums(const QMetaObject *metaObject) const;
- void insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const;
+ const ProxyMetaObjects *init() const;
QUrl sourceUrl() const
{
switch (regType) {
case QQmlType::CompositeType:
- return extraData.fd->url;
+ return extraData.compositeTypeData;
case QQmlType::CompositeSingletonType:
- return extraData.sd->singletonInstanceInfo->url;
+ return extraData.singletonTypeData->singletonInstanceInfo->url;
+ case QQmlType::InlineComponentType:
+ return extraData.inlineComponentTypeData;
default:
return QUrl();
}
}
+ const QQmlTypePrivate *attachedPropertiesBase(QQmlEnginePrivate *engine) const
+ {
+ for (const QQmlTypePrivate *d = this; d; d = d->resolveCompositeBaseType(engine).d.data()) {
+ if (d->regType == QQmlType::CppType)
+ return d->extraData.cppTypeData->attachedPropertiesType ? d : nullptr;
+
+ if (d->regType != QQmlType::CompositeType)
+ return nullptr;
+ }
+ return nullptr;
+ }
+
bool isComposite() const
{
return regType == QQmlType::CompositeType || regType == QQmlType::CompositeSingletonType;
}
- QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const;
- QQmlPropertyCache *compositePropertyCache(QQmlEnginePrivate *engine) const;
+ bool isValueType() const
+ {
+ return regType == QQmlType::CppType && !(typeId.flags() & QMetaType::PointerToQObject);
+ }
- QQmlType::RegistrationType regType;
+ QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const;
+ QQmlPropertyCache::ConstPtr compositePropertyCache(QQmlEnginePrivate *engine) const;
struct QQmlCppTypeData
{
int allocationSize;
- void (*newFunc)(void *);
+ void (*newFunc)(void *, void *);
+ void *userdata = nullptr;
QString noCreationReason;
+ QVariant (*createValueTypeFunc)(const QJSValue &);
int parserStatusCast;
QObject *(*extFunc)(QObject *);
const QMetaObject *extMetaObject;
@@ -105,52 +112,155 @@ public:
const QMetaObject *attachedPropertiesType;
int propertyValueSourceCast;
int propertyValueInterceptorCast;
+ int finalizerCast;
bool registerEnumClassesUnscoped;
+ bool registerEnumsFromRelatedTypes;
+ bool constructValueType;
+ bool populateValueType;
};
struct QQmlSingletonTypeData
{
- QQmlType::SingletonInstanceInfo *singletonInstanceInfo;
+ QQmlType::SingletonInstanceInfo::ConstPtr singletonInstanceInfo;
+ QObject *(*extFunc)(QObject *);
+ const QMetaObject *extMetaObject;
};
- struct QQmlCompositeTypeData
- {
- QUrl url;
- };
+ int index = -1;
union extraData {
- QQmlCppTypeData* cd;
- QQmlSingletonTypeData* sd;
- QQmlCompositeTypeData* fd;
+ extraData() {} // QQmlTypePrivate() does the actual construction.
+ ~extraData() {} // ~QQmlTypePrivate() does the actual destruction.
+
+ QQmlCppTypeData *cppTypeData;
+ QQmlSingletonTypeData *singletonTypeData;
+ QUrl compositeTypeData;
+ QUrl inlineComponentTypeData;
+ QMetaSequence sequentialContainerTypeData;
+ const char *interfaceTypeData;
} extraData;
+ static_assert(sizeof(extraData) == sizeof(void *));
- const char *iid;
QHashedString module;
QString name;
QString elementName;
- int version_maj;
- int version_min;
- int typeId;
- int listId;
- int revision;
- mutable bool containsRevisionedAttributes;
- mutable QQmlType superType;
- const QMetaObject *baseMetaObject;
-
- int index;
- mutable volatile bool isSetup:1;
- mutable volatile bool isEnumFromCacheSetup:1;
- mutable volatile bool isEnumFromBaseSetup:1;
- mutable bool haveSuperType:1;
- mutable QList<QQmlProxyMetaObject::ProxyData> metaObjects;
- mutable QStringHash<int> enums;
- mutable QStringHash<int> scopedEnumIndex; // maps from enum name to index in scopedEnums
- mutable QList<QStringHash<int>*> scopedEnums;
+ QMetaType typeId;
+ QMetaType listId;
+ QQmlType::RegistrationType regType;
+ QTypeRevision version;
+ QTypeRevision revision = QTypeRevision::zero();
+ const QMetaObject *baseMetaObject = nullptr;
void setName(const QString &uri, const QString &element);
+ template<typename String>
+ static int enumValue(
+ const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine,
+ const String &name, bool *ok)
+ {
+ return doGetEnumValue(d, engine, [&](const QQmlTypePrivate::Enums *enums) {
+ return enums->enums.value(name);
+ }, ok);
+ }
+
+ template<typename String>
+ static int scopedEnumIndex(
+ const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine,
+ const String &name, bool *ok)
+ {
+ return doGetEnumValue(d, engine, [&](const QQmlTypePrivate::Enums *enums) {
+ return enums->scopedEnumIndex.value(name);
+ }, ok);
+ }
+
+ template<typename String>
+ static int scopedEnumValue(
+ const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine, int index,
+ const String &name, bool *ok)
+ {
+ return doGetEnumValue(d, engine, [&](const QQmlTypePrivate::Enums *enums) {
+ Q_ASSERT(index > -1 && index < enums->scopedEnums.size());
+ return enums->scopedEnums.at(index)->value(name);
+ }, ok);
+ }
+
+ template<typename String1, typename String2>
+ static int scopedEnumValue(
+ const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine,
+ const String1 &scopedEnumName, const String2 &name, bool *ok)
+ {
+ return doGetEnumValue(d, engine, [&](const QQmlTypePrivate::Enums *enums) -> const int * {
+ const int *rv = enums->scopedEnumIndex.value(scopedEnumName);
+ if (!rv)
+ return nullptr;
+
+ const int index = *rv;
+ Q_ASSERT(index > -1 && index < enums->scopedEnums.size());
+ return enums->scopedEnums.at(index)->value(name);
+ }, ok);
+ }
+
+ const QMetaObject *metaObject() const
+ {
+ if (isValueType())
+ return metaObjectForValueType();
+
+ const QQmlTypePrivate::ProxyMetaObjects *proxies = init();
+ return proxies->data.isEmpty()
+ ? baseMetaObject
+ : proxies->data.constFirst().metaObject;
+ }
+
+ const QMetaObject *metaObjectForValueType() const
+ {
+ Q_ASSERT(isValueType());
+
+ // Prefer the extension meta object, if any.
+ // Extensions allow registration of non-gadget value types.
+ if (const QMetaObject *extensionMetaObject = extraData.cppTypeData->extMetaObject) {
+ // This may be a namespace even if the original metaType isn't.
+ // You can do such things with QML_FOREIGN declarations.
+ if (extensionMetaObject->metaType().flags() & QMetaType::IsGadget)
+ return extensionMetaObject;
+ }
+
+ if (baseMetaObject) {
+ // This may be a namespace even if the original metaType isn't.
+ // You can do such things with QML_FOREIGN declarations.
+ if (baseMetaObject->metaType().flags() & QMetaType::IsGadget)
+ return baseMetaObject;
+ }
+
+ return nullptr;
+ }
+
+ static QQmlType compositeQmlType(
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit,
+ QQmlTypeLoader *typeLoader, const QString &type)
+ {
+ Q_ASSERT(typeLoader);
+
+ const QQmlType qmltype
+ = unit->typeNameCache->query<QQmlImport::AllowRecursion>(type, typeLoader).type;
+ if (!qmltype.isValid())
+ return qmltype;
+
+ if (qmltype.isInlineComponentType()
+ && !QQmlMetaType::obtainCompilationUnit(qmltype.typeId())) {
+ // If it seems to be an IC type, make sure there is an actual
+ // compilation unit for it. We create inline component types speculatively.
+ return QQmlType();
+ }
+
+ return qmltype;
+ }
+
private:
- ~QQmlTypePrivate() override;
+ mutable QAtomicPointer<const ProxyMetaObjects> proxyMetaObjects;
+ mutable QAtomicPointer<const Enums> enums;
+
+ ~QQmlTypePrivate();
+ friend class QQmlRefCounted<QQmlTypePrivate>;
struct EnumInfo {
QStringList path;
@@ -161,6 +271,29 @@ private:
bool scoped;
};
+ template<typename Op>
+ static int doGetEnumValue(
+ const QQmlRefPointer<const QQmlTypePrivate> &d, QQmlEnginePrivate *engine,
+ Op &&op, bool *ok)
+ {
+ Q_ASSERT(ok);
+ if (d) {
+ if (const QQmlTypePrivate::Enums *enums = d->initEnums(engine)) {
+ if (const int *rv = op(enums)) {
+ *ok = true;
+ return *rv;
+ }
+ }
+ }
+
+ *ok = false;
+ return -1;
+ }
+
+ const Enums *initEnums(QQmlEnginePrivate *engine) const;
+ void insertEnums(Enums *enums, const QMetaObject *metaObject) const;
+ void insertEnumsFromPropertyCache(Enums *enums, const QQmlPropertyCache::ConstPtr &cache) const;
+
void createListOfPossibleConflictingItems(const QMetaObject *metaObject, QList<EnumInfo> &enumInfoList, QStringList path) const;
void createEnumConflictReport(const QMetaObject *metaObject, const QString &conflictingKey) const;
};
diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp
index 9ff0e3fb9e..cdabd6d5bc 100644
--- a/src/qml/qml/qqmltypecompiler.cpp
+++ b/src/qml/qml/qqmltypecompiler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmltypecompiler_p.h"
@@ -44,6 +8,8 @@
#include <private/qqmlvmemetaobject_p.h>
#include <private/qqmlcomponent_p.h>
#include <private/qqmlpropertyresolver_p.h>
+#include <private/qqmlcomponentandaliasresolver_p.h>
+#include <private/qqmlsignalnames_p.h>
#define COMPILE_EXCEPTION(token, desc) \
{ \
@@ -53,25 +19,30 @@
QT_BEGIN_NAMESPACE
-QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData,
- QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
+DEFINE_BOOL_CONFIG_OPTION(
+ disableInternalDeferredProperties, QML_DISABLE_INTERNAL_DEFERRED_PROPERTIES);
+
+Q_LOGGING_CATEGORY(lcQmlTypeCompiler, "qt.qml.typecompiler");
+
+QQmlTypeCompiler::QQmlTypeCompiler(
+ QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *parsedQML,
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
+ const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
: resolvedTypes(resolvedTypeCache)
, engine(engine)
- , typeData(typeData)
, dependencyHasher(dependencyHasher)
- , typeNameCache(typeNameCache)
, document(parsedQML)
+ , typeData(typeData)
{
}
-QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeCompiler::compile()
{
// Build property caches and VME meta object data
for (auto it = resolvedTypes->constBegin(), end = resolvedTypes->constEnd();
it != end; ++it) {
- QQmlCustomParser *customParser = (*it)->type.customParser();
+ QQmlCustomParser *customParser = (*it)->type().customParser();
if (customParser)
customParsers.insert(it.key(), customParser);
}
@@ -81,12 +52,31 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
{
QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, &pendingGroupPropertyBindings,
- engine, this, imports());
- QQmlJS::DiagnosticMessage error = propertyCacheBuilder.buildMetaObjects();
- if (error.isValid()) {
- recordError(error);
+ engine, this, imports(), typeData->typeClassName());
+ QQmlError cycleError = propertyCacheBuilder.verifyNoICCycle();
+ if (cycleError.isValid()) {
+ recordError(cycleError);
return nullptr;
}
+ QQmlPropertyCacheCreatorBase::IncrementalResult result;
+ do {
+ result = propertyCacheBuilder.buildMetaObjectsIncrementally();
+ const QQmlError &error = result.error;
+ if (error.isValid()) {
+ recordError(error);
+ return nullptr;
+ } else {
+ // Resolve component boundaries and aliases
+
+ QQmlComponentAndAliasResolver resolver(this, enginePrivate(), &m_propertyCaches);
+ if (QQmlError error = resolver.resolve(result.processedRoot); error.isValid()) {
+ recordError(error);
+ return nullptr;
+ }
+ pendingGroupPropertyBindings.resolveMissingPropertyCaches(&m_propertyCaches);
+ pendingGroupPropertyBindings.clear(); // anything that can be processed is now processed
+ }
+ } while (result.canResume);
}
{
@@ -95,8 +85,8 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
}
{
- SignalHandlerConverter converter(this);
- if (!converter.convertSignalHandlerExpressionsToFunctionDeclarations())
+ SignalHandlerResolver converter(this);
+ if (!converter.resolveSignalHandlerExpressions())
return nullptr;
}
@@ -116,24 +106,13 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
annotator.annotateBindingsToAliases();
}
- // Resolve component boundaries and aliases
-
- {
- // Scan for components, determine their scopes and resolve aliases within the scope.
- QQmlComponentAndAliasResolver resolver(this);
- if (!resolver.resolve())
- return nullptr;
-
- pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_propertyCaches);
- }
-
{
QQmlDeferredAndCustomParserBindingScanner deferredAndCustomParserBindingScanner(this);
if (!deferredAndCustomParserBindingScanner.scanObject())
return nullptr;
}
- if (!document->javaScriptCompilationUnit.unitData()) {
+ if (!document->javaScriptCompilationUnit || !document->javaScriptCompilationUnit->unitData()) {
// Compile JS binding expressions and signal handlers if necessary
{
// We can compile script strings ahead of time, but they must be compiled
@@ -145,11 +124,13 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
document->jsModule.fileName = typeData->urlString();
document->jsModule.finalUrl = typeData->finalUrlString();
QmlIR::JSCodeGen v4CodeGenerator(document, engine->v4engine()->illegalNames());
- if (!v4CodeGenerator.generateCodeForComponents(componentRoots())) {
- recordError(v4CodeGenerator.error());
- return nullptr;
+ for (QmlIR::Object *object : std::as_const(document->objects)) {
+ if (!v4CodeGenerator.generateRuntimeFunctions(object)) {
+ Q_ASSERT(v4CodeGenerator.hasError());
+ recordError(v4CodeGenerator.error());
+ return nullptr;
+ }
}
-
document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(/*generated unit data*/false);
}
@@ -161,21 +142,14 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
if (!errors.isEmpty())
return nullptr;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
- = QV4::ExecutableCompilationUnit::create(std::move(
- document->javaScriptCompilationUnit));
- compilationUnit->typeNameCache = typeNameCache;
- compilationUnit->resolvedTypes = *resolvedTypes;
- compilationUnit->propertyCaches = std::move(m_propertyCaches);
- Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->objectCount()));
- return compilationUnit;
+ return std::move(document->javaScriptCompilationUnit);
}
void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description)
{
QQmlError error;
- error.setLine(location.line);
- error.setColumn(location.column);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
error.setUrl(url());
errors << error;
@@ -185,8 +159,15 @@ void QQmlTypeCompiler::recordError(const QQmlJS::DiagnosticMessage &message)
{
QQmlError error;
error.setDescription(message.message);
- error.setLine(message.line);
- error.setColumn(message.column);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(message.loc.startLine));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(message.loc.startColumn));
+ error.setUrl(url());
+ errors << error;
+}
+
+void QQmlTypeCompiler::recordError(const QQmlError &e)
+{
+ QQmlError error = e;
error.setUrl(url());
errors << error;
}
@@ -208,12 +189,12 @@ int QQmlTypeCompiler::registerConstant(QV4::ReturnedValue v)
const QV4::CompiledData::Unit *QQmlTypeCompiler::qmlUnit() const
{
- return document->javaScriptCompilationUnit.unitData();
+ return document->javaScriptCompilationUnit->unitData();
}
const QQmlImports *QQmlTypeCompiler::imports() const
{
- return &typeData->imports();
+ return typeData->imports();
}
QVector<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects() const
@@ -221,10 +202,9 @@ QVector<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects() const
return &document->objects;
}
-void QQmlTypeCompiler::setPropertyCaches(QQmlPropertyCacheVector &&caches)
+QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches()
{
- m_propertyCaches = std::move(caches);
- Q_ASSERT(m_propertyCaches.count() > 0);
+ return &m_propertyCaches;
}
const QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches() const
@@ -232,17 +212,12 @@ const QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches() const
return &m_propertyCaches;
}
-QQmlPropertyCacheVector &&QQmlTypeCompiler::takePropertyCaches()
-{
- return std::move(m_propertyCaches);
-}
-
QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
{
return document->jsParserEngine.pool();
}
-QStringRef QQmlTypeCompiler::newStringRef(const QString &string)
+QStringView QQmlTypeCompiler::newStringRef(const QString &string)
{
return document->jsParserEngine.newStringRef(string);
}
@@ -257,12 +232,12 @@ QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scrip
return object->bindingAsString(document, scriptIndex);
}
-void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion)
+void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, QTypeRevision version)
{
const quint32 moduleIdx = registerString(module);
const quint32 qualifierIdx = registerString(qualifier);
- for (int i = 0, count = document->imports.count(); i < count; ++i) {
+ for (int i = 0, count = document->imports.size(); i < count; ++i) {
const QV4::CompiledData::Import *existingImport = document->imports.at(i);
if (existingImport->type == QV4::CompiledData::Import::ImportLibrary
&& existingImport->uriIndex == moduleIdx
@@ -272,21 +247,23 @@ void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier
auto pool = memoryPool();
QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>();
import->type = QV4::CompiledData::Import::ImportLibrary;
- import->majorVersion = majorVersion;
- import->minorVersion = minorVersion;
+ import->version = version;
import->uriIndex = moduleIdx;
import->qualifierIndex = qualifierIdx;
document->imports.append(import);
}
+QQmlType QQmlTypeCompiler::qmlTypeForComponent(const QString &inlineComponentName) const
+{
+ return typeData->qmlType(inlineComponentName);
+}
+
QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
: compiler(typeCompiler)
{
}
-
-
-SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler)
+SignalHandlerResolver::SignalHandlerResolver(QQmlTypeCompiler *typeCompiler)
: QQmlCompilePass(typeCompiler)
, enginePrivate(typeCompiler->enginePrivate())
, qmlObjects(*typeCompiler->qmlObjects())
@@ -297,11 +274,11 @@ SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler)
{
}
-bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations()
+bool SignalHandlerResolver::resolveSignalHandlerExpressions()
{
- for (int objectIndex = 0; objectIndex < qmlObjects.count(); ++objectIndex) {
+ for (int objectIndex = 0; objectIndex < qmlObjects.size(); ++objectIndex) {
const QmlIR::Object * const obj = qmlObjects.at(objectIndex);
- QQmlPropertyCache *cache = propertyCaches->at(objectIndex);
+ QQmlPropertyCache::ConstPtr cache = propertyCaches->at(objectIndex);
if (!cache)
continue;
if (QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex)) {
@@ -309,65 +286,74 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
continue;
}
const QString elementName = stringAt(obj->inheritedTypeNameIndex);
- if (!convertSignalHandlerExpressionsToFunctionDeclarations(obj, elementName, cache))
+ if (!resolveSignalHandlerExpressions(obj, elementName, cache))
return false;
}
return true;
}
-bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache)
+bool SignalHandlerResolver::resolveSignalHandlerExpressions(
+ const QmlIR::Object *obj, const QString &typeName,
+ const QQmlPropertyCache::ConstPtr &propertyCache)
{
// map from signal name defined in qml itself to list of parameters
QHash<QString, QStringList> customSignals;
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- QString propertyName = stringAt(binding->propertyNameIndex);
+ const QString bindingPropertyName = stringAt(binding->propertyNameIndex);
// Attached property?
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
auto *typeRef = resolvedType(binding->propertyNameIndex);
- QQmlType type = typeRef ? typeRef->type : QQmlType();
- if (!type.isValid())
- imports->resolveType(propertyName, &type, nullptr, nullptr, nullptr);
+ QQmlType type = typeRef ? typeRef->type() : QQmlType();
+ if (!type.isValid()) {
+ imports->resolveType(
+ QQmlTypeLoader::get(enginePrivate), bindingPropertyName, &type, nullptr,
+ nullptr);
+ }
const QMetaObject *attachedType = type.attachedPropertiesType(enginePrivate);
if (!attachedType)
COMPILE_EXCEPTION(binding, tr("Non-existent attached object"));
- QQmlPropertyCache *cache = compiler->enginePrivate()->cache(attachedType);
- if (!convertSignalHandlerExpressionsToFunctionDeclarations(attachedObj, propertyName, cache))
+ QQmlPropertyCache::ConstPtr cache = QQmlMetaType::propertyCache(attachedType);
+ if (!resolveSignalHandlerExpressions(attachedObj, bindingPropertyName, cache))
return false;
continue;
}
- if (!QmlIR::IRBuilder::isSignalPropertyName(propertyName))
+ QString qPropertyName;
+ QString signalName;
+ if (auto propertyName =
+ QQmlSignalNames::changedHandlerNameToPropertyName(bindingPropertyName)) {
+ qPropertyName = *propertyName;
+ signalName = *QQmlSignalNames::changedHandlerNameToSignalName(bindingPropertyName);
+ } else {
+ signalName = QQmlSignalNames::handlerNameToSignalName(bindingPropertyName)
+ .value_or(QString());
+ }
+ if (signalName.isEmpty())
continue;
QQmlPropertyResolver resolver(propertyCache);
- Q_ASSERT(propertyName.startsWith(QLatin1String("on")));
- propertyName.remove(0, 2);
-
- // Note that the property name could start with any alpha or '_' or '$' character,
- // so we need to do the lower-casing of the first alpha character.
- for (int firstAlphaIndex = 0; firstAlphaIndex < propertyName.size(); ++firstAlphaIndex) {
- if (propertyName.at(firstAlphaIndex).isUpper()) {
- propertyName[firstAlphaIndex] = propertyName.at(firstAlphaIndex).toLower();
- break;
- }
- }
-
- QList<QString> parameters;
-
bool notInRevision = false;
- QQmlPropertyData *signal = resolver.signal(propertyName, &notInRevision);
- if (signal) {
+ const QQmlPropertyData * const signal = resolver.signal(signalName, &notInRevision);
+ const QQmlPropertyData * const signalPropertyData = resolver.property(signalName, /*notInRevision ptr*/nullptr);
+ const QQmlPropertyData * const qPropertyData = !qPropertyName.isEmpty() ? resolver.property(qPropertyName) : nullptr;
+ QString finalSignalHandlerPropertyName = signalName;
+ QV4::CompiledData::Binding::Flag flag
+ = QV4::CompiledData::Binding::IsSignalHandlerExpression;
+
+ const bool isPropertyObserver = !signalPropertyData && qPropertyData && qPropertyData->isBindable();
+ if (signal && !(qPropertyData && qPropertyData->isAlias() && isPropertyObserver)) {
int sigIndex = propertyCache->methodIndexToSignalIndex(signal->coreIndex());
sigIndex = propertyCache->originalClone(sigIndex);
bool unnamedParameter = false;
QList<QByteArray> parameterNames = propertyCache->signalParameterNames(sigIndex);
- for (int i = 0; i < parameterNames.count(); ++i) {
+ for (int i = 0; i < parameterNames.size(); ++i) {
const QString param = QString::fromUtf8(parameterNames.at(i));
if (param.isEmpty())
unnamedParameter = true;
@@ -376,20 +362,25 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
} else if (illegalNames.contains(param)) {
COMPILE_EXCEPTION(binding, tr("Signal parameter \"%1\" hides global variable.").arg(param));
}
- parameters += param;
}
+ } else if (isPropertyObserver) {
+ finalSignalHandlerPropertyName = qPropertyName;
+ flag = QV4::CompiledData::Binding::IsPropertyObserver;
} else {
if (notInRevision) {
// Try assinging it as a property later
- if (resolver.property(propertyName, /*notInRevision ptr*/nullptr))
+ if (signalPropertyData)
continue;
const QString &originalPropertyName = stringAt(binding->propertyNameIndex);
auto *typeRef = resolvedType(obj->inheritedTypeNameIndex);
- const QQmlType type = typeRef ? typeRef->type : QQmlType();
+ const QQmlType type = typeRef ? typeRef->type() : QQmlType();
if (type.isValid()) {
- COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(originalPropertyName).arg(type.module()).arg(type.majorVersion()).arg(type.minorVersion()));
+ COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.")
+ .arg(typeName).arg(originalPropertyName).arg(type.module())
+ .arg(type.version().majorVersion())
+ .arg(type.version().minorVersion()));
} else {
COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(originalPropertyName));
}
@@ -410,74 +401,33 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
}
}
- QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(propertyName);
- if (entry == customSignals.constEnd() && propertyName.endsWith(QLatin1String("Changed"))) {
- QString alternateName = propertyName.mid(0, propertyName.length() - static_cast<int>(strlen("Changed")));
- entry = customSignals.constFind(alternateName);
- }
+ QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(signalName);
+ if (entry == customSignals.constEnd() && !qPropertyName.isEmpty())
+ entry = customSignals.constFind(qPropertyName);
if (entry == customSignals.constEnd()) {
// Can't find even a custom signal, then just don't do anything and try
// keeping the binding as a regular property assignment.
continue;
}
-
- parameters = entry.value();
}
// Binding object to signal means connect the signal to the object's default method.
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerObject;
+ if (bindingType == QV4::CompiledData::Binding::Type_Object) {
+ binding->setFlag(QV4::CompiledData::Binding::IsSignalHandlerObject);
continue;
}
- if (binding->type != QV4::CompiledData::Binding::Type_Script) {
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Script) {
+ if (bindingType < QV4::CompiledData::Binding::Type_Script) {
COMPILE_EXCEPTION(binding, tr("Cannot assign a value to a signal (expecting a script to be run)"));
} else {
COMPILE_EXCEPTION(binding, tr("Incorrectly specified signal assignment"));
}
}
- QQmlJS::MemoryPool *pool = compiler->memoryPool();
-
- QQmlJS::AST::FormalParameterList *paramList = nullptr;
- for (const QString &param : qAsConst(parameters)) {
- QStringRef paramNameRef = compiler->newStringRef(param);
-
- QQmlJS::AST::PatternElement *b = new (pool) QQmlJS::AST::PatternElement(paramNameRef, nullptr);
- paramList = new (pool) QQmlJS::AST::FormalParameterList(paramList, b);
- }
-
- if (paramList)
- paramList = paramList->finish(pool);
-
- QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex);
- QQmlJS::AST::FunctionDeclaration *functionDeclaration = nullptr;
- if (QQmlJS::AST::ExpressionStatement *es = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(foe->node)) {
- if (QQmlJS::AST::FunctionExpression *fe = QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression*>(es->expression)) {
- functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(fe->name, fe->formals, fe->body);
- functionDeclaration->functionToken = fe->functionToken;
- functionDeclaration->identifierToken = fe->identifierToken;
- functionDeclaration->lparenToken = fe->lparenToken;
- functionDeclaration->rparenToken = fe->rparenToken;
- functionDeclaration->lbraceToken = fe->lbraceToken;
- functionDeclaration->rbraceToken = fe->rbraceToken;
- }
- }
- if (!functionDeclaration) {
- QQmlJS::AST::Statement *statement = static_cast<QQmlJS::AST::Statement*>(foe->node);
- QQmlJS::AST::StatementList *body = new (pool) QQmlJS::AST::StatementList(statement);
- body = body->finish();
-
- functionDeclaration = new (pool) QQmlJS::AST::FunctionDeclaration(compiler->newStringRef(stringAt(binding->propertyNameIndex)), paramList, body);
- functionDeclaration->lbraceToken = functionDeclaration->functionToken
- = foe->node->firstSourceLocation();
- functionDeclaration->rbraceToken = foe->node->lastSourceLocation();
- }
- foe->node = functionDeclaration;
- binding->propertyNameIndex = compiler->registerString(propertyName);
- binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerExpression;
+ binding->propertyNameIndex = compiler->registerString(finalSignalHandlerPropertyName);
+ binding->setFlag(flag);
}
return true;
}
@@ -492,8 +442,8 @@ QQmlEnumTypeResolver::QQmlEnumTypeResolver(QQmlTypeCompiler *typeCompiler)
bool QQmlEnumTypeResolver::resolveEnumBindings()
{
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
+ for (int i = 0; i < qmlObjects.size(); ++i) {
+ QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
if (!propertyCache)
continue;
const QmlIR::Object *obj = qmlObjects.at(i);
@@ -501,20 +451,22 @@ bool QQmlEnumTypeResolver::resolveEnumBindings()
QQmlPropertyResolver resolver(propertyCache);
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject
+ || bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver)
continue;
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script)
continue;
const QString propertyName = stringAt(binding->propertyNameIndex);
bool notInRevision = false;
- QQmlPropertyData *pd = resolver.property(propertyName, &notInRevision);
- if (!pd)
+ const QQmlPropertyData *pd = resolver.property(propertyName, &notInRevision);
+ if (!pd || pd->isQList())
continue;
- if (!pd->isEnum() && pd->propType() != QMetaType::Int)
+ if (!pd->isEnum() && pd->propType().id() != QMetaType::Int)
continue;
if (!tryQualifiedEnumAssignment(obj, propertyCache, pd, binding))
@@ -525,48 +477,51 @@ bool QQmlEnumTypeResolver::resolveEnumBindings()
return true;
}
-struct StaticQtMetaObject : public QObject
-{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
-
-bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject)
+bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, QStringView, int enumValue, bool)
{
- if (enumName.length() > 0 && enumName[0].isLower() && !isQtObject) {
- COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString()));
- }
- binding->type = QV4::CompiledData::Binding::Type_Number;
+ binding->setType(QV4::CompiledData::Binding::Type_Number);
binding->value.constantValueIndex = compiler->registerConstant(QV4::Encode((double)enumValue));
// binding->setNumberValueInternal((double)enumValue);
- binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum;
+ binding->setFlag(QV4::CompiledData::Binding::IsResolvedEnum);
return true;
}
-bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding)
+bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(
+ const QmlIR::Object *obj, const QQmlPropertyCache::ConstPtr &propertyCache,
+ const QQmlPropertyData *prop, QmlIR::Binding *binding)
{
- bool isIntProp = (prop->propType() == QMetaType::Int) && !prop->isEnum();
+ bool isIntProp = (prop->propType().id() == QMetaType::Int) && !prop->isEnum();
if (!prop->isEnum() && !isIntProp)
return true;
- if (!prop->isWritable() && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))
- COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property").arg(stringAt(binding->propertyNameIndex)));
+ if (!prop->isWritable()
+ && !(binding->hasFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))) {
+ COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property")
+ .arg(stringAt(binding->propertyNameIndex)));
+ }
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
if (!string.constData()->isUpper())
return true;
+ // reject any "complex" expression (even simple arithmetic)
+ // we do this by excluding everything that is not part of a
+ // valid identifier or a dot
+ for (const QChar &c : string)
+ if (!(c.isLetterOrNumber() || c == u'.' || c == u'_' || c.isSpace()))
+ return true;
+
// we support one or two '.' in the enum phrase:
// * <TypeName>.<EnumValue>
// * <TypeName>.<ScopedEnumName>.<EnumValue>
int dot = string.indexOf(QLatin1Char('.'));
- if (dot == -1 || dot == string.length()-1)
+ if (dot == -1 || dot == string.size()-1)
return true;
int dot2 = string.indexOf(QLatin1Char('.'), dot+1);
- if (dot2 != -1 && dot2 != string.length()-1) {
+ if (dot2 != -1 && dot2 != string.size()-1) {
if (!string.at(dot+1).isUpper())
return true;
if (string.indexOf(QLatin1Char('.'), dot2+1) != -1)
@@ -575,9 +530,9 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
QHashedStringRef typeName(string.constData(), dot);
const bool isQtObject = (typeName == QLatin1String("Qt"));
- const QStringRef scopedEnumName = (dot2 != -1 ? string.midRef(dot + 1, dot2 - dot - 1) : QStringRef());
+ const QStringView scopedEnumName = (dot2 != -1 ? QStringView{string}.mid(dot + 1, dot2 - dot - 1) : QStringView());
// ### consider supporting scoped enums in Qt namespace
- const QStringRef enumValue = string.midRef(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
+ const QStringView enumValue = QStringView{string}.mid(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
if (isIntProp) { // ### C++11 allows enums to be other integral types. Should we support other integral types here?
// Allow enum assignment to ints.
@@ -590,7 +545,8 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
return true;
}
QQmlType type;
- imports->resolveType(typeName, &type, nullptr, nullptr, nullptr);
+ imports->resolveType(
+ QQmlTypeLoader::get(compiler->enginePrivate()), typeName, &type, nullptr, nullptr);
if (!type.isValid() && !isQtObject)
return true;
@@ -599,10 +555,20 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
bool ok = false;
auto *tr = resolvedType(obj->inheritedTypeNameIndex);
- if (type.isValid() && tr && tr->type == type) {
- // When these two match, we can short cut the search
- QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
- QMetaEnum menum = mprop.enumerator();
+
+ // When these two match, we can short cut the search, unless...
+ bool useFastPath = type.isValid() && tr && tr->type() == type;
+ QMetaProperty mprop;
+ QMetaEnum menum;
+ if (useFastPath) {
+ mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
+ menum = mprop.enumerator();
+ // ...the enumerator merely comes from a related metaobject, but the enum scope does not match
+ // the typename we resolved
+ if (!menum.isScoped() && scopedEnumName.isEmpty() && typeName != QString::fromUtf8(menum.scope()))
+ useFastPath = false;;
+ }
+ if (useFastPath) {
QByteArray enumName = enumValue.toUtf8();
if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8())
return true;
@@ -621,7 +587,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
value = type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok);
} else {
QByteArray enumName = enumValue.toUtf8();
- const QMetaObject *metaObject = StaticQtMetaObject::get();
+ const QMetaObject *metaObject = &Qt::staticMetaObject;
for (int ii = metaObject->enumeratorCount() - 1; !ok && ii >= 0; --ii) {
QMetaEnum e = metaObject->enumerator(ii);
value = e.keyToValue(enumName.constData(), &ok);
@@ -635,22 +601,23 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
return assignEnumToBinding(binding, enumValue, value, isQtObject);
}
-int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const
+int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, QStringView enumName, QStringView enumValue, bool *ok) const
{
Q_ASSERT_X(ok, "QQmlEnumTypeResolver::evaluateEnum", "ok must not be a null pointer");
*ok = false;
if (scope != QLatin1String("Qt")) {
QQmlType type;
- imports->resolveType(scope, &type, nullptr, nullptr, nullptr);
+ imports->resolveType(
+ QQmlTypeLoader::get(compiler->enginePrivate()), scope, &type, nullptr, nullptr);
if (!type.isValid())
return -1;
if (!enumName.isEmpty())
return type.scopedEnumValue(compiler->enginePrivate(), enumName, enumValue, ok);
- return type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue.constData(), enumValue.length()), ok);
+ return type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue.constData(), enumValue.size()), ok);
}
- const QMetaObject *mo = StaticQtMetaObject::get();
+ const QMetaObject *mo = &Qt::staticMetaObject;
int i = mo->enumeratorCount();
const QByteArray ba = enumValue.toUtf8();
while (i--) {
@@ -671,6 +638,9 @@ QQmlCustomParserScriptIndexer::QQmlCustomParserScriptIndexer(QQmlTypeCompiler *t
void QQmlCustomParserScriptIndexer::annotateBindingsWithScriptStrings()
{
scanObjectRecursively(/*root object*/0);
+ for (int i = 0; i < qmlObjects.size(); ++i)
+ if (qmlObjects.at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
+ scanObjectRecursively(i);
}
void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool annotateScriptBindings)
@@ -679,15 +649,21 @@ void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool
if (!annotateScriptBindings)
annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Script:
+ if (annotateScriptBindings) {
+ binding->stringIndex = compiler->registerString(
+ compiler->bindingAsString(obj, binding->value.compiledScriptIndex));
+ }
+ break;
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ case QV4::CompiledData::Binding::Type_GroupProperty:
scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
- continue;
- } else if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
- if (!annotateScriptBindings)
- continue;
- const QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
- binding->stringIndex = compiler->registerString(script);
+ break;
+ default:
+ break;
+ }
}
}
@@ -700,23 +676,23 @@ QQmlAliasAnnotator::QQmlAliasAnnotator(QQmlTypeCompiler *typeCompiler)
void QQmlAliasAnnotator::annotateBindingsToAliases()
{
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
+ for (int i = 0; i < qmlObjects.size(); ++i) {
+ QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
if (!propertyCache)
continue;
const QmlIR::Object *obj = qmlObjects.at(i);
QQmlPropertyResolver resolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
+ const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (!binding->isValueBinding())
continue;
bool notInRevision = false;
- QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
+ const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
if (pd && pd->isAlias())
- binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias;
+ binding->setFlag(QV4::CompiledData::Binding::IsBindingToAlias);
}
}
}
@@ -731,22 +707,22 @@ QQmlScriptStringScanner::QQmlScriptStringScanner(QQmlTypeCompiler *typeCompiler)
void QQmlScriptStringScanner::scan()
{
- const int scriptStringMetaType = qMetaTypeId<QQmlScriptString>();
- for (int i = 0; i < qmlObjects.count(); ++i) {
- QQmlPropertyCache *propertyCache = propertyCaches->at(i);
+ const QMetaType scriptStringMetaType = QMetaType::fromType<QQmlScriptString>();
+ for (int i = 0; i < qmlObjects.size(); ++i) {
+ QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(i);
if (!propertyCache)
continue;
const QmlIR::Object *obj = qmlObjects.at(i);
QQmlPropertyResolver resolver(propertyCache);
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
+ const QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script)
continue;
bool notInRevision = false;
- QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
+ const QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
if (!pd || pd->propType() != scriptStringMetaType)
continue;
@@ -756,300 +732,99 @@ void QQmlScriptStringScanner::scan()
}
}
-QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler)
- : QQmlCompilePass(typeCompiler)
- , enginePrivate(typeCompiler->enginePrivate())
- , pool(typeCompiler->memoryPool())
- , qmlObjects(typeCompiler->qmlObjects())
- , propertyCaches(std::move(typeCompiler->takePropertyCaches()))
+template<>
+void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::allocateNamedObjects(
+ QmlIR::Object *object) const
{
+ object->namedObjectsInComponent.allocate(m_compiler->memoryPool(), m_idToObjectIndex);
}
-static bool isUsableComponent(const QMetaObject *metaObject)
+template<>
+bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::markAsComponent(int index) const
{
- // The metaObject is a component we're interested in if it either is a QQmlComponent itself
- // or if any of its parents is a QQmlAbstractDelegateComponent. We don't want to include
- // qqmldelegatecomponent_p.h because it belongs to QtQmlModels.
-
- if (metaObject == &QQmlComponent::staticMetaObject)
- return true;
-
- for (; metaObject; metaObject = metaObject->superClass()) {
- if (qstrcmp(metaObject->className(), "QQmlAbstractDelegateComponent") == 0)
- return true;
- }
-
- return false;
+ m_compiler->qmlObjects()->at(index)->flags |= QV4::CompiledData::Object::IsComponent;
+ return true;
}
-void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache)
+template<>
+void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::setObjectId(int index) const
{
- QQmlPropertyResolver propertyResolver(propertyCache);
-
- QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
-
- for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object)
- continue;
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
-
- const QmlIR::Object *targetObject = qmlObjects->at(binding->value.objectIndex);
- auto *tr = resolvedType(targetObject->inheritedTypeNameIndex);
- Q_ASSERT(tr);
-
- const QMetaObject *firstMetaObject = nullptr;
- if (tr->type.isValid())
- firstMetaObject = tr->type.metaObject();
- else if (tr->compilationUnit)
- firstMetaObject = tr->compilationUnit->rootPropertyCache()->firstCppMetaObject();
- if (isUsableComponent(firstMetaObject))
- continue;
- // if here, not a QQmlComponent, so needs wrapping
-
- QQmlPropertyData *pd = nullptr;
- if (binding->propertyNameIndex != quint32(0)) {
- bool notInRevision = false;
- pd = propertyResolver.property(stringAt(binding->propertyNameIndex), &notInRevision);
- } else {
- pd = defaultProperty;
- }
- if (!pd || !pd->isQObject())
- continue;
-
- QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType(), pd->typeMinorVersion());
- const QMetaObject *mo = pc ? pc->firstCppMetaObject() : nullptr;
- while (mo) {
- if (mo == &QQmlComponent::staticMetaObject)
- break;
- mo = mo->superClass();
- }
-
- if (!mo)
- continue;
-
- // emulate "import Qml 2.0 as QmlInternals" and then wrap the component in "QmlInternals.Component {}"
- QQmlType componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject);
- Q_ASSERT(componentType.isValid());
- const QString qualifier = QStringLiteral("QmlInternals");
-
- compiler->addImport(componentType.module(), qualifier, componentType.majorVersion(), componentType.minorVersion());
-
- QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
- syntheticComponent->init(pool, compiler->registerString(qualifier + QLatin1Char('.') + componentType.elementName()), compiler->registerString(QString()));
- syntheticComponent->location = binding->valueLocation;
- syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
-
- if (!containsResolvedType(syntheticComponent->inheritedTypeNameIndex)) {
- auto typeRef = new QV4::ResolvedTypeReference;
- typeRef->type = componentType;
- typeRef->majorVersion = componentType.majorVersion();
- typeRef->minorVersion = componentType.minorVersion();
- insertResolvedType(syntheticComponent->inheritedTypeNameIndex, typeRef);
- }
-
- qmlObjects->append(syntheticComponent);
- const int componentIndex = qmlObjects->count() - 1;
- // Keep property caches symmetric
- QQmlPropertyCache *componentCache = enginePrivate->cache(&QQmlComponent::staticMetaObject);
- propertyCaches.append(componentCache);
-
- QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
- *syntheticBinding = *binding;
- syntheticBinding->type = QV4::CompiledData::Binding::Type_Object;
- QString error = syntheticComponent->appendBinding(syntheticBinding, /*isListBinding*/false);
- Q_ASSERT(error.isEmpty());
- Q_UNUSED(error);
-
- binding->value.objectIndex = componentIndex;
-
- componentRoots.append(componentIndex);
- }
+ m_compiler->qmlObjects()->at(index)->id = m_idToObjectIndex.size();
}
-bool QQmlComponentAndAliasResolver::resolve()
+template<>
+bool QQmlComponentAndAliasResolver<QQmlTypeCompiler>::wrapImplicitComponent(QmlIR::Binding *binding)
{
- // Detect real Component {} objects as well as implicitly defined components, such as
- // someItemDelegate: Item {}
- // In the implicit case Item is surrounded by a synthetic Component {} because the property
- // on the left hand side is of QQmlComponent type.
- const int objCountWithoutSynthesizedComponents = qmlObjects->count();
- for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) {
- QmlIR::Object *obj = qmlObjects->at(i);
- QQmlPropertyCache *cache = propertyCaches.at(i);
- if (obj->inheritedTypeNameIndex == 0 && !cache)
- continue;
-
- bool isExplicitComponent = false;
-
- if (obj->inheritedTypeNameIndex) {
- auto *tref = resolvedType(obj->inheritedTypeNameIndex);
- Q_ASSERT(tref);
- if (tref->type.metaObject() == &QQmlComponent::staticMetaObject)
- isExplicitComponent = true;
- }
- if (!isExplicitComponent) {
- if (cache)
- findAndRegisterImplicitComponents(obj, cache);
- continue;
- }
-
- obj->flags |= QV4::CompiledData::Object::IsComponent;
-
- if (obj->functionCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
- if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
- if (obj->signalCount() > 0)
- COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
-
- if (obj->bindingCount() == 0)
- COMPILE_EXCEPTION(obj, tr("Cannot create empty component specification"));
-
- const QmlIR::Binding *rootBinding = obj->firstBinding();
-
- for (const QmlIR::Binding *b = rootBinding; b; b = b->next) {
- if (b->propertyNameIndex != 0)
- COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
- }
-
- if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
- COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
-
- // For the root object, we are going to collect ids/aliases and resolve them for as a separate
- // last pass.
- if (i != 0)
- componentRoots.append(i);
-
- }
-
- for (int i = 0; i < componentRoots.count(); ++i) {
- QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
- const QmlIR::Binding *rootBinding = component->firstBinding();
-
- _idToObjectIndex.clear();
-
- _objectsWithAliases.clear();
-
- if (!collectIdsAndAliases(rootBinding->value.objectIndex))
- return false;
-
- component->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
-
- if (!resolveAliases(componentRoots.at(i)))
- return false;
+ QQmlJS::MemoryPool *pool = m_compiler->memoryPool();
+ QVector<QmlIR::Object *> *qmlObjects = m_compiler->qmlObjects();
+
+ // emulate "import QML 1.0" and then wrap the component in "QML.Component {}"
+ QQmlType componentType = QQmlMetaType::qmlType(
+ &QQmlComponent::staticMetaObject, QStringLiteral("QML"),
+ QTypeRevision::fromVersion(1, 0));
+ Q_ASSERT(componentType.isValid());
+ const QString qualifier = QStringLiteral("QML");
+
+ m_compiler->addImport(componentType.module(), qualifier, componentType.version());
+
+ QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
+ syntheticComponent->init(
+ pool,
+ m_compiler->registerString(
+ qualifier + QLatin1Char('.') + componentType.elementName()),
+ m_compiler->registerString(QString()), binding->valueLocation);
+ syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
+
+ if (!m_compiler->resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) {
+ auto typeRef = new QV4::ResolvedTypeReference;
+ typeRef->setType(componentType);
+ typeRef->setVersion(componentType.version());
+ m_compiler->resolvedTypes->insert(syntheticComponent->inheritedTypeNameIndex, typeRef);
}
- // Collect ids and aliases for root
- _idToObjectIndex.clear();
- _objectsWithAliases.clear();
+ qmlObjects->append(syntheticComponent);
+ const int componentIndex = qmlObjects->size() - 1;
+ // Keep property caches symmetric
+ QQmlPropertyCache::ConstPtr componentCache
+ = QQmlMetaType::propertyCache(&QQmlComponent::staticMetaObject);
+ m_propertyCaches->append(componentCache);
- collectIdsAndAliases(/*root object*/0);
+ QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
+ *syntheticBinding = *binding;
- QmlIR::Object *rootComponent = qmlObjects->at(/*root object*/0);
- rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
+ // The synthetic binding inside Component has no name. It's just "Component { Foo {} }".
+ syntheticBinding->propertyNameIndex = 0;
- if (!resolveAliases(/*root object*/0))
- return false;
+ syntheticBinding->setType(QV4::CompiledData::Binding::Type_Object);
+ QString error = syntheticComponent->appendBinding(syntheticBinding, /*isListBinding*/false);
+ Q_ASSERT(error.isEmpty());
+ Q_UNUSED(error);
- // Implicit component insertion may have added objects and thus we also need
- // to extend the symmetric propertyCaches.
- compiler->setPropertyCaches(std::move(propertyCaches));
- compiler->setComponentRoots(componentRoots);
+ binding->value.objectIndex = componentIndex;
+ m_componentRoots.append(componentIndex);
return true;
}
-bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
+template<>
+void QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveGeneralizedGroupProperty(
+ const CompiledObject &component, CompiledBinding *binding)
{
- QmlIR::Object *obj = qmlObjects->at(objectIndex);
-
- if (obj->idNameIndex != 0) {
- if (_idToObjectIndex.contains(obj->idNameIndex)) {
- recordError(obj->locationOfIdProperty, tr("id is not unique"));
- return false;
- }
- obj->id = _idToObjectIndex.count();
- _idToObjectIndex.insert(obj->idNameIndex, objectIndex);
- }
-
- if (obj->aliasCount() > 0)
- _objectsWithAliases.append(objectIndex);
-
- // Stop at Component boundary
- if (obj->flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0)
- return true;
-
- for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object
- && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- if (!collectIdsAndAliases(binding->value.objectIndex))
- return false;
- }
-
- return true;
+ Q_UNUSED(component);
+ // We cannot make it fail here. It might be a custom-parsed property
+ const int targetObjectIndex = m_idToObjectIndex.value(binding->propertyNameIndex, -1);
+ if (targetObjectIndex != -1)
+ m_propertyCaches->set(binding->value.objectIndex, m_propertyCaches->at(targetObjectIndex));
}
-bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
+template<>
+typename QQmlComponentAndAliasResolver<QQmlTypeCompiler>::AliasResolutionResult
+QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject(
+ const CompiledObject &component, int objectIndex, QQmlError *error)
{
- if (_objectsWithAliases.isEmpty())
- return true;
-
- QQmlPropertyCacheAliasCreator<QQmlTypeCompiler> aliasCacheCreator(&propertyCaches, compiler);
-
- bool atLeastOneAliasResolved;
- do {
- atLeastOneAliasResolved = false;
- QVector<int> pendingObjects;
-
- for (int objectIndex: qAsConst(_objectsWithAliases)) {
+ Q_UNUSED(component);
- QQmlJS::DiagnosticMessage error;
- const auto result = resolveAliasesInObject(objectIndex, &error);
-
- if (error.isValid()) {
- recordError(error);
- return false;
- }
-
- if (result == AllAliasesResolved) {
- QQmlJS::DiagnosticMessage error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex, enginePrivate);
- if (error.isValid()) {
- recordError(error);
- return false;
- }
- atLeastOneAliasResolved = true;
- } else if (result == SomeAliasesResolved) {
- atLeastOneAliasResolved = true;
- pendingObjects.append(objectIndex);
- } else {
- pendingObjects.append(objectIndex);
- }
- }
- qSwap(_objectsWithAliases, pendingObjects);
- } while (!_objectsWithAliases.isEmpty() && atLeastOneAliasResolved);
-
- if (!atLeastOneAliasResolved && !_objectsWithAliases.isEmpty()) {
- const QmlIR::Object *obj = qmlObjects->at(_objectsWithAliases.first());
- for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
- if (!(alias->flags & QV4::CompiledData::Alias::Resolved)) {
- recordError(alias->location, tr("Circular alias reference detected"));
- return false;
- }
- }
- }
-
- return true;
-}
-
-QQmlComponentAndAliasResolver::AliasResolutionResult
-QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
- QQmlJS::DiagnosticMessage *error)
-{
- const QmlIR::Object * const obj = qmlObjects->at(objectIndex);
+ const QmlIR::Object * const obj = m_compiler->objectAt(objectIndex);
if (!obj->aliasCount())
return AllAliasesResolved;
@@ -1057,13 +832,13 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
bool seenUnresolvedAlias = false;
for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next) {
- if (alias->flags & QV4::CompiledData::Alias::Resolved)
+ if (alias->hasFlag(QV4::CompiledData::Alias::Resolved))
continue;
seenUnresolvedAlias = true;
- const int idIndex = alias->idIndex;
- const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
+ const int idIndex = alias->idIndex();
+ const int targetObjectIndex = m_idToObjectIndex.value(idIndex, -1);
if (targetObjectIndex == -1) {
*error = qQmlCompileError(
alias->referenceLocation,
@@ -1071,29 +846,29 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
break;
}
- const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
+ const QmlIR::Object *targetObject = m_compiler->objectAt(targetObjectIndex);
Q_ASSERT(targetObject->id >= 0);
- alias->targetObjectId = targetObject->id;
- alias->aliasToLocalAlias = false;
+ alias->setTargetObjectId(targetObject->id);
+ alias->setIsAliasToLocalAlias(false);
const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
- QStringRef property;
- QStringRef subProperty;
+ QStringView property;
+ QStringView subProperty;
const int propertySeparator = aliasPropertyValue.indexOf(QLatin1Char('.'));
if (propertySeparator != -1) {
- property = aliasPropertyValue.leftRef(propertySeparator);
- subProperty = aliasPropertyValue.midRef(propertySeparator + 1);
+ property = QStringView{aliasPropertyValue}.left(propertySeparator);
+ subProperty = QStringView{aliasPropertyValue}.mid(propertySeparator + 1);
} else
- property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());
+ property = QStringView(aliasPropertyValue);
QQmlPropertyIndex propIdx;
if (property.isEmpty()) {
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
+ alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject);
} else {
- QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
+ QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex);
if (!targetCache) {
*error = qQmlCompileError(
alias->referenceLocation,
@@ -1103,14 +878,14 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
QQmlPropertyResolver resolver(targetCache);
- QQmlPropertyData *targetProperty = resolver.property(property.toString());
+ const QQmlPropertyData *targetProperty = resolver.property(property.toString());
// If it's an alias that we haven't resolved yet, try again later.
if (!targetProperty) {
bool aliasPointsToOtherAlias = false;
int localAliasIndex = 0;
for (auto targetAlias = targetObject->aliasesBegin(), end = targetObject->aliasesEnd(); targetAlias != end; ++targetAlias, ++localAliasIndex) {
- if (stringAt(targetAlias->nameIndex) == property) {
+ if (stringAt(targetAlias->nameIndex()) == property) {
aliasPointsToOtherAlias = true;
break;
}
@@ -1118,14 +893,14 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
if (aliasPointsToOtherAlias) {
if (targetObjectIndex == objectIndex) {
alias->localAliasIndex = localAliasIndex;
- alias->aliasToLocalAlias = true;
- alias->flags |= QV4::CompiledData::Alias::Resolved;
+ alias->setIsAliasToLocalAlias(true);
+ alias->setFlag(QV4::CompiledData::Alias::Resolved);
++numResolvedAliases;
continue;
}
// restore
- alias->idIndex = idIndex;
+ alias->setIdIndex(idIndex);
// Try again later and resolve the target alias first.
break;
}
@@ -1141,7 +916,7 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
propIdx = QQmlPropertyIndex(targetProperty->coreIndex());
if (!subProperty.isEmpty()) {
- const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(targetProperty->propType());
+ const QMetaObject *valueTypeMetaObject = QQmlMetaType::metaObjectForValueType(targetProperty->propType());
if (!valueTypeMetaObject) {
// could be a deep alias
bool isDeepAlias = subProperty.at(0).isLower();
@@ -1149,9 +924,9 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
isDeepAlias = false;
for (auto it = targetObject->bindingsBegin(); it != targetObject->bindingsEnd(); ++it) {
auto binding = *it;
- if (compiler->stringAt(binding.propertyNameIndex) == property) {
- resolver = QQmlPropertyResolver(propertyCaches.at(binding.value.objectIndex));
- QQmlPropertyData *actualProperty = resolver.property(subProperty.toString());
+ if (m_compiler->stringAt(binding.propertyNameIndex) == property) {
+ resolver = QQmlPropertyResolver(m_propertyCaches->at(binding.value.objectIndex));
+ const QQmlPropertyData *actualProperty = resolver.property(subProperty.toString());
if (actualProperty) {
propIdx = QQmlPropertyIndex(propIdx.coreIndex(), actualProperty->coreIndex());
isDeepAlias = true;
@@ -1181,12 +956,12 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
}
} else {
if (targetProperty->isQObject())
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
+ alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject);
}
}
alias->encodedMetaPropertyIndex = propIdx.toEncoded();
- alias->flags |= QV4::CompiledData::Alias::Resolved;
+ alias->setFlag(QV4::CompiledData::Alias::Resolved);
numResolvedAliases++;
}
@@ -1207,30 +982,40 @@ QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingSca
bool QQmlDeferredAndCustomParserBindingScanner::scanObject()
{
- return scanObject(/*root object*/0);
+ for (int i = 0; i < qmlObjects->size(); ++i) {
+ if ((qmlObjects->at(i)->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
+ && !scanObject(i, ScopeDeferred::False)) {
+ return false;
+ }
+ }
+ return scanObject(/*root object*/0, ScopeDeferred::False);
}
-bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
+bool QQmlDeferredAndCustomParserBindingScanner::scanObject(
+ int objectIndex, ScopeDeferred scopeDeferred)
{
+ using namespace QV4::CompiledData;
+
QmlIR::Object *obj = qmlObjects->at(objectIndex);
if (obj->idNameIndex != 0)
_seenObjectWithId = true;
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ if (obj->flags & Object::IsComponent) {
Q_ASSERT(obj->bindingCount() == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- return scanObject(componentBinding->value.objectIndex);
+ const Binding *componentBinding = obj->firstBinding();
+ Q_ASSERT(componentBinding->type() == Binding::Type_Object);
+ // Components are separate from their surrounding scope. They cannot be deferred.
+ return scanObject(componentBinding->value.objectIndex, ScopeDeferred::False);
}
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
+ QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(objectIndex);
if (!propertyCache)
return true;
QString defaultPropertyName;
- QQmlPropertyData *defaultProperty = nullptr;
+ const QQmlPropertyData *defaultProperty = nullptr;
if (obj->indexOfDefaultPropertyOrAlias != -1) {
- QQmlPropertyCache *cache = propertyCache->parent();
+ const QQmlPropertyCache *cache = propertyCache->parent().data();
defaultPropertyName = cache->defaultPropertyName();
defaultProperty = cache->defaultProperty();
} else {
@@ -1243,74 +1028,126 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
QQmlPropertyResolver propertyResolver(propertyCache);
QStringList deferredPropertyNames;
+ QStringList immediatePropertyNames;
{
const QMetaObject *mo = propertyCache->firstCppMetaObject();
- const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
- if (namesIndex != -1) {
- QMetaClassInfo classInfo = mo->classInfo(namesIndex);
- deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
+ const int deferredNamesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
+ const int immediateNamesIndex = mo->indexOfClassInfo("ImmediatePropertyNames");
+ if (deferredNamesIndex != -1) {
+ if (immediateNamesIndex != -1) {
+ COMPILE_EXCEPTION(obj, tr("You cannot define both DeferredPropertyNames and "
+ "ImmediatePropertyNames on the same type."));
+ }
+ const QMetaClassInfo classInfo = mo->classInfo(deferredNamesIndex);
+ deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(u',');
+ } else if (immediateNamesIndex != -1) {
+ const QMetaClassInfo classInfo = mo->classInfo(immediateNamesIndex);
+ immediatePropertyNames = QString::fromUtf8(classInfo.value()).split(u',');
+
+ // If the property contains an empty string, all properties shall be deferred.
+ if (immediatePropertyNames.isEmpty())
+ immediatePropertyNames.append(QString());
}
}
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- QQmlPropertyData *pd = nullptr;
QString name = stringAt(binding->propertyNameIndex);
if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (binding->type() == Binding::Type_AttachedProperty) {
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
+ binding->setFlag(Binding::IsCustomParserBinding);
+ obj->flags |= Object::HasCustomParserBindings;
continue;
}
- } else if (QmlIR::IRBuilder::isSignalPropertyName(name)
+ } else if (QQmlSignalNames::isHandlerName(name)
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
+ obj->flags |= Object::HasCustomParserBindings;
+ binding->setFlag(Binding::IsCustomParserBinding);
continue;
}
}
- if (name.isEmpty()) {
- pd = defaultProperty;
- name = defaultPropertyName;
- } else {
- if (name.constData()->isUpper())
- continue;
-
- bool notInRevision = false;
- pd = propertyResolver.property(name, &notInRevision,
- QQmlPropertyResolver::CheckRevision);
- }
+ const bool hasPropertyData = [&]() {
+ if (name.isEmpty()) {
+ name = defaultPropertyName;
+ if (defaultProperty)
+ return true;
+ } else if (name.constData()->isUpper()) {
+ // Upper case names cannot be custom-parsed unless they are attached properties
+ // and the custom parser explicitly accepts them. See above for that case.
+ return false;
+ } else {
+ bool notInRevision = false;
+ if (propertyResolver.property(
+ name, &notInRevision, QQmlPropertyResolver::CheckRevision)) {
+ return true;
+ }
+ }
- bool seenSubObjectWithId = false;
+ if (!customParser)
+ return false;
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
- qSwap(_seenObjectWithId, seenSubObjectWithId);
- const bool subObjectValid = scanObject(binding->value.objectIndex);
- qSwap(_seenObjectWithId, seenSubObjectWithId);
- if (!subObjectValid)
+ const Binding::Flags bindingFlags = binding->flags();
+ if (bindingFlags & Binding::IsSignalHandlerExpression
+ || bindingFlags & Binding::IsSignalHandlerObject
+ || bindingFlags & Binding::IsPropertyObserver) {
+ // These signal handlers cannot be custom-parsed. We have already established
+ // that the signal exists.
return false;
- _seenObjectWithId |= seenSubObjectWithId;
- }
+ }
- if (!seenSubObjectWithId && binding->type != QV4::CompiledData::Binding::Type_GroupProperty
- && !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
+ // If the property isn't found, we may want to custom-parse the binding.
+ obj->flags |= Object::HasCustomParserBindings;
+ binding->setFlag(Binding::IsCustomParserBinding);
+ return false;
+ }();
- binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding;
- obj->flags |= QV4::CompiledData::Object::HasDeferredBindings;
+ bool seenSubObjectWithId = false;
+ bool isExternal = false;
+ if (binding->type() >= Binding::Type_Object) {
+ const bool isOwnProperty = hasPropertyData || binding->isAttachedProperty();
+ isExternal = !isOwnProperty && binding->isGroupProperty();
+ if (isOwnProperty || isExternal) {
+ qSwap(_seenObjectWithId, seenSubObjectWithId);
+ const bool subObjectValid = scanObject(
+ binding->value.objectIndex,
+ (isExternal || scopeDeferred == ScopeDeferred::True)
+ ? ScopeDeferred::True
+ : ScopeDeferred::False);
+ qSwap(_seenObjectWithId, seenSubObjectWithId);
+ if (!subObjectValid)
+ return false;
+ _seenObjectWithId |= seenSubObjectWithId;
+ }
}
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
- continue;
+ bool isDeferred = false;
+ if (!immediatePropertyNames.isEmpty() && !immediatePropertyNames.contains(name)) {
+ if (seenSubObjectWithId) {
+ COMPILE_EXCEPTION(binding, tr("You cannot assign an id to an object assigned "
+ "to a deferred property."));
+ }
+ if (isExternal || !disableInternalDeferredProperties())
+ isDeferred = true;
+ } else if (!deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
+ if (!seenSubObjectWithId && binding->type() != Binding::Type_GroupProperty) {
+ if (isExternal || !disableInternalDeferredProperties())
+ isDeferred = true;
+ }
+ }
- if (!pd) {
- if (customParser) {
- obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
+ if (binding->type() >= Binding::Type_Object) {
+ if (isExternal && !isDeferred && !customParser) {
+ COMPILE_EXCEPTION(
+ binding, tr("Cannot assign to non-existent property \"%1\"").arg(name));
}
}
+
+ if (isDeferred) {
+ binding->setFlag(Binding::IsDeferredBinding);
+ obj->flags |= Object::HasDeferredBindings;
+ }
}
return true;
@@ -1326,13 +1163,13 @@ QQmlDefaultPropertyMerger::QQmlDefaultPropertyMerger(QQmlTypeCompiler *typeCompi
void QQmlDefaultPropertyMerger::mergeDefaultProperties()
{
- for (int i = 0; i < qmlObjects.count(); ++i)
+ for (int i = 0; i < qmlObjects.size(); ++i)
mergeDefaultProperties(i);
}
void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
{
- QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex);
+ QQmlPropertyCache::ConstPtr propertyCache = propertyCaches->at(objectIndex);
if (!propertyCache)
return;
diff --git a/src/qml/qml/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h
index 40b0337848..6d9e5a77ca 100644
--- a/src/qml/qml/qqmltypecompiler_p.h
+++ b/src/qml/qml/qqmltypecompiler_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPECOMPILER_P_H
#define QQMLTYPECOMPILER_P_H
@@ -79,26 +43,43 @@ struct QQmlTypeCompiler
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler)
public:
- QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document,
- const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
+ QQmlTypeCompiler(QQmlEnginePrivate *engine,
+ QQmlTypeData *typeData,
+ QmlIR::Document *document,
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
// --- interface used by QQmlPropertyCacheCreator
typedef QmlIR::Object CompiledObject;
+ typedef QmlIR::Binding CompiledBinding;
+ using ListPropertyAssignBehavior = QmlIR::Pragma::ListPropertyAssignBehaviorValue;
+
+ // Deliberate choice of map over hash here to ensure stable generated output.
+ using IdToObjectMap = QMap<int, int>;
+
const QmlIR::Object *objectAt(int index) const { return document->objects.at(index); }
- int objectCount() const { return document->objects.count(); }
+ QmlIR::Object *objectAt(int index) { return document->objects.at(index); }
+ int objectCount() const { return document->objects.size(); }
QString stringAt(int idx) const;
QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsBegin(const QmlIR::Object *object) const { return object->functionsBegin(); }
QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsEnd(const QmlIR::Object *object) const { return object->functionsEnd(); }
- QV4::ResolvedTypeReferenceMap *resolvedTypes = nullptr;
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypes = nullptr;
+ ListPropertyAssignBehavior listPropertyAssignBehavior() const
+ {
+ for (const QmlIR::Pragma *pragma: document->pragmas) {
+ if (pragma->type == QmlIR::Pragma::ListPropertyAssignBehavior)
+ return pragma->listPropertyAssignBehavior;
+ }
+ return ListPropertyAssignBehavior::Append;
+ }
// ---
- QQmlRefPointer<QV4::ExecutableCompilationUnit> compile();
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compile();
QList<QQmlError> compilationErrors() const { return errors; }
void recordError(const QV4::CompiledData::Location &location, const QString &description);
- void recordError(const QQmlJS::DiagnosticMessage &error);
+ void recordError(const QQmlJS::DiagnosticMessage &message);
+ void recordError(const QQmlError &e);
int registerString(const QString &str);
int registerConstant(QV4::ReturnedValue v);
@@ -109,39 +90,46 @@ public:
QQmlEnginePrivate *enginePrivate() const { return engine; }
const QQmlImports *imports() const;
QVector<QmlIR::Object *> *qmlObjects() const;
- void setPropertyCaches(QQmlPropertyCacheVector &&caches);
+ QQmlPropertyCacheVector *propertyCaches();
const QQmlPropertyCacheVector *propertyCaches() const;
- QQmlPropertyCacheVector &&takePropertyCaches();
- void setComponentRoots(const QVector<quint32> &roots) { m_componentRoots = roots; }
- const QVector<quint32> &componentRoots() const { return m_componentRoots; }
QQmlJS::MemoryPool *memoryPool();
- QStringRef newStringRef(const QString &string);
+ QStringView newStringRef(const QString &string);
const QV4::Compiler::StringTableGenerator *stringPool() const;
const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; }
QString bindingAsString(const QmlIR::Object *object, int scriptIndex) const;
- void addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion);
+ void addImport(const QString &module, const QString &qualifier, QTypeRevision version);
QV4::ResolvedTypeReference *resolvedType(int id) const
{
return resolvedTypes->value(id);
}
+ QV4::ResolvedTypeReference *resolvedType(QMetaType type) const
+ {
+ for (QV4::ResolvedTypeReference *ref : std::as_const(*resolvedTypes)) {
+ if (ref->type().typeId() == type)
+ return ref;
+ }
+ return nullptr;
+ }
+
+ QQmlType qmlTypeForComponent(const QString &inlineComponentName = QString()) const;
+
private:
QList<QQmlError> errors;
QQmlEnginePrivate *engine;
- QQmlTypeData *typeData;
const QV4::CompiledData::DependentTypesHasher &dependencyHasher;
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QmlIR::Document *document;
// index is string index of type name (use obj->inheritedTypeNameIndex)
QHash<int, QQmlCustomParser*> customParsers;
// index in first hash is component index, vector inside contains object indices of objects with id property
- QVector<quint32> m_componentRoots;
QQmlPropertyCacheVector m_propertyCaches;
+
+ QQmlTypeData *typeData;
};
struct QQmlCompilePass
@@ -152,34 +140,27 @@ struct QQmlCompilePass
protected:
void recordError(const QV4::CompiledData::Location &location, const QString &description) const
{ compiler->recordError(location, description); }
- void recordError(const QQmlJS::DiagnosticMessage &error)
- { compiler->recordError(error); }
QV4::ResolvedTypeReference *resolvedType(int id) const
{ return compiler->resolvedType(id); }
- bool containsResolvedType(int id) const
- { return compiler->resolvedTypes->contains(id); }
- QV4::ResolvedTypeReferenceMap::iterator insertResolvedType(
- int id, QV4::ResolvedTypeReference *value)
- { return compiler->resolvedTypes->insert(id, value); }
QQmlTypeCompiler *compiler;
};
-// "Converts" signal expressions to full-fleged function declarations with
-// parameters taken from the signal declarations
-// It also updates the QV4::CompiledData::Binding objects to set the property name
-// to the final signal name (onTextChanged -> textChanged) and sets the IsSignalExpression flag.
-struct SignalHandlerConverter : public QQmlCompilePass
+// Resolves signal handlers. Updates the QV4::CompiledData::Binding objects to
+// set the property name to the final signal name (onTextChanged -> textChanged)
+// and sets the IsSignalExpression flag.
+struct SignalHandlerResolver : public QQmlCompilePass
{
- Q_DECLARE_TR_FUNCTIONS(SignalHandlerConverter)
+ Q_DECLARE_TR_FUNCTIONS(SignalHandlerResolver)
public:
- SignalHandlerConverter(QQmlTypeCompiler *typeCompiler);
+ SignalHandlerResolver(QQmlTypeCompiler *typeCompiler);
- bool convertSignalHandlerExpressionsToFunctionDeclarations();
+ bool resolveSignalHandlerExpressions();
private:
- bool convertSignalHandlerExpressionsToFunctionDeclarations(const QmlIR::Object *obj, const QString &typeName, QQmlPropertyCache *propertyCache);
+ bool resolveSignalHandlerExpressions(const QmlIR::Object *obj, const QString &typeName,
+ const QQmlPropertyCache::ConstPtr &propertyCache);
QQmlEnginePrivate *enginePrivate;
const QVector<QmlIR::Object*> &qmlObjects;
@@ -201,15 +182,15 @@ public:
bool resolveEnumBindings();
private:
- bool assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject);
+ bool assignEnumToBinding(QmlIR::Binding *binding, QStringView enumName, int enumValue, bool isQtObject);
bool assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject)
{
- return assignEnumToBinding(binding, QStringRef(&enumName), enumValue, isQtObject);
+ return assignEnumToBinding(binding, QStringView(enumName), enumValue, isQtObject);
}
- bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache,
- const QQmlPropertyData *prop,
- QmlIR::Binding *binding);
- int evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const;
+ bool tryQualifiedEnumAssignment(
+ const QmlIR::Object *obj, const QQmlPropertyCache::ConstPtr &propertyCache,
+ const QQmlPropertyData *prop, QmlIR::Binding *binding);
+ int evaluateEnum(const QString &scope, QStringView enumName, QStringView enumValue, bool *ok) const;
const QVector<QmlIR::Object*> &qmlObjects;
@@ -255,52 +236,17 @@ private:
const QQmlPropertyCacheVector * const propertyCaches;
};
-class QQmlComponentAndAliasResolver : public QQmlCompilePass
-{
- Q_DECLARE_TR_FUNCTIONS(QQmlAnonymousComponentResolver)
-public:
- QQmlComponentAndAliasResolver(QQmlTypeCompiler *typeCompiler);
-
- bool resolve();
-
-protected:
- void findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache);
- bool collectIdsAndAliases(int objectIndex);
- bool resolveAliases(int componentIndex);
- void propertyDataForAlias(QmlIR::Alias *alias, int *type, quint32 *propertyFlags);
-
- enum AliasResolutionResult {
- NoAliasResolved,
- SomeAliasesResolved,
- AllAliasesResolved
- };
-
- AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlJS::DiagnosticMessage *error);
-
- QQmlEnginePrivate *enginePrivate;
- QQmlJS::MemoryPool *pool;
-
- QVector<QmlIR::Object*> *qmlObjects;
-
- // indices of the objects that are actually Component {}
- QVector<quint32> componentRoots;
-
- // Deliberate choice of map over hash here to ensure stable generated output.
- QMap<int, int> _idToObjectIndex;
- QVector<int> _objectsWithAliases;
-
- QQmlPropertyCacheVector propertyCaches;
-};
-
class QQmlDeferredAndCustomParserBindingScanner : public QQmlCompilePass
{
+ Q_DECLARE_TR_FUNCTIONS(QQmlDeferredAndCustomParserBindingScanner)
public:
QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler);
bool scanObject();
private:
- bool scanObject(int objectIndex);
+ enum class ScopeDeferred { False, True };
+ bool scanObject(int objectIndex, ScopeDeferred scopeDeferred);
QVector<QmlIR::Object*> *qmlObjects;
const QQmlPropertyCacheVector * const propertyCaches;
diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp
index cfdcf6aad5..9acd801672 100644
--- a/src/qml/qml/qqmltypedata.cpp
+++ b/src/qml/qml/qqmltypedata.cpp
@@ -1,56 +1,25 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <private/qqmltypedata_p.h>
+#include <private/qqmlcomponentandaliasresolver_p.h>
#include <private/qqmlengine_p.h>
-#include <private/qqmlpropertycachecreator_p.h>
-#include <private/qqmlpropertyvalidator_p.h>
#include <private/qqmlirbuilder_p.h>
#include <private/qqmlirloader_p.h>
+#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qqmlpropertyvalidator_p.h>
#include <private/qqmlscriptblob_p.h>
#include <private/qqmlscriptdata_p.h>
#include <private/qqmltypecompiler_p.h>
+#include <private/qqmltypedata_p.h>
+#include <private/qqmltypeloaderqmldircontent_p.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qcryptographichash.h>
+#include <memory>
+
Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
+Q_LOGGING_CATEGORY(lcCycle, "qt.qml.typeresolution.cycle", QtWarningMsg)
QT_BEGIN_NAMESPACE
@@ -82,12 +51,7 @@ QQmlTypeData::~QQmlTypeData()
m_resolvedTypes.clear();
}
-const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const
-{
- return m_scripts;
-}
-
-QV4::ExecutableCompilationUnit *QQmlTypeData::compilationUnit() const
+QV4::CompiledData::CompilationUnit *QQmlTypeData::compilationUnit() const
{
return m_compiledData.data();
}
@@ -105,19 +69,19 @@ void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
Q_ASSERT(!m_callbacks.contains(callback));
}
-bool QQmlTypeData::tryLoadFromDiskCache()
+QQmlType QQmlTypeData::qmlType(const QString &inlineComponentName) const
{
- if (diskCacheDisabled() && !diskCacheForced())
- return false;
-
- if (isDebugging())
- return false;
+ if (inlineComponentName.isEmpty())
+ return m_qmlType;
+ return m_inlineComponentData[inlineComponentName].qmlType;
+}
- QV4::ExecutionEngine *v4 = typeLoader()->engine()->handle();
- if (!v4)
+bool QQmlTypeData::tryLoadFromDiskCache()
+{
+ if (!readCacheFile())
return false;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> unit = QV4::ExecutableCompilationUnit::create();
+ auto unit = QQml::makeRefPointer<QV4::CompiledData::CompilationUnit>();
{
QString error;
if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
@@ -127,16 +91,23 @@ bool QQmlTypeData::tryLoadFromDiskCache()
}
if (unit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation) {
- restoreIR(std::move(*unit));
+ restoreIR(unit);
return true;
}
- m_compiledData = unit;
+ m_compiledData = std::move(unit);
- for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
- m_typeReferences.collectFromObject(m_compiledData->objectAt(i));
+ QVector<QV4::CompiledData::InlineComponent> ics;
+ for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i) {
+ auto object = m_compiledData->objectAt(i);
+ m_typeReferences.collectFromObject(object);
+ const auto inlineComponentTable = object->inlineComponentTable();
+ for (auto i = 0; i != object->nInlineComponents; ++i) {
+ ics.push_back(inlineComponentTable[i]);
+ }
+ }
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+ m_importCache->setBaseUrl(finalUrl(), finalUrlString());
// For remote URLs, we don't delay the loading of the implicit import
// because the loading probably requires an asynchronous fetch of the
@@ -152,10 +123,12 @@ bool QQmlTypeData::tryLoadFromDiskCache()
const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
if (m_compiledData->stringAt(import->uriIndex) == QLatin1String(".")
&& import->qualifierIndex == 0
- && import->majorVersion == -1
- && import->minorVersion == -1) {
+ && !import->version.hasMajorVersion()
+ && !import->version.hasMinorVersion()) {
QList<QQmlError> errors;
- auto pendingImport = std::make_shared<PendingImport>(this, import);
+ auto pendingImport = std::make_shared<PendingImport>(
+ this, import, QQmlImports::ImportNoFlag);
+ pendingImport->precedence = QQmlImportInstance::Implicit;
if (!fetchQmldir(qmldirUrl, pendingImport, 1, &errors)) {
setError(errors);
return false;
@@ -169,61 +142,161 @@ bool QQmlTypeData::tryLoadFromDiskCache()
for (int i = 0, count = m_compiledData->importCount(); i < count; ++i) {
const QV4::CompiledData::Import *import = m_compiledData->importAt(i);
QList<QQmlError> errors;
- if (!addImport(import, &errors)) {
+ if (!addImport(import, {}, &errors)) {
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
+ error.setUrl(m_importCache->baseUrl());
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column()));
errors.prepend(error); // put it back on the list after filling out information.
setError(errors);
return false;
}
}
+ for (auto&& ic: ics) {
+ QString const nameString = m_compiledData->stringAt(ic.nameIndex);
+ auto importUrl = finalUrl();
+ importUrl.setFragment(nameString);
+ auto import = new QQmlImportInstance();
+ m_importCache->addInlineComponentImport(import, nameString, importUrl);
+ }
+
return true;
}
-void QQmlTypeData::createTypeAndPropertyCaches(
+template<>
+void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::allocateNamedObjects(
+ const QV4::CompiledData::Object *object) const
+{
+ Q_UNUSED(object);
+}
+
+template<>
+bool QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::markAsComponent(int index) const
+{
+ return m_compiler->objectAt(index)->hasFlag(QV4::CompiledData::Object::IsComponent);
+}
+
+template<>
+void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::setObjectId(int index) const
+{
+ Q_UNUSED(index)
+ // we cannot sanity-check the index here because bindings are sorted in a different order
+ // in the CU vs the IR.
+}
+
+template<>
+void QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::resolveGeneralizedGroupProperty(
+ const CompiledObject &component, CompiledBinding *binding)
+{
+ // We cannot make it fail here. It might be a custom-parsed property
+ for (int i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
+ const int candidateIndex = component.namedObjectsInComponentTable()[i];
+ if (m_compiler->objectAt(candidateIndex)->idNameIndex == binding->propertyNameIndex) {
+ m_propertyCaches->set(binding->value.objectIndex, m_propertyCaches->at(candidateIndex));
+ return;
+ }
+ }
+}
+
+template<>
+typename QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::AliasResolutionResult
+QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::resolveAliasesInObject(
+ const CompiledObject &component, int objectIndex, QQmlError *error)
+{
+ const CompiledObject *obj = m_compiler->objectAt(objectIndex);
+ for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
+ if (!alias->hasFlag(QV4::CompiledData::Alias::Resolved)) {
+ *error = qQmlCompileError( alias->referenceLocation, tr("Unresolved alias found"));
+ return NoAliasResolved;
+ }
+
+ if (alias->isAliasToLocalAlias() || alias->encodedMetaPropertyIndex == -1)
+ continue;
+
+ const int targetObjectIndex
+ = objectForId(m_compiler, component, alias->targetObjectId());
+ const int coreIndex
+ = QQmlPropertyIndex::fromEncoded(alias->encodedMetaPropertyIndex).coreIndex();
+
+ QQmlPropertyCache::ConstPtr targetCache = m_propertyCaches->at(targetObjectIndex);
+ Q_ASSERT(targetCache);
+
+ if (!targetCache->property(coreIndex))
+ return SomeAliasesResolved;
+ }
+
+ return AllAliasesResolved;
+}
+
+template<>
+bool QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::wrapImplicitComponent(
+ const QV4::CompiledData::Binding *binding)
+{
+ // This should have been done when creating the CU.
+ Q_UNUSED(binding);
+ return false;
+}
+
+QQmlError QQmlTypeData::createTypeAndPropertyCaches(
const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- const QV4::ResolvedTypeReferenceMap &resolvedTypeCache)
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
{
Q_ASSERT(m_compiledData);
m_compiledData->typeNameCache = typeNameCache;
m_compiledData->resolvedTypes = resolvedTypeCache;
+ m_compiledData->inlineComponentData = m_inlineComponentData;
QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings;
{
- QQmlPropertyCacheCreator<QV4::ExecutableCompilationUnit> propertyCacheCreator(
+ QQmlPropertyCacheCreator<QV4::CompiledData::CompilationUnit> propertyCacheCreator(
&m_compiledData->propertyCaches, &pendingGroupPropertyBindings, engine,
- m_compiledData.data(), &m_importCache);
- QQmlJS::DiagnosticMessage error = propertyCacheCreator.buildMetaObjects();
- if (error.isValid()) {
- setError(error);
- return;
- }
- }
+ m_compiledData.data(), m_importCache.data(), typeClassName());
- QQmlPropertyCacheAliasCreator<QV4::ExecutableCompilationUnit> aliasCreator(
- &m_compiledData->propertyCaches, m_compiledData.data());
- aliasCreator.appendAliasPropertiesToMetaObjects(engine);
+ QQmlError error = propertyCacheCreator.verifyNoICCycle();
+ if (error.isValid())
+ return error;
- pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_compiledData->propertyCaches);
+ QQmlPropertyCacheCreatorBase::IncrementalResult result;
+ do {
+ result = propertyCacheCreator.buildMetaObjectsIncrementally();
+ if (result.error.isValid()) {
+ return result.error;
+ } else {
+ QQmlComponentAndAliasResolver resolver(
+ m_compiledData.data(), engine, &m_compiledData->propertyCaches);
+ if (const QQmlError error = resolver.resolve(result.processedRoot);
+ error.isValid()) {
+ return error;
+ }
+ pendingGroupPropertyBindings.resolveMissingPropertyCaches(
+ &m_compiledData->propertyCaches);
+ pendingGroupPropertyBindings.clear(); // anything that can be processed is now processed
+ }
+
+ } while (result.canResume);
+ }
+
+ pendingGroupPropertyBindings.resolveMissingPropertyCaches(&m_compiledData->propertyCaches);
+ return QQmlError();
}
-static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeReference> &typeRefs, QCryptographicHash *hash, QQmlEngine *engine)
+static bool addTypeReferenceChecksumsToHash(
+ const QList<QQmlTypeData::TypeReference> &typeRefs,
+ QHash<quintptr, QByteArray> *checksums, QCryptographicHash *hash)
{
for (const auto &typeRef: typeRefs) {
if (typeRef.typeData) {
const auto unit = typeRef.typeData->compilationUnit()->unitData();
- hash->addData(unit->md5Checksum, sizeof(unit->md5Checksum));
- } else if (typeRef.type.isValid()) {
- const auto propertyCache = QQmlEnginePrivate::get(engine)->cache(typeRef.type.metaObject());
+ hash->addData({unit->md5Checksum, sizeof(unit->md5Checksum)});
+ } else if (const QMetaObject *mo = typeRef.type.metaObject()) {
+ const auto propertyCache = QQmlMetaType::propertyCache(mo);
bool ok = false;
- hash->addData(propertyCache->checksum(&ok));
+ hash->addData(propertyCache->checksum(checksums, &ok));
if (!ok)
return false;
}
@@ -231,28 +304,78 @@ static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeRefere
return true;
}
+// local helper function for inline components
+namespace {
+using InlineComponentData = QV4::CompiledData::InlineComponentData;
+
+template<typename ObjectContainer>
+void setupICs(
+ const ObjectContainer &container, QHash<QString, InlineComponentData> *icData,
+ const QUrl &baseUrl,
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit) {
+ Q_ASSERT(icData->empty());
+ for (int i = 0; i != container->objectCount(); ++i) {
+ auto root = container->objectAt(i);
+ for (auto it = root->inlineComponentsBegin(); it != root->inlineComponentsEnd(); ++it) {
+ // We cannot re-use a previously finalized inline component type here. We need our own.
+ // We can and should re-use speculative type references, though.
+ InlineComponentData icDatum(
+ QQmlMetaType::findInlineComponentType(
+ baseUrl, container->stringAt(it->nameIndex), compilationUnit),
+ int(it->objectIndex), int(it->nameIndex), 0, 0, 0);
+
+ icData->insert(container->stringAt(it->nameIndex), icDatum);
+ }
+ }
+};
+}
+
+template<typename Container>
+void QQmlTypeData::setCompileUnit(const Container &container)
+{
+ for (int i = 0; i != container->objectCount(); ++i) {
+ auto const root = container->objectAt(i);
+ for (auto it = root->inlineComponentsBegin(); it != root->inlineComponentsEnd(); ++it) {
+ auto *typeRef = m_compiledData->resolvedType(it->nameIndex);
+
+ // We don't want the type reference to keep a strong reference to the compilation unit
+ // here. The compilation unit owns the type reference, and having a strong reference
+ // would prevent the compilation unit from ever getting deleted. We can still be sure
+ // that the compilation unit outlives the type reference, due to ownership.
+ typeRef->setReferencesCompilationUnit(false);
+
+ typeRef->setCompilationUnit(m_compiledData); // share compilation unit
+ }
+ }
+}
+
void QQmlTypeData::done()
{
auto cleanup = qScopeGuard([this]{
+ m_backupSourceCode = SourceCodeData();
m_document.reset();
m_typeReferences.clear();
- if (isError())
- m_compiledData = nullptr;
+ if (isError()) {
+ const auto encounteredErrors = errors();
+ for (const QQmlError &e : encounteredErrors)
+ qCDebug(DBG_DISK_CACHE) << e.toString();
+ m_compiledData.reset();
+ }
});
if (isError())
return;
// Check all script dependencies for errors
- for (int ii = 0; ii < m_scripts.count(); ++ii) {
+ for (int ii = 0; ii < m_scripts.size(); ++ii) {
const ScriptReference &script = m_scripts.at(ii);
Q_ASSERT(script.script->isCompleteOrError());
if (script.script->isError()) {
QList<QQmlError> errors = script.script->errors();
QQmlError error;
error.setUrl(url());
- error.setLine(script.location.line);
- error.setColumn(script.location.column);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column()));
error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
errors.prepend(error);
setError(errors);
@@ -261,48 +384,73 @@ void QQmlTypeData::done()
}
// Check all type dependencies for errors
- for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); it != end;
+ auto createError = [&](const TypeReference &type , const QString &message) {
+ QList<QQmlError> errors = type.typeData ? type.typeData->errors() : QList<QQmlError>{};
+ QQmlError error;
+ error.setUrl(url());
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column()));
+ error.setDescription(message);
+ errors.prepend(error);
+ setError(errors);
+ };
+ for (auto it = std::as_const(m_resolvedTypes).begin(), end = std::as_const(m_resolvedTypes).end(); it != end;
++it) {
const TypeReference &type = *it;
- Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
+ Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError() || type.type.isInlineComponentType());
+
+ if (type.type.isInlineComponentType()) {
+ const QUrl url = type.type.sourceUrl();
+ if (!QQmlMetaType::equalBaseUrls(url, finalUrl())
+ && !QQmlMetaType::obtainCompilationUnit(type.type.typeId())) {
+ const QString &typeName = stringAt(it.key());
+ int lastDot = typeName.lastIndexOf(u'.');
+ createError(
+ type,
+ QQmlTypeLoader::tr("Type %1 has no inline component type called %2")
+ .arg(QStringView{typeName}.left(lastDot), type.type.elementName()));
+ return;
+ }
+ }
if (type.typeData && type.typeData->isError()) {
- const QString typeName = stringAt(it.key());
-
- QList<QQmlError> errors = type.typeData->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(type.location.line);
- error.setColumn(type.location.column);
- error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
- errors.prepend(error);
- setError(errors);
+ const QString &typeName = stringAt(it.key());
+ createError(type, QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
return;
}
}
// Check all composite singleton type dependencies for errors
- for (int ii = 0; ii < m_compositeSingletons.count(); ++ii) {
+ for (int ii = 0; ii < m_compositeSingletons.size(); ++ii) {
const TypeReference &type = m_compositeSingletons.at(ii);
Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
if (type.typeData && type.typeData->isError()) {
QString typeName = type.type.qmlTypeName();
- QList<QQmlError> errors = type.typeData->errors();
- QQmlError error;
- error.setUrl(url());
- error.setLine(type.location.line);
- error.setColumn(type.location.column);
- error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
- errors.prepend(error);
- setError(errors);
+ createError(type, QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
return;
}
}
+ if (QQmlPropertyCacheCreatorBase::canCreateClassNameTypeByUrl(finalUrl())) {
+ const bool isSingleton = m_document
+ ? m_document.data()->isSingleton()
+ : (m_compiledData->unitData()->flags & QV4::CompiledData::Unit::IsSingleton);
+ m_qmlType = QQmlMetaType::findCompositeType(
+ finalUrl(), m_compiledData, isSingleton
+ ? QQmlMetaType::Singleton
+ : QQmlMetaType::NonSingleton);
+ m_typeClassName = QByteArray(m_qmlType.typeId().name()).chopped(1);
+ }
+
+ if (m_document)
+ setupICs(m_document, &m_inlineComponentData, finalUrl(), m_compiledData);
+ else
+ setupICs(m_compiledData, &m_inlineComponentData, finalUrl(), m_compiledData);
+
+ QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache;
QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
- QV4::ResolvedTypeReferenceMap resolvedTypeCache;
{
- QQmlJS::DiagnosticMessage error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
+ QQmlError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
if (error.isValid()) {
setError(error);
qDeleteAll(resolvedTypeCache);
@@ -310,48 +458,81 @@ void QQmlTypeData::done()
}
}
- QQmlEngine *const engine = typeLoader()->engine();
-
- const auto dependencyHasher = [engine, &resolvedTypeCache, this]() {
+ const auto dependencyHasher = [&resolvedTypeCache, this]() {
QCryptographicHash hash(QCryptographicHash::Md5);
- return (resolvedTypeCache.addToHash(&hash, engine)
- && ::addTypeReferenceChecksumsToHash(m_compositeSingletons, &hash, engine))
+ return (resolvedTypeCache.addToHash(&hash, typeLoader()->checksumCache())
+ && ::addTypeReferenceChecksumsToHash(
+ m_compositeSingletons, typeLoader()->checksumCache(), &hash))
? hash.result()
: QByteArray();
};
// verify if any dependencies changed if we're using a cache
- if (m_document.isNull() && !m_compiledData->verifyChecksum(dependencyHasher)) {
- qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->fileName();
- if (!loadFromSource())
- return;
- m_backupSourceCode = SourceCodeData();
- m_compiledData = nullptr;
+ if (m_document.isNull()) {
+ const QQmlError error = createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
+ if (!error.isValid() && m_compiledData->verifyChecksum(dependencyHasher)) {
+ setCompileUnit(m_compiledData);
+ } else {
+
+ if (error.isValid()) {
+ qCDebug(DBG_DISK_CACHE)
+ << "Failed to create property caches for"
+ << m_compiledData->fileName()
+ << "because" << error.description();
+ } else {
+ qCDebug(DBG_DISK_CACHE)
+ << "Checksum mismatch for cached version of"
+ << m_compiledData->fileName();
+ }
+
+ if (!loadFromSource())
+ return;
+
+ // We want to keep our resolve types ...
+ m_compiledData->resolvedTypes.clear();
+ // ... but we don't want the property caches we've created for the broken CU.
+ for (QV4::ResolvedTypeReference *ref: std::as_const(resolvedTypeCache)) {
+ const auto compilationUnit = ref->compilationUnit();
+ if (compilationUnit.isNull()) {
+ // Inline component references without CU belong to the surrounding CU.
+ // We have to clear them. Inline component references to other documents
+ // have a CU.
+ if (!ref->type().isInlineComponentType())
+ continue;
+ } else if (compilationUnit != m_compiledData) {
+ continue;
+ }
+ ref->setTypePropertyCache(QQmlPropertyCache::ConstPtr());
+ ref->setCompilationUnit(QQmlRefPointer<QV4::CompiledData::CompilationUnit>());
+ }
+
+ m_compiledData.reset();
+ }
}
if (!m_document.isNull()) {
// Compile component
compile(typeNameCache, &resolvedTypeCache, dependencyHasher);
- } else {
- createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
+ if (isError())
+ return;
+ else
+ setCompileUnit(m_document);
}
- if (isError())
- return;
-
{
- QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(engine);
+ QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
+ m_compiledData->inlineComponentData = m_inlineComponentData;
{
// Sanity check property bindings
- QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData);
- QVector<QQmlJS::DiagnosticMessage> errors = validator.validate();
+ QQmlPropertyValidator validator(enginePrivate, m_importCache.data(), m_compiledData);
+ QVector<QQmlError> errors = validator.validate();
if (!errors.isEmpty()) {
setError(errors);
return;
}
}
- m_compiledData->finalizeCompositeType(enginePrivate);
+ m_compiledData->finalizeCompositeType(qmlType());
}
{
@@ -381,11 +562,11 @@ void QQmlTypeData::done()
{
// Collect imported scripts
- m_compiledData->dependentScripts.reserve(m_scripts.count());
- for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) {
+ m_compiledData->dependentScripts.reserve(m_scripts.size());
+ for (int scriptIndex = 0; scriptIndex < m_scripts.size(); ++scriptIndex) {
const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex);
- QStringRef qualifier(&script.qualifier);
+ QStringView qualifier(script.qualifier);
QString enclosingNamespace;
const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
@@ -394,7 +575,8 @@ void QQmlTypeData::done()
qualifier = qualifier.mid(lastDotIndex+1);
}
- m_compiledData->typeNameCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
+ m_compiledData->typeNameCache->add(
+ qualifier.toString(), scriptIndex, enclosingNamespace);
QQmlRefPointer<QQmlScriptData> scriptData = script.script->scriptData();
m_compiledData->dependentScripts << scriptData;
}
@@ -414,14 +596,28 @@ bool QQmlTypeData::loadImplicitImport()
{
m_implicitImportLoaded = true; // Even if we hit an error, count as loaded (we'd just keep hitting the error)
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+ m_importCache->setBaseUrl(finalUrl(), finalUrlString());
- QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
// For local urls, add an implicit import "." as most overridden lookup.
// This will also trigger the loading of the qmldir and the import of any native
// types from available plugins.
QList<QQmlError> implicitImportErrors;
- m_importCache.addImplicitImport(importDatabase, &implicitImportErrors);
+ QString localQmldir;
+ m_importCache->addImplicitImport(typeLoader(), &localQmldir, &implicitImportErrors);
+
+ // When loading with QQmlImports::ImportImplicit, the imports are _appended_ to the namespace
+ // in the order they are loaded. Therefore, the addImplicitImport above gets the highest
+ // precedence. This is in contrast to normal priority imports. Those are _prepended_ in the
+ // order they are loaded.
+ if (!localQmldir.isEmpty()) {
+ const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(localQmldir);
+ const QList<QQmlDirParser::Import> moduleImports
+ = QQmlMetaType::moduleImports(qmldir.typeNamespace(), QTypeRevision())
+ + qmldir.imports();
+ loadDependentImports(moduleImports, QString(), QTypeRevision(),
+ QQmlImportInstance::Implicit + 1, QQmlImports::ImportNoFlag,
+ &implicitImportErrors);
+ }
if (!implicitImportErrors.isEmpty()) {
setError(implicitImportErrors);
@@ -457,14 +653,17 @@ void QQmlTypeData::dataReceived(const SourceCodeData &data)
continueLoadFromIR();
}
-void QQmlTypeData::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit)
+void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit)
{
m_document.reset(new QmlIR::Document(isDebugging()));
- QQmlIRLoader loader(unit, m_document.data());
+ QQmlIRLoader loader(unit->qmlData, m_document.data());
loader.load();
m_document->jsModule.fileName = urlString();
m_document->jsModule.finalUrl = finalUrlString();
- m_document->javaScriptCompilationUnit = QV4::CompiledData::CompilationUnit(unit);
+ m_document->javaScriptCompilationUnit
+ = QQmlRefPointer<QV4::CompiledData::CompilationUnit>(
+ new QV4::CompiledData::CompilationUnit(unit->qmlData, unit->aotCompiledFunctions),
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit>::Adopt);
continueLoadFromIR();
}
@@ -484,12 +683,12 @@ bool QQmlTypeData::loadFromSource()
if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) {
QList<QQmlError> errors;
- errors.reserve(compiler.errors.count());
- for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) {
+ errors.reserve(compiler.errors.size());
+ for (const QQmlJS::DiagnosticMessage &msg : std::as_const(compiler.errors)) {
QQmlError e;
e.setUrl(url());
- e.setLine(msg.line);
- e.setColumn(msg.column);
+ e.setLine(qmlConvertSourceCoordinate<quint32, int>(msg.loc.startLine));
+ e.setColumn(qmlConvertSourceCoordinate<quint32, int>(msg.loc.startColumn));
e.setDescription(msg.message);
errors << e;
}
@@ -499,21 +698,31 @@ bool QQmlTypeData::loadFromSource()
return true;
}
-void QQmlTypeData::restoreIR(QV4::CompiledData::CompilationUnit &&unit)
+void QQmlTypeData::restoreIR(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit)
{
m_document.reset(new QmlIR::Document(isDebugging()));
- QQmlIRLoader loader(unit.unitData(), m_document.data());
+ QQmlIRLoader loader(unit->unitData(), m_document.data());
loader.load();
m_document->jsModule.fileName = urlString();
m_document->jsModule.finalUrl = finalUrlString();
- m_document->javaScriptCompilationUnit = std::move(unit);
+ m_document->javaScriptCompilationUnit = unit;
continueLoadFromIR();
}
void QQmlTypeData::continueLoadFromIR()
{
+ for (auto const& object: m_document->objects) {
+ for (auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it) {
+ QString const nameString = m_document->stringAt(it->nameIndex);
+ auto importUrl = finalUrl();
+ importUrl.setFragment(nameString);
+ auto import = new QQmlImportInstance(); // Note: The cache takes ownership of the QQmlImportInstance
+ m_importCache->addInlineComponentImport(import, nameString, importUrl);
+ }
+ }
+
m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
- m_importCache.setBaseUrl(finalUrl(), finalUrlString());
+ m_importCache->setBaseUrl(finalUrl(), finalUrlString());
// For remote URLs, we don't delay the loading of the implicit import
// because the loading probably requires an asynchronous fetch of the
@@ -526,8 +735,7 @@ void QQmlTypeData::continueLoadFromIR()
// This qmldir is for the implicit import
auto implicitImport = std::make_shared<PendingImport>();
implicitImport->uri = QLatin1String(".");
- implicitImport->majorVersion = -1;
- implicitImport->minorVersion = -1;
+ implicitImport->version = QTypeRevision();
QList<QQmlError> errors;
if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) {
@@ -539,15 +747,18 @@ void QQmlTypeData::continueLoadFromIR()
QList<QQmlError> errors;
- for (const QV4::CompiledData::Import *import : qAsConst(m_document->imports)) {
- if (!addImport(import, &errors)) {
+ for (const QV4::CompiledData::Import *import : std::as_const(m_document->imports)) {
+ if (!addImport(import, {}, &errors)) {
Q_ASSERT(errors.size());
- QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
- errors.prepend(error); // put it back on the list after filling out information.
- setError(errors);
+
+ // We're only interested in the chronoligically last error. The previous
+ // errors might be from unsuccessfully trying to load a module from the
+ // resource file system.
+ QQmlError error = errors.first();
+ error.setUrl(m_importCache->baseUrl());
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column()));
+ setError(error);
return;
}
}
@@ -567,12 +778,14 @@ void QQmlTypeData::allDependenciesDone()
for (auto keyIt = m_unresolvedImports.constBegin(),
keyEnd = m_unresolvedImports.constEnd();
keyIt != keyEnd; ++keyIt) {
- PendingImportPtr import = *keyIt;
+ const PendingImportPtr &import = *keyIt;
QQmlError error;
error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(import->uri));
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
+ error.setUrl(m_importCache->baseUrl());
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(
+ import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(
+ import->location.column()));
errors.prepend(error);
}
}
@@ -589,7 +802,7 @@ void QQmlTypeData::allDependenciesDone()
void QQmlTypeData::downloadProgressChanged(qreal p)
{
- for (int ii = 0; ii < m_callbacks.count(); ++ii) {
+ for (int ii = 0; ii < m_callbacks.size(); ++ii) {
TypeDataCallback *callback = m_callbacks.at(ii);
callback->typeDataProgress(this, p);
}
@@ -603,43 +816,58 @@ QString QQmlTypeData::stringAt(int index) const
}
void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
{
Q_ASSERT(m_compiledData.isNull());
- const bool typeRecompilation = m_document && m_document->javaScriptCompilationUnit.unitData()
- && (m_document->javaScriptCompilationUnit.unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation);
+ const bool typeRecompilation = m_document
+ && m_document->javaScriptCompilationUnit
+ && m_document->javaScriptCompilationUnit->unitData()
+ && (m_document->javaScriptCompilationUnit->unitData()->flags
+ & QV4::CompiledData::Unit::PendingTypeCompilation);
QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
- QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache, dependencyHasher);
- m_compiledData = compiler.compile();
- if (!m_compiledData) {
+ QQmlTypeCompiler compiler(
+ enginePrivate, this, m_document.data(), resolvedTypeCache, dependencyHasher);
+ auto compilationUnit = compiler.compile();
+ if (!compilationUnit) {
qDeleteAll(*resolvedTypeCache);
resolvedTypeCache->clear();
setError(compiler.compilationErrors());
return;
}
- const bool trySaveToDisk = (!diskCacheDisabled() || diskCacheForced())
- && !m_document->jsModule.debugMode && !typeRecompilation;
+ const bool trySaveToDisk = writeCacheFile() && !typeRecompilation;
if (trySaveToDisk) {
QString errorString;
- if (m_compiledData->saveToDisk(url(), &errorString)) {
+ if (compilationUnit->saveToDisk(url(), &errorString)) {
QString error;
- if (!m_compiledData->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
+ if (!compilationUnit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) {
// ignore error, keep using the in-memory compilation unit.
}
} else {
- qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->fileName() << "to disk:" << errorString;
+ qCDebug(DBG_DISK_CACHE) << "Error saving cached version of"
+ << compilationUnit->fileName() << "to disk:" << errorString;
}
}
+
+ m_compiledData = std::move(compilationUnit);
+ m_compiledData->typeNameCache = typeNameCache;
+ m_compiledData->resolvedTypes = *resolvedTypeCache;
+ m_compiledData->propertyCaches = std::move(*compiler.propertyCaches());
+ Q_ASSERT(m_compiledData->propertyCaches.count()
+ == static_cast<int>(m_compiledData->objectCount()));
}
void QQmlTypeData::resolveTypes()
{
+ // Load the implicit import since it may have additional scripts.
+ if (!m_implicitImportLoaded && !loadImplicitImport())
+ return;
+
// Add any imported scripts to our resolved set
- const auto resolvedScripts = m_importCache.resolvedScripts();
+ const auto resolvedScripts = m_importCache->resolvedScripts();
for (const QQmlImports::ScriptReference &script : resolvedScripts) {
QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(script.location);
addDependency(blob.data());
@@ -660,7 +888,7 @@ void QQmlTypeData::resolveTypes()
}
// Lets handle resolved composite singleton types
- const auto resolvedCompositeSingletons = m_importCache.resolvedCompositeSingletons();
+ const auto resolvedCompositeSingletons = m_importCache->resolvedCompositeSingletons();
for (const QQmlImports::CompositeSingletonReference &csRef : resolvedCompositeSingletons) {
TypeReference ref;
QString typeName;
@@ -672,17 +900,15 @@ void QQmlTypeData::resolveTypes()
typeName = csRef.typeName;
}
- int majorVersion = csRef.majorVersion > -1 ? csRef.majorVersion : -1;
- int minorVersion = csRef.minorVersion > -1 ? csRef.minorVersion : -1;
-
- if (!resolveType(typeName, majorVersion, minorVersion, ref, -1, -1, true,
- QQmlType::CompositeSingletonType))
+ QTypeRevision version = csRef.version;
+ if (!resolveType(typeName, version, ref, -1, -1, true, QQmlType::CompositeSingletonType))
return;
if (ref.type.isCompositeSingleton()) {
ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
- if (ref.typeData->status() == QQmlDataBlob::ResolvingDependencies || m_waitingOnMe.contains(ref.typeData.data())) {
- // TODO: give an error message? If so, we should record and show the path of the cycle.
+ if (ref.typeData->isWaiting() || m_waitingOnMe.contains(ref.typeData.data())) {
+ qCDebug(lcCycle) << "Possible cyclic dependency detected between"
+ << ref.typeData->urlString() << "and" << urlString();
continue;
}
addDependency(ref.typeData.data());
@@ -699,28 +925,36 @@ void QQmlTypeData::resolveTypes()
const bool reportErrors = unresolvedRef->errorWhenNotFound;
- int majorVersion = -1;
- int minorVersion = -1;
+ QTypeRevision version;
const QString name = stringAt(unresolvedRef.key());
- if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line,
- unresolvedRef->location.column, reportErrors,
- QQmlType::AnyRegistrationType) && reportErrors)
+ bool *selfReferenceDetection = unresolvedRef->needsCreation ? nullptr : &ref.selfReference;
+
+ if (!resolveType(name, version, ref, unresolvedRef->location.line(),
+ unresolvedRef->location.column(), reportErrors,
+ QQmlType::AnyRegistrationType, selfReferenceDetection) && reportErrors)
return;
- if (ref.type.isComposite()) {
+ if (ref.type.isComposite() && !ref.selfReference) {
ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
addDependency(ref.typeData.data());
}
- ref.majorVersion = majorVersion;
- ref.minorVersion = minorVersion;
-
- ref.location.line = unresolvedRef->location.line;
- ref.location.column = unresolvedRef->location.column;
+ if (ref.type.isInlineComponentType()) {
+ QUrl containingTypeUrl = ref.type.sourceUrl();
+ containingTypeUrl.setFragment(QString());
+ if (!containingTypeUrl.isEmpty()) {
+ auto typeData = typeLoader()->getType(containingTypeUrl);
+ if (typeData.data() != this) {
+ ref.typeData = typeData;
+ addDependency(typeData.data());
+ }
+ }
+ }
+ ref.version = version;
+ ref.location = unresolvedRef->location;
ref.needsCreation = unresolvedRef->needsCreation;
-
m_resolvedTypes.insert(unresolvedRef.key(), ref);
}
@@ -729,10 +963,9 @@ void QQmlTypeData::resolveTypes()
loadImplicitImport();
}
-QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches(
+QQmlError QQmlTypeData::buildTypeResolutionCaches(
QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache
- ) const
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache) const
{
typeNameCache->adopt(new QQmlTypeNameCache(m_importCache));
@@ -743,59 +976,88 @@ QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches(
for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
(*typeNameCache)->add(singleton.type.qmlTypeName(), singleton.type.sourceUrl(), singleton.prefix);
- m_importCache.populateCache(typeNameCache->data());
-
- QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
+ m_importCache->populateCache(typeNameCache->data());
for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) {
- QScopedPointer<QV4::ResolvedTypeReference> ref(new QV4::ResolvedTypeReference);
+ auto ref = std::make_unique<QV4::ResolvedTypeReference>();
QQmlType qmlType = resolvedType->type;
if (resolvedType->typeData) {
if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) {
return qQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName()));
}
- ref->compilationUnit = resolvedType->typeData->compilationUnit();
- } else if (qmlType.isValid()) {
- ref->type = qmlType;
- Q_ASSERT(ref->type.isValid());
+ ref->setCompilationUnit(resolvedType->typeData->compilationUnit());
+ if (resolvedType->type.isInlineComponentType()) {
+ // Inline component which is part of an already resolved type
+ QString icName = qmlType.elementName();
+ Q_ASSERT(!icName.isEmpty());
+
+ const auto compilationUnit = resolvedType->typeData->compilationUnit();
+ ref->setTypePropertyCache(compilationUnit->propertyCaches.at(
+ compilationUnit->inlineComponentId(icName)));
+ ref->setType(std::move(qmlType));
+ Q_ASSERT(ref->type().isInlineComponentType());
+ }
+ } else if (resolvedType->type.isInlineComponentType()) {
+ ref->setType(qmlType);
+
+ // Inline component
+ // If it's defined in the same file we're currently compiling, we don't want to use it.
+ // We're going to fill in the property caches later after all.
+ if (qmlType.isValid()
+ && !QQmlMetaType::equalBaseUrls(finalUrl(), qmlType.sourceUrl())) {
+
+ // this is required for inline components in singletons
+ const QMetaType type = qmlType.typeId();
+ if (auto unit = QQmlMetaType::obtainCompilationUnit(type)) {
+ ref->setCompilationUnit(std::move(unit));
+ ref->setTypePropertyCache(QQmlMetaType::propertyCacheForType(type));
+ }
+ }
+ } else if (qmlType.isValid() && !resolvedType->selfReference) {
+ ref->setType(qmlType);
+ Q_ASSERT(ref->type().isValid());
- if (resolvedType->needsCreation && !ref->type.isCreatable()) {
- QString reason = ref->type.noCreationReason();
+ if (resolvedType->needsCreation && !qmlType.isCreatable()) {
+ QString reason = qmlType.noCreationReason();
if (reason.isEmpty())
reason = tr("Element is not creatable.");
return qQmlCompileError(resolvedType->location, reason);
}
- if (ref->type.containsRevisionedAttributes()) {
- ref->typePropertyCache = engine->cache(ref->type,
- resolvedType->minorVersion);
+ if (qmlType.containsRevisionedAttributes()) {
+ // It can only have (revisioned) properties or methods if it has a metaobject
+ Q_ASSERT(qmlType.metaObject());
+ ref->setTypePropertyCache(
+ QQmlMetaType::propertyCache(qmlType, resolvedType->version));
}
}
- ref->majorVersion = resolvedType->majorVersion;
- ref->minorVersion = resolvedType->minorVersion;
+ ref->setVersion(resolvedType->version);
ref->doDynamicTypeCheck();
- resolvedTypeCache->insert(resolvedType.key(), ref.take());
+ resolvedTypeCache->insert(resolvedType.key(), ref.release());
}
- QQmlJS::DiagnosticMessage noError;
+ QQmlError noError;
return noError;
}
-bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
+bool QQmlTypeData::resolveType(const QString &typeName, QTypeRevision &version,
TypeReference &ref, int lineNumber, int columnNumber,
- bool reportErrors, QQmlType::RegistrationType registrationType)
+ bool reportErrors, QQmlType::RegistrationType registrationType,
+ bool *typeRecursionDetected)
{
QQmlImportNamespace *typeNamespace = nullptr;
QList<QQmlError> errors;
- bool typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
- &typeNamespace, &errors, registrationType);
+ bool typeFound = m_importCache->resolveType(
+ typeLoader(), typeName, &ref.type, &version, &typeNamespace, &errors, registrationType,
+ typeRecursionDetected);
if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
// Lazy loading of implicit import
if (loadImplicitImport()) {
// Try again to find the type
errors.clear();
- typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion,
- &typeNamespace, &errors, registrationType);
+ typeFound = m_importCache->resolveType(
+ typeLoader(), typeName, &ref.type, &version, &typeNamespace, &errors,
+ registrationType, typeRecursionDetected);
} else {
return false; //loadImplicitImport() hit an error, and called setError already
}
@@ -816,7 +1078,7 @@ bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &
// Description should come from error provided by addImport() function.
error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database"));
}
- error.setUrl(m_importCache.baseUrl());
+ error.setUrl(m_importCache->baseUrl());
error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(typeName).arg(error.description()));
}
@@ -833,12 +1095,14 @@ bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &
return true;
}
-void QQmlTypeData::scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &/*nameSpace*/)
+void QQmlTypeData::scriptImported(
+ const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location,
+ const QString &nameSpace, const QString &qualifier)
{
ScriptReference ref;
ref.script = blob;
ref.location = location;
- ref.qualifier = qualifier;
+ ref.qualifier = qualifier.isEmpty() ? nameSpace : qualifier + QLatin1Char('.') + nameSpace;
m_scripts << ref;
}
diff --git a/src/qml/qml/qqmltypedata_p.h b/src/qml/qml/qqmltypedata_p.h
index e1d0c900ea..97419b916b 100644
--- a/src/qml/qml/qqmltypedata_p.h
+++ b/src/qml/qml/qqmltypedata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPEDATA_P_H
#define QQMLTYPEDATA_P_H
@@ -62,13 +26,13 @@ class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
public:
struct TypeReference
{
- TypeReference() : majorVersion(0), minorVersion(0), needsCreation(true) {}
+ TypeReference() : version(QTypeRevision::zero()), needsCreation(true) {}
QV4::CompiledData::Location location;
QQmlType type;
- int majorVersion;
- int minorVersion;
+ QTypeRevision version;
QQmlRefPointer<QQmlTypeData> typeData;
+ bool selfReference = false;
QString prefix; // used by CompositeSingleton types
QString qualifiedName() const;
bool needsCreation;
@@ -85,13 +49,13 @@ private:
friend class QQmlTypeLoader;
QQmlTypeData(const QUrl &, QQmlTypeLoader *);
+ template<typename Container>
+ void setCompileUnit(const Container &container);
public:
~QQmlTypeData() override;
- const QList<ScriptReference> &resolvedScripts() const;
-
- QV4::ExecutableCompilationUnit *compilationUnit() const;
+ QV4::CompiledData::CompilationUnit *compilationUnit() const;
// Used by QQmlComponent to get notifications
struct TypeDataCallback {
@@ -102,38 +66,47 @@ public:
void registerCallback(TypeDataCallback *);
void unregisterCallback(TypeDataCallback *);
+ QQmlType qmlType(const QString &inlineComponentName = QString()) const;
+ QByteArray typeClassName() const { return m_typeClassName; }
+ SourceCodeData backupSourceCode() const { return m_backupSourceCode; }
+
protected:
void done() override;
void completed() override;
void dataReceived(const SourceCodeData &) override;
- void initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) override;
+ void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) override;
void allDependenciesDone() override;
void downloadProgressChanged(qreal) override;
QString stringAt(int index) const override;
private:
+ using InlineComponentData = QV4::CompiledData::InlineComponentData;
+
bool tryLoadFromDiskCache();
bool loadFromSource();
- void restoreIR(QV4::CompiledData::CompilationUnit &&unit);
+ void restoreIR(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit);
void continueLoadFromIR();
void resolveTypes();
- QQmlJS::DiagnosticMessage buildTypeResolutionCaches(
+ QQmlError buildTypeResolutionCaches(
QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
) const;
void compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
+ QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
- void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
- const QV4::ResolvedTypeReferenceMap &resolvedTypeCache);
- bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion,
+ QQmlError createTypeAndPropertyCaches(
+ const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
+ const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
+ bool resolveType(const QString &typeName, QTypeRevision &version,
TypeReference &ref, int lineNumber = -1, int columnNumber = -1,
bool reportErrors = true,
- QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType);
-
- void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override;
+ QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
+ bool *typeRecursionDetected = nullptr);
+ void scriptImported(
+ const QQmlRefPointer<QQmlScriptBlob> &blob, const QV4::CompiledData::Location &location,
+ const QString &nameSpace, const QString &qualifier) override;
SourceCodeData m_backupSourceCode; // used when cache verification fails.
QScopedPointer<QmlIR::Document> m_document;
@@ -150,7 +123,15 @@ private:
QMap<int, TypeReference> m_resolvedTypes;
bool m_typesResolved:1;
- QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compiledData;
+ // Used for self-referencing types, otherwise invalid.
+ QQmlType m_qmlType;
+ QByteArray m_typeClassName; // used for meta-object later
+
+ using CompilationUnitPtr = QQmlRefPointer<QV4::CompiledData::CompilationUnit>;
+
+ QHash<QString, InlineComponentData> m_inlineComponentData;
+
+ CompilationUnitPtr m_compiledData;
QList<TypeDataCallback *> m_callbacks;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 54f94d6a11..a74397bd93 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmltypeloader_p.h>
@@ -45,12 +9,15 @@
#include <private/qqmltypedata_p.h>
#include <private/qqmltypeloaderqmldircontent_p.h>
#include <private/qqmltypeloaderthread_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
#include <QtQml/qqmlabstracturlinterceptor.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlextensioninterface.h>
#include <QtQml/qqmlfile.h>
+#include <qtqml_tracepoints_p.h>
+
#include <QtCore/qdir.h>
#include <QtCore/qdiriterator.h>
#include <QtCore/qfile.h>
@@ -65,8 +32,6 @@
#define ASSERT_LOADTHREAD()
#endif
-DEFINE_BOOL_CONFIG_OPTION(disableDiskCache, QML_DISABLE_DISK_CACHE);
-DEFINE_BOOL_CONFIG_OPTION(forceDiskCache, QML_FORCE_DISK_CACHE);
QT_BEGIN_NAMESPACE
@@ -81,6 +46,9 @@ namespace {
};
}
+Q_TRACE_POINT(qtqml, QQmlCompiling_entry, const QUrl &url)
+Q_TRACE_POINT(qtqml, QQmlCompiling_exit)
+
/*!
\class QQmlTypeLoader
\brief The QQmlTypeLoader class abstracts loading files and their dependencies over the network.
@@ -123,8 +91,6 @@ void QQmlTypeLoader::invalidate()
// Need to delete the network replies after
// the loader thread is shutdown as it could be
// getting new replies while we clear them
- for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter)
- (*iter)->release();
m_networkReplies.clear();
#endif // qml_network
}
@@ -171,8 +137,8 @@ struct StaticLoader {
};
struct CachedLoader {
- const QV4::CompiledData::Unit *unit;
- CachedLoader(const QV4::CompiledData::Unit *unit) : unit(unit) {}
+ const QQmlPrivate::CachedQmlUnit *unit;
+ CachedLoader(const QQmlPrivate::CachedQmlUnit *unit) : unit(unit) {}
void loadThread(QQmlTypeLoader *loader, QQmlDataBlob *blob) const
{
@@ -216,9 +182,7 @@ void QQmlTypeLoader::doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode)
} else {
Q_ASSERT(mode == Synchronous);
while (!blob->isCompleteOrError()) {
- unlock();
m_thread->waitForNextMessage();
- lock();
}
}
}
@@ -244,26 +208,26 @@ void QQmlTypeLoader::loadWithStaticData(QQmlDataBlob *blob, const QByteArray &da
doLoad(StaticLoader(data), blob, mode);
}
-void QQmlTypeLoader::loadWithCachedUnit(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit, Mode mode)
+void QQmlTypeLoader::loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit, Mode mode)
{
doLoad(CachedLoader(unit), blob, mode);
}
-void QQmlTypeLoader::loadWithStaticDataThread(QQmlDataBlob *blob, const QByteArray &data)
+void QQmlTypeLoader::loadWithStaticDataThread(const QQmlDataBlob::Ptr &blob, const QByteArray &data)
{
ASSERT_LOADTHREAD();
setData(blob, data);
}
-void QQmlTypeLoader::loadWithCachedUnitThread(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit)
+void QQmlTypeLoader::loadWithCachedUnitThread(const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit)
{
ASSERT_LOADTHREAD();
setCachedUnit(blob, unit);
}
-void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
+void QQmlTypeLoader::loadThread(const QQmlDataBlob::Ptr &blob)
{
ASSERT_LOADTHREAD();
@@ -289,7 +253,7 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
return;
}
- blob->m_data.setProgress(0xFF);
+ blob->m_data.setProgress(1.f);
if (blob->m_data.isAsync())
m_thread->callDownloadProgressChanged(blob, 1.);
@@ -299,7 +263,6 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
#if QT_CONFIG(qml_network)
QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(blob->m_url));
QQmlTypeLoaderNetworkReplyProxy *nrp = m_thread->networkReplyProxy();
- blob->addref();
m_networkReplies.insert(reply, blob);
if (reply->isFinished()) {
@@ -331,7 +294,7 @@ void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
reply->deleteLater();
- QQmlDataBlob *blob = m_networkReplies.take(reply);
+ QQmlRefPointer<QQmlDataBlob> blob = m_networkReplies.take(reply);
Q_ASSERT(blob);
@@ -347,7 +310,7 @@ void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(url));
QObject *nrp = m_thread->networkReplyProxy();
QObject::connect(reply, SIGNAL(finished()), nrp, SLOT(finished()));
- m_networkReplies.insert(reply, blob);
+ m_networkReplies.insert(reply, std::move(blob));
#ifdef DATABLOB_DEBUG
qWarning("QQmlDataBlob: redirected to %s", qPrintable(blob->finalUrlString()));
#endif
@@ -361,8 +324,6 @@ void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
QByteArray data = reply->readAll();
setData(blob, data);
}
-
- blob->release();
}
void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply,
@@ -370,12 +331,12 @@ void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply,
{
Q_ASSERT(m_thread->isThisThread());
- QQmlDataBlob *blob = m_networkReplies.value(reply);
+ const QQmlRefPointer<QQmlDataBlob> blob = m_networkReplies.value(reply);
Q_ASSERT(blob);
if (bytesTotal != 0) {
- quint8 progress = 0xFF * (qreal(bytesReceived) / qreal(bytesTotal));
+ qreal progress = (qreal(bytesReceived) / qreal(bytesTotal));
blob->m_data.setProgress(progress);
if (blob->m_data.isAsync())
m_thread->callDownloadProgressChanged(blob, blob->m_data.progress());
@@ -391,7 +352,7 @@ QQmlEngine *QQmlTypeLoader::engine() const
return m_engine;
}
-/*!
+/*! \internal
Call the initializeEngine() method on \a iface. Used by QQmlImportDatabase to ensure it
gets called in the correct thread.
*/
@@ -419,7 +380,7 @@ void QQmlTypeLoader::initializeEngine(QQmlExtensionInterface *iface, const char
doInitializeEngine(iface, m_thread, engine(), uri);
}
-void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
+void QQmlTypeLoader::setData(const QQmlDataBlob::Ptr &blob, const QByteArray &data)
{
QQmlDataBlob::SourceCodeData d;
d.inlineSourceCode = QString::fromUtf8(data);
@@ -427,16 +388,17 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data)
setData(blob, d);
}
-void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName)
+void QQmlTypeLoader::setData(const QQmlDataBlob::Ptr &blob, const QString &fileName)
{
QQmlDataBlob::SourceCodeData d;
d.fileInfo = QFileInfo(fileName);
setData(blob, d);
}
-void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeData &d)
+void QQmlTypeLoader::setData(const QQmlDataBlob::Ptr &blob, const QQmlDataBlob::SourceCodeData &d)
{
- QQmlCompilingProfiler prof(profiler(), blob);
+ Q_TRACE_SCOPE(QQmlCompiling, blob->url());
+ QQmlCompilingProfiler prof(profiler(), blob.data());
blob->m_inCallback = true;
@@ -453,9 +415,10 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeD
blob->tryDone();
}
-void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit)
+void QQmlTypeLoader::setCachedUnit(const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit)
{
- QQmlCompilingProfiler prof(profiler(), blob);
+ Q_TRACE_SCOPE(QQmlCompiling, blob->url());
+ QQmlCompilingProfiler prof(profiler(), blob.data());
blob->m_inCallback = true;
@@ -478,18 +441,21 @@ void QQmlTypeLoader::shutdownThread()
m_thread->shutdown();
}
-QQmlTypeLoader::Blob::PendingImport::PendingImport(QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import)
+QQmlTypeLoader::Blob::PendingImport::PendingImport(
+ QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import,
+ QQmlImports::ImportFlags flags)
+ : uri(blob->stringAt(import->uriIndex))
+ , qualifier(blob->stringAt(import->qualifierIndex))
+ , type(static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type)))
+ , location(import->location)
+ , flags(flags)
+ , version(import->version)
{
- type = static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type));
- uri = blob->stringAt(import->uriIndex);
- qualifier = blob->stringAt(import->qualifierIndex);
- majorVersion = import->majorVersion;
- minorVersion = import->minorVersion;
- location = import->location;
}
QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
- : QQmlDataBlob(url, type, loader), m_importCache(loader)
+ : QQmlDataBlob(url, type, loader)
+ , m_importCache(new QQmlImports(), QQmlRefPointer<QQmlImports>::Adopt)
{
}
@@ -501,8 +467,7 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, PendingImportPtr import,
{
QQmlRefPointer<QQmlQmldirData> data = typeLoader()->getQmldir(url);
- data->setImport(this, std::move(import));
- data->setPriority(this, priority);
+ data->setPriority(this, std::move(import), priority);
if (data->status() == Error) {
// This qmldir must not exist - which is not an error
@@ -517,188 +482,387 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, PendingImportPtr import,
return true;
}
-bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, PendingImportPtr import, QList<QQmlError> *errors)
+/*!
+ * \internal
+ * Import any qualified scripts of for \a import as listed in \a qmldir.
+ * Precondition is that \a import is actually qualified.
+ */
+void QQmlTypeLoader::Blob::importQmldirScripts(
+ const QQmlTypeLoader::Blob::PendingImportPtr &import,
+ const QQmlTypeLoaderQmldirContent &qmldir, const QUrl &qmldirUrl)
+{
+ const auto qmldirScripts = qmldir.scripts();
+ for (const QQmlDirParser::Script &script : qmldirScripts) {
+ const QUrl scriptUrl = qmldirUrl.resolved(QUrl(script.fileName));
+ QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
+ addDependency(blob.data());
+ scriptImported(blob, import->location, script.nameSpace, import->qualifier);
+ }
+}
+
+template<typename URL>
+void postProcessQmldir(
+ QQmlTypeLoader::Blob *self,
+ const QQmlTypeLoader::Blob::PendingImportPtr &import, const QString &qmldirFilePath,
+ const URL &qmldirUrl)
+{
+ const QQmlTypeLoaderQmldirContent qmldir = self->typeLoader()->qmldirContent(qmldirFilePath);
+ if (!import->qualifier.isEmpty())
+ self->importQmldirScripts(import, qmldir, QUrl(qmldirUrl));
+
+ if (qmldir.plugins().isEmpty()) {
+ // If the qmldir does not register a plugin, we might still have declaratively
+ // registered types (if we are dealing with an application instead of a library)
+ // We should use module name given in the qmldir rather than the one given by the
+ // import since the import may be a directory import.
+ auto module = QQmlMetaType::typeModule(qmldir.typeNamespace(), import->version);
+ if (!module)
+ QQmlMetaType::qmlRegisterModuleTypes(qmldir.typeNamespace());
+ // else: If the module already exists, the types must have been already registered
+ }
+}
+
+bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
{
QString qmldirIdentifier = data->urlString();
QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char('/')) + 1);
typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
- if (!m_importCache.updateQmldirContent(typeLoader()->importDatabase(), import->uri, import->qualifier, qmldirIdentifier, qmldirUrl, errors))
+ const QTypeRevision version = m_importCache->updateQmldirContent(
+ typeLoader(), import->uri, import->qualifier, qmldirIdentifier, qmldirUrl, errors);
+ if (!version.isValid())
return false;
- if (!loadImportDependencies(import, qmldirIdentifier, errors))
+ // Use more specific version for dependencies if possible
+ if (version.hasMajorVersion())
+ import->version = version;
+
+ if (!loadImportDependencies(import, qmldirIdentifier, import->flags, errors))
return false;
- import->priority = data->priority(this);
+ import->priority = 0;
// Release this reference at destruction
m_qmldirs << data;
- if (!import->qualifier.isEmpty()) {
- // Does this library contain any qualified scripts?
- QUrl libraryUrl(qmldirUrl);
- const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
- const auto qmldirScripts = qmldir.scripts();
- for (const QQmlDirParser::Script &script : qmldirScripts) {
- QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
- QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
- addDependency(blob.data());
-
- scriptImported(blob, import->location, script.nameSpace, import->qualifier);
- }
- }
+ postProcessQmldir(this, import, qmldirIdentifier, qmldirUrl);
+ return true;
+}
+bool QQmlTypeLoader::Blob::addScriptImport(const QQmlTypeLoader::Blob::PendingImportPtr &import)
+{
+ const QUrl url(import->uri);
+ QQmlTypeLoader *loader = typeLoader();
+ QQmlRefPointer<QQmlScriptBlob> blob = loader->injectedScript(url);
+ if (!blob)
+ blob = loader->getScript(finalUrl().resolved(url));
+ else
+ Q_ASSERT(blob->status() == QQmlDataBlob::Status::Complete);
+ addDependency(blob.data());
+ scriptImported(blob, import->location, import->qualifier, QString());
return true;
}
-bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::addFileImport(const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
{
- return addImport(std::make_shared<PendingImport>(this, import), errors);
+ QQmlImports::ImportFlags flags;
+
+ QUrl importUrl(import->uri);
+ QString path = importUrl.path();
+ path.append(QLatin1String(path.endsWith(QLatin1Char('/')) ? "qmldir" : "/qmldir"));
+ importUrl.setPath(path);
+ QUrl qmldirUrl = finalUrl().resolved(importUrl);
+ if (!QQmlImports::isLocal(qmldirUrl)) {
+ // This is a remote file; the import is currently incomplete
+ flags = QQmlImports::ImportIncomplete;
+ }
+
+ const QTypeRevision version = m_importCache->addFileImport(
+ typeLoader(), import->uri, import->qualifier, import->version, flags,
+ import->precedence, nullptr, errors);
+ if (!version.isValid())
+ return false;
+
+ // Use more specific version for the qmldir if possible
+ if (version.hasMajorVersion())
+ import->version = version;
+
+ if (flags & QQmlImports::ImportIncomplete) {
+ if (!fetchQmldir(qmldirUrl, import, 1, errors))
+ return false;
+ } else {
+ const QString qmldirFilePath = QQmlFile::urlToLocalFileOrQrc(qmldirUrl);
+ if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors))
+ return false;
+
+ postProcessQmldir(this, import, qmldirFilePath, qmldirUrl);
+ }
+
+ return true;
}
-bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr import, QList<QQmlError> *errors)
+static void addDependencyImportError(
+ const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
{
- Q_ASSERT(errors);
+ QQmlError error;
+ QString reason = errors->front().description();
+ if (reason.size() > 512)
+ reason = reason.first(252) + QLatin1String("... ...") + reason.last(252);
+ if (import->version.hasMajorVersion()) {
+ error.setDescription(QQmlImportDatabase::tr(
+ "module \"%1\" version %2.%3 cannot be imported because:\n%4")
+ .arg(import->uri).arg(import->version.majorVersion())
+ .arg(import->version.hasMinorVersion()
+ ? QString::number(import->version.minorVersion())
+ : QLatin1String("x"))
+ .arg(reason));
+ } else {
+ error.setDescription(QQmlImportDatabase::tr("module \"%1\" cannot be imported because:\n%2")
+ .arg(import->uri, reason));
+ }
+ errors->prepend(error);
+}
+bool QQmlTypeLoader::Blob::addLibraryImport(const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
+{
QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
- if (import->type == QV4::CompiledData::Import::ImportScript) {
- QUrl scriptUrl = finalUrl().resolved(QUrl(import->uri));
- QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
- addDependency(blob.data());
+ const QQmlImportDatabase::LocalQmldirSearchLocation searchMode =
+ QQmlMetaType::isStronglyLockedModule(import->uri, import->version)
+ ? QQmlImportDatabase::QmldirCacheOnly
+ : QQmlImportDatabase::QmldirFileAndCache;
+
+ const QQmlImportDatabase::LocalQmldirResult qmldirResult
+ = importDatabase->locateLocalQmldir(
+ import->uri, import->version, searchMode,
+ [&](const QString &qmldirFilePath, const QString &qmldirUrl) {
+ // This is a local library import
+ const QTypeRevision actualVersion = m_importCache->addLibraryImport(
+ typeLoader(), import->uri, import->qualifier, import->version, qmldirFilePath,
+ qmldirUrl, import->flags, import->precedence, errors);
+ if (!actualVersion.isValid())
+ return false;
- scriptImported(blob, import->location, import->qualifier, QString());
- } else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
- QString qmldirFilePath;
- QString qmldirUrl;
+ // Use more specific version for dependencies if possible
+ if (actualVersion.hasMajorVersion())
+ import->version = actualVersion;
- if (m_importCache.locateQmldir(importDatabase, import->uri, import->majorVersion, import->minorVersion,
- &qmldirFilePath, &qmldirUrl)) {
- // This is a local library import
- if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
- import->minorVersion, qmldirFilePath, qmldirUrl, false, errors))
- return false;
+ if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors)) {
+ addDependencyImportError(import, errors);
+ return false;
+ }
- if (!loadImportDependencies(import, qmldirFilePath, errors))
- return false;
+ postProcessQmldir(this, import, qmldirFilePath, qmldirUrl);
+ return true;
+ });
- if (!import->qualifier.isEmpty()) {
- // Does this library contain any qualified scripts?
- QUrl libraryUrl(qmldirUrl);
- const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirFilePath);
- const auto qmldirScripts = qmldir.scripts();
- for (const QQmlDirParser::Script &script : qmldirScripts) {
- QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
- QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(scriptUrl);
- addDependency(blob.data());
-
- scriptImported(blob, import->location, script.nameSpace, import->qualifier);
- }
- }
- } else {
- // Is this a module?
- if (QQmlMetaType::isAnyModule(import->uri)) {
- if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
- import->minorVersion, QString(), QString(), false, errors))
- return false;
- } else {
- // We haven't yet resolved this import
- m_unresolvedImports << import;
-
- QQmlAbstractUrlInterceptor *interceptor = typeLoader()->engine()->urlInterceptor();
-
- // Query any network import paths for this library.
- // Interceptor might redirect local paths.
- QStringList remotePathList = importDatabase->importPathList(
- interceptor ? QQmlImportDatabase::LocalOrRemote
- : QQmlImportDatabase::Remote);
- if (!remotePathList.isEmpty()) {
- // Add this library and request the possible locations for it
- if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
- import->minorVersion, QString(), QString(), true, errors))
- return false;
+ switch (qmldirResult) {
+ case QQmlImportDatabase::QmldirFound:
+ return true;
+ case QQmlImportDatabase::QmldirNotFound: {
+ if (!loadImportDependencies(import, QString(), import->flags, errors)) {
+ addDependencyImportError(import, errors);
+ return false;
+ }
+ break;
+ }
+ case QQmlImportDatabase::QmldirInterceptedToRemote:
+ break;
+ case QQmlImportDatabase::QmldirRejected:
+ return false;
+ }
- // Probe for all possible locations
- int priority = 0;
- const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(import->uri, remotePathList, import->majorVersion, import->minorVersion);
- for (const QString &qmldirPath : qmlDirPaths) {
- if (interceptor) {
- QUrl url = interceptor->intercept(
- QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
- QQmlAbstractUrlInterceptor::QmldirFile);
- if (!QQmlFile::isLocalFile(url)
- && !fetchQmldir(url, import, ++priority, errors)) {
- return false;
- }
- } else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) {
- return false;
- }
+ // If there is a qmldir we cannot see, yet, then we have to wait.
+ // The qmldir might contain import directives.
+ if (qmldirResult != QQmlImportDatabase::QmldirInterceptedToRemote && (
+ // Major version of module already registered:
+ // We believe that the registration is complete.
+ QQmlMetaType::typeModule(import->uri, import->version)
- }
- }
- }
+ // Otherwise, try to register further module types.
+ || QQmlMetaType::qmlRegisterModuleTypes(import->uri)
+
+ // Otherwise, there is no way to register any further types.
+ // Try with any module of that name.
+ || QQmlMetaType::latestModuleVersion(import->uri).isValid())) {
+
+ if (!m_importCache->addLibraryImport(
+ typeLoader(), import->uri, import->qualifier, import->version, QString(),
+ QString(), import->flags, import->precedence, errors).isValid()) {
+ return false;
}
} else {
- Q_ASSERT(import->type == QV4::CompiledData::Import::ImportFile);
-
- bool incomplete = false;
-
- QUrl importUrl(import->uri);
- QString path = importUrl.path();
- path.append(QLatin1String(path.endsWith(QLatin1Char('/')) ? "qmldir" : "/qmldir"));
- importUrl.setPath(path);
- QUrl qmldirUrl = finalUrl().resolved(importUrl);
- if (!QQmlImports::isLocal(qmldirUrl)) {
- // This is a remote file; the import is currently incomplete
- incomplete = true;
- }
+ // We haven't yet resolved this import
+ m_unresolvedImports << import;
+
+ const QQmlEngine *engine = typeLoader()->engine();
+ const bool hasInterceptors
+ = !(QQmlEnginePrivate::get(engine)->urlInterceptors.isEmpty());
+
+ // Query any network import paths for this library.
+ // Interceptor might redirect local paths.
+ QStringList remotePathList = importDatabase->importPathList(
+ hasInterceptors ? QQmlImportDatabase::LocalOrRemote
+ : QQmlImportDatabase::Remote);
+ if (!remotePathList.isEmpty()) {
+ // Add this library and request the possible locations for it
+ const QTypeRevision version = m_importCache->addLibraryImport(
+ typeLoader(), import->uri, import->qualifier, import->version, QString(),
+ QString(), import->flags | QQmlImports::ImportIncomplete, import->precedence,
+ errors);
+
+ if (!version.isValid())
+ return false;
- if (!m_importCache.addFileImport(importDatabase, import->uri, import->qualifier, import->majorVersion,
- import->minorVersion, incomplete, errors))
- return false;
+ // Use more specific version for finding the qmldir if possible
+ if (version.hasMajorVersion())
+ import->version = version;
+
+ // Probe for all possible locations
+ int priority = 0;
+ const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
+ import->uri, remotePathList, import->version);
+ for (const QString &qmldirPath : qmlDirPaths) {
+ if (hasInterceptors) {
+ QUrl url = engine->interceptUrl(
+ QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath),
+ QQmlAbstractUrlInterceptor::QmldirFile);
+ if (!QQmlFile::isLocalFile(url)
+ && !fetchQmldir(url, import, ++priority, errors)) {
+ return false;
+ }
+ } else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) {
+ return false;
+ }
- if (incomplete) {
- if (!fetchQmldir(qmldirUrl, import, 1, errors))
- return false;
+ }
}
}
return true;
}
+bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import,
+ QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
+{
+ return addImport(std::make_shared<PendingImport>(this, import, flags), errors);
+}
+
+bool QQmlTypeLoader::Blob::addImport(
+ QQmlTypeLoader::Blob::PendingImportPtr import, QList<QQmlError> *errors)
+{
+ Q_ASSERT(errors);
+
+ switch (import->type)
+ {
+ case QV4::CompiledData::Import::ImportLibrary:
+ return addLibraryImport(import, errors);
+ case QV4::CompiledData::Import::ImportFile:
+ return addFileImport(import ,errors);
+ case QV4::CompiledData::Import::ImportScript:
+ return addScriptImport(import);
+ case QV4::CompiledData::Import::ImportInlineComponent:
+ Q_UNREACHABLE_RETURN(false); // addImport is never called with an inline component import
+ }
+
+ Q_UNREACHABLE_RETURN(false);
+}
+
void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob)
{
if (blob->type() == QQmlDataBlob::QmldirFile) {
QQmlQmldirData *data = static_cast<QQmlQmldirData *>(blob);
-
- PendingImportPtr import = data->import(this);
-
QList<QQmlError> errors;
if (!qmldirDataAvailable(data, &errors)) {
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
- error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
+ error.setUrl(m_importCache->baseUrl());
+ const QV4::CompiledData::Location importLocation = data->importLocation(this);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(importLocation.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(importLocation.column()));
errors.prepend(error); // put it back on the list after filling out information.
setError(errors);
}
}
}
-bool QQmlTypeLoader::Blob::loadImportDependencies(PendingImportPtr currentImport, const QString &qmldirUri, QList<QQmlError> *errors)
+bool QQmlTypeLoader::Blob::loadDependentImports(
+ const QList<QQmlDirParser::Import> &imports, const QString &qualifier,
+ QTypeRevision version, quint16 precedence, QQmlImports::ImportFlags flags,
+ QList<QQmlError> *errors)
{
- const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirUri);
- for (const QString &implicitImports: qmldir.imports()) {
+ for (const auto &import : imports) {
+ if (import.flags & QQmlDirParser::Import::Optional)
+ continue;
auto dependencyImport = std::make_shared<PendingImport>();
- dependencyImport->uri = implicitImports;
- dependencyImport->qualifier = currentImport->qualifier;
- dependencyImport->majorVersion = currentImport->majorVersion;
- dependencyImport->minorVersion = currentImport->minorVersion;
- if (!addImport(dependencyImport, errors))
+ dependencyImport->uri = import.module;
+ dependencyImport->qualifier = qualifier;
+ dependencyImport->version = (import.flags & QQmlDirParser::Import::Auto)
+ ? version : import.version;
+ dependencyImport->flags = flags;
+ dependencyImport->precedence = precedence;
+
+ qCDebug(lcQmlImport)
+ << "loading dependent import" << dependencyImport->uri << "version"
+ << dependencyImport->version << "as" << dependencyImport->qualifier;
+
+ if (!addImport(dependencyImport, errors)) {
+ QQmlError error;
+ error.setDescription(
+ QString::fromLatin1(
+ "Failed to load dependent import \"%1\" version %2.%3")
+ .arg(dependencyImport->uri)
+ .arg(dependencyImport->version.majorVersion())
+ .arg(dependencyImport->version.minorVersion()));
+ errors->append(error);
return false;
+ }
}
+
+ return true;
+}
+
+bool QQmlTypeLoader::Blob::loadImportDependencies(
+ const QQmlTypeLoader::Blob::PendingImportPtr &currentImport, const QString &qmldirUri,
+ QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
+{
+ QList<QQmlDirParser::Import> implicitImports
+ = QQmlMetaType::moduleImports(currentImport->uri, currentImport->version);
+ if (!qmldirUri.isEmpty())
+ implicitImports += typeLoader()->qmldirContent(qmldirUri).imports();
+
+ // Prevent overflow from one category of import into the other.
+ switch (currentImport->precedence) {
+ case QQmlImportInstance::Implicit - 1:
+ case QQmlImportInstance::Lowest: {
+ QQmlError error;
+ error.setDescription(
+ QString::fromLatin1("Too many dependent imports for %1 %2.%3")
+ .arg(currentImport->uri)
+ .arg(currentImport->version.majorVersion())
+ .arg(currentImport->version.minorVersion()));
+ errors->append(error);
+ return false;
+ }
+ default:
+ break;
+ }
+
+ if (!loadDependentImports(
+ implicitImports, currentImport->qualifier, currentImport->version,
+ currentImport->precedence + 1, flags, errors)) {
+ QQmlError error;
+ error.setDescription(
+ QString::fromLatin1(
+ "Failed to load dependencies for module \"%1\" version %2.%3")
+ .arg(currentImport->uri)
+ .arg(currentImport->version.majorVersion())
+ .arg(currentImport->version.minorVersion()));
+ errors->append(error);
+ return false;
+ }
+
return true;
}
@@ -707,40 +871,34 @@ bool QQmlTypeLoader::Blob::isDebugging() const
return typeLoader()->engine()->handle()->debugger() != nullptr;
}
-bool QQmlTypeLoader::Blob::diskCacheDisabled()
+bool QQmlTypeLoader::Blob::readCacheFile() const
{
- return disableDiskCache();
+ return typeLoader()->engine()->handle()->diskCacheOptions()
+ & QV4::ExecutionEngine::DiskCache::QmlcRead;
}
-bool QQmlTypeLoader::Blob::diskCacheForced()
+bool QQmlTypeLoader::Blob::writeCacheFile() const
{
- return forceDiskCache();
+ return typeLoader()->engine()->handle()->diskCacheOptions()
+ & QV4::ExecutionEngine::DiskCache::QmlcWrite;
}
-bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
+QQmlMetaType::CacheMode QQmlTypeLoader::Blob::aotCacheMode() const
{
- PendingImportPtr import = data->import(this);
- data->setImport(this, nullptr);
-
- int priority = data->priority(this);
- data->setPriority(this, 0);
-
- if (import) {
- // Do we need to resolve this import?
- const bool resolve = (import->priority == 0) || (import->priority > priority);
-
- if (resolve) {
- // This is the (current) best resolution for this import
- if (!updateQmldir(data, import, errors)) {
- return false;
- }
-
- import->priority = priority;
- return true;
- }
- }
+ const QV4::ExecutionEngine::DiskCacheOptions options
+ = typeLoader()->engine()->handle()->diskCacheOptions();
+ if (!(options & QV4::ExecutionEngine::DiskCache::Aot))
+ return QQmlMetaType::RejectAll;
+ if (options & QV4::ExecutionEngine::DiskCache::AotByteCode)
+ return QQmlMetaType::AcceptUntyped;
+ return QQmlMetaType::RequireFullyTyped;
+}
- return true;
+bool QQmlTypeLoader::Blob::qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &data, QList<QQmlError> *errors)
+{
+ return data->processImports(this, [&](PendingImportPtr import) {
+ return updateQmldir(data, import, errors);
+ });
}
/*!
@@ -805,7 +963,11 @@ QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QUrl &unNormalizedUrl
// TODO: if (compiledData == 0), is it safe to omit this insertion?
m_typeCache.insert(url, typeData);
QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
- if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(typeData->url(), &error)) {
+
+ const QQmlMetaType::CacheMode cacheMode = typeData->aotCacheMode();
+ if (const QQmlPrivate::CachedQmlUnit *cachedUnit = (cacheMode != QQmlMetaType::RejectAll)
+ ? QQmlMetaType::findCachedCompilationUnit(typeData->url(), cacheMode, &error)
+ : nullptr) {
QQmlTypeLoader::loadWithCachedUnit(typeData, cachedUnit, mode);
} else {
typeData->setCachedUnitStatus(error);
@@ -815,16 +977,16 @@ QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QUrl &unNormalizedUrl
// this was started Asynchronous, but we need to force Synchronous
// completion now (if at all possible with this type of URL).
+#if QT_CONFIG(thread)
if (!m_thread->isThisThread()) {
// this only works when called directly from the UI thread, but not
// when recursively called on the QML thread via resolveTypes()
while (!typeData->isCompleteOrError()) {
- unlock();
m_thread->waitForNextMessage();
- lock();
}
}
+#endif
}
return typeData;
@@ -844,6 +1006,26 @@ QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QByteArray &data, con
return QQmlRefPointer<QQmlTypeData>(typeData, QQmlRefPointer<QQmlTypeData>::Adopt);
}
+void QQmlTypeLoader::injectScript(const QUrl &relativeUrl, const QV4::Value &value)
+{
+ LockHolder<QQmlTypeLoader> holder(this);
+
+ QQmlScriptBlob *blob = new QQmlScriptBlob(relativeUrl, this);
+ blob->initializeFromNative(value);
+ blob->m_isDone = true;
+ blob->m_data.setStatus(QQmlDataBlob::Complete);
+ m_scriptCache.insert(relativeUrl, blob);
+}
+
+QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::injectedScript(const QUrl &relativeUrl)
+{
+ LockHolder<QQmlTypeLoader> holder(this);
+ const auto it = m_scriptCache.constFind(relativeUrl);
+ return (it != m_scriptCache.constEnd() && (*it)->isNative())
+ ? *it
+ : QQmlRefPointer<QQmlScriptBlob>();
+}
+
/*!
Return a QQmlScriptBlob for \a url. The QQmlScriptData may be cached.
*/
@@ -863,8 +1045,11 @@ QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::getScript(const QUrl &unNormalize
scriptBlob = new QQmlScriptBlob(url, this);
m_scriptCache.insert(url, scriptBlob);
- QQmlMetaType::CachedUnitLookupError error;
- if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(scriptBlob->url(), &error)) {
+ QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError;
+ const QQmlMetaType::CacheMode cacheMode = scriptBlob->aotCacheMode();
+ if (const QQmlPrivate::CachedQmlUnit *cachedUnit = (cacheMode != QQmlMetaType::RejectAll)
+ ? QQmlMetaType::findCachedCompilationUnit(scriptBlob->url(), cacheMode, &error)
+ : nullptr) {
QQmlTypeLoader::loadWithCachedUnit(scriptBlob, cachedUnit);
} else {
scriptBlob->setCachedUnitStatus(error);
@@ -913,19 +1098,19 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path)
// qrc resource
QFileInfo fileInfo(path);
return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
- } else if (path.count() > 3 && path.at(3) == QLatin1Char(':') &&
+ } else if (path.size() > 3 && path.at(3) == QLatin1Char(':') &&
path.startsWith(QLatin1String("qrc"), Qt::CaseInsensitive)) {
// qrc resource url
QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
}
#if defined(Q_OS_ANDROID)
- else if (path.count() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/') &&
+ else if (path.size() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/') &&
path.startsWith(QLatin1String("assets"), Qt::CaseInsensitive)) {
// assets resource url
QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
- } else if (path.count() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/') &&
+ } else if (path.size() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/') &&
path.startsWith(QLatin1String("content"), Qt::CaseInsensitive)) {
// content url
QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path));
@@ -947,7 +1132,7 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path)
return QString();
QString absoluteFilePath;
- QString fileName(path.mid(lastSlash+1, path.length()-lastSlash-1));
+ QString fileName(path.mid(lastSlash+1, path.size()-lastSlash-1));
bool *value = fileSet->object(fileName);
if (value) {
@@ -960,7 +1145,7 @@ QString QQmlTypeLoader::absoluteFilePath(const QString &path)
absoluteFilePath = path;
}
- if (absoluteFilePath.length() > 2 && absoluteFilePath.at(0) != QLatin1Char('/') && absoluteFilePath.at(1) != QLatin1Char(':'))
+ if (absoluteFilePath.size() > 2 && absoluteFilePath.at(0) != QLatin1Char('/') && absoluteFilePath.at(1) != QLatin1Char(':'))
absoluteFilePath = QFileInfo(absoluteFilePath).absoluteFilePath();
return absoluteFilePath;
@@ -973,48 +1158,56 @@ bool QQmlTypeLoader::fileExists(const QString &path, const QString &file)
return false;
Q_ASSERT(path.endsWith(QLatin1Char('/')));
+
+ LockHolder<QQmlTypeLoader> holder(this);
+ QCache<QString, bool> *fileSet = m_importDirCache.object(path);
+ if (fileSet) {
+ if (bool *value = fileSet->object(file))
+ return *value;
+ } else if (m_importDirCache.contains(path)) {
+ // explicit nullptr in cache
+ return false;
+ }
+
+ auto addToCache = [&](const QFileInfo &fileInfo) {
+ if (!fileSet) {
+ fileSet = fileInfo.dir().exists() ? new QCache<QString, bool> : nullptr;
+ m_importDirCache.insert(path, fileSet);
+ if (!fileSet)
+ return false;
+ }
+
+ const bool exists = fileInfo.exists();
+ fileSet->insert(file, new bool(exists));
+ return exists;
+ };
+
if (path.at(0) == QLatin1Char(':')) {
// qrc resource
- QFileInfo fileInfo(path + file);
- return fileInfo.isFile();
- } else if (path.count() > 3 && path.at(3) == QLatin1Char(':') &&
- path.startsWith(QLatin1String("qrc"), Qt::CaseInsensitive)) {
+ return addToCache(QFileInfo(path + file));
+ }
+
+ if (path.size() > 3 && path.at(3) == QLatin1Char(':')
+ && path.startsWith(QLatin1String("qrc"), Qt::CaseInsensitive)) {
// qrc resource url
- QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path + file));
- return fileInfo.isFile();
+ return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
}
+
#if defined(Q_OS_ANDROID)
- else if (path.count() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/') &&
- path.startsWith(QLatin1String("assets"), Qt::CaseInsensitive)) {
+ if (path.size() > 7 && path.at(6) == QLatin1Char(':') && path.at(7) == QLatin1Char('/')
+ && path.startsWith(QLatin1String("assets"), Qt::CaseInsensitive)) {
// assets resource url
- QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path + file));
- return fileInfo.isFile();
- } else if (path.count() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/') &&
- path.startsWith(QLatin1String("content"), Qt::CaseInsensitive)) {
- // content url
- QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(path + file));
- return fileInfo.isFile();
+ return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
}
-#endif
- LockHolder<QQmlTypeLoader> holder(this);
- if (!m_importDirCache.contains(path)) {
- bool exists = QDir(path).exists();
- QCache<QString, bool> *entry = exists ? new QCache<QString, bool> : nullptr;
- m_importDirCache.insert(path, entry);
+ if (path.size() > 8 && path.at(7) == QLatin1Char(':') && path.at(8) == QLatin1Char('/')
+ && path.startsWith(QLatin1String("content"), Qt::CaseInsensitive)) {
+ // content url
+ return addToCache(QFileInfo(QQmlFile::urlToLocalFileOrQrc(path + file)));
}
- QCache<QString, bool> *fileSet = m_importDirCache.object(path);
- if (!fileSet)
- return false;
+#endif
- bool *value = fileSet->object(file);
- if (value) {
- return *value;
- } else {
- bool exists = QFile::exists(path + file);
- fileSet->insert(file, new bool(exists));
- return exists;
- }
+ return addToCache(QFileInfo(path + file));
}
@@ -1038,7 +1231,7 @@ bool QQmlTypeLoader::directoryExists(const QString &path)
return fileInfo.exists() && fileInfo.isDir();
}
- int length = path.length();
+ int length = path.size();
if (path.endsWith(QLatin1Char('/')))
--length;
QString dirPath(path.left(length));
@@ -1075,7 +1268,7 @@ const QQmlTypeLoaderQmldirContent QQmlTypeLoader::qmldirContent(const QString &f
// Yet, this heuristic is the best we can do until we pass more structured information here,
// for example a QUrl also for local files.
QUrl url(filePathIn);
- if (url.scheme().length() < 2) {
+ if (url.scheme().size() < 2) {
filePath = filePathIn;
} else {
filePath = QQmlFile::urlToLocalFileOrQrc(url);
@@ -1125,7 +1318,8 @@ void QQmlTypeLoader::setQmldirContent(const QString &url, const QString &content
m_importQmlDirCache.insert(url, qmldir);
}
- qmldir->setContent(url, content);
+ if (!qmldir->hasContent())
+ qmldir->setContent(url, content);
}
/*!
@@ -1134,6 +1328,11 @@ and qmldir information.
*/
void QQmlTypeLoader::clearCache()
{
+ // Pending messages typically hold references to the blobs they want to be delivered to.
+ // We don't want them anymore.
+ if (m_thread)
+ m_thread->discardMessages();
+
for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end; ++iter)
(*iter)->release();
for (ScriptCache::Iterator iter = m_scriptCache.begin(), end = m_scriptCache.end(); iter != end; ++iter)
@@ -1149,7 +1348,7 @@ void QQmlTypeLoader::clearCache()
m_qmldirCache.clear();
m_importDirCache.clear();
m_importQmlDirCache.clear();
- QQmlMetaType::freeUnusedTypesAndCaches();
+ m_checksumCache.clear();
}
void QQmlTypeLoader::updateTypeCacheTrimThreshold()
@@ -1164,29 +1363,40 @@ void QQmlTypeLoader::updateTypeCacheTrimThreshold()
void QQmlTypeLoader::trimCache()
{
while (true) {
- QList<TypeCache::Iterator> unneededTypes;
- for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end; ++iter) {
+ bool deletedOneType = false;
+ for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end;) {
QQmlTypeData *typeData = iter.value();
// typeData->m_compiledData may be set early on in the proccess of loading a file, so
// it's important to check the general loading status of the typeData before making any
// other decisions.
- if (typeData->count() == 1 && (typeData->isError() || typeData->isComplete())
- && (!typeData->m_compiledData || typeData->m_compiledData->count() == 1)) {
- // There are no live objects of this type
- unneededTypes.append(iter);
+ if (typeData->count() != 1 || (!typeData->isError() && !typeData->isComplete())) {
+ ++iter;
+ continue;
}
- }
- if (unneededTypes.isEmpty())
- break;
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit
+ = typeData->m_compiledData;
+ if (compilationUnit) {
+ if (compilationUnit->count()
+ > QQmlMetaType::countInternalCompositeTypeSelfReferences(
+ compilationUnit) + 1) {
+ ++iter;
+ continue;
+ }
- while (!unneededTypes.isEmpty()) {
- TypeCache::Iterator iter = unneededTypes.takeLast();
+ QQmlMetaType::unregisterInternalCompositeType(compilationUnit);
+ Q_ASSERT(compilationUnit->count() == 1);
+ }
+ // There are no live objects of this type
iter.value()->release();
- m_typeCache.erase(iter);
+ iter = m_typeCache.erase(iter);
+ deletedOneType = true;
}
+
+ if (!deletedOneType)
+ break;
}
updateTypeCacheTrimThreshold();
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index d45f0e095c..e9c4559527 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPELOADER_P_H
#define QQMLTYPELOADER_P_H
@@ -54,6 +18,7 @@
#include <private/qqmldatablob_p.h>
#include <private/qqmlimport_p.h>
#include <private/qqmlmetatype_p.h>
+#include <private/qv4compileddata_p.h>
#include <QtQml/qtqmlglobal.h>
#include <QtQml/qqmlerror.h>
@@ -74,66 +39,82 @@ class QQmlProfiler;
class QQmlTypeLoaderThread;
class QQmlEngine;
-class Q_QML_PRIVATE_EXPORT QQmlTypeLoader
+class Q_QML_EXPORT QQmlTypeLoader
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader)
public:
+ using ChecksumCache = QHash<quintptr, QByteArray>;
enum Mode { PreferSynchronous, Asynchronous, Synchronous };
- class Q_QML_PRIVATE_EXPORT Blob : public QQmlDataBlob
+ class Q_QML_EXPORT Blob : public QQmlDataBlob
{
public:
Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader);
~Blob() override;
- const QQmlImports &imports() const { return m_importCache; }
+ const QQmlImports *imports() const { return m_importCache.data(); }
void setCachedUnitStatus(QQmlMetaType::CachedUnitLookupError status) { m_cachedUnitStatus = status; }
struct PendingImport
{
- QV4::CompiledData::Import::ImportType type = QV4::CompiledData::Import::ImportType::ImportLibrary;
-
QString uri;
QString qualifier;
- int majorVersion = -1;
- int minorVersion = -1;
-
+ QV4::CompiledData::Import::ImportType type
+ = QV4::CompiledData::Import::ImportType::ImportLibrary;
QV4::CompiledData::Location location;
+ QQmlImports::ImportFlags flags;
+ quint8 precedence = 0;
int priority = 0;
+ QTypeRevision version;
+
PendingImport() = default;
- PendingImport(Blob *blob, const QV4::CompiledData::Import *import);
+ PendingImport(Blob *blob, const QV4::CompiledData::Import *import,
+ QQmlImports::ImportFlags flags);
};
using PendingImportPtr = std::shared_ptr<PendingImport>;
+ void importQmldirScripts(const PendingImportPtr &import, const QQmlTypeLoaderQmldirContent &qmldir, const QUrl &qmldirUrl);
+
protected:
- bool addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors);
+ bool addImport(const QV4::CompiledData::Import *import, QQmlImports::ImportFlags,
+ QList<QQmlError> *errors);
bool addImport(PendingImportPtr import, QList<QQmlError> *errors);
bool fetchQmldir(const QUrl &url, PendingImportPtr import, int priority, QList<QQmlError> *errors);
- bool updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, PendingImportPtr import, QList<QQmlError> *errors);
+ bool updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, const PendingImportPtr &import, QList<QQmlError> *errors);
private:
+ bool addScriptImport(const PendingImportPtr &import);
+ bool addFileImport(const PendingImportPtr &import, QList<QQmlError> *errors);
+ bool addLibraryImport(const PendingImportPtr &import, QList<QQmlError> *errors);
+
virtual bool qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &, QList<QQmlError> *);
virtual void scriptImported(const QQmlRefPointer<QQmlScriptBlob> &, const QV4::CompiledData::Location &, const QString &, const QString &) {}
void dependencyComplete(QQmlDataBlob *) override;
- bool loadImportDependencies(PendingImportPtr currentImport, const QString &qmldirUri, QList<QQmlError> *errors);
+ bool loadImportDependencies(
+ const PendingImportPtr &currentImport, const QString &qmldirUri,
+ QQmlImports::ImportFlags flags, QList<QQmlError> *errors);
protected:
+ bool loadDependentImports(
+ const QList<QQmlDirParser::Import> &imports, const QString &qualifier,
+ QTypeRevision version, quint16 precedence, QQmlImports::ImportFlags flags,
+ QList<QQmlError> *errors);
virtual QString stringAt(int) const { return QString(); }
bool isDebugging() const;
+ bool readCacheFile() const;
+ bool writeCacheFile() const;
+ QQmlMetaType::CacheMode aotCacheMode() const;
- static bool diskCacheDisabled();
- static bool diskCacheForced();
-
- QQmlImports m_importCache;
+ QQmlRefPointer<QQmlImports> m_importCache;
QVector<PendingImportPtr> m_unresolvedImports;
QVector<QQmlRefPointer<QQmlQmldirData>> m_qmldirs;
QQmlMetaType::CachedUnitLookupError m_cachedUnitStatus = QQmlMetaType::CachedUnitLookupError::NoError;
@@ -142,13 +123,35 @@ public:
QQmlTypeLoader(QQmlEngine *);
~QQmlTypeLoader();
+ template<
+ typename Engine,
+ typename EnginePrivate = QQmlEnginePrivate,
+ typename = std::enable_if_t<std::is_same_v<Engine, QQmlEngine>>>
+ static QQmlTypeLoader *get(Engine *engine)
+ {
+ return get(EnginePrivate::get(engine));
+ }
+
+ template<
+ typename Engine,
+ typename = std::enable_if_t<std::is_same_v<Engine, QQmlEnginePrivate>>>
+ static QQmlTypeLoader *get(Engine *engine)
+ {
+ return &engine->typeLoader;
+ }
+
QQmlImportDatabase *importDatabase() const;
+ ChecksumCache *checksumCache() { return &m_checksumCache; }
+ const ChecksumCache *checksumCache() const { return &m_checksumCache; }
static QUrl normalize(const QUrl &unNormalizedUrl);
QQmlRefPointer<QQmlTypeData> getType(const QUrl &unNormalizedUrl, Mode mode = PreferSynchronous);
QQmlRefPointer<QQmlTypeData> getType(const QByteArray &, const QUrl &url, Mode mode = PreferSynchronous);
+ void injectScript(const QUrl &relativeUrl, const QV4::Value &value);
+ QQmlRefPointer<QQmlScriptBlob> injectedScript(const QUrl &relativeUrl);
+
QQmlRefPointer<QQmlScriptBlob> getScript(const QUrl &unNormalizedUrl);
QQmlRefPointer<QQmlQmldirData> getQmldir(const QUrl &);
@@ -170,7 +173,7 @@ public:
void load(QQmlDataBlob *, Mode = PreferSynchronous);
void loadWithStaticData(QQmlDataBlob *, const QByteArray &, Mode = PreferSynchronous);
- void loadWithCachedUnit(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit, Mode mode = PreferSynchronous);
+ void loadWithCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit, Mode mode = PreferSynchronous);
QQmlEngine *engine() const;
void initializeEngine(QQmlEngineExtensionInterface *, const char *);
@@ -195,36 +198,20 @@ private:
void shutdownThread();
- void loadThread(QQmlDataBlob *);
- void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &);
- void loadWithCachedUnitThread(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit);
+ void loadThread(const QQmlDataBlob::Ptr &);
+ void loadWithStaticDataThread(const QQmlDataBlob::Ptr &, const QByteArray &);
+ void loadWithCachedUnitThread(const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit);
#if QT_CONFIG(qml_network)
void networkReplyFinished(QNetworkReply *);
void networkReplyProgress(QNetworkReply *, qint64, qint64);
- typedef QHash<QNetworkReply *, QQmlDataBlob *> NetworkReplies;
+ typedef QHash<QNetworkReply *, QQmlDataBlob::Ptr> NetworkReplies;
#endif
- void setData(QQmlDataBlob *, const QByteArray &);
- void setData(QQmlDataBlob *, const QString &fileName);
- void setData(QQmlDataBlob *, const QQmlDataBlob::SourceCodeData &);
- void setCachedUnit(QQmlDataBlob *blob, const QV4::CompiledData::Unit *unit);
-
- template<typename T>
- struct TypedCallback
- {
- TypedCallback(T *object, void (T::*func)(QQmlTypeData *)) : o(object), mf(func) {}
-
- static void redirect(void *arg, QQmlTypeData *type)
- {
- TypedCallback<T> *self = reinterpret_cast<TypedCallback<T> *>(arg);
- ((self->o)->*(self->mf))(type);
- }
-
- private:
- T *o;
- void (T::*mf)(QQmlTypeData *);
- };
+ void setData(const QQmlDataBlob::Ptr &, const QByteArray &);
+ void setData(const QQmlDataBlob::Ptr &, const QString &fileName);
+ void setData(const QQmlDataBlob::Ptr &, const QQmlDataBlob::SourceCodeData &);
+ void setCachedUnit(const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit);
typedef QHash<QUrl, QQmlTypeData *> TypeCache;
typedef QHash<QUrl, QQmlScriptBlob *> ScriptCache;
@@ -249,6 +236,7 @@ private:
QmldirCache m_qmldirCache;
ImportDirCache m_importDirCache;
ImportQmlDirCache m_importQmlDirCache;
+ ChecksumCache m_checksumCache;
template<typename Loader>
void doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode);
diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
index af97643163..cea7ae6650 100644
--- a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
+++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmltypeloadernetworkreplyproxy_p.h>
#include <private/qqmltypeloader_p.h>
@@ -72,3 +36,5 @@ void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply)
}
QT_END_NAMESPACE
+
+#include "moc_qqmltypeloadernetworkreplyproxy_p.cpp"
diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h b/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h
index ed87a2b508..47e59b4bba 100644
--- a/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h
+++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPELOADERNETWORKREPLYPROXY_P_H
#define QQMLTYPELOADERNETWORKREPLYPROXY_P_H
@@ -53,6 +17,7 @@
#include <QtQml/qtqmlglobal.h>
#include <QtCore/qobject.h>
+#include <QtCore/private/qglobal_p.h>
QT_REQUIRE_CONFIG(qml_network);
@@ -72,7 +37,7 @@ class QQmlTypeLoaderNetworkReplyProxy : public QObject
public:
QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l);
-public slots:
+public Q_SLOTS:
void finished();
void downloadProgress(qint64, qint64);
void manualFinished(QNetworkReply*);
diff --git a/src/qml/qml/qqmltypeloaderqmldircontent.cpp b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
index 8e983db756..5744cf2bb7 100644
--- a/src/qml/qml/qqmltypeloaderqmldircontent.cpp
+++ b/src/qml/qml/qqmltypeloaderqmldircontent.cpp
@@ -1,121 +1,43 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmltypeloaderqmldircontent_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
#include <QtQml/qqmlerror.h>
QT_BEGIN_NAMESPACE
-QQmlTypeLoaderQmldirContent::QQmlTypeLoaderQmldirContent()
-{
-}
-
-bool QQmlTypeLoaderQmldirContent::hasError() const
-{
- return m_parser.hasError();
-}
-
-QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const
+QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri, const QUrl &url) const
{
QList<QQmlError> errors;
- const QUrl url(uri);
const auto parseErrors = m_parser.errors(uri);
for (const auto &parseError : parseErrors) {
QQmlError error;
error.setUrl(url);
- error.setLine(parseError.line);
- error.setColumn(parseError.column);
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(parseError.loc.startLine));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(parseError.loc.startColumn));
error.setDescription(parseError.message);
errors.append(error);
}
return errors;
}
-QString QQmlTypeLoaderQmldirContent::typeNamespace() const
-{
- return m_parser.typeNamespace();
-}
-
void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
{
+ Q_ASSERT(!m_hasContent);
m_hasContent = true;
m_location = location;
m_parser.parse(content);
+ m_parser.disambiguateFileSelectors();
}
void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error)
{
QQmlJS::DiagnosticMessage parseError;
- parseError.line = error.line();
- parseError.column = error.column();
+ parseError.loc.startLine = error.line();
+ parseError.loc.startColumn = error.column();
parseError.message = error.description();
m_parser.setError(parseError);
}
-QQmlDirComponents QQmlTypeLoaderQmldirContent::components() const
-{
- return m_parser.components();
-}
-
-QQmlDirScripts QQmlTypeLoaderQmldirContent::scripts() const
-{
- return m_parser.scripts();
-}
-
-QQmlDirPlugins QQmlTypeLoaderQmldirContent::plugins() const
-{
- return m_parser.plugins();
-}
-
-QStringList QQmlTypeLoaderQmldirContent::imports() const
-{
- return m_parser.imports();
-}
-
-QString QQmlTypeLoaderQmldirContent::pluginLocation() const
-{
- return m_location;
-}
-
-bool QQmlTypeLoaderQmldirContent::designerSupported() const
-{
- return m_parser.designerSupported();
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypeloaderqmldircontent_p.h b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
index 698643c7ec..421eb16da4 100644
--- a/src/qml/qml/qqmltypeloaderqmldircontent_p.h
+++ b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPELOADERQMLDIRCONTENT_P_H
#define QQMLTYPELOADERQMLDIRCONTENT_P_H
@@ -65,24 +29,33 @@ private:
void setError(const QQmlError &);
public:
- QQmlTypeLoaderQmldirContent();
+ QQmlTypeLoaderQmldirContent() = default;
QQmlTypeLoaderQmldirContent(const QQmlTypeLoaderQmldirContent &) = default;
QQmlTypeLoaderQmldirContent &operator=(const QQmlTypeLoaderQmldirContent &) = default;
bool hasContent() const { return m_hasContent; }
- bool hasError() const;
- QList<QQmlError> errors(const QString &uri) const;
+ bool hasError() const { return m_parser.hasError(); }
+ QList<QQmlError> errors(const QString &uri, const QUrl &url) const;
- QString typeNamespace() const;
+ QString typeNamespace() const { return m_parser.typeNamespace(); }
- QQmlDirComponents components() const;
- QQmlDirScripts scripts() const;
- QQmlDirPlugins plugins() const;
- QStringList imports() const;
+ QQmlDirComponents components() const { return m_parser.components(); }
+ QQmlDirScripts scripts() const { return m_parser.scripts(); }
+ QQmlDirPlugins plugins() const { return m_parser.plugins(); }
+ QQmlDirImports imports() const { return m_parser.imports(); }
- QString pluginLocation() const;
+ QString qmldirLocation() const { return m_location; }
+ QString preferredPath() const { return m_parser.preferredPath(); }
- bool designerSupported() const;
+ bool hasRedirection() const
+ {
+ const QString preferred = preferredPath();
+ return !preferred.isEmpty()
+ && preferred != QStringView(m_location).chopped(strlen("qmldir"));
+ }
+
+ bool designerSupported() const { return m_parser.designerSupported(); }
+ bool hasTypeInfo() const { return !m_parser.typeInfos().isEmpty(); }
private:
QQmlDirParser m_parser;
diff --git a/src/qml/qml/qqmltypeloaderthread.cpp b/src/qml/qml/qqmltypeloaderthread.cpp
index 618bb09039..18d1dbe7ce 100644
--- a/src/qml/qml/qqmltypeloaderthread.cpp
+++ b/src/qml/qml/qqmltypeloaderthread.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qqmlengine_p.h>
#include <private/qqmlextensionplugin_p.h>
@@ -49,9 +13,6 @@ QT_BEGIN_NAMESPACE
QQmlTypeLoaderThread::QQmlTypeLoaderThread(QQmlTypeLoader *loader)
: m_loader(loader)
-#if QT_CONFIG(qml_network)
- , m_networkAccessManager(nullptr), m_networkReplyProxy(nullptr)
-#endif // qml_network
{
// Do that after initializing all the members.
startup();
@@ -63,7 +24,9 @@ QNetworkAccessManager *QQmlTypeLoaderThread::networkAccessManager() const
Q_ASSERT(isThisThread());
if (!m_networkAccessManager) {
m_networkAccessManager = QQmlEnginePrivate::get(m_loader->engine())->createNetworkAccessManager(nullptr);
+ QObject::connect(thread(), &QThread::finished, m_networkAccessManager, &QObject::deleteLater);
m_networkReplyProxy = new QQmlTypeLoaderNetworkReplyProxy(m_loader);
+ QObject::connect(thread(), &QThread::finished, m_networkReplyProxy, &QObject::deleteLater);
}
return m_networkAccessManager;
@@ -77,62 +40,44 @@ QQmlTypeLoaderNetworkReplyProxy *QQmlTypeLoaderThread::networkReplyProxy() const
}
#endif // qml_network
-void QQmlTypeLoaderThread::load(QQmlDataBlob *b)
+void QQmlTypeLoaderThread::load(const QQmlDataBlob::Ptr &b)
{
- b->addref();
callMethodInThread(&This::loadThread, b);
}
-void QQmlTypeLoaderThread::loadAsync(QQmlDataBlob *b)
+void QQmlTypeLoaderThread::loadAsync(const QQmlDataBlob::Ptr &b)
{
- b->addref();
postMethodToThread(&This::loadThread, b);
}
-void QQmlTypeLoaderThread::loadWithStaticData(QQmlDataBlob *b, const QByteArray &d)
+void QQmlTypeLoaderThread::loadWithStaticData(const QQmlDataBlob::Ptr &b, const QByteArray &d)
{
- b->addref();
callMethodInThread(&This::loadWithStaticDataThread, b, d);
}
-void QQmlTypeLoaderThread::loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &d)
+void QQmlTypeLoaderThread::loadWithStaticDataAsync(const QQmlDataBlob::Ptr &b, const QByteArray &d)
{
- b->addref();
postMethodToThread(&This::loadWithStaticDataThread, b, d);
}
-void QQmlTypeLoaderThread::loadWithCachedUnit(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
+void QQmlTypeLoaderThread::loadWithCachedUnit(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit)
{
- b->addref();
callMethodInThread(&This::loadWithCachedUnitThread, b, unit);
}
-void QQmlTypeLoaderThread::loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
+void QQmlTypeLoaderThread::loadWithCachedUnitAsync(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit)
{
- b->addref();
postMethodToThread(&This::loadWithCachedUnitThread, b, unit);
}
-void QQmlTypeLoaderThread::callCompleted(QQmlDataBlob *b)
+void QQmlTypeLoaderThread::callCompleted(const QQmlDataBlob::Ptr &b)
{
- b->addref();
-#if !QT_CONFIG(thread)
- if (!isThisThread())
- postMethodToThread(&This::callCompletedMain, b);
-#else
postMethodToMain(&This::callCompletedMain, b);
-#endif
}
-void QQmlTypeLoaderThread::callDownloadProgressChanged(QQmlDataBlob *b, qreal p)
+void QQmlTypeLoaderThread::callDownloadProgressChanged(const QQmlDataBlob::Ptr &b, qreal p)
{
- b->addref();
-#if !QT_CONFIG(thread)
- if (!isThisThread())
- postMethodToThread(&This::callDownloadProgressChangedMain, b, p);
-#else
postMethodToMain(&This::callDownloadProgressChangedMain, b, p);
-#endif
}
void QQmlTypeLoaderThread::initializeEngine(QQmlExtensionInterface *iface,
@@ -147,51 +92,36 @@ void QQmlTypeLoaderThread::initializeEngine(QQmlEngineExtensionInterface *iface,
callMethodInMain(&This::initializeEngineExtensionMain, iface, uri);
}
-void QQmlTypeLoaderThread::shutdownThread()
-{
-#if QT_CONFIG(qml_network)
- delete m_networkAccessManager;
- m_networkAccessManager = nullptr;
- delete m_networkReplyProxy;
- m_networkReplyProxy = nullptr;
-#endif // qml_network
-}
-
-void QQmlTypeLoaderThread::loadThread(QQmlDataBlob *b)
+void QQmlTypeLoaderThread::loadThread(const QQmlDataBlob::Ptr &b)
{
m_loader->loadThread(b);
- b->release();
}
-void QQmlTypeLoaderThread::loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &d)
+void QQmlTypeLoaderThread::loadWithStaticDataThread(const QQmlDataBlob::Ptr &b, const QByteArray &d)
{
m_loader->loadWithStaticDataThread(b, d);
- b->release();
}
-void QQmlTypeLoaderThread::loadWithCachedUnitThread(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit)
+void QQmlTypeLoaderThread::loadWithCachedUnitThread(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit)
{
m_loader->loadWithCachedUnitThread(b, unit);
- b->release();
}
-void QQmlTypeLoaderThread::callCompletedMain(QQmlDataBlob *b)
+void QQmlTypeLoaderThread::callCompletedMain(const QQmlDataBlob::Ptr &b)
{
#ifdef DATABLOB_DEBUG
qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->urlString()));
#endif
b->completed();
- b->release();
}
-void QQmlTypeLoaderThread::callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p)
+void QQmlTypeLoaderThread::callDownloadProgressChangedMain(const QQmlDataBlob::Ptr &b, qreal p)
{
#ifdef DATABLOB_DEBUG
qWarning("QQmlTypeLoaderThread: %s downloadProgressChanged(%f) callback",
qPrintable(b->urlString()), p);
#endif
b->downloadProgressChanged(p);
- b->release();
}
void QQmlTypeLoaderThread::initializeExtensionMain(QQmlExtensionInterface *iface,
diff --git a/src/qml/qml/qqmltypeloaderthread_p.h b/src/qml/qml/qqmltypeloaderthread_p.h
index 9fb441e6e2..4f65fc0cbd 100644
--- a/src/qml/qml/qqmltypeloaderthread_p.h
+++ b/src/qml/qml/qqmltypeloaderthread_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPELOADERTHREAD_P_H
#define QQMLTYPELOADERTHREAD_P_H
@@ -53,6 +17,7 @@
#include <private/qqmlthread_p.h>
#include <private/qv4compileddata_p.h>
+#include <private/qqmldatablob_p.h>
#include <QtQml/qtqmlglobal.h>
@@ -63,11 +28,14 @@
QT_BEGIN_NAMESPACE
-class QQmlDataBlob;
class QQmlTypeLoader;
class QQmlEngineExtensionInterface;
class QQmlExtensionInterface;
+namespace QQmlPrivate {
+struct CachedQmlUnit;
+}
+
class QQmlTypeLoaderThread : public QQmlThread
{
typedef QQmlTypeLoaderThread This;
@@ -78,33 +46,30 @@ public:
QNetworkAccessManager *networkAccessManager() const;
QQmlTypeLoaderNetworkReplyProxy *networkReplyProxy() const;
#endif // qml_network
- void load(QQmlDataBlob *b);
- void loadAsync(QQmlDataBlob *b);
- void loadWithStaticData(QQmlDataBlob *b, const QByteArray &);
- void loadWithStaticDataAsync(QQmlDataBlob *b, const QByteArray &);
- void loadWithCachedUnit(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
- void loadWithCachedUnitAsync(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
- void callCompleted(QQmlDataBlob *b);
- void callDownloadProgressChanged(QQmlDataBlob *b, qreal p);
+ void load(const QQmlDataBlob::Ptr &b);
+ void loadAsync(const QQmlDataBlob::Ptr &b);
+ void loadWithStaticData(const QQmlDataBlob::Ptr &b, const QByteArray &);
+ void loadWithStaticDataAsync(const QQmlDataBlob::Ptr &b, const QByteArray &);
+ void loadWithCachedUnit(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit);
+ void loadWithCachedUnitAsync(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit);
+ void callCompleted(const QQmlDataBlob::Ptr &b);
+ void callDownloadProgressChanged(const QQmlDataBlob::Ptr &b, qreal p);
void initializeEngine(QQmlExtensionInterface *, const char *);
void initializeEngine(QQmlEngineExtensionInterface *, const char *);
-protected:
- void shutdownThread() override;
-
private:
- void loadThread(QQmlDataBlob *b);
- void loadWithStaticDataThread(QQmlDataBlob *b, const QByteArray &);
- void loadWithCachedUnitThread(QQmlDataBlob *b, const QV4::CompiledData::Unit *unit);
- void callCompletedMain(QQmlDataBlob *b);
- void callDownloadProgressChangedMain(QQmlDataBlob *b, qreal p);
+ void loadThread(const QQmlDataBlob::Ptr &b);
+ void loadWithStaticDataThread(const QQmlDataBlob::Ptr &b, const QByteArray &);
+ void loadWithCachedUnitThread(const QQmlDataBlob::Ptr &b, const QQmlPrivate::CachedQmlUnit *unit);
+ void callCompletedMain(const QQmlDataBlob::Ptr &b);
+ void callDownloadProgressChangedMain(const QQmlDataBlob::Ptr &b, qreal p);
void initializeExtensionMain(QQmlExtensionInterface *iface, const char *uri);
void initializeEngineExtensionMain(QQmlEngineExtensionInterface *iface, const char *uri);
QQmlTypeLoader *m_loader;
#if QT_CONFIG(qml_network)
- mutable QNetworkAccessManager *m_networkAccessManager;
- mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy;
+ mutable QNetworkAccessManager *m_networkAccessManager = nullptr;
+ mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy = nullptr;
#endif // qml_network
};
diff --git a/src/qml/qml/qqmltypemodule.cpp b/src/qml/qml/qqmltypemodule.cpp
index 9c9bf3e48f..b188b7fb90 100644
--- a/src/qml/qml/qqmltypemodule.cpp
+++ b/src/qml/qml/qqmltypemodule.cpp
@@ -1,43 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qqmltypemodule_p_p.h"
+#include "qqmltypemodule_p.h"
#include <private/qqmltype_p_p.h>
@@ -45,62 +9,36 @@
QT_BEGIN_NAMESPACE
-QQmlTypeModule::QQmlTypeModule(const QString &module, int majorVersion)
- : d(new QQmlTypeModulePrivate(module, majorVersion))
+void QQmlTypeModule::addMinorVersion(quint8 version)
{
-}
-
-QQmlTypeModule::~QQmlTypeModule()
-{
- delete d;
-}
-
-QString QQmlTypeModule::module() const
-{
- // No need to lock. d->module is const
- return d->module;
-}
-
-int QQmlTypeModule::majorVersion() const
-{
- // No need to lock. d->majorVersion is const
- return d->majorVersion;
-}
-
-int QQmlTypeModule::minimumMinorVersion() const
-{
- return d->minMinorVersion.loadRelaxed();
-}
-
-int QQmlTypeModule::maximumMinorVersion() const
-{
- return d->maxMinorVersion.loadRelaxed();
-}
-
-void QQmlTypeModule::addMinorVersion(int version)
-{
- for (int oldVersion = d->minMinorVersion.loadRelaxed();
- oldVersion > version && !d->minMinorVersion.testAndSetOrdered(oldVersion, version);
- oldVersion = d->minMinorVersion.loadRelaxed()) {
+ for (int oldVersion = m_minMinorVersion.loadRelaxed();
+ oldVersion > version && !m_minMinorVersion.testAndSetOrdered(oldVersion, version);
+ oldVersion = m_minMinorVersion.loadRelaxed()) {
}
- for (int oldVersion = d->maxMinorVersion.loadRelaxed();
- oldVersion < version && !d->maxMinorVersion.testAndSetOrdered(oldVersion, version);
- oldVersion = d->maxMinorVersion.loadRelaxed()) {
+ for (int oldVersion = m_maxMinorVersion.loadRelaxed();
+ oldVersion < version && !m_maxMinorVersion.testAndSetOrdered(oldVersion, version);
+ oldVersion = m_maxMinorVersion.loadRelaxed()) {
}
}
void QQmlTypeModule::add(QQmlTypePrivate *type)
{
- QMutexLocker lock(&d->mutex);
- addMinorVersion(type->version_min);
+ QMutexLocker lock(&m_mutex);
- QList<QQmlTypePrivate *> &list = d->typeHash[type->elementName];
- for (int ii = 0; ii < list.count(); ++ii) {
- Q_ASSERT(list.at(ii));
- if (list.at(ii)->version_min < type->version_min) {
+ if (type->version.hasMinorVersion())
+ addMinorVersion(type->version.minorVersion());
+
+ QList<QQmlTypePrivate *> &list = m_typeHash[type->elementName];
+ for (int ii = 0; ii < list.size(); ++ii) {
+ QQmlTypePrivate *in_list = list.at(ii);
+ Q_ASSERT(in_list);
+ if (in_list->version.minorVersion() < type->version.minorVersion()) {
list.insert(ii, type);
return;
+ } else if (in_list->version.minorVersion() == type->version.minorVersion()) {
+ list[ii] = type;
+ return;
}
}
list.append(type);
@@ -108,51 +46,16 @@ void QQmlTypeModule::add(QQmlTypePrivate *type)
void QQmlTypeModule::remove(const QQmlTypePrivate *type)
{
- QMutexLocker lock(&d->mutex);
- for (auto elementIt = d->typeHash.begin(); elementIt != d->typeHash.end();) {
+ QMutexLocker lock(&m_mutex);
+ for (auto elementIt = m_typeHash.begin(); elementIt != m_typeHash.end(); ++elementIt)
QQmlMetaType::removeQQmlTypePrivate(elementIt.value(), type);
-
-#if 0
- if (list.isEmpty())
- elementIt = typeHash.erase(elementIt);
- else
- ++elementIt;
-#else
- ++elementIt;
-#endif
- }
-}
-
-bool QQmlTypeModule::isLocked() const
-{
- return d->locked.loadRelaxed() != 0;
-}
-
-void QQmlTypeModule::lock()
-{
- d->locked.storeRelaxed(1);
-}
-
-QQmlType QQmlTypeModule::type(const QHashedStringRef &name, int minor) const
-{
- QMutexLocker lock(&d->mutex);
- QList<QQmlTypePrivate *> *types = d->typeHash.value(name);
- if (types) {
- for (int ii = 0; ii < types->count(); ++ii)
- if (types->at(ii)->version_min <= minor)
- return QQmlType(types->at(ii));
- }
-
- return QQmlType();
}
-QQmlType QQmlTypeModule::type(const QV4::String *name, int minor) const
+QQmlType QQmlTypeModule::findType(const QList<QQmlTypePrivate *> *types, QTypeRevision version)
{
- QMutexLocker lock(&d->mutex);
- QList<QQmlTypePrivate *> *types = d->typeHash.value(name);
if (types) {
- for (int ii = 0; ii < types->count(); ++ii)
- if (types->at(ii)->version_min <= minor)
+ for (int ii = 0; ii < types->size(); ++ii)
+ if (types->at(ii)->version.minorVersion() <= version.minorVersion())
return QQmlType(types->at(ii));
}
@@ -161,8 +64,8 @@ QQmlType QQmlTypeModule::type(const QV4::String *name, int minor) const
void QQmlTypeModule::walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const
{
- QMutexLocker lock(&d->mutex);
- for (auto typeCandidates = d->typeHash.begin(), end = d->typeHash.end();
+ QMutexLocker lock(&m_mutex);
+ for (auto typeCandidates = m_typeHash.begin(), end = m_typeHash.end();
typeCandidates != end; ++typeCandidates) {
for (auto type: typeCandidates.value()) {
if (type->regType == QQmlType::CompositeSingletonType)
diff --git a/src/qml/qml/qqmltypemodule_p.h b/src/qml/qml/qqmltypemodule_p.h
index b84a91b5db..717b07ec60 100644
--- a/src/qml/qml/qqmltypemodule_p.h
+++ b/src/qml/qml/qqmltypemodule_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPEMODULE_P_H
#define QQMLTYPEMODULE_P_H
@@ -52,7 +16,11 @@
//
#include <QtQml/qtqmlglobal.h>
+#include <QtQml/private/qstringhash_p.h>
+#include <QtQml/private/qqmltype_p.h>
+#include <QtCore/qmutex.h>
#include <QtCore/qstring.h>
+#include <QtCore/qversionnumber.h>
#include <functional>
@@ -61,40 +29,90 @@ QT_BEGIN_NAMESPACE
class QQmlType;
class QQmlTypePrivate;
struct QQmlMetaTypeData;
-class QHashedString;
-class QHashedStringRef;
namespace QV4 {
struct String;
}
-class QQmlTypeModulePrivate;
class QQmlTypeModule
{
public:
- QQmlTypeModule(const QString &uri = QString(), int majorVersion = 0);
- ~QQmlTypeModule();
+ enum class LockLevel {
+ Open = 0,
+ Weak = 1,
+ Strong = 2
+ };
+
+ QQmlTypeModule() = default;
+ QQmlTypeModule(const QString &uri, quint8 majorVersion)
+ : m_module(uri), m_majorVersion(majorVersion)
+ {}
void add(QQmlTypePrivate *);
void remove(const QQmlTypePrivate *type);
- bool isLocked() const;
- void lock();
+ LockLevel lockLevel() const { return LockLevel(m_lockLevel.loadRelaxed()); }
+ bool setLockLevel(LockLevel mode)
+ {
+ while (true) {
+ const int currentLock = m_lockLevel.loadAcquire();
+ if (currentLock > int(mode))
+ return false;
+ if (currentLock == int(mode) || m_lockLevel.testAndSetRelease(currentLock, int(mode)))
+ return true;
+ }
+ }
+
+ QString module() const
+ {
+ // No need to lock. m_module is const
+ return m_module;
+ }
+
+ quint8 majorVersion() const
+ {
+ // No need to lock. d->majorVersion is const
+ return m_majorVersion;
+ }
+
+ void addMinorVersion(quint8 minorVersion);
+ quint8 minimumMinorVersion() const { return m_minMinorVersion.loadRelaxed(); }
+ quint8 maximumMinorVersion() const { return m_maxMinorVersion.loadRelaxed(); }
+
+ QQmlType type(const QHashedStringRef &name, QTypeRevision version) const
+ {
+ QMutexLocker lock(&m_mutex);
+ return findType(m_typeHash.value(name), version);
+ }
+
+ QQmlType type(const QV4::String *name, QTypeRevision version) const
+ {
+ QMutexLocker lock(&m_mutex);
+ return findType(m_typeHash.value(name), version);
+ }
- QString module() const;
- int majorVersion() const;
+ void walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const;
- void addMinorVersion(int minorVersion);
- int minimumMinorVersion() const;
- int maximumMinorVersion() const;
+private:
+ static Q_QML_EXPORT QQmlType findType(
+ const QList<QQmlTypePrivate *> *types, QTypeRevision version);
- QQmlType type(const QHashedStringRef &, int) const;
- QQmlType type(const QV4::String *, int) const;
+ const QString m_module;
+ const quint8 m_majorVersion = 0;
- void walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const;
+ // Can only ever decrease
+ QAtomicInt m_minMinorVersion = std::numeric_limits<quint8>::max();
-private:
- QQmlTypeModulePrivate *d;
+ // Can only ever increase
+ QAtomicInt m_maxMinorVersion = 0;
+
+ // LockLevel. Can only be increased.
+ QAtomicInt m_lockLevel = int(LockLevel::Open);
+
+ using TypeHash = QStringHash<QList<QQmlTypePrivate *>>;
+ TypeHash m_typeHash;
+
+ mutable QMutex m_mutex;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypemodule_p_p.h b/src/qml/qml/qqmltypemodule_p_p.h
deleted file mode 100644
index b1dab1c4a0..0000000000
--- a/src/qml/qml/qqmltypemodule_p_p.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLTYPEMODULE_P_P_H
-#define QQMLTYPEMODULE_P_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qqmltypemodule_p.h>
-#include <private/qstringhash_p.h>
-#include <private/qqmlmetatypedata_p.h>
-
-#include <QtCore/qmutex.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlTypeModulePrivate
-{
-public:
- QQmlTypeModulePrivate(QString module, int majorVersion) :
- module(std::move(module)), majorVersion(majorVersion)
- {}
-
- const QString module;
- const int majorVersion = 0;
-
- // Can only ever decrease
- QAtomicInt minMinorVersion = std::numeric_limits<int>::max();
-
- // Can only ever increase
- QAtomicInt maxMinorVersion = 0;
-
- // Bool. Can only be set to 1 once.
- QAtomicInt locked = 0;
-
- typedef QStringHash<QList<QQmlTypePrivate *> > TypeHash;
- TypeHash typeHash;
-
- QMutex mutex;
-};
-
-QT_END_NAMESPACE
-
-#endif // QQMLTYPEMODULE_P_P_H
diff --git a/src/qml/qml/qqmltypemoduleversion.cpp b/src/qml/qml/qqmltypemoduleversion.cpp
index bbbfa1a7b6..072cf8a1cd 100644
--- a/src/qml/qml/qqmltypemoduleversion.cpp
+++ b/src/qml/qml/qqmltypemoduleversion.cpp
@@ -1,47 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmltypemoduleversion_p.h"
-#include <private/qqmltype_p.h>
-#include <private/qqmltypemodule_p.h>
-
QT_BEGIN_NAMESPACE
QQmlTypeModuleVersion::QQmlTypeModuleVersion()
@@ -49,11 +10,10 @@ QQmlTypeModuleVersion::QQmlTypeModuleVersion()
{
}
-QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor)
- : m_module(module), m_minor(minor)
+QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, QTypeRevision version)
+ : m_module(module), m_minor(version.minorVersion())
{
Q_ASSERT(m_module);
- Q_ASSERT(m_minor >= 0);
}
QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o)
@@ -68,28 +28,4 @@ QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVers
return *this;
}
-QQmlTypeModule *QQmlTypeModuleVersion::module() const
-{
- return m_module;
-}
-
-int QQmlTypeModuleVersion::minorVersion() const
-{
- return m_minor;
-}
-
-QQmlType QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
-{
- if (!m_module)
- return QQmlType();
- return m_module->type(name, m_minor);
-}
-
-QQmlType QQmlTypeModuleVersion::type(const QV4::String *name) const
-{
- if (!m_module)
- return QQmlType();
- return m_module->type(name, m_minor);
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypemoduleversion_p.h b/src/qml/qml/qqmltypemoduleversion_p.h
index 20f4709ecb..8c9b6c68b2 100644
--- a/src/qml/qml/qqmltypemoduleversion_p.h
+++ b/src/qml/qml/qqmltypemoduleversion_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPEMODULEVERSION_P_H
#define QQMLTYPEMODULEVERSION_P_H
@@ -52,6 +16,9 @@
//
#include <QtQml/qtqmlglobal.h>
+#include <QtQml/private/qqmltype_p.h>
+#include <QtQml/private/qqmltypemodule_p.h>
+#include <QtCore/qversionnumber.h>
QT_BEGIN_NAMESPACE
@@ -67,19 +34,23 @@ class QQmlTypeModuleVersion
{
public:
QQmlTypeModuleVersion();
- QQmlTypeModuleVersion(QQmlTypeModule *, int);
+ QQmlTypeModuleVersion(QQmlTypeModule *, QTypeRevision);
QQmlTypeModuleVersion(const QQmlTypeModuleVersion &);
QQmlTypeModuleVersion &operator=(const QQmlTypeModuleVersion &);
- QQmlTypeModule *module() const;
- int minorVersion() const;
-
- QQmlType type(const QHashedStringRef &) const;
- QQmlType type(const QV4::String *) const;
+ template<typename String>
+ QQmlType type(String name) const
+ {
+ if (!m_module)
+ return QQmlType();
+ return m_module->type(name, QTypeRevision::isValidSegment(m_minor)
+ ? QTypeRevision::fromMinorVersion(m_minor)
+ : QTypeRevision());
+ }
private:
QQmlTypeModule *m_module;
- int m_minor;
+ quint8 m_minor;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
index 8f1a61e6ad..7d3c81cfd7 100644
--- a/src/qml/qml/qqmltypenamecache.cpp
+++ b/src/qml/qml/qqmltypenamecache.cpp
@@ -1,60 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmltypenamecache_p.h"
-#include "qqmlengine_p.h"
-
QT_BEGIN_NAMESPACE
-QQmlTypeNameCache::QQmlTypeNameCache(const QQmlImports &importCache)
- : m_imports(importCache)
-{
-}
-
-QQmlTypeNameCache::~QQmlTypeNameCache()
-{
-}
-
void QQmlTypeNameCache::add(const QHashedString &name, const QUrl &url, const QHashedString &nameSpace)
{
- if (nameSpace.length() != 0) {
+ if (nameSpace.size() != 0) {
QQmlImportRef *i = m_namedImports.value(nameSpace);
Q_ASSERT(i != nullptr);
i->compositeSingletons.insert(name, url);
@@ -73,7 +26,7 @@ void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex,
import.scriptIndex = importedScriptIndex;
import.m_qualifier = name;
- if (nameSpace.length() != 0) {
+ if (nameSpace.size() != 0) {
QQmlImportRef *i = m_namedImports.value(nameSpace);
Q_ASSERT(i != nullptr);
m_namespacedImports[i].insert(name, import);
@@ -86,117 +39,5 @@ void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex,
m_namedImports.insert(name, import);
}
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name) const
-{
- Result result = query(m_namedImports, name);
-
- if (!result.isValid())
- result = typeSearch(m_anonymousImports, name);
-
- if (!result.isValid())
- result = query(m_anonymousCompositeSingletons, name);
-
- if (!result.isValid()) {
- // Look up anonymous types from the imports of this document
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
- QQmlType t;
- bool typeFound = m_imports.resolveType(name, &t, nullptr, nullptr, &typeNamespace, &errors);
- if (typeFound) {
- return Result(t);
- }
-
- }
-
- return result;
-}
-
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name,
- const QQmlImportRef *importNamespace) const
-{
- Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1);
-
- Result result = typeSearch(importNamespace->modules, name);
-
- if (!result.isValid())
- result = query(importNamespace->compositeSingletons, name);
-
- if (!result.isValid()) {
- // Look up types from the imports of this document
- // ### it would be nice if QQmlImports allowed us to resolve a namespace
- // first, and then types on it.
- QString qualifiedTypeName = importNamespace->m_qualifier + QLatin1Char('.') + name.toString();
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
- QQmlType t;
- bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, nullptr, nullptr, &typeNamespace, &errors);
- if (typeFound) {
- return Result(t);
- }
- }
-
- return result;
-}
-
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, QQmlImport::RecursionRestriction recursionRestriction) const
-{
- Result result = query(m_namedImports, name);
-
- if (!result.isValid())
- result = typeSearch(m_anonymousImports, name);
-
- if (!result.isValid())
- result = query(m_anonymousCompositeSingletons, name);
-
- if (!result.isValid()) {
- // Look up anonymous types from the imports of this document
- QString typeName = name->toQStringNoThrow();
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
- QQmlType t;
- bool typeFound = m_imports.resolveType(typeName, &t, nullptr, nullptr, &typeNamespace, &errors,
- QQmlType::AnyRegistrationType, recursionRestriction);
- if (typeFound) {
- return Result(t);
- }
-
- }
-
- return result;
-}
-
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, const QQmlImportRef *importNamespace) const
-{
- Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1);
-
- QMap<const QQmlImportRef *, QStringHash<QQmlImportRef> >::const_iterator it = m_namespacedImports.constFind(importNamespace);
- if (it != m_namespacedImports.constEnd()) {
- Result r = query(*it, name);
- if (r.isValid())
- return r;
- }
-
- Result r = typeSearch(importNamespace->modules, name);
-
- if (!r.isValid())
- r = query(importNamespace->compositeSingletons, name);
-
- if (!r.isValid()) {
- // Look up types from the imports of this document
- // ### it would be nice if QQmlImports allowed us to resolve a namespace
- // first, and then types on it.
- QString qualifiedTypeName = importNamespace->m_qualifier + QLatin1Char('.') + name->toQStringNoThrow();
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
- QQmlType t;
- bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, nullptr, nullptr, &typeNamespace, &errors);
- if (typeFound) {
- return Result(t);
- }
- }
-
- return r;
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h
index b98fe77ed5..1ec0a65fa0 100644
--- a/src/qml/qml/qqmltypenamecache_p.h
+++ b/src/qml/qml/qqmltypenamecache_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTYPENAMECACHE_P_H
#define QQMLTYPENAMECACHE_P_H
@@ -52,7 +16,6 @@
//
#include <private/qqmlrefcount_p.h>
-#include "qqmlcleanup_p.h"
#include "qqmlmetatype_p.h"
#include <private/qstringhash_p.h>
@@ -82,11 +45,11 @@ struct QQmlImportRef {
class QQmlType;
class QQmlEngine;
-class Q_QML_PRIVATE_EXPORT QQmlTypeNameCache : public QQmlRefCount
+class Q_QML_EXPORT QQmlTypeNameCache final : public QQmlRefCounted<QQmlTypeNameCache>
{
public:
- QQmlTypeNameCache(const QQmlImports &imports);
- ~QQmlTypeNameCache() override;
+ QQmlTypeNameCache(const QQmlRefPointer<QQmlImports> &imports) : m_imports(imports) {}
+ ~QQmlTypeNameCache() {}
inline bool isEmpty() const;
@@ -98,7 +61,6 @@ public:
inline Result(const QQmlImportRef *importNamespace);
inline Result(const QQmlType &type);
inline Result(int scriptIndex);
- inline Result(const Result &);
inline bool isValid() const;
@@ -106,16 +68,133 @@ public:
const QQmlImportRef *importNamespace;
int scriptIndex;
};
- Result query(const QHashedStringRef &) const;
- Result query(const QHashedStringRef &, const QQmlImportRef *importNamespace) const;
- Result query(const QV4::String *, QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion) const;
- Result query(const QV4::String *, const QQmlImportRef *importNamespace) const;
+
+ enum class QueryNamespaced { No, Yes };
+
+ // Restrict the types allowed for key. We don't want QV4::ScopedString, for example.
+
+ template<QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion>
+ Result query(const QHashedStringRef &key, QQmlTypeLoader *typeLoader) const
+ {
+ return doQuery<const QHashedStringRef &, recursionRestriction>(key, typeLoader);
+ }
+
+ template<QueryNamespaced queryNamespaced = QueryNamespaced::Yes>
+ Result query(const QHashedStringRef &key, const QQmlImportRef *importNamespace,
+ QQmlTypeLoader *typeLoader) const
+ {
+ return doQuery<const QHashedStringRef &, queryNamespaced>(key, importNamespace, typeLoader);
+ }
+
+ template<QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion>
+ Result query(const QV4::String *key, QQmlTypeLoader *typeLoader) const
+ {
+ return doQuery<const QV4::String *, recursionRestriction>(key, typeLoader);
+ }
+
+ template<QueryNamespaced queryNamespaced = QueryNamespaced::Yes>
+ Result query(const QV4::String *key, const QQmlImportRef *importNamespace,
+ QQmlTypeLoader *typeLoader) const
+ {
+ return doQuery<const QV4::String *, queryNamespaced>(key, importNamespace, typeLoader);
+ }
private:
friend class QQmlImports;
+ static QHashedStringRef toHashedStringRef(const QHashedStringRef &key) { return key; }
+ static QHashedStringRef toHashedStringRef(const QV4::String *key)
+ {
+ const QV4::Heap::String *heapString = key->d();
+
+ // toQString() would also do simplifyString(). Therefore, we can be sure that this
+ // is safe. Any other operation on the string data cannot keep references on the
+ // non-simplified pieces.
+ if (heapString->subtype >= QV4::Heap::String::StringType_Complex)
+ heapString->simplifyString();
+
+ // This is safe because the string data is backed by the QV4::String we got as
+ // parameter. The contract about passing V4 values as parameters is that you have to
+ // scope them first, so that they don't get gc'd while the callee is working on them.
+ const QStringPrivate &text = heapString->text();
+ return QHashedStringRef(QStringView(text.ptr, text.size));
+ }
+
+ static QString toQString(const QHashedStringRef &key) { return key.toString(); }
+ static QString toQString(const QV4::String *key) { return key->toQStringNoThrow(); }
+
+ template<typename Key, QQmlImport::RecursionRestriction recursionRestriction>
+ Result doQuery(Key name, QQmlTypeLoader *typeLoader) const
+ {
+ Result result = doQuery(m_namedImports, name);
+
+ if (!result.isValid())
+ result = typeSearch(m_anonymousImports, name);
+
+ if (!result.isValid())
+ result = doQuery(m_anonymousCompositeSingletons, name);
+
+ if (!result.isValid()) {
+ // Look up anonymous types from the imports of this document
+ // ### it would be nice if QQmlImports allowed us to resolve a namespace
+ // first, and then types on it.
+ QQmlImportNamespace *typeNamespace = nullptr;
+ QList<QQmlError> errors;
+ QQmlType t;
+ bool typeRecursionDetected = false;
+ const bool typeFound = m_imports->resolveType(
+ typeLoader, toHashedStringRef(name), &t, nullptr, &typeNamespace, &errors,
+ QQmlType::AnyRegistrationType,
+ recursionRestriction == QQmlImport::AllowRecursion
+ ? &typeRecursionDetected
+ : nullptr);
+ if (typeFound)
+ return Result(t);
+
+ }
+
+ return result;
+ }
+
+ template<typename Key, QueryNamespaced queryNamespaced>
+ Result doQuery(Key name, const QQmlImportRef *importNamespace, QQmlTypeLoader *typeLoader) const
+ {
+ Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1);
+
+ if constexpr (queryNamespaced == QueryNamespaced::Yes) {
+ QMap<const QQmlImportRef *, QStringHash<QQmlImportRef> >::const_iterator it
+ = m_namespacedImports.constFind(importNamespace);
+ if (it != m_namespacedImports.constEnd()) {
+ Result r = doQuery(*it, name);
+ if (r.isValid())
+ return r;
+ }
+ }
+
+ Result result = typeSearch(importNamespace->modules, name);
+
+ if (!result.isValid())
+ result = doQuery(importNamespace->compositeSingletons, name);
+
+ if (!result.isValid()) {
+ // Look up types from the imports of this document
+ // ### it would be nice if QQmlImports allowed us to resolve a namespace
+ // first, and then types on it.
+ const QString qualifiedTypeName = importNamespace->m_qualifier + u'.' + toQString(name);
+ QQmlImportNamespace *typeNamespace = nullptr;
+ QList<QQmlError> errors;
+ QQmlType t;
+ bool typeFound = m_imports->resolveType(
+ typeLoader, qualifiedTypeName, &t, nullptr, &typeNamespace, &errors);
+ if (typeFound)
+ return Result(t);
+ }
+
+ return result;
+ }
+
template<typename Key>
- Result query(const QStringHash<QQmlImportRef> &imports, Key key) const
+ Result doQuery(const QStringHash<QQmlImportRef> &imports, Key key) const
{
QQmlImportRef *i = imports.value(key);
if (i) {
@@ -131,7 +210,7 @@ private:
}
template<typename Key>
- Result query(const QStringHash<QUrl> &urls, Key key) const
+ Result doQuery(const QStringHash<QUrl> &urls, Key key) const
{
QUrl *url = urls.value(key);
if (url) {
@@ -159,7 +238,7 @@ private:
QMap<const QQmlImportRef *, QStringHash<QQmlImportRef> > m_namespacedImports;
QVector<QQmlTypeModuleVersion> m_anonymousImports;
QStringHash<QUrl> m_anonymousCompositeSingletons;
- QQmlImports m_imports;
+ QQmlRefPointer<QQmlImports> m_imports;
};
QQmlTypeNameCache::Result::Result()
@@ -182,11 +261,6 @@ QQmlTypeNameCache::Result::Result(int scriptIndex)
{
}
-QQmlTypeNameCache::Result::Result(const Result &o)
-: type(o.type), importNamespace(o.importNamespace), scriptIndex(o.scriptIndex)
-{
-}
-
bool QQmlTypeNameCache::Result::isValid() const
{
return type.isValid() || importNamespace || scriptIndex != -1;
diff --git a/src/qml/qml/qqmltypenotavailable.cpp b/src/qml/qml/qqmltypenotavailable.cpp
deleted file mode 100644
index ffa4472e4b..0000000000
--- a/src/qml/qml/qqmltypenotavailable.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmltypenotavailable_p.h"
-
-QT_BEGIN_NAMESPACE
-
-int qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message)
-{
- return qmlRegisterUncreatableType<QQmlTypeNotAvailable>(uri,versionMajor,versionMinor,qmlName,message);
-}
-
-QQmlTypeNotAvailable::QQmlTypeNotAvailable() { }
-
-QT_END_NAMESPACE
-
-#include "moc_qqmltypenotavailable_p.cpp"
diff --git a/src/qml/qml/qqmltypenotavailable_p.h b/src/qml/qml/qqmltypenotavailable_p.h
deleted file mode 100644
index 8db5876b10..0000000000
--- a/src/qml/qml/qqmltypenotavailable_p.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLTYPENOTAVAILABLE_H
-#define QQMLTYPENOTAVAILABLE_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <qqml.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QQmlTypeNotAvailable : public QObject {
- Q_OBJECT
- QML_NAMED_ELEMENT(TypeNotAvailable)
- QML_UNCREATABLE("Type not available.")
-
-public:
- QQmlTypeNotAvailable();
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlTypeNotAvailable)
-
-#endif // QQMLTYPENOTAVAILABLE_H
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index ef4a628a04..0d8786a9df 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmltypewrapper_p.h"
@@ -43,6 +7,7 @@
#include <private/qqmlcontext_p.h>
#include <private/qqmlmetaobject_p.h>
#include <private/qqmltypedata_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
#include <private/qjsvalue_p.h>
#include <private/qv4functionobject_p.h>
@@ -58,15 +23,32 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(QQmlTypeWrapper);
DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper);
-void Heap::QQmlTypeWrapper::init()
+
+void Heap::QQmlTypeWrapper::init(TypeNameMode m, QObject *o, const QQmlTypePrivate *type)
+{
+ Q_ASSERT(type);
+ Object::init();
+ mode = m;
+ object.init(o);
+ typePrivate = type;
+ QQmlType::refHandle(typePrivate);
+}
+
+void Heap::QQmlTypeWrapper::init(
+ TypeNameMode m, QObject *o, QQmlTypeNameCache *type, const QQmlImportRef *import)
{
+ Q_ASSERT(type);
Object::init();
- mode = IncludeEnums;
- object.init();
+ mode = m;
+ object.init(o);
+ typeNamespace = type;
+ typeNamespace->addref();
+ importNamespace = import;
}
void Heap::QQmlTypeWrapper::destroy()
{
+ Q_ASSERT(typePrivate || typeNamespace);
QQmlType::derefHandle(typePrivate);
typePrivate = nullptr;
if (typeNamespace)
@@ -85,6 +67,50 @@ bool QQmlTypeWrapper::isSingleton() const
return d()->type().isSingleton();
}
+const QMetaObject *QQmlTypeWrapper::metaObject() const
+{
+ const QQmlType type = d()->type();
+ if (!type.isValid())
+ return nullptr;
+
+ if (type.isSingleton()) {
+ auto metaObjectCandidate = type.metaObject();
+ // if the candidate is the same as te baseMetaObject, we know that
+ // we don't have an extended singleton; in that case the
+ // actual instance might be subclass of type instead of type itself
+ // so we need to query the actual object for it's meta-object
+ if (metaObjectCandidate == type.baseMetaObject()) {
+ QQmlEnginePrivate *qmlEngine = QQmlEnginePrivate::get(engine()->qmlEngine());
+ auto object = qmlEngine->singletonInstance<QObject *>(type);
+ if (object)
+ return object->metaObject();
+ }
+ /* if we instead have an extended singleton, the dynamic proxy
+ meta-object must alreday be set up correctly
+ ### TODO: it isn't, as QQmlTypePrivate::init has no way to
+ query the object
+ */
+ return metaObjectCandidate;
+ }
+
+ return type.attachedPropertiesType(QQmlEnginePrivate::get(engine()->qmlEngine()));
+}
+
+QObject *QQmlTypeWrapper::object() const
+{
+ const QQmlType type = d()->type();
+ if (!type.isValid())
+ return nullptr;
+
+ QQmlEnginePrivate *qmlEngine = QQmlEnginePrivate::get(engine()->qmlEngine());
+ if (type.isSingleton())
+ return qmlEngine->singletonInstance<QObject *>(type);
+
+ return qmlAttachedPropertiesObject(
+ d()->object,
+ type.attachedPropertiesFunction(qmlEngine));
+}
+
QObject* QQmlTypeWrapper::singletonObject() const
{
if (!isSingleton())
@@ -96,11 +122,14 @@ QObject* QQmlTypeWrapper::singletonObject() const
QVariant QQmlTypeWrapper::toVariant() const
{
- if (!isSingleton())
- return QVariant::fromValue<QObject *>(d()->object);
-
QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine());
const QQmlType type = d()->type();
+
+ if (!isSingleton()) {
+ return QVariant::fromValue(qmlAttachedPropertiesObject(
+ d()->object, type.attachedPropertiesFunction(e)));
+ }
+
if (type.isQJSValueSingleton())
return QVariant::fromValue<QJSValue>(e->singletonInstance<QJSValue>(type));
@@ -115,55 +144,31 @@ ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o,
Q_ASSERT(t.isValid());
Scope scope(engine);
- Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>());
- w->d()->mode = mode; w->d()->object = o;
- w->d()->typePrivate = t.priv();
- QQmlType::refHandle(w->d()->typePrivate);
+ Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>(
+ mode, o, t.priv()));
return w.asReturnedValue();
}
// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
// namespace.
-ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlRefPointer<QQmlTypeNameCache> &t, const QQmlImportRef *importNamespace,
- Heap::QQmlTypeWrapper::TypeNameMode mode)
+ReturnedValue QQmlTypeWrapper::create(
+ QV4::ExecutionEngine *engine, QObject *o, const QQmlRefPointer<QQmlTypeNameCache> &t,
+ const QQmlImportRef *importNamespace, Heap::QQmlTypeWrapper::TypeNameMode mode)
{
Q_ASSERT(t);
Q_ASSERT(importNamespace);
Scope scope(engine);
- Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>());
- w->d()->mode = mode; w->d()->object = o; w->d()->typeNamespace = t.data(); w->d()->importNamespace = importNamespace;
- t->addref();
+ Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>(
+ mode, o, t.data(), importNamespace));
return w.asReturnedValue();
}
-static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, QObject *qobjectSingleton,
- const QQmlType &type, bool *ok)
+static int enumForSingleton(QV4::ExecutionEngine *v4, String *name, const QQmlType &type, bool *ok)
{
Q_ASSERT(ok != nullptr);
- int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, ok);
- if (*ok)
- return value;
-
- // ### Optimize
- QByteArray enumName = name->toQString().toUtf8();
- const QMetaObject *metaObject = qobjectSingleton->metaObject();
- for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
- QMetaEnum e = metaObject->enumerator(ii);
- value = e.keyToValue(enumName.constData(), ok);
- if (*ok)
- return value;
- }
- *ok = false;
- return -1;
-}
-
-static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *name, const QQmlType &type)
-{
- const QString message =
- QStringLiteral("Cannot access enum value '%1' of '%2', enum values need to start with an uppercase letter.")
- .arg(name->toQString()).arg(QLatin1String(type.typeName()));
- return v4->throwTypeError(message);
+ const int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, ok);
+ return *ok ? value : -1;
}
ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
@@ -174,7 +179,7 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
if (!id.isString())
return Object::virtualGet(m, id, receiver, hasProperty);
- QV4::ExecutionEngine *v4 = static_cast<const QQmlTypeWrapper *>(m)->engine();
+ QV4::ExecutionEngine *v4 = m->engine();
QV4::Scope scope(v4);
ScopedString name(scope, id.asStringOrSymbol());
@@ -183,28 +188,29 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
if (hasProperty)
*hasProperty = true;
- QQmlContextData *context = v4->callingQmlContext();
+ QQmlRefPointer<QQmlContextData> context = v4->callingQmlContext();
QObject *object = w->d()->object;
QQmlType type = w->d()->type();
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(v4->qmlEngine());
if (type.isValid()) {
// singleton types are handled differently to other types.
if (type.isSingleton()) {
- QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine());
+
QJSValue scriptSingleton;
if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
- if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
+ if (QObject *qobjectSingleton = enginePrivate->singletonInstance<QObject*>(type)) {
// check for enum value
const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
if (includeEnums && name->startsWithUpper()) {
bool ok = false;
- int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok);
+ int value = enumForSingleton(v4, name, type, &ok);
if (ok)
return QV4::Value::fromInt32(value).asReturnedValue();
- value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
+ value = type.scopedEnumIndex(enginePrivate, name, &ok);
if (ok) {
Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
enumWrapper->d()->typePrivate = type.priv();
@@ -216,24 +222,19 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
// check for property.
bool ok;
- const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok);
+ const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(
+ v4, context, w->d(), qobjectSingleton, name,
+ QV4::QObjectWrapper::AttachMethods, &ok);
if (hasProperty)
*hasProperty = ok;
- // Warn when attempting to access a lowercased enum value, singleton case
- if (!ok && includeEnums && !name->startsWithUpper()) {
- enumForSingleton(v4, name, qobjectSingleton, type, &ok);
- if (ok)
- return throwLowercaseEnumError(v4, name, type);
- }
-
return result;
}
} else if (type.isQJSValueSingleton()) {
- QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
+ QJSValue scriptSingleton = enginePrivate->singletonInstance<QJSValue>(type);
if (!scriptSingleton.isUndefined()) {
// NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
- QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, scriptSingleton));
+ QV4::ScopedObject o(scope, QJSValuePrivate::asReturnedValue(&scriptSingleton));
if (!!o)
return o->get(name);
}
@@ -245,11 +246,11 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
if (name->startsWithUpper()) {
bool ok = false;
- int value = type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
+ int value = type.enumValue(enginePrivate, name, &ok);
if (ok)
return QV4::Value::fromInt32(value).asReturnedValue();
- value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
+ value = type.scopedEnumIndex(enginePrivate, name, &ok);
if (ok) {
Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>());
enumWrapper->d()->typePrivate = type.priv();
@@ -265,7 +266,9 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
object,
type.attachedPropertiesFunction(QQmlEnginePrivate::get(v4->qmlEngine())));
if (ao)
- return QV4::QObjectWrapper::getQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty);
+ return QV4::QObjectWrapper::getQmlProperty(
+ v4, context, w->d(), ao, name, QV4::QObjectWrapper::AttachMethods,
+ hasProperty);
// Fall through to base implementation
}
@@ -277,16 +280,17 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
} else if (w->d()->typeNamespace) {
Q_ASSERT(w->d()->importNamespace);
- QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(name, w->d()->importNamespace);
+ QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(
+ name, w->d()->importNamespace, QQmlTypeLoader::get(enginePrivate));
if (r.isValid()) {
if (r.type.isValid()) {
return create(scope.engine, object, r.type, w->d()->mode);
} else if (r.scriptIndex != -1) {
- QV4::ScopedObject scripts(scope, context->importedScripts.valueRef());
+ QV4::ScopedObject scripts(scope, context->importedScripts().valueRef());
return scripts->get(r.scriptIndex);
} else if (r.importNamespace) {
- return create(scope.engine, object, context->imports, r.importNamespace);
+ return create(scope.engine, object, context->imports(), r.importNamespace);
}
return QV4::Encode::undefined();
@@ -304,14 +308,6 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
if (hasProperty)
*hasProperty = ok;
- // Warn when attempting to access a lowercased enum value, non-singleton case
- if (!ok && type.isValid() && !type.isSingleton() && !name->startsWithUpper()) {
- bool enumOk = false;
- type.enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &enumOk);
- if (enumOk)
- return throwLowercaseEnumError(v4, name, type);
- }
-
return result;
}
@@ -325,11 +321,11 @@ bool QQmlTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
Q_ASSERT(m->as<QQmlTypeWrapper>());
QQmlTypeWrapper *w = static_cast<QQmlTypeWrapper *>(m);
QV4::Scope scope(w);
- if (scope.engine->hasException)
+ if (scope.hasException())
return false;
ScopedString name(scope, id.asStringOrSymbol());
- QQmlContextData *context = scope.engine->callingQmlContext();
+ QQmlRefPointer<QQmlContextData> context = scope.engine->callingQmlContext();
QQmlType type = w->d()->type();
if (type.isValid() && !type.isSingleton() && w->d()->object) {
@@ -338,18 +334,21 @@ bool QQmlTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
QObject *ao = qmlAttachedPropertiesObject(
object, type.attachedPropertiesFunction(QQmlEnginePrivate::get(e)));
if (ao)
- return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value);
+ return QV4::QObjectWrapper::setQmlProperty(
+ scope.engine, context, ao, name, QV4::QObjectWrapper::NoFlag, value);
return false;
} else if (type.isSingleton()) {
QQmlEnginePrivate *e = QQmlEnginePrivate::get(scope.engine->qmlEngine());
if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type))
- return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
+ return QV4::QObjectWrapper::setQmlProperty(
+ scope.engine, context, qobjectSingleton, name,
+ QV4::QObjectWrapper::NoFlag, value);
} else {
QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type);
if (!scriptSingleton.isUndefined()) {
- QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, scriptSingleton));
+ QV4::ScopedObject apiprivate(scope, QJSValuePrivate::asReturnedValue(&scriptSingleton));
if (!apiprivate) {
QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
scope.engine->throwError(error);
@@ -390,39 +389,35 @@ bool QQmlTypeWrapper::virtualIsEqualTo(Managed *a, Managed *b)
return false;
}
-ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const Value &var)
+static ReturnedValue instanceOfQObject(const QV4::QQmlTypeWrapper *typeWrapper, const QObjectWrapper *objectWrapper)
{
- Q_ASSERT(typeObject->as<QV4::QQmlTypeWrapper>());
- const QV4::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::QQmlTypeWrapper *>(typeObject);
- QV4::ExecutionEngine *engine = typeObject->internalClass()->engine;
- QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine());
-
- // can only compare a QObject* against a QML type
- const QObjectWrapper *wrapper = var.as<QObjectWrapper>();
- if (!wrapper)
- return engine->throwTypeError();
-
+ QV4::ExecutionEngine *engine = typeWrapper->internalClass()->engine;
// in case the wrapper outlived the QObject*
- const QObject *wrapperObject = wrapper->object();
+ const QObject *wrapperObject = objectWrapper->object();
if (!wrapperObject)
return engine->throwTypeError();
- const int myTypeId = typeWrapper->d()->type().typeId();
+ const QMetaType myTypeId = typeWrapper->d()->type().typeId();
QQmlMetaObject myQmlType;
- if (myTypeId == 0) {
+ if (!myTypeId.isValid()) {
// we're a composite type; a composite type cannot be equal to a
// non-composite object instance (Rectangle{} is never an instance of
// CustomRectangle)
- QQmlData *theirDData = QQmlData::get(wrapperObject, /*create=*/false);
+ QQmlData *theirDData = QQmlData::get(wrapperObject);
Q_ASSERT(theirDData); // must exist, otherwise how do we have a QObjectWrapper for it?!
if (!theirDData->compilationUnit)
return Encode(false);
+ QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine());
QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
- ExecutableCompilationUnit *cu = td->compilationUnit();
- myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
+ if (CompiledData::CompilationUnit *cu = td->compilationUnit())
+ myQmlType = QQmlMetaType::metaObjectForType(cu->metaType());
+ else
+ return Encode(false); // It seems myQmlType has some errors, so we could not compile it.
} else {
- myQmlType = qenginepriv->metaObjectForType(myTypeId);
+ myQmlType = QQmlMetaType::metaObjectForType(myTypeId);
+ if (myQmlType.isNull())
+ return Encode(false);
}
const QMetaObject *theirType = wrapperObject->metaObject();
@@ -430,6 +425,29 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType));
}
+ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const Value &var)
+{
+ Q_ASSERT(typeObject->as<QV4::QQmlTypeWrapper>());
+ const QV4::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::QQmlTypeWrapper *>(typeObject);
+
+ if (const QObjectWrapper *objectWrapper = var.as<QObjectWrapper>())
+ return instanceOfQObject(typeWrapper, objectWrapper);
+
+ const QQmlType type = typeWrapper->d()->type();
+ if (type.isValueType()) {
+ if (const QQmlValueTypeWrapper *valueWrapper = var.as<QQmlValueTypeWrapper>()) {
+ return QV4::Encode(QQmlMetaObject::canConvert(valueWrapper->metaObject(),
+ type.metaObjectForValueType()));
+ }
+
+ // We want "foo as valuetype" to return undefined if it doesn't match.
+ return Encode::undefined();
+ }
+
+ // If the target type is an object type we want null.
+ return Encode(false);
+}
+
ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
{
// Keep this code in sync with ::virtualGet
@@ -440,7 +458,7 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
const QQmlTypeWrapper *This = static_cast<const QQmlTypeWrapper *>(object);
ScopedString name(scope, id.asStringOrSymbol());
- QQmlContextData *qmlContext = engine->callingQmlContext();
+ QQmlRefPointer<QQmlContextData> qmlContext = engine->callingQmlContext();
Scoped<QQmlTypeWrapper> w(scope, static_cast<const QQmlTypeWrapper *>(This));
QQmlType type = w->d()->type();
@@ -455,15 +473,19 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
if (!includeEnums || !name->startsWithUpper()) {
QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
if (ddata && ddata->propertyCache) {
- QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
+ const QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
if (property) {
ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
- lookup->qobjectLookup.qmlTypeIc = This->internalClass();
- lookup->qobjectLookup.ic = val->objectValue()->internalClass();
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = property;
- lookup->getter = QQmlTypeWrapper::lookupSingletonProperty;
+ if (qualifiesForMethodLookup(property)) {
+ QV4::Heap::QObjectMethod *method = nullptr;
+ setupQObjectMethodLookup(
+ lookup, ddata, property, val->objectValue(), method);
+ lookup->getter = QQmlTypeWrapper::lookupSingletonMethod;
+ } else {
+ setupQObjectLookup(
+ lookup, ddata, property, val->objectValue(), This);
+ lookup->getter = QQmlTypeWrapper::lookupSingletonProperty;
+ }
return lookup->getter(lookup, engine, *object);
}
// Fall through to base implementation
@@ -481,7 +503,7 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
bool ok = false;
int value = type.enumValue(QQmlEnginePrivate::get(engine->qmlEngine()), name, &ok);
if (ok) {
- lookup->qmlEnumValueLookup.ic = This->internalClass();
+ lookup->qmlEnumValueLookup.ic.set(engine, This->internalClass());
lookup->qmlEnumValueLookup.encodedEnumValue
= QV4::Value::fromInt32(value).asReturnedValue();
lookup->getter = QQmlTypeWrapper::lookupEnumValue;
@@ -496,9 +518,9 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
QQmlType::refHandle(enumWrapper->d()->typePrivate);
enumWrapper->d()->scopeEnumIndex = value;
- lookup->qmlScopedEnumWrapperLookup.ic = This->internalClass();
- lookup->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper
- = static_cast<Heap::Object*>(enumWrapper->heapObject());
+ lookup->qmlScopedEnumWrapperLookup.ic.set(engine, This->internalClass());
+ lookup->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper.set(engine,
+ static_cast<Heap::Object*>(enumWrapper->heapObject()));
lookup->getter = QQmlTypeWrapper::lookupScopedEnum;
return enumWrapper.asReturnedValue();
}
@@ -514,6 +536,30 @@ bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine
return Object::virtualResolveLookupSetter(object, engine, lookup, value);
}
+OwnPropertyKeyIterator *QQmlTypeWrapper::virtualOwnPropertyKeys(const Object *m, Value *target)
+{
+ QV4::Scope scope(m->engine());
+ QV4::Scoped<QQmlTypeWrapper> typeWrapper(scope, m);
+ Q_ASSERT(typeWrapper);
+ if (QObject *object = typeWrapper->object()) {
+ QV4::Scoped<QV4::QObjectWrapper> objectWrapper(scope, QV4::QObjectWrapper::wrap(typeWrapper->engine(), object));
+ return QV4::QObjectWrapper::virtualOwnPropertyKeys(objectWrapper, target);
+ }
+
+ return Object::virtualOwnPropertyKeys(m, target);
+}
+
+int QQmlTypeWrapper::virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a)
+{
+ QQmlTypeWrapper *wrapper = object->as<QQmlTypeWrapper>();
+ Q_ASSERT(wrapper);
+
+ if (QObject *qObject = wrapper->object())
+ return QMetaObject::metacall(qObject, call, index, a);
+
+ return 0;
+}
+
ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &object)
{
const auto revertLookup = [l, engine, &object]() {
@@ -526,6 +572,16 @@ ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngin
// we can safely cast to a QV4::Object here. If object is something else,
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
+
+ // The qmlTypeIc check is not strictly necessary.
+ // If we have different ways to get to the same QObject type
+ // we can use the same lookup to get its properties, no matter
+ // how we've found the object. Most of the few times this check
+ // fails, we will, of course have different object types. So
+ // this check provides an early exit for the error case.
+ //
+ // So, if we ever need more bits in qobjectLookup, qmlTypeIc is the
+ // member to be replaced.
if (!o || o->internalClass != l->qobjectLookup.qmlTypeIc)
return revertLookup();
@@ -544,7 +600,42 @@ ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngin
Scope scope(engine);
ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, qobjectSingleton));
- return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup);
+ const QObjectWrapper::Flags flags = l->forCall
+ ? QObjectWrapper::AllowOverride
+ : (QObjectWrapper::AttachMethods | QObjectWrapper::AllowOverride);
+ return QObjectWrapper::lookupPropertyGetterImpl(l, engine, obj, flags, revertLookup);
+}
+
+ReturnedValue QQmlTypeWrapper::lookupSingletonMethod(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ const auto revertLookup = [l, engine, &object]() {
+ l->qobjectMethodLookup.propertyCache->release();
+ l->qobjectMethodLookup.propertyCache = nullptr;
+ l->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(l, engine, object);
+ };
+
+ // We cannot safely cast here as we don't explicitly check the IC. Therefore as().
+ const QQmlTypeWrapper *This = object.as<QQmlTypeWrapper>();
+ if (!This)
+ return revertLookup();
+
+ QQmlType type = This->d()->type();
+ if (!type.isValid())
+ return revertLookup();
+
+ if (!type.isQObjectSingleton() && !type.isCompositeSingleton())
+ return revertLookup();
+
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
+ QObject *qobjectSingleton = e->singletonInstance<QObject *>(type);
+ Q_ASSERT(qobjectSingleton);
+
+ Scope scope(engine);
+ ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, qobjectSingleton));
+ return QObjectWrapper::lookupMethodGetterImpl(
+ l, engine, obj, l->forCall ? QObjectWrapper::NoFlag : QObjectWrapper::AttachMethods,
+ revertLookup);
}
ReturnedValue QQmlTypeWrapper::lookupEnumValue(Lookup *l, ExecutionEngine *engine, const Value &base)
@@ -562,12 +653,12 @@ ReturnedValue QQmlTypeWrapper::lookupScopedEnum(Lookup *l, ExecutionEngine *engi
{
Scope scope(engine);
Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, static_cast<Heap::QQmlScopedEnumWrapper *>(
- l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper));
+ l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper.get()));
auto *o = static_cast<Heap::Object *>(base.heapObject());
if (!o || o->internalClass != l->qmlScopedEnumWrapperLookup.ic) {
QQmlType::derefHandle(enumWrapper->d()->typePrivate);
- l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper = nullptr;
+ l->qmlScopedEnumWrapperLookup.qmlScopedEnumWrapper.clear();
l->getter = Lookup::getterGeneric;
return Lookup::getterGeneric(l, engine, base);
}
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index 7dc3f55310..717efaf20e 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV8TYPEWRAPPER_P_H
#define QV8TYPEWRAPPER_P_H
@@ -74,10 +38,12 @@ struct QQmlTypeWrapper : Object {
ExcludeEnums
};
- void init();
+ void init(TypeNameMode m, QObject *o, const QQmlTypePrivate *type);
+ void init(TypeNameMode m, QObject *o, QQmlTypeNameCache *type, const QQmlImportRef *import);
+
void destroy();
TypeNameMode mode;
- QQmlQPointer<QObject> object;
+ QV4QPointer<QObject> object;
QQmlType type() const;
@@ -102,6 +68,8 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object
V4_NEEDS_DESTROY
bool isSingleton() const;
+ const QMetaObject *metaObject() const;
+ QObject *object() const;
QObject *singletonObject() const;
QVariant toVariant() const;
@@ -113,8 +81,11 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object
static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
+ static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
+ static int virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a);
static ReturnedValue lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &base);
+ static ReturnedValue lookupSingletonMethod(Lookup *l, ExecutionEngine *engine, const Value &base);
static ReturnedValue lookupEnumValue(Lookup *l, ExecutionEngine *engine, const Value &base);
static ReturnedValue lookupScopedEnum(Lookup *l, ExecutionEngine *engine, const Value &base);
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index d83fc4bb48..4088d6e6c4 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -1,295 +1,117 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlvaluetype_p.h"
#include <QtCore/qmutex.h>
#include <private/qqmlglobal_p.h>
#include <QtCore/qdebug.h>
+#include <private/qqmlengine_p.h>
#include <private/qmetaobjectbuilder_p.h>
-#if QT_CONFIG(qml_itemmodel)
-#include <private/qqmlmodelindexvaluetype_p.h>
-#endif
-#include <private/qmetatype_p.h>
QT_BEGIN_NAMESPACE
-namespace {
-
-struct QQmlValueTypeFactoryImpl
-{
- QQmlValueTypeFactoryImpl();
- ~QQmlValueTypeFactoryImpl();
-
- bool isValueType(int idx);
-
- const QMetaObject *metaObjectForMetaType(int);
- QQmlValueType *valueType(int);
-
- QQmlValueType *valueTypes[QVariant::UserType];
- QHash<int, QQmlValueType *> userTypes;
- QMutex mutex;
-
- QQmlValueType invalidValueType;
-};
-
-QQmlValueTypeFactoryImpl::QQmlValueTypeFactoryImpl()
-{
- std::fill_n(valueTypes, int(QVariant::UserType), &invalidValueType);
-
-#if QT_CONFIG(qml_itemmodel)
- // See types wrapped in qqmlmodelindexvaluetype_p.h
- qRegisterMetaType<QItemSelectionRange>();
-#endif
-}
-
-QQmlValueTypeFactoryImpl::~QQmlValueTypeFactoryImpl()
-{
- for (QQmlValueType *type : valueTypes) {
- if (type != &invalidValueType)
- delete type;
- }
- qDeleteAll(userTypes);
-}
-
-bool isInternalType(int idx)
-{
- // Qt internal types
- switch (idx) {
- case QMetaType::UnknownType:
- case QMetaType::QStringList:
- case QMetaType::QObjectStar:
- case QMetaType::VoidStar:
- case QMetaType::Nullptr:
- case QMetaType::QVariant:
- case QMetaType::QLocale:
- case QMetaType::QImage: // scarce type, keep as QVariant
- case QMetaType::QPixmap: // scarce type, keep as QVariant
- return true;
- default:
- return false;
- }
-}
-
-bool QQmlValueTypeFactoryImpl::isValueType(int idx)
+QQmlValueType::~QQmlValueType()
{
- if (idx < 0 || isInternalType(idx))
- return false;
-
- return valueType(idx) != nullptr;
+ ::free(m_dynamicMetaObject);
}
-const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
+QQmlGadgetPtrWrapper *QQmlGadgetPtrWrapper::instance(QQmlEngine *engine, QMetaType type)
{
- switch (t) {
- case QVariant::Point:
- return &QQmlPointValueType::staticMetaObject;
- case QVariant::PointF:
- return &QQmlPointFValueType::staticMetaObject;
- case QVariant::Size:
- return &QQmlSizeValueType::staticMetaObject;
- case QVariant::SizeF:
- return &QQmlSizeFValueType::staticMetaObject;
- case QVariant::Rect:
- return &QQmlRectValueType::staticMetaObject;
- case QVariant::RectF:
- return &QQmlRectFValueType::staticMetaObject;
-#if QT_CONFIG(easingcurve)
- case QVariant::EasingCurve:
- return &QQmlEasingValueType::staticMetaObject;
-#endif
-#if QT_CONFIG(qml_itemmodel)
- case QVariant::ModelIndex:
- return &QQmlModelIndexValueType::staticMetaObject;
- case QVariant::PersistentModelIndex:
- return &QQmlPersistentModelIndexValueType::staticMetaObject;
-#endif
- default:
-#if QT_CONFIG(qml_itemmodel)
- if (t == qMetaTypeId<QItemSelectionRange>())
- return &QQmlItemSelectionRangeValueType::staticMetaObject;
-#endif
-
- if (const QMetaObject *mo = QQml_valueTypeProvider()->metaObjectForMetaType(t))
- return mo;
- break;
- }
-
- QMetaType metaType(t);
- if (metaType.flags() & QMetaType::IsGadget)
- return metaType.metaObject();
- return nullptr;
+ return engine ? QQmlEnginePrivate::get(engine)->valueTypeInstance(type) : nullptr;
}
-QQmlValueType *QQmlValueTypeFactoryImpl::valueType(int idx)
+QQmlGadgetPtrWrapper::QQmlGadgetPtrWrapper(QQmlValueType *valueType, QObject *parent)
+ : QObject(parent), m_gadgetPtr(valueType->create())
{
- if (idx >= (int)QVariant::UserType) {
- // Protect the hash with a mutex
- mutex.lock();
-
- QHash<int, QQmlValueType *>::iterator it = userTypes.find(idx);
- if (it == userTypes.end()) {
- QQmlValueType *vt = nullptr;
- if (const QMetaObject *mo = metaObjectForMetaType(idx))
- vt = new QQmlValueType(idx, mo);
- it = userTypes.insert(idx, vt);
- }
-
- mutex.unlock();
- return *it;
- }
-
- QQmlValueType *rv = valueTypes[idx];
- if (rv == &invalidValueType) {
- // No need for mutex protection - the most we can lose is a valueType instance
-
- // TODO: Investigate the performance/memory characteristics of
- // removing the preallocated array
- if (isInternalType(idx))
- rv = valueTypes[idx] = nullptr;
- else if (const QMetaObject *mo = metaObjectForMetaType(idx))
- rv = valueTypes[idx] = new QQmlValueType(idx, mo);
- else
- rv = valueTypes[idx] = nullptr;
- }
-
- return rv;
+ QObjectPrivate *d = QObjectPrivate::get(this);
+ Q_ASSERT(!d->metaObject);
+ d->metaObject = valueType;
}
-}
-
-Q_GLOBAL_STATIC(QQmlValueTypeFactoryImpl, factoryImpl);
-
-bool QQmlValueTypeFactory::isValueType(int idx)
+QQmlGadgetPtrWrapper::~QQmlGadgetPtrWrapper()
{
- return factoryImpl()->isValueType(idx);
+ QObjectPrivate *d = QObjectPrivate::get(this);
+ static_cast<const QQmlValueType *>(d->metaObject)->destroy(m_gadgetPtr);
+ d->metaObject = nullptr;
}
-QQmlValueType *QQmlValueTypeFactory::valueType(int idx)
+void QQmlGadgetPtrWrapper::read(QObject *obj, int idx)
{
- return factoryImpl()->valueType(idx);
+ Q_ASSERT(m_gadgetPtr);
+ void *a[] = { m_gadgetPtr, nullptr };
+ QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
}
-const QMetaObject *QQmlValueTypeFactory::metaObjectForMetaType(int type)
+void QQmlGadgetPtrWrapper::write(
+ QObject *obj, int idx, QQmlPropertyData::WriteFlags flags, int internalIndex) const
{
- return factoryImpl()->metaObjectForMetaType(type);
+ Q_ASSERT(m_gadgetPtr);
+ int status = -1;
+ void *a[] = { m_gadgetPtr, nullptr, &status, &flags, &internalIndex };
+ QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
}
-void QQmlValueTypeFactory::registerValueTypes(const char *uri, int versionMajor, int versionMinor)
+QVariant QQmlGadgetPtrWrapper::value() const
{
-#if QT_CONFIG(easingcurve)
- qmlRegisterValueTypeEnums<QQmlEasingValueType>(uri, versionMajor, versionMinor, "Easing");
-#endif
-}
+ Q_ASSERT(m_gadgetPtr);
-QQmlValueType::QQmlValueType() :
- _metaObject(nullptr),
- gadgetPtr(nullptr),
- metaType(QMetaType::UnknownType)
-{
+ const QMetaType m = metaType();
+ return m == QMetaType::fromType<QVariant>()
+ ? *static_cast<const QVariant *>(m_gadgetPtr)
+ : QVariant(m, m_gadgetPtr);
}
-QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject)
- : gadgetPtr(QMetaType::create(typeId))
- , metaType(typeId)
+void QQmlGadgetPtrWrapper::setValue(const QVariant &value)
{
- QObjectPrivate *op = QObjectPrivate::get(this);
- Q_ASSERT(!op->metaObject);
- op->metaObject = this;
+ Q_ASSERT(m_gadgetPtr);
- QMetaObjectBuilder builder(gadgetMetaObject);
- _metaObject = builder.toMetaObject();
-
- *static_cast<QMetaObject*>(this) = *_metaObject;
-}
-
-QQmlValueType::~QQmlValueType()
-{
- QObjectPrivate *op = QObjectPrivate::get(this);
- Q_ASSERT(op->metaObject == nullptr || op->metaObject == this);
- op->metaObject = nullptr;
- ::free(const_cast<QMetaObject *>(_metaObject));
- metaType.destroy(gadgetPtr);
+ const QMetaType m = metaType();
+ m.destruct(m_gadgetPtr);
+ if (m == QMetaType::fromType<QVariant>()) {
+ m.construct(m_gadgetPtr, &value);
+ } else {
+ Q_ASSERT(m == value.metaType());
+ m.construct(m_gadgetPtr, value.constData());
+ }
}
-void QQmlValueType::read(QObject *obj, int idx)
+int QQmlGadgetPtrWrapper::metaCall(QMetaObject::Call type, int id, void **argv)
{
- void *a[] = { gadgetPtr, nullptr };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a);
+ Q_ASSERT(m_gadgetPtr);
+ const QMetaObject *metaObject = valueType()->staticMetaObject();
+ QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &id);
+ metaObject->d.static_metacall(static_cast<QObject *>(m_gadgetPtr), type, id, argv);
+ return id;
}
-void QQmlValueType::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags)
+const QQmlValueType *QQmlGadgetPtrWrapper::valueType() const
{
- Q_ASSERT(gadgetPtr);
- int status = -1;
- void *a[] = { gadgetPtr, nullptr, &status, &flags };
- QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a);
+ const QObjectPrivate *d = QObjectPrivate::get(this);
+ return static_cast<const QQmlValueType *>(d->metaObject);
}
-QVariant QQmlValueType::value()
+QMetaObject *QQmlValueType::toDynamicMetaObject(QObject *)
{
- Q_ASSERT(gadgetPtr);
- return QVariant(metaType.id(), gadgetPtr);
-}
+ if (!m_dynamicMetaObject) {
+ QMetaObjectBuilder builder(m_staticMetaObject);
-void QQmlValueType::setValue(const QVariant &value)
-{
- Q_ASSERT(metaType.id() == value.userType());
- metaType.destruct(gadgetPtr);
- metaType.construct(gadgetPtr, value.constData());
-}
+ // Do not set PropertyAccessInStaticMetaCall here. QQmlGadgetPtrWrapper likes to
+ // to intercept the metacalls since it needs to use its gadgetPtr.
+ // For QQmlValueType::metaObject() we use the base type that has the flag.
-QAbstractDynamicMetaObject *QQmlValueType::toDynamicMetaObject(QObject *)
-{
- return this;
+ m_dynamicMetaObject = builder.toMetaObject();
+ }
+ return m_dynamicMetaObject;
}
void QQmlValueType::objectDestroyed(QObject *)
{
}
-int QQmlValueType::metaCall(QObject *, QMetaObject::Call type, int _id, void **argv)
+int QQmlValueType::metaCall(QObject *object, QMetaObject::Call type, int _id, void **argv)
{
- const QMetaObject *mo = _metaObject;
- QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &mo, &_id);
- mo->d.static_metacall(reinterpret_cast<QObject*>(gadgetPtr), type, _id, argv);
- return _id;
+ return static_cast<QQmlGadgetPtrWrapper *>(object)->metaCall(type, _id, argv);
}
QString QQmlPointFValueType::toString() const
@@ -318,6 +140,11 @@ void QQmlPointFValueType::setY(qreal y)
}
+QString QQmlPointValueType::toString() const
+{
+ return QString::asprintf("QPoint(%d, %d)", v.x(), v.y());
+}
+
int QQmlPointValueType::x() const
{
return v.x();
@@ -365,6 +192,11 @@ void QQmlSizeFValueType::setHeight(qreal h)
}
+QString QQmlSizeValueType::toString() const
+{
+ return QString::asprintf("QSize(%d, %d)", v.width(), v.height());
+}
+
int QQmlSizeValueType::width() const
{
return v.width();
@@ -450,6 +282,12 @@ qreal QQmlRectFValueType::bottom() const
return v.bottom();
}
+
+QString QQmlRectValueType::toString() const
+{
+ return QString::asprintf("QRect(%d, %d, %d, %d)", v.x(), v.y(), v.width(), v.height());
+}
+
int QQmlRectValueType::x() const
{
return v.x();
@@ -511,9 +349,9 @@ int QQmlRectValueType::bottom() const
}
#if QT_CONFIG(easingcurve)
-QQmlEasingValueType::Type QQmlEasingValueType::type() const
+QQmlEasingEnums::Type QQmlEasingValueType::type() const
{
- return (QQmlEasingValueType::Type)v.type();
+ return (QQmlEasingEnums::Type)v.type();
}
qreal QQmlEasingValueType::amplitude() const
@@ -531,7 +369,7 @@ qreal QQmlEasingValueType::period() const
return v.period();
}
-void QQmlEasingValueType::setType(QQmlEasingValueType::Type type)
+void QQmlEasingValueType::setType(QQmlEasingEnums::Type type)
{
v.setType((QEasingCurve::Type)type);
}
@@ -556,7 +394,7 @@ void QQmlEasingValueType::setBezierCurve(const QVariantList &customCurveVariant)
if (customCurveVariant.isEmpty())
return;
- if ((customCurveVariant.count() % 6) != 0)
+ if ((customCurveVariant.size() % 6) != 0)
return;
auto convert = [](const QVariant &v, qreal &r) {
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 0601237c4b..8815c914ce 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLVALUETYPE_P_H
#define QQMLVALUETYPE_P_H
@@ -51,10 +15,11 @@
// We mean it.
//
-#include "qqml.h"
-#include "qqmlproperty.h"
-#include "qqmlproperty_p.h"
+#include <QtQml/private/qqmlproperty_p.h>
+
#include <private/qqmlnullablevalue_p.h>
+#include <private/qmetatype_p.h>
+#include <private/qv4referenceobject_p.h>
#include <QtCore/qobject.h>
#include <QtCore/qrect.h>
@@ -65,96 +30,176 @@
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QQmlValueType : public QObject, public QAbstractDynamicMetaObject
+class Q_QML_EXPORT QQmlValueType : public QDynamicMetaObjectData
{
public:
- QQmlValueType();
- QQmlValueType(int userType, const QMetaObject *metaObject);
- ~QQmlValueType() override;
- void read(QObject *, int);
- void write(QObject *, int, QQmlPropertyData::WriteFlags flags);
- QVariant value();
- void setValue(const QVariant &);
+ QQmlValueType() = default;
+ QQmlValueType(QMetaType type, const QMetaObject *staticMetaObject)
+ : m_metaType(type), m_staticMetaObject(staticMetaObject)
+ {}
+ ~QQmlValueType();
+
+ void *create() const { return m_metaType.create(); }
+ void destroy(void *gadgetPtr) const { m_metaType.destroy(gadgetPtr); }
+
+ void construct(void *gadgetPtr, const void *copy) const { m_metaType.construct(gadgetPtr, copy); }
+ void destruct(void *gadgetPtr) const { m_metaType.destruct(gadgetPtr); }
+
+ QMetaType metaType() const { return m_metaType; }
+ const QMetaObject *staticMetaObject() const { return m_staticMetaObject; }
// ---- dynamic meta object data interface
- QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) override;
+ QMetaObject *toDynamicMetaObject(QObject *) override;
void objectDestroyed(QObject *) override;
int metaCall(QObject *obj, QMetaObject::Call type, int _id, void **argv) override;
// ----
private:
- const QMetaObject *_metaObject;
- void *gadgetPtr;
-
-public:
- QMetaType metaType;
+ QMetaType m_metaType;
+ const QMetaObject *m_staticMetaObject = nullptr;
+ QMetaObject *m_dynamicMetaObject = nullptr;
};
-class Q_QML_PRIVATE_EXPORT QQmlValueTypeFactory
+class Q_QML_EXPORT QQmlGadgetPtrWrapper : public QObject
{
+ Q_OBJECT
public:
- static bool isValueType(int idx);
- static QQmlValueType *valueType(int idx);
- static const QMetaObject *metaObjectForMetaType(int type);
+ static QQmlGadgetPtrWrapper *instance(QQmlEngine *engine, QMetaType type);
+
+ QQmlGadgetPtrWrapper(QQmlValueType *valueType, QObject *parent = nullptr);
+ ~QQmlGadgetPtrWrapper();
+
+ void read(QObject *obj, int idx);
+ void write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags,
+ int internalIndex = QV4::ReferenceObject::AllProperties) const;
+ QVariant value() const;
+ void setValue(const QVariant &value);
+
+ QMetaType metaType() const { return valueType()->metaType(); }
+ int metaCall(QMetaObject::Call type, int id, void **argv);
+
+ QMetaProperty property(int index) const
+ {
+ return valueType()->staticMetaObject()->property(index);
+ }
+
+ QVariant readOnGadget(const QMetaProperty &property) const
+ {
+ return property.readOnGadget(m_gadgetPtr);
+ }
+
+ void writeOnGadget(const QMetaProperty &property, const QVariant &value)
+ {
+ property.writeOnGadget(m_gadgetPtr, value);
+ }
- static void registerValueTypes(const char *uri, int versionMajor, int versionMinor);
+ void writeOnGadget(const QMetaProperty &property, QVariant &&value)
+ {
+ property.writeOnGadget(m_gadgetPtr, std::move(value));
+ }
+
+private:
+ const QQmlValueType *valueType() const;
+ void *m_gadgetPtr = nullptr;
};
-struct QQmlPointFValueType
+struct Q_QML_EXPORT QQmlPointFValueType
{
QPointF v;
Q_PROPERTY(qreal x READ x WRITE setX FINAL)
Q_PROPERTY(qreal y READ y WRITE setY FINAL)
Q_GADGET
+ QML_VALUE_TYPE(point)
+ QML_FOREIGN(QPointF)
+ QML_ADDED_IN_VERSION(2, 0)
+ QML_EXTENDED(QQmlPointFValueType)
+ QML_STRUCTURED_VALUE
+
public:
+ QQmlPointFValueType() = default;
+ Q_INVOKABLE QQmlPointFValueType(const QPoint &point) : v(point) {}
Q_INVOKABLE QString toString() const;
qreal x() const;
qreal y() const;
void setX(qreal);
void setY(qreal);
+
+ operator QPointF() const { return v; }
};
-struct QQmlPointValueType
+struct Q_QML_EXPORT QQmlPointValueType
{
QPoint v;
Q_PROPERTY(int x READ x WRITE setX FINAL)
Q_PROPERTY(int y READ y WRITE setY FINAL)
Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QPoint)
+ QML_ADDED_IN_VERSION(2, 0)
+ QML_EXTENDED(QQmlPointValueType)
+ QML_STRUCTURED_VALUE
+
public:
+ QQmlPointValueType() = default;
+ Q_INVOKABLE QQmlPointValueType(const QPointF &point) : v(point.toPoint()) {}
+ Q_INVOKABLE QString toString() const;
int x() const;
int y() const;
void setX(int);
void setY(int);
+
+ operator QPoint() const { return v; }
};
-struct QQmlSizeFValueType
+struct Q_QML_EXPORT QQmlSizeFValueType
{
QSizeF v;
Q_PROPERTY(qreal width READ width WRITE setWidth FINAL)
Q_PROPERTY(qreal height READ height WRITE setHeight FINAL)
Q_GADGET
+ QML_VALUE_TYPE(size)
+ QML_FOREIGN(QSizeF)
+ QML_ADDED_IN_VERSION(2, 0)
+ QML_EXTENDED(QQmlSizeFValueType)
+ QML_STRUCTURED_VALUE
+
public:
+ QQmlSizeFValueType() = default;
+ Q_INVOKABLE QQmlSizeFValueType(const QSize &size) : v(size) {}
Q_INVOKABLE QString toString() const;
qreal width() const;
qreal height() const;
void setWidth(qreal);
void setHeight(qreal);
+
+ operator QSizeF() const { return v; }
};
-struct QQmlSizeValueType
+struct Q_QML_EXPORT QQmlSizeValueType
{
QSize v;
Q_PROPERTY(int width READ width WRITE setWidth FINAL)
Q_PROPERTY(int height READ height WRITE setHeight FINAL)
Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QSize)
+ QML_ADDED_IN_VERSION(2, 0)
+ QML_EXTENDED(QQmlSizeValueType)
+ QML_STRUCTURED_VALUE
+
public:
+ QQmlSizeValueType() = default;
+ Q_INVOKABLE QQmlSizeValueType(const QSizeF &size) : v(size.toSize()) {}
+ Q_INVOKABLE QString toString() const;
int width() const;
int height() const;
void setWidth(int);
void setHeight(int);
+
+ operator QSize() const { return v; }
};
-struct QQmlRectFValueType
+struct Q_QML_EXPORT QQmlRectFValueType
{
QRectF v;
Q_PROPERTY(qreal x READ x WRITE setX FINAL)
@@ -166,7 +211,15 @@ struct QQmlRectFValueType
Q_PROPERTY(qreal top READ top DESIGNABLE false FINAL)
Q_PROPERTY(qreal bottom READ bottom DESIGNABLE false FINAL)
Q_GADGET
+ QML_VALUE_TYPE(rect)
+ QML_FOREIGN(QRectF)
+ QML_ADDED_IN_VERSION(2, 0)
+ QML_EXTENDED(QQmlRectFValueType)
+ QML_STRUCTURED_VALUE
+
public:
+ QQmlRectFValueType() = default;
+ Q_INVOKABLE QQmlRectFValueType(const QRect &rect) : v(rect) {}
Q_INVOKABLE QString toString() const;
qreal x() const;
qreal y() const;
@@ -182,9 +235,11 @@ public:
qreal right() const;
qreal top() const;
qreal bottom() const;
+
+ operator QRectF() const { return v; }
};
-struct QQmlRectValueType
+struct Q_QML_EXPORT QQmlRectValueType
{
QRect v;
Q_PROPERTY(int x READ x WRITE setX FINAL)
@@ -196,7 +251,16 @@ struct QQmlRectValueType
Q_PROPERTY(int top READ top DESIGNABLE false FINAL)
Q_PROPERTY(int bottom READ bottom DESIGNABLE false FINAL)
Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QRect)
+ QML_ADDED_IN_VERSION(2, 0)
+ QML_EXTENDED(QQmlRectValueType)
+ QML_STRUCTURED_VALUE
+
public:
+ QQmlRectValueType() = default;
+ Q_INVOKABLE QQmlRectValueType(const QRectF &rect) : v(rect.toRect()) {}
+ Q_INVOKABLE QString toString() const;
int x() const;
int y() const;
void setX(int);
@@ -211,91 +275,87 @@ public:
int right() const;
int top() const;
int bottom() const;
+
+ operator QRect() const { return v; }
};
#if QT_CONFIG(easingcurve)
-struct QQmlEasingValueType
+namespace QQmlEasingEnums
+{
+Q_NAMESPACE_EXPORT(Q_QML_EXPORT)
+QML_NAMED_ELEMENT(Easing)
+QML_ADDED_IN_VERSION(2, 0)
+
+enum Type {
+ Linear = QEasingCurve::Linear,
+ InQuad = QEasingCurve::InQuad, OutQuad = QEasingCurve::OutQuad,
+ InOutQuad = QEasingCurve::InOutQuad, OutInQuad = QEasingCurve::OutInQuad,
+ InCubic = QEasingCurve::InCubic, OutCubic = QEasingCurve::OutCubic,
+ InOutCubic = QEasingCurve::InOutCubic, OutInCubic = QEasingCurve::OutInCubic,
+ InQuart = QEasingCurve::InQuart, OutQuart = QEasingCurve::OutQuart,
+ InOutQuart = QEasingCurve::InOutQuart, OutInQuart = QEasingCurve::OutInQuart,
+ InQuint = QEasingCurve::InQuint, OutQuint = QEasingCurve::OutQuint,
+ InOutQuint = QEasingCurve::InOutQuint, OutInQuint = QEasingCurve::OutInQuint,
+ InSine = QEasingCurve::InSine, OutSine = QEasingCurve::OutSine,
+ InOutSine = QEasingCurve::InOutSine, OutInSine = QEasingCurve::OutInSine,
+ InExpo = QEasingCurve::InExpo, OutExpo = QEasingCurve::OutExpo,
+ InOutExpo = QEasingCurve::InOutExpo, OutInExpo = QEasingCurve::OutInExpo,
+ InCirc = QEasingCurve::InCirc, OutCirc = QEasingCurve::OutCirc,
+ InOutCirc = QEasingCurve::InOutCirc, OutInCirc = QEasingCurve::OutInCirc,
+ InElastic = QEasingCurve::InElastic, OutElastic = QEasingCurve::OutElastic,
+ InOutElastic = QEasingCurve::InOutElastic, OutInElastic = QEasingCurve::OutInElastic,
+ InBack = QEasingCurve::InBack, OutBack = QEasingCurve::OutBack,
+ InOutBack = QEasingCurve::InOutBack, OutInBack = QEasingCurve::OutInBack,
+ InBounce = QEasingCurve::InBounce, OutBounce = QEasingCurve::OutBounce,
+ InOutBounce = QEasingCurve::InOutBounce, OutInBounce = QEasingCurve::OutInBounce,
+ InCurve = QEasingCurve::InCurve, OutCurve = QEasingCurve::OutCurve,
+ SineCurve = QEasingCurve::SineCurve, CosineCurve = QEasingCurve::CosineCurve,
+ BezierSpline = QEasingCurve::BezierSpline,
+
+ Bezier = BezierSpline // Evil! Don't use this!
+};
+Q_ENUM_NS(Type)
+};
+
+struct Q_QML_EXPORT QQmlEasingValueType
{
QEasingCurve v;
Q_GADGET
- QML_NAMED_ELEMENT(Easing)
- QML_UNCREATABLE("Use the Type enum.")
+ QML_ANONYMOUS
+ QML_FOREIGN(QEasingCurve)
+ QML_ADDED_IN_VERSION(2, 0)
+ QML_EXTENDED(QQmlEasingValueType)
+ QML_STRUCTURED_VALUE
- Q_PROPERTY(QQmlEasingValueType::Type type READ type WRITE setType FINAL)
+ Q_PROPERTY(QQmlEasingEnums::Type type READ type WRITE setType FINAL)
Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude FINAL)
Q_PROPERTY(qreal overshoot READ overshoot WRITE setOvershoot FINAL)
Q_PROPERTY(qreal period READ period WRITE setPeriod FINAL)
Q_PROPERTY(QVariantList bezierCurve READ bezierCurve WRITE setBezierCurve FINAL)
+
public:
- enum Type {
- Linear = QEasingCurve::Linear,
- InQuad = QEasingCurve::InQuad, OutQuad = QEasingCurve::OutQuad,
- InOutQuad = QEasingCurve::InOutQuad, OutInQuad = QEasingCurve::OutInQuad,
- InCubic = QEasingCurve::InCubic, OutCubic = QEasingCurve::OutCubic,
- InOutCubic = QEasingCurve::InOutCubic, OutInCubic = QEasingCurve::OutInCubic,
- InQuart = QEasingCurve::InQuart, OutQuart = QEasingCurve::OutQuart,
- InOutQuart = QEasingCurve::InOutQuart, OutInQuart = QEasingCurve::OutInQuart,
- InQuint = QEasingCurve::InQuint, OutQuint = QEasingCurve::OutQuint,
- InOutQuint = QEasingCurve::InOutQuint, OutInQuint = QEasingCurve::OutInQuint,
- InSine = QEasingCurve::InSine, OutSine = QEasingCurve::OutSine,
- InOutSine = QEasingCurve::InOutSine, OutInSine = QEasingCurve::OutInSine,
- InExpo = QEasingCurve::InExpo, OutExpo = QEasingCurve::OutExpo,
- InOutExpo = QEasingCurve::InOutExpo, OutInExpo = QEasingCurve::OutInExpo,
- InCirc = QEasingCurve::InCirc, OutCirc = QEasingCurve::OutCirc,
- InOutCirc = QEasingCurve::InOutCirc, OutInCirc = QEasingCurve::OutInCirc,
- InElastic = QEasingCurve::InElastic, OutElastic = QEasingCurve::OutElastic,
- InOutElastic = QEasingCurve::InOutElastic, OutInElastic = QEasingCurve::OutInElastic,
- InBack = QEasingCurve::InBack, OutBack = QEasingCurve::OutBack,
- InOutBack = QEasingCurve::InOutBack, OutInBack = QEasingCurve::OutInBack,
- InBounce = QEasingCurve::InBounce, OutBounce = QEasingCurve::OutBounce,
- InOutBounce = QEasingCurve::InOutBounce, OutInBounce = QEasingCurve::OutInBounce,
- InCurve = QEasingCurve::InCurve, OutCurve = QEasingCurve::OutCurve,
- SineCurve = QEasingCurve::SineCurve, CosineCurve = QEasingCurve::CosineCurve,
- Bezier = QEasingCurve::BezierSpline
- };
- Q_ENUM(Type)
-
- Type type() const;
+ QQmlEasingEnums::Type type() const;
qreal amplitude() const;
qreal overshoot() const;
qreal period() const;
- void setType(Type);
+ void setType(QQmlEasingEnums::Type);
void setAmplitude(qreal);
void setOvershoot(qreal);
void setPeriod(qreal);
void setBezierCurve(const QVariantList &);
QVariantList bezierCurve() const;
+
+ operator QEasingCurve() const { return v; }
};
#endif
-template<typename T>
-int qmlRegisterValueTypeEnums(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+struct QQmlV4ExecutionEnginePtrForeign
{
- QByteArray name(T::staticMetaObject.className());
-
- QByteArray pointerName(name + '*');
-
- QQmlPrivate::RegisterType type = {
- 0,
-
- qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, 0, nullptr,
-
- QString(),
-
- uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject,
-
- nullptr, nullptr,
-
- 0, 0, 0,
-
- nullptr, nullptr,
-
- nullptr,
- 0
- };
-
- return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
-}
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQmlV4ExecutionEnginePtr)
+ QML_EXTENDED(QQmlV4ExecutionEnginePtrForeign)
+};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding.cpp b/src/qml/qml/qqmlvaluetypeproxybinding.cpp
index d5cff26444..a1cf9f802b 100644
--- a/src/qml/qml/qqmlvaluetypeproxybinding.cpp
+++ b/src/qml/qml/qqmlvaluetypeproxybinding.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlvaluetypeproxybinding_p.h"
@@ -67,11 +31,6 @@ void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags
}
}
-bool QQmlValueTypeProxyBinding::isValueTypeProxy() const
-{
- return true;
-}
-
QQmlAbstractBinding *QQmlValueTypeProxyBinding::subBindings() const
{
return m_bindings.data();
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
index 35b54c339b..79cb935e94 100644
--- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h
+++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLVALUETYPEPROXYBINDING_P_H
#define QQMLVALUETYPEPROXYBINDING_P_H
@@ -65,7 +29,7 @@ public:
void removeBindings(quint32 mask);
void setEnabled(bool, QQmlPropertyData::WriteFlags) override;
- bool isValueTypeProxy() const override;
+ Kind kind() const final { return QQmlAbstractBinding::ValueTypeProxy; }
protected:
~QQmlValueTypeProxyBinding();
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index f23921497c..7075d0f5f6 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlvaluetypewrapper_p.h"
@@ -53,7 +17,23 @@
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4identifiertable_p.h>
#include <private/qv4lookup_p.h>
+#include <private/qv4sequenceobject_p.h>
+#include <private/qv4arraybuffer_p.h>
+#include <private/qv4dateobject_p.h>
+#include <private/qv4jsonobject_p.h>
+#if QT_CONFIG(regularexpression)
+#include <private/qv4regexpobject_p.h>
+#endif
+#if QT_CONFIG(qml_locale)
+#include <private/qqmllocale_p.h>
+#endif
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/QLine>
+#include <QtCore/QLineF>
+#include <QtCore/QSize>
+#include <QtCore/QSizeF>
+#include <QtCore/QTimeZone>
QT_BEGIN_NAMESPACE
@@ -62,116 +42,95 @@ Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeWrapper);
namespace QV4 {
-namespace Heap {
-struct QQmlValueTypeReference : QQmlValueTypeWrapper
+Heap::QQmlValueTypeWrapper *Heap::QQmlValueTypeWrapper::detached() const
{
- void init() {
- QQmlValueTypeWrapper::init();
- object.init();
- }
- void destroy() {
- object.destroy();
- QQmlValueTypeWrapper::destroy();
- }
- QQmlQPointer<QObject> object;
- int property;
-};
-
+ return internalClass->engine->memoryManager->allocate<QV4::QQmlValueTypeWrapper>(
+ m_gadgetPtr, QMetaType(m_metaType), m_metaObject, nullptr, -1, NoFlag);
}
-struct QQmlValueTypeReference : public QQmlValueTypeWrapper
-{
- V4_OBJECT2(QQmlValueTypeReference, QQmlValueTypeWrapper)
- V4_NEEDS_DESTROY
-
- bool readReferenceValue() const;
-};
-
-}
-
-DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeReference);
-
-using namespace QV4;
-
void Heap::QQmlValueTypeWrapper::destroy()
{
if (m_gadgetPtr) {
- m_valueType->metaType.destruct(m_gadgetPtr);
+ metaType().destruct(m_gadgetPtr);
::operator delete(m_gadgetPtr);
}
- if (m_propertyCache)
- m_propertyCache->release();
- Object::destroy();
-}
-
-void Heap::QQmlValueTypeWrapper::setValue(const QVariant &value) const
-{
- Q_ASSERT(valueType()->metaType.id() == value.userType());
- if (auto *gadget = gadgetPtr())
- valueType()->metaType.destruct(gadget);
- if (!gadgetPtr())
- setGadgetPtr(::operator new(valueType()->metaType.sizeOf()));
- valueType()->metaType.construct(gadgetPtr(), value.constData());
+ ReferenceObject::destroy();
}
QVariant Heap::QQmlValueTypeWrapper::toVariant() const
{
Q_ASSERT(gadgetPtr());
- return QVariant(valueType()->metaType.id(), gadgetPtr());
+ return QVariant(metaType(), gadgetPtr());
}
-
-bool QQmlValueTypeReference::readReferenceValue() const
+bool Heap::QQmlValueTypeWrapper::setVariant(const QVariant &variant)
{
- if (!d()->object)
- return false;
- // A reference resource may be either a "true" reference (eg, to a QVector3D property)
- // or a "variant" reference (eg, to a QVariant property which happens to contain a value-type).
- QMetaProperty writebackProperty = d()->object->metaObject()->property(d()->property);
- if (writebackProperty.userType() == QMetaType::QVariant) {
- // variant-containing-value-type reference
- QVariant variantReferenceValue;
-
- void *a[] = { &variantReferenceValue, nullptr };
- QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->property, a);
-
- int variantReferenceType = variantReferenceValue.userType();
- if (variantReferenceType != typeId()) {
- // This is a stale VariantReference. That is, the variant has been
- // overwritten with a different type in the meantime.
- // We need to modify this reference to the updated value type, if
- // possible, or return false if it is not a value type.
- if (QQmlValueTypeFactory::isValueType(variantReferenceType)) {
- QQmlPropertyCache *cache = nullptr;
- if (const QMetaObject *mo = QQmlValueTypeFactory::metaObjectForMetaType(variantReferenceType))
- cache = QJSEnginePrivate::get(engine())->cache(mo);
- if (d()->gadgetPtr()) {
- d()->valueType()->metaType.destruct(d()->gadgetPtr());
- ::operator delete(d()->gadgetPtr());
- }
- d()->setGadgetPtr(nullptr);
- d()->setPropertyCache(cache);
- d()->setValueType(QQmlValueTypeFactory::valueType(variantReferenceType));
- if (!cache)
- return false;
- } else {
- return false;
+ Q_ASSERT(isVariant());
+
+ const QMetaType variantReferenceType = variant.metaType();
+ if (variantReferenceType != metaType()) {
+ // This is a stale VariantReference. That is, the variant has been
+ // overwritten with a different type in the meantime.
+ // We need to modify this reference to the updated value type, if
+ // possible, or return false if it is not a value type.
+ if (QQmlMetaType::isValueType(variantReferenceType)) {
+ const QMetaObject *mo = QQmlMetaType::metaObjectForValueType(variantReferenceType);
+ if (gadgetPtr()) {
+ metaType().destruct(gadgetPtr());
+ ::operator delete(gadgetPtr());
}
+ setGadgetPtr(nullptr);
+ setMetaObject(mo);
+ setMetaType(variantReferenceType);
+ if (!mo)
+ return false;
+ } else {
+ return false;
}
- d()->setValue(variantReferenceValue);
- } else {
- if (!d()->gadgetPtr()) {
- d()->setGadgetPtr(::operator new(d()->valueType()->metaType.sizeOf()));
- d()->valueType()->metaType.construct(d()->gadgetPtr(), nullptr);
- }
- // value-type reference
- void *args[] = { d()->gadgetPtr(), nullptr };
- QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->property, args);
}
+
+ setData(variant.constData());
return true;
}
+void *Heap::QQmlValueTypeWrapper::storagePointer()
+{
+ if (!gadgetPtr()) {
+ setGadgetPtr(::operator new(metaType().sizeOf()));
+ metaType().construct(gadgetPtr(), nullptr);
+ }
+ return gadgetPtr();
+}
+
+bool Heap::QQmlValueTypeWrapper::readReference()
+{
+ // If locations are enforced we only read once
+ return enforcesLocation() || QV4::ReferenceObject::readReference(this);
+}
+
+bool Heap::QQmlValueTypeWrapper::writeBack(int propertyIndex)
+{
+ return isAttachedToProperty() && QV4::ReferenceObject::writeBack(this, propertyIndex);
+}
+
+ReturnedValue QQmlValueTypeWrapper::create(
+ ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *cloneFrom, Heap::Object *object)
+{
+ QV4::Scope scope(engine);
+ initProto(engine);
+
+ // Either we're enforcing the location, then we have to read right away.
+ // Or we don't then we lazy-load. In neither case we pass any data.
+ Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>(
+ nullptr, cloneFrom->metaType(), cloneFrom->metaObject(),
+ object, cloneFrom->property(), cloneFrom->flags()));
+ r->d()->setLocation(cloneFrom->function(), cloneFrom->statementIndex());
+ if (cloneFrom->enforcesLocation())
+ QV4::ReferenceObject::readReference(r->d());
+ return r->asReturnedValue();
+}
+
void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4)
{
if (v4->valueTypeWrapperPrototype()->d_unchecked())
@@ -183,49 +142,103 @@ void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4)
v4->jsObjects[QV4::ExecutionEngine::ValueTypeProto] = o->d();
}
-ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *object, int property, const QMetaObject *metaObject, int typeId)
+int QQmlValueTypeWrapper::virtualMetacall(
+ Object *object, QMetaObject::Call call, int index, void **a)
+{
+ QQmlValueTypeWrapper *wrapper = object->as<QQmlValueTypeWrapper>();
+ Q_ASSERT(wrapper);
+
+ switch (call) {
+ case QMetaObject::InvokeMetaMethod:
+ case QMetaObject::ReadProperty:
+ case QMetaObject::BindableProperty:
+ case QMetaObject::CustomCall:
+ if (wrapper->d()->object())
+ wrapper->d()->readReference();
+ break;
+ default:
+ break;
+ }
+
+ const QMetaObject *mo = wrapper->d()->metaObject();
+ if (!mo->d.static_metacall)
+ return 0;
+
+ mo->d.static_metacall(static_cast<QObject *>(wrapper->d()->gadgetPtr()), call, index, a);
+
+ switch (call) {
+ case QMetaObject::ReadProperty:
+ break;
+ case QMetaObject::WriteProperty:
+ case QMetaObject::ResetProperty:
+ if (wrapper->d()->object())
+ wrapper->d()->writeBack(index);
+ break;
+ case QMetaObject::InvokeMetaMethod:
+ case QMetaObject::CustomCall:
+ if (wrapper->d()->object())
+ wrapper->d()->writeBack();
+ break;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+ReturnedValue QQmlValueTypeWrapper::create(
+ ExecutionEngine *engine, const void *data, const QMetaObject *metaObject, QMetaType type,
+ Heap::Object *object, int property, Heap::ReferenceObject::Flags flags)
{
Scope scope(engine);
initProto(engine);
- Scoped<QQmlValueTypeReference> r(scope, engine->memoryManager->allocate<QQmlValueTypeReference>());
- r->d()->object = object;
- r->d()->property = property;
- r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
- r->d()->setValueType(QQmlValueTypeFactory::valueType(typeId));
- r->d()->setGadgetPtr(nullptr);
+ if (!type.isValid()) {
+ return engine->throwTypeError(QLatin1String("Type %1 is not a value type")
+ .arg(QString::fromUtf8(type.name())));
+ }
+
+ // If data is given explicitly, we assume it has just been read from the property
+ Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>(
+ data, type, metaObject, object, property, flags));
+ if (CppStackFrame *frame = engine->currentStackFrame)
+ r->d()->setLocation(frame->v4Function, frame->statementNumber());
+ if (!data && r->d()->enforcesLocation())
+ QV4::ReferenceObject::readReference(r->d());
return r->asReturnedValue();
}
-ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVariant &value, const QMetaObject *metaObject, int typeId)
+ReturnedValue QQmlValueTypeWrapper::create(
+ ExecutionEngine *engine, const void *data, const QMetaObject *metaObject, QMetaType type)
{
Scope scope(engine);
initProto(engine);
- Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>());
- r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
- r->d()->setValueType(QQmlValueTypeFactory::valueType(typeId));
- r->d()->setGadgetPtr(nullptr);
- r->d()->setValue(value);
+ if (!type.isValid()) {
+ return engine->throwTypeError(QLatin1String("Type %1 is not a value type")
+ .arg(QString::fromUtf8(type.name())));
+ }
+
+ Scoped<QQmlValueTypeWrapper> r(
+ scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>(
+ data, type, metaObject, nullptr, -1, Heap::ReferenceObject::NoFlag));
return r->asReturnedValue();
}
QVariant QQmlValueTypeWrapper::toVariant() const
{
- if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
- if (!ref->readReferenceValue())
- return QVariant();
+ if (d()->isReference() && !readReferenceValue())
+ return QVariant();
return d()->toVariant();
}
bool QQmlValueTypeWrapper::toGadget(void *data) const
{
- if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
- if (!ref->readReferenceValue())
- return false;
- const int typeId = d()->valueType()->metaType.id();
- QMetaType::destruct(typeId, data);
- QMetaType::construct(typeId, data, d()->gadgetPtr());
+ if (d()->isReference() && !readReferenceValue())
+ return false;
+ const QMetaType type = d()->metaType();
+ type.destruct(data);
+ type.construct(data, d()->gadgetPtr());
return true;
}
@@ -243,14 +256,191 @@ bool QQmlValueTypeWrapper::virtualIsEqualTo(Managed *m, Managed *other)
return false;
}
+bool QQmlValueTypeWrapper::virtualHasProperty(const Managed *m, PropertyKey id)
+{
+ if (!id.isString())
+ return Object::virtualHasProperty(m, id);
+ Q_ASSERT(m && m->as<QQmlValueTypeWrapper>());
+ auto wrapper = static_cast<const QQmlValueTypeWrapper *>(m);
+ if (auto mo = wrapper->d()->metaObject())
+ if (mo->indexOfProperty(id.toQString().toUtf8()) != -1)
+ return true;
+
+ /* we don't want to fallback to QObject::virtualHasProperty
+ as that would end up calling getOwnProperty which is wasteful,
+ as it calls our own virtualGetOwnProperty.
+ As we know that our own properties are only those found on the meta-object,
+ we can instead skip the call, and simply check whether the property exists
+ on the prototype.
+ */
+ Scope scope(m->engine());
+ ScopedObject o(scope, m);
+ o = o->getPrototypeOf();
+ if (o)
+ return o->hasProperty(id);
+
+ return false;
+}
+
+static Heap::ReferenceObject::Flags referenceFlags(const QMetaObject *metaObject, int index)
+{
+ return metaObject->property(index).isWritable()
+ ? (Heap::ReferenceObject::CanWriteBack | Heap::ReferenceObject::EnforcesLocation)
+ : Heap::ReferenceObject::EnforcesLocation;
+}
+
+static void doStaticReadCall(
+ const QMetaObject *metaObject, Heap::QQmlValueTypeWrapper *valueTypeWrapper,
+ int index, void **args)
+{
+ metaObject->d.static_metacall(
+ reinterpret_cast<QObject*>(
+ valueTypeWrapper->gadgetPtr()), QMetaObject::ReadProperty, index, args);
+}
+
+static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
+ Heap::QQmlValueTypeWrapper *valueTypeWrapper,
+ QMetaType metaType, quint16 coreIndex, bool isFunction, bool isEnum)
+{
+ if (isFunction) {
+ // calling a Q_INVOKABLE function of a value type
+ return QV4::QObjectMethod::create(engine->rootContext(), valueTypeWrapper, coreIndex);
+ }
+
+ const QMetaObject *metaObject = valueTypeWrapper->metaObject();
+ int index = coreIndex;
+
+ const auto wrapChar16 = [engine](char16_t c) {
+ return engine->newString(QChar(c));
+ };
+ const auto wrapQObject = [engine](QObject *object) {
+ return QObjectWrapper::wrap(engine, object);
+ };
+ const auto wrapJsonValue = [engine](const QJsonValue &value) {
+ return JsonObject::fromJsonValue(engine, value);
+ };
+ const auto wrapJsonObject = [engine](const QJsonObject &object) {
+ return JsonObject::fromJsonObject(engine, object);
+ };
+ const auto wrapJsonArray = [engine](const QJsonArray &array) {
+ return JsonObject::fromJsonArray(engine, array);
+ };
+
+ const auto wrapQDateTime = [&](const QDateTime &dateTime) {
+ return engine->newDateObject(
+ dateTime, valueTypeWrapper, index, referenceFlags(metaObject, index));
+ };
+ const auto wrapQDate = [&](QDate date) {
+ return engine->newDateObject(
+ date, valueTypeWrapper, index, referenceFlags(metaObject, index));
+ };
+ const auto wrapQTime = [&](QTime time) {
+ return engine->newDateObject(
+ time, valueTypeWrapper, index, referenceFlags(metaObject, index));
+ };
+
+#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
+ case metatype: { \
+ cpptype v; \
+ void *args[] = { &v, nullptr }; \
+ doStaticReadCall(metaObject, valueTypeWrapper, index, args); \
+ return QV4::Encode(constructor(v)); \
+ }
+
+ QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(
+ QMetaObject::ReadProperty, &metaObject, &index);
+
+ const int metaTypeId = isEnum
+ ? metaType.underlyingType().id()
+ : (metaType.flags() & QMetaType::PointerToQObject)
+ ? QMetaType::QObjectStar
+ : metaType.id();
+
+ switch (metaTypeId) {
+ case QMetaType::UnknownType:
+ case QMetaType::Void:
+ return Encode::undefined();
+ case QMetaType::Nullptr:
+ case QMetaType::VoidStar:
+ return Encode::null();
+ VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool);
+ VALUE_TYPE_LOAD(QMetaType::Int, int, int);
+ VALUE_TYPE_LOAD(QMetaType::UInt, uint, uint);
+ VALUE_TYPE_LOAD(QMetaType::Long, long, double);
+ VALUE_TYPE_LOAD(QMetaType::ULong, ulong, double);
+ VALUE_TYPE_LOAD(QMetaType::LongLong, qlonglong, double);
+ VALUE_TYPE_LOAD(QMetaType::ULongLong, qulonglong, double);
+ VALUE_TYPE_LOAD(QMetaType::Double, double, double);
+ VALUE_TYPE_LOAD(QMetaType::QString, QString, engine->newString);
+ VALUE_TYPE_LOAD(QMetaType::QByteArray, QByteArray, engine->newArrayBuffer);
+ VALUE_TYPE_LOAD(QMetaType::Float, float, float);
+ VALUE_TYPE_LOAD(QMetaType::Short, short, int);
+ VALUE_TYPE_LOAD(QMetaType::UShort, unsigned short, int);
+ VALUE_TYPE_LOAD(QMetaType::Char, char, int);
+ VALUE_TYPE_LOAD(QMetaType::UChar, unsigned char, int);
+ VALUE_TYPE_LOAD(QMetaType::SChar, signed char, int);
+ VALUE_TYPE_LOAD(QMetaType::QChar, QChar, engine->newString);
+ VALUE_TYPE_LOAD(QMetaType::Char16, char16_t, wrapChar16);
+ VALUE_TYPE_LOAD(QMetaType::QDateTime, QDateTime, wrapQDateTime);
+ VALUE_TYPE_LOAD(QMetaType::QDate, QDate, wrapQDate);
+ VALUE_TYPE_LOAD(QMetaType::QTime, QTime, wrapQTime);
+#if QT_CONFIG(regularexpression)
+ VALUE_TYPE_LOAD(QMetaType::QRegularExpression, QRegularExpression, engine->newRegExpObject);
+#endif
+ VALUE_TYPE_LOAD(QMetaType::QObjectStar, QObject*, wrapQObject);
+ VALUE_TYPE_LOAD(QMetaType::QJsonValue, QJsonValue, wrapJsonValue);
+ VALUE_TYPE_LOAD(QMetaType::QJsonObject, QJsonObject, wrapJsonObject);
+ VALUE_TYPE_LOAD(QMetaType::QJsonArray, QJsonArray, wrapJsonArray);
+ case QMetaType::QPixmap:
+ case QMetaType::QImage: {
+ QVariant v(metaType);
+ void *args[] = { v.data(), nullptr };
+ doStaticReadCall(metaObject, valueTypeWrapper, index, args);
+ return Encode(engine->newVariantObject(metaType, v.data()));
+ }
+ case QMetaType::QVariant: {
+ QVariant v;
+ void *args[] = { &v, nullptr };
+ doStaticReadCall(metaObject, valueTypeWrapper, index, args);
+ return engine->fromVariant(
+ v, valueTypeWrapper, index,
+ referenceFlags(metaObject, index) | Heap::ReferenceObject::IsVariant);
+ }
+ default:
+ break;
+ }
+
+ QVariant v(metaType);
+ void *args[] = { v.data(), nullptr };
+ doStaticReadCall(metaObject, valueTypeWrapper, index, args);
+ return engine->fromVariant(v, valueTypeWrapper, index, referenceFlags(metaObject, index));
+#undef VALUE_TYPE_LOAD
+}
+
PropertyAttributes QQmlValueTypeWrapper::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p)
{
if (id.isString()) {
- Scope scope(m);
- ScopedString n(scope, id.asStringOrSymbol());
const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
- QQmlPropertyData *result = r->d()->propertyCache()->property(n.getPointer(), nullptr, nullptr);
- return result ? Attr_Data : Attr_Invalid;
+ Q_ASSERT(r);
+
+ const QQmlPropertyData result = r->dataForPropertyKey(id);
+ if (!result.isValid())
+ return Attr_Invalid; // Property doesn't exist. Object shouldn't meddle with it.
+
+ if (!p)
+ return Attr_Data; // Property exists, but we're not interested in the value
+
+ if (!r->d()->isReference() || r->readReferenceValue()) {
+ // Property exists, and we can retrieve it
+ p->value = getGadgetProperty(
+ r->engine(), r->d(), result.propType(), result.coreIndex(),
+ result.isFunction(), result.isEnum());
+ } else {
+ // Property exists, but we can't retrieve it. Make it undefined.
+ p->value = Encode::undefined();
+ }
+
+ return Attr_Data;
}
return QV4::Object::virtualGetOwnProperty(m, id, p);
@@ -267,24 +457,25 @@ struct QQmlValueTypeWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
PropertyKey QQmlValueTypeWrapperOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) {
const QQmlValueTypeWrapper *that = static_cast<const QQmlValueTypeWrapper *>(o);
- if (const QQmlValueTypeReference *ref = that->as<QQmlValueTypeReference>()) {
- if (!ref->readReferenceValue())
- return PropertyKey::invalid();
- }
-
- if (that->d()->propertyCache()) {
- const QMetaObject *mo = that->d()->propertyCache()->createMetaObject();
- const int propertyCount = mo->propertyCount();
- if (propertyIndex < propertyCount) {
- Scope scope(that->engine());
- ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(mo->property(propertyIndex).name())));
- ++propertyIndex;
- if (attrs)
- *attrs = QV4::Attr_Data;
- if (pd)
- pd->value = that->QV4::Object::get(propName);
- return propName->toPropertyKey();
+ if (that->d()->isReference() && !that->readReferenceValue())
+ return PropertyKey::invalid();
+
+ const QMetaObject *mo = that->d()->metaObject();
+ // We don't return methods, ie. they are not visible when iterating
+ const int propertyCount = mo->propertyCount();
+ if (propertyIndex < propertyCount) {
+ Scope scope(that->engine());
+ QMetaProperty p = mo->property(propertyIndex); // TODO: Implement and use QBasicMetaProperty
+ ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(p.name())));
+ ++propertyIndex;
+ if (attrs)
+ *attrs = QV4::Attr_Data;
+ if (pd) {
+ QQmlPropertyData data;
+ data.load(p);
+ pd->value = getGadgetProperty(that->engine(), that->d(), data.propType(), data.coreIndex(), data.isFunction(), data.isEnum());
}
+ return propName->toPropertyKey();
}
return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
@@ -299,29 +490,75 @@ OwnPropertyKeyIterator *QQmlValueTypeWrapper::virtualOwnPropertyKeys(const Objec
bool QQmlValueTypeWrapper::isEqual(const QVariant& value) const
{
- if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>())
- if (!ref->readReferenceValue())
- return false;
- return (value == d()->toVariant());
+ if (d()->isReference() && !readReferenceValue())
+ return false;
+ int id1 = value.metaType().id();
+ QVariant v = d()->toVariant();
+ int id2 = v.metaType().id();
+ if (id1 != id2) {
+ // conversions for weak comparison
+ switch (id1) {
+ case QMetaType::QPoint:
+ if (id2 == QMetaType::QPointF)
+ return value.value<QPointF>() == v.value<QPointF>();
+ break;
+ case QMetaType::QPointF:
+ if (id2 == QMetaType::QPoint)
+ return value.value<QPointF>() == v.value<QPointF>();
+ break;
+ case QMetaType::QRect:
+ if (id2 == QMetaType::QRectF)
+ return value.value<QRectF>() == v.value<QRectF>();
+ break;
+ case QMetaType::QRectF:
+ if (id2 == QMetaType::QRect)
+ return value.value<QRectF>() == v.value<QRectF>();
+ break;
+ case QMetaType::QLine:
+ if (id2 == QMetaType::QLineF)
+ return value.value<QLineF>() == v.value<QLineF>();
+ break;
+ case QMetaType::QLineF:
+ if (id2 == QMetaType::QLine)
+ return value.value<QLineF>() == v.value<QLineF>();
+ break;
+ case QMetaType::QSize:
+ if (id2 == QMetaType::QSizeF)
+ return value.value<QSizeF>() == v.value<QSizeF>();
+ break;
+ case QMetaType::QSizeF:
+ if (id2 == QMetaType::QSize)
+ return value.value<QSizeF>() == v.value<QSizeF>();
+ break;
+ default:
+ break;
+ }
+ }
+ return (value == v);
}
int QQmlValueTypeWrapper::typeId() const
{
- return d()->valueType()->metaType.id();
+ return d()->metaType().id();
+}
+
+QMetaType QQmlValueTypeWrapper::type() const
+{
+ return d()->metaType();
}
bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
{
bool destructGadgetOnExit = false;
Q_ALLOCA_DECLARE(void, gadget);
- if (const QQmlValueTypeReference *ref = as<const QQmlValueTypeReference>()) {
+ if (d()->isReference()) {
if (!d()->gadgetPtr()) {
- Q_ALLOCA_ASSIGN(void, gadget, d()->valueType()->metaType.sizeOf());
+ Q_ALLOCA_ASSIGN(void, gadget, d()->metaType().sizeOf());
d()->setGadgetPtr(gadget);
- d()->valueType()->metaType.construct(d()->gadgetPtr(), nullptr);
+ d()->metaType().construct(d()->gadgetPtr(), nullptr);
destructGadgetOnExit = true;
}
- if (!ref->readReferenceValue())
+ if (!readReferenceValue())
return false;
}
@@ -331,12 +568,30 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
QMetaObject::metacall(target, QMetaObject::WriteProperty, propertyIndex, a);
if (destructGadgetOnExit) {
- d()->valueType()->metaType.destruct(d()->gadgetPtr());
+ d()->metaType().destruct(d()->gadgetPtr());
d()->setGadgetPtr(nullptr);
}
return true;
}
+QQmlPropertyData QQmlValueTypeWrapper::dataForPropertyKey(PropertyKey id) const
+{
+ if (!id.isStringOrSymbol())
+ return QQmlPropertyData {};
+ QByteArray name = id.asStringOrSymbol()->toQString().toUtf8();
+ const QMetaObject *mo = d()->metaObject();
+ QQmlPropertyData result;
+ QMetaMethod metaMethod = QMetaObjectPrivate::firstMethod(mo, name);
+ if (metaMethod.isValid()) {
+ result.load(metaMethod);
+ } else {
+ int propertyIndex = d()->metaObject()->indexOfProperty(name.constData());
+ if (propertyIndex >= 0)
+ result.load(mo->property(propertyIndex));
+ }
+ return result;
+}
+
ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
const Object *o = thisObject->as<Object>();
@@ -346,20 +601,14 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, con
if (!w)
return b->engine()->throwTypeError();
- if (const QQmlValueTypeReference *ref = w->as<QQmlValueTypeReference>())
- if (!ref->readReferenceValue())
- RETURN_UNDEFINED();
+ if (w->d()->isReference() && !w->readReferenceValue())
+ RETURN_UNDEFINED();
QString result;
- // Prepare a buffer to pass to QMetaType::convert()
- QString convertResult;
- convertResult.~QString();
- if (QMetaType::convert(w->d()->gadgetPtr(), w->d()->valueType()->metaType.id(), &convertResult, QMetaType::QString)) {
- result = convertResult;
- } else {
- result += QString::fromUtf8(QMetaType::typeName(w->d()->valueType()->metaType.id()))
- + QLatin1Char('(');
- const QMetaObject *mo = w->d()->propertyCache()->metaObject();
+ if (!QMetaType::convert(w->d()->metaType(), w->d()->gadgetPtr(),
+ QMetaType(QMetaType::QString), &result)) {
+ result = QString::fromUtf8(w->d()->metaType().name()) + QLatin1Char('(');
+ const QMetaObject *mo = w->d()->metaObject();
const int propCount = mo->propertyCount();
for (int i = 0; i < propCount; ++i) {
if (mo->property(i).isDesignable()) {
@@ -374,50 +623,6 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, con
return Encode(b->engine()->newString(result));
}
-Q_ALWAYS_INLINE static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
- Heap::QQmlValueTypeWrapper *valueTypeWrapper,
- QQmlPropertyData *property)
-{
- if (property->isFunction()) {
- // calling a Q_INVOKABLE function of a value type
- return QV4::QObjectMethod::create(engine->rootContext(), valueTypeWrapper, property->coreIndex());
- }
-
-#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
- if (property->propType() == metatype) { \
- cpptype v; \
- void *args[] = { &v, nullptr }; \
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr()), \
- QMetaObject::ReadProperty, index, args); \
- return QV4::Encode(constructor(v)); \
- }
-
- const QMetaObject *metaObject = valueTypeWrapper->propertyCache()->metaObject();
-
- int index = property->coreIndex();
- QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index);
-
- // These four types are the most common used by the value type wrappers
- VALUE_TYPE_LOAD(QMetaType::QReal, qreal, qreal);
- VALUE_TYPE_LOAD(QMetaType::Int || property->isEnum(), int, int);
- VALUE_TYPE_LOAD(QMetaType::Int, int, int);
- VALUE_TYPE_LOAD(QMetaType::QString, QString, engine->newString);
- VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool);
-
- QVariant v;
- void *args[] = { nullptr, nullptr };
- if (property->propType() == QMetaType::QVariant) {
- args[0] = &v;
- } else {
- v = QVariant(property->propType(), static_cast<void *>(nullptr));
- args[0] = v.data();
- }
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr()), QMetaObject::ReadProperty,
- index, args);
- return engine->fromVariant(v);
-#undef VALUE_TYPE_LOAD
-}
-
ReturnedValue QQmlValueTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine,
Lookup *lookup)
{
@@ -432,19 +637,20 @@ ReturnedValue QQmlValueTypeWrapper::virtualResolveLookupGetter(const Object *obj
ScopedString name(scope, id.asStringOrSymbol());
// Note: readReferenceValue() can change the reference->type.
- if (const QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) {
- if (!reference->readReferenceValue())
- return Value::undefinedValue().asReturnedValue();
- }
+ if (r->d()->isReference() && !r->readReferenceValue())
+ return Value::undefinedValue().asReturnedValue();
- QQmlPropertyData *result = r->d()->propertyCache()->property(name.getPointer(), nullptr, nullptr);
- if (!result)
+ QQmlPropertyData result = r->dataForPropertyKey(id);
+ if (!result.isValid())
return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
- lookup->qgadgetLookup.ic = r->internalClass();
- lookup->qgadgetLookup.propertyCache = r->d()->propertyCache();
- lookup->qgadgetLookup.propertyCache->addref();
- lookup->qgadgetLookup.propertyData = result;
+ lookup->qgadgetLookup.ic.set(engine, r->internalClass());
+ // & 1 to tell the gc that this is not heap allocated; see markObjects in qv4lookup_p.h
+ lookup->qgadgetLookup.metaObject = quintptr(r->d()->metaObject()) + 1;
+ lookup->qgadgetLookup.metaType = result.propType().iface();
+ lookup->qgadgetLookup.coreIndex = result.coreIndex();
+ lookup->qgadgetLookup.isFunction = result.isFunction();
+ lookup->qgadgetLookup.isEnum = result.isEnum();
lookup->getter = QQmlValueTypeWrapper::lookupGetter;
return lookup->getter(lookup, engine, *object);
}
@@ -452,8 +658,7 @@ ReturnedValue QQmlValueTypeWrapper::virtualResolveLookupGetter(const Object *obj
ReturnedValue QQmlValueTypeWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object)
{
const auto revertLookup = [lookup, engine, &object]() {
- lookup->qgadgetLookup.propertyCache->release();
- lookup->qgadgetLookup.propertyCache = nullptr;
+ lookup->qgadgetLookup.metaObject = quintptr(0);
lookup->getter = Lookup::getterGeneric;
return Lookup::getterGeneric(lookup, engine, object);
};
@@ -466,17 +671,22 @@ ReturnedValue QQmlValueTypeWrapper::lookupGetter(Lookup *lookup, ExecutionEngine
Heap::QQmlValueTypeWrapper *valueTypeWrapper =
const_cast<Heap::QQmlValueTypeWrapper*>(static_cast<const Heap::QQmlValueTypeWrapper *>(o));
- if (valueTypeWrapper->propertyCache() != lookup->qgadgetLookup.propertyCache)
+ if (valueTypeWrapper->metaObject() != reinterpret_cast<const QMetaObject *>(lookup->qgadgetLookup.metaObject - 1))
return revertLookup();
- if (lookup->qgadgetLookup.ic->vtable == QQmlValueTypeReference::staticVTable()) {
- Scope scope(engine);
- Scoped<QQmlValueTypeReference> referenceWrapper(scope, valueTypeWrapper);
- referenceWrapper->readReferenceValue();
- }
+ if (valueTypeWrapper->isReference() && !valueTypeWrapper->readReference())
+ return Encode::undefined();
- QQmlPropertyData *property = lookup->qgadgetLookup.propertyData;
- return getGadgetProperty(engine, valueTypeWrapper, property);
+ return getGadgetProperty(
+ engine, valueTypeWrapper, QMetaType(lookup->qgadgetLookup.metaType),
+ lookup->qgadgetLookup.coreIndex, lookup->qgadgetLookup.isFunction,
+ lookup->qgadgetLookup.isEnum);
+}
+
+bool QQmlValueTypeWrapper::lookupSetter(
+ Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+{
+ return QV4::Lookup::setterFallback(l, engine, object, value);
}
bool QQmlValueTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
@@ -494,23 +704,19 @@ ReturnedValue QQmlValueTypeWrapper::virtualGet(const Managed *m, PropertyKey id,
const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
QV4::ExecutionEngine *v4 = r->engine();
- Scope scope(v4);
- ScopedString name(scope, id.asStringOrSymbol());
// Note: readReferenceValue() can change the reference->type.
- if (const QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) {
- if (!reference->readReferenceValue())
- return Value::undefinedValue().asReturnedValue();
- }
+ if (r->d()->isReference() && !r->readReferenceValue())
+ return Value::undefinedValue().asReturnedValue();
- QQmlPropertyData *result = r->d()->propertyCache()->property(name.getPointer(), nullptr, nullptr);
- if (!result)
+ QQmlPropertyData result = r->dataForPropertyKey(id);
+ if (!result.isValid())
return Object::virtualGet(m, id, receiver, hasProperty);
if (hasProperty)
*hasProperty = true;
- return getGadgetProperty(v4, r->d(), result);
+ return getGadgetProperty(v4, r->d(), result.propType(), result.coreIndex(), result.isFunction(), result.isEnum());
}
bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
@@ -525,30 +731,30 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
return false;
Scoped<QQmlValueTypeWrapper> r(scope, static_cast<QQmlValueTypeWrapper *>(m));
- Scoped<QQmlValueTypeReference> reference(scope, m->d());
-
- int writeBackPropertyType = -1;
-
- if (reference) {
- QMetaProperty writebackProperty = reference->d()->object->metaObject()->property(reference->d()->property);
-
- if (!writebackProperty.isWritable() || !reference->readReferenceValue())
+ Heap::Object *heapObject = nullptr;
+ if (r->d()->isReference()) {
+ heapObject = r->d()->object();
+ if (!r->readReferenceValue() || !r->d()->canWriteBack())
return false;
-
- writeBackPropertyType = writebackProperty.userType();
}
- ScopedString name(scope, id.asStringOrSymbol());
-
- const QMetaObject *metaObject = r->d()->propertyCache()->metaObject();
- const QQmlPropertyData *pd = r->d()->propertyCache()->property(name.getPointer(), nullptr, nullptr);
- if (!pd)
+ const QMetaObject *metaObject = r->d()->metaObject();
+ const QQmlPropertyData pd = r->dataForPropertyKey(id);
+ if (!pd.isValid())
return false;
- if (reference) {
+ if (heapObject) {
+ QObject *referenceObject = nullptr;
QV4::ScopedFunctionObject f(scope, value);
- const QQmlQPointer<QObject> &referenceObject = reference->d()->object;
- const int referencePropertyIndex = reference->d()->property;
+ const int referencePropertyIndex = r->d()->property();
+ QV4::Scoped<QV4::QObjectWrapper> o(scope, heapObject);
+ if (o) {
+ referenceObject = o->object();
+ } else {
+ QV4::Scoped<QV4::QQmlTypeWrapper> t(scope, heapObject);
+ if (t)
+ referenceObject = t->object();
+ }
if (f) {
if (!f->isBinding()) {
@@ -559,7 +765,18 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
return false;
}
- QQmlContextData *context = v4->callingQmlContext();
+ if (!referenceObject) {
+ QString error = QStringLiteral("Cannot create binding on nested value type property");
+ ScopedString e(scope, v4->newString(error));
+ v4->throwError(e);
+ return false;
+ }
+
+ const QMetaProperty writebackProperty
+ = referenceObject->metaObject()->property(referencePropertyIndex);
+ const QMetaType writeBackPropertyType = writebackProperty.metaType();
+
+ QQmlRefPointer<QQmlContextData> context = v4->callingQmlContext();
QQmlPropertyData cacheData;
cacheData.setWritable(true);
@@ -575,57 +792,50 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
if (f->isBoundFunction())
newBinding->setBoundFunction(static_cast<QV4::BoundFunction *>(f.getPointer()));
newBinding->setSourceLocation(bindingFunction->currentLocation());
- newBinding->setTarget(referenceObject, cacheData, pd);
+ newBinding->setTarget(referenceObject, cacheData, &pd);
QQmlPropertyPrivate::setBinding(newBinding);
return true;
- } else {
+ } else if (referenceObject) {
if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
- if (auto binding = QQmlPropertyPrivate::binding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex()))) {
- Q_ASSERT(!binding->isValueTypeProxy());
+ if (auto binding = QQmlPropertyPrivate::binding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd.coreIndex()))) {
+ Q_ASSERT(binding->kind() == QQmlAbstractBinding::QmlBinding);
const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
const auto stackFrame = v4->currentStackFrame;
qCInfo(lcBindingRemoval,
"Overwriting binding on %s::%s which was initially bound at %s by setting \"%s\" at %s:%d",
referenceObject->metaObject()->className(), referenceObject->metaObject()->property(referencePropertyIndex).name(),
qPrintable(qmlBinding->expressionIdentifier()),
- metaObject->property(pd->coreIndex()).name(),
+ metaObject->property(pd.coreIndex()).name(),
qPrintable(stackFrame->source()), stackFrame->lineNumber());
}
}
- QQmlPropertyPrivate::removeBinding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex()));
+ QQmlPropertyPrivate::removeBinding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd.coreIndex()));
}
}
- QMetaProperty property = metaObject->property(pd->coreIndex());
+ QMetaProperty property = metaObject->property(pd.coreIndex());
Q_ASSERT(property.isValid());
+ if (value.isUndefined() && pd.isResettable()) {
+ property.resetOnGadget(reinterpret_cast<QObject *>(r->d()->gadgetPtr()));
+ if (heapObject)
+ r->d()->writeBack(pd.coreIndex());
+ return true;
+ }
- QVariant v = v4->toVariant(value, property.userType());
+ QVariant v = QV4::ExecutionEngine::toVariant(value, property.metaType());
- if (property.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
+ if (property.isEnumType() && (QMetaType::Type)v.userType() == QMetaType::Double)
v = v.toInt();
void *gadget = r->d()->gadgetPtr();
- property.writeOnGadget(gadget, v);
-
-
- if (reference) {
- if (writeBackPropertyType == QMetaType::QVariant) {
- QVariant variantReferenceValue = r->d()->toVariant();
+ property.writeOnGadget(gadget, std::move(v));
- int flags = 0;
- int status = -1;
- void *a[] = { &variantReferenceValue, nullptr, &status, &flags };
- QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a);
-
- } else {
- int flags = 0;
- int status = -1;
- void *a[] = { r->d()->gadgetPtr(), nullptr, &status, &flags };
- QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a);
- }
- }
+ if (heapObject)
+ r->d()->writeBack(pd.coreIndex());
return true;
}
+} // namespace QV4
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index 60079aa623..5b3894a07f 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLVALUETYPEWRAPPER_P_H
#define QQMLVALUETYPEWRAPPER_P_H
@@ -54,9 +18,15 @@
#include <QtCore/qglobal.h>
#include <private/qtqmlglobal_p.h>
-#include <private/qv4value_p.h>
-#include <private/qv4object_p.h>
+#include <private/qv4referenceobject_p.h>
#include <private/qqmlpropertycache_p.h>
+#include <private/qqmltype_p_p.h>
+#include <private/qqmltypewrapper_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4sequenceobject_p.h>
+#include <private/qv4value_p.h>
+#include <private/qv4referenceobject_p.h>
QT_BEGIN_NAMESPACE
@@ -66,80 +36,126 @@ namespace QV4 {
namespace Heap {
-struct QQmlValueTypeWrapper : Object {
- void init() { Object::init(); }
- void destroy();
+#define QQmlValueTypeWrapperMembers(class, Member)
- QQmlPropertyCache *propertyCache() const { return m_propertyCache; }
- void setPropertyCache(QQmlPropertyCache *c) {
- if (c)
- c->addref();
- if (m_propertyCache)
- m_propertyCache->release();
- m_propertyCache = c;
- }
+DECLARE_HEAP_OBJECT(QQmlValueTypeWrapper, ReferenceObject) {
+ DECLARE_MARKOBJECTS(QQmlValueTypeWrapper);
- void setValueType(QQmlValueType *valueType)
+ void init(
+ const void *data, QMetaType metaType, const QMetaObject *metaObject,
+ Object *object, int property, Flags flags)
{
- Q_ASSERT(valueType != nullptr);
- m_valueType = valueType;
+ ReferenceObject::init(object, property, flags);
+ setMetaType(metaType);
+ setMetaObject(metaObject);
+ if (data)
+ setData(data);
}
- QQmlValueType *valueType() const
- {
- Q_ASSERT(m_valueType != nullptr);
- return m_valueType;
- }
+ QQmlValueTypeWrapper *detached() const;
- void setGadgetPtr(void *gadgetPtr) const
+ void destroy();
+
+ QMetaType metaType() const
{
- m_gadgetPtr = gadgetPtr;
+ Q_ASSERT(m_metaType != nullptr);
+ return QMetaType(m_metaType);
}
- void *gadgetPtr() const
+ void setGadgetPtr(void *gadgetPtr) { m_gadgetPtr = gadgetPtr; }
+ void *gadgetPtr() const { return m_gadgetPtr; }
+
+ const QMetaObject *metaObject() const { return m_metaObject; }
+
+ void setData(const void *data)
{
- return m_gadgetPtr;
+ const QMetaType type = metaType();
+ void *gadget = gadgetPtr();
+ if (gadget) {
+ type.destruct(gadget);
+ } else {
+ gadget = ::operator new(type.sizeOf());
+ setGadgetPtr(gadget);
+ }
+ type.construct(gadget, data);
}
- void setValue(const QVariant &value) const;
QVariant toVariant() const;
+ void *storagePointer();
+ bool setVariant(const QVariant &variant);
+
+ bool readReference();
+ bool writeBack(int propertyIndex = QV4::ReferenceObject::AllProperties);
+
private:
- mutable void *m_gadgetPtr;
- QQmlValueType *m_valueType;
- QQmlPropertyCache *m_propertyCache;
+ void setMetaObject(const QMetaObject *metaObject) { m_metaObject = metaObject; }
+ void setMetaType(QMetaType metaType)
+ {
+ Q_ASSERT(metaType.isValid());
+ m_metaType = metaType.iface();
+ }
+
+ void *m_gadgetPtr;
+ const QtPrivate::QMetaTypeInterface *m_metaType;
+ const QMetaObject *m_metaObject;
};
}
-struct Q_QML_EXPORT QQmlValueTypeWrapper : Object
+struct Q_QML_EXPORT QQmlValueTypeWrapper : public ReferenceObject
{
- V4_OBJECT2(QQmlValueTypeWrapper, Object)
+ V4_OBJECT2(QQmlValueTypeWrapper, ReferenceObject)
V4_PROTOTYPE(valueTypeWrapperPrototype)
V4_NEEDS_DESTROY
public:
- static ReturnedValue create(ExecutionEngine *engine, QObject *, int, const QMetaObject *metaObject, int typeId);
- static ReturnedValue create(ExecutionEngine *engine, const QVariant &, const QMetaObject *metaObject, int typeId);
+ static ReturnedValue create(
+ ExecutionEngine *engine, const void *data, const QMetaObject *metaObject,
+ QMetaType type, Heap::Object *object, int property, Heap::ReferenceObject::Flags flags);
+ static ReturnedValue create(
+ ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *cloneFrom, Heap::Object *object);
+ static ReturnedValue create(
+ ExecutionEngine *engine, const void *, const QMetaObject *metaObject, QMetaType type);
QVariant toVariant() const;
+
+ template<typename ValueType>
+ ValueType *cast()
+ {
+ if (QMetaType::fromType<ValueType>() != d()->metaType())
+ return nullptr;
+ if (d()->isReference() && !readReferenceValue())
+ return nullptr;
+ return static_cast<ValueType *>(d()->gadgetPtr());
+ }
+
bool toGadget(void *data) const;
bool isEqual(const QVariant& value) const;
int typeId() const;
+ QMetaType type() const;
bool write(QObject *target, int propertyIndex) const;
+ bool readReferenceValue() const { return d()->readReference(); }
+ const QMetaObject *metaObject() const { return d()->metaObject(); }
+
+ QQmlPropertyData dataForPropertyKey(PropertyKey id) const;
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
static bool virtualIsEqualTo(Managed *m, Managed *other);
+ static bool virtualHasProperty(const Managed *m, PropertyKey id);
static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p);
static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
static ReturnedValue method_toString(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
static ReturnedValue lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object);
+ static bool lookupSetter(QV4::Lookup *l, QV4::ExecutionEngine *engine,
+ QV4::Value &object, const QV4::Value &value);
static void initProto(ExecutionEngine *v4);
+ static int virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a);
};
}
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index 018769948d..3b9bf80940 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -1,67 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlvme_p.h"
-#include "qqmlboundsignal_p.h"
-#include "qqmlstringconverters_p.h"
#include <private/qmetaobjectbuilder_p.h>
-#include "qqmldata_p.h"
-#include "qqml.h"
-#include "qqmlinfo.h"
-#include "qqmlcustomparser_p.h"
#include "qqmlengine.h"
-#include "qqmlcontext.h"
-#include "qqmlcomponent.h"
-#include "qqmlcomponentattached_p.h"
-#include "qqmlbinding_p.h"
-#include "qqmlengine_p.h"
-#include "qqmlcomponent_p.h"
-#include "qqmlvmemetaobject_p.h"
-#include "qqmlcontext_p.h"
-#include "qqmlglobal_p.h"
#include <private/qfinitestack_p.h>
-#include "qqmlscriptstring.h"
-#include "qqmlscriptstring_p.h"
-#include "qqmlpropertyvalueinterceptor_p.h"
-#include "qqmlvaluetypeproxybinding_p.h"
-#include "qqmlexpression_p.h"
+#include <QtQml/private/qqmlcomponent_p.h>
#include <QStack>
#include <QPointF>
@@ -76,8 +21,6 @@
QT_BEGIN_NAMESPACE
-using namespace QQmlVMETypes;
-
bool QQmlVME::s_enableComponentComplete = true;
void QQmlVME::enableComponentComplete()
@@ -109,9 +52,9 @@ void QQmlVMEGuard::guard(QQmlObjectCreator *creator)
{
clear();
- QFiniteStack<QPointer<QObject> > &objects = creator->allCreatedObjects();
+ QFiniteStack<QQmlGuard<QObject> > &objects = creator->allCreatedObjects();
m_objectCount = objects.count();
- m_objects = new QPointer<QObject>[m_objectCount];
+ m_objects = new QQmlGuard<QObject>[m_objectCount];
for (int ii = 0; ii < m_objectCount; ++ii)
m_objects[ii] = objects[ii];
@@ -138,7 +81,7 @@ bool QQmlVMEGuard::isOK() const
return false;
for (int ii = 0; ii < m_contextCount; ++ii)
- if (m_contexts[ii].isNull() || !m_contexts[ii]->engine)
+ if (m_contexts[ii].isNull() || !m_contexts[ii]->engine())
return false;
return true;
diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h
index 13c5524d96..b8dfc28050 100644
--- a/src/qml/qml/qqmlvme_p.h
+++ b/src/qml/qml/qqmlvme_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLVME_P_H
#define QQMLVME_P_H
@@ -51,66 +15,40 @@
// We mean it.
//
-#include "qqmlerror.h"
-#include <private/qbitfield_p.h>
#include <private/qrecursionwatcher_p.h>
#include <QtCore/QStack>
#include <QtCore/QString>
#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qdeadlinetimer.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qtypeinfo.h>
#include <private/qqmlengine_p.h>
#include <private/qfinitestack_p.h>
+#include <atomic>
+
QT_BEGIN_NAMESPACE
class QObject;
-class QJSValue;
-class QQmlScriptData;
-class QQmlContextData;
-
-namespace QQmlVMETypes {
- struct List
- {
- List() : type(0) {}
- List(int t) : type(t) {}
-
- int type;
- QQmlListProperty<void> qListProperty;
- };
- struct State {
- enum Flag { Deferred = 0x00000001 };
-
- State() : flags(0), context(nullptr), instructionStream(nullptr) {}
- quint32 flags;
- QQmlContextData *context;
- const char *instructionStream;
- QBitField bindingSkipList;
- };
-}
-Q_DECLARE_TYPEINFO(QQmlVMETypes::List, Q_PRIMITIVE_TYPE | Q_MOVABLE_TYPE);
-template<>
-class QTypeInfo<QQmlVMETypes::State> : public QTypeInfoMerger<QQmlVMETypes::State, QBitField> {}; //Q_DECLARE_TYPEINFO
class QQmlInstantiationInterrupt {
public:
inline QQmlInstantiationInterrupt();
- inline QQmlInstantiationInterrupt(volatile bool *runWhile, int nsecs=0);
- inline QQmlInstantiationInterrupt(int nsecs);
+ inline QQmlInstantiationInterrupt(std::atomic<bool> *runWhile,
+ QDeadlineTimer deadline = QDeadlineTimer::Forever);
+ inline QQmlInstantiationInterrupt(QDeadlineTimer deadline);
- inline void reset();
inline bool shouldInterrupt() const;
private:
enum Mode { None, Time, Flag };
Mode mode;
- QElapsedTimer timer;
- int nsecs;
- volatile bool *runWhile;
+ QDeadlineTimer deadline;
+ std::atomic<bool> *runWhile = nullptr;
};
-class Q_QML_PRIVATE_EXPORT QQmlVME
+class Q_QML_EXPORT QQmlVME
{
public:
static void enableComponentComplete();
@@ -141,43 +79,37 @@ public:
private:
int m_objectCount;
- QPointer<QObject> *m_objects;
+ QQmlGuard<QObject> *m_objects;
int m_contextCount;
QQmlGuardedContextData *m_contexts;
};
QQmlInstantiationInterrupt::QQmlInstantiationInterrupt()
- : mode(None), nsecs(0), runWhile(nullptr)
-{
-}
-
-QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(volatile bool *runWhile, int nsecs)
- : mode(Flag), nsecs(nsecs), runWhile(runWhile)
+ : mode(None)
{
}
-QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(int nsecs)
- : mode(Time), nsecs(nsecs), runWhile(nullptr)
+QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(std::atomic<bool> *runWhile, QDeadlineTimer deadline)
+ : mode(Flag), deadline(deadline), runWhile(runWhile)
{
}
-void QQmlInstantiationInterrupt::reset()
+QQmlInstantiationInterrupt::QQmlInstantiationInterrupt(QDeadlineTimer deadline)
+ : mode(Time), deadline(deadline)
{
- if (mode == Time || nsecs)
- timer.start();
}
bool QQmlInstantiationInterrupt::shouldInterrupt() const
{
- if (mode == None) {
- return false;
- } else if (mode == Time) {
- return timer.nsecsElapsed() > nsecs;
- } else if (mode == Flag) {
- return !*runWhile || (nsecs && timer.nsecsElapsed() > nsecs);
- } else {
+ switch (mode) {
+ case None:
return false;
+ case Time:
+ return deadline.hasExpired();
+ case Flag:
+ return !runWhile->load(std::memory_order_acquire) || deadline.hasExpired();
}
+ Q_UNREACHABLE_RETURN(false);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 9b5490b6e5..5f3b6975ca 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -1,53 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 BasysKom GmbH.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 BasysKom GmbH.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlvmemetaobject_p.h"
-
-#include "qqml.h"
#include <private/qqmlrefcount_p.h>
-#include "qqmlexpression.h"
-#include "qqmlexpression_p.h"
-#include "qqmlcontext_p.h"
-#include "qqmlbinding_p.h"
#include "qqmlpropertyvalueinterceptor_p.h"
+#include <qqmlinfo.h>
#include <private/qqmlglobal_p.h>
@@ -57,63 +16,162 @@
#include <private/qv4scopedvalue_p.h>
#include <private/qv4jscall_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4sequenceobject_p.h>
#include <private/qqmlpropertycachecreator_p.h>
#include <private/qqmlpropertycachemethodarguments_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
+
+#include <QtCore/qsequentialiterable.h>
+
+#include <climits> // for CHAR_BIT
QT_BEGIN_NAMESPACE
-static void list_append(QQmlListProperty<QObject> *prop, QObject *o)
+QQmlVMEResolvedList::QQmlVMEResolvedList(QQmlListProperty<QObject> *prop)
+{
+ // see QQmlVMEMetaObject::metaCall for how this was constructed
+ auto encodedIndex = quintptr(prop->data);
+ constexpr quintptr usableBits = sizeof(quintptr) * CHAR_BIT;
+ quintptr inheritanceDepth = encodedIndex >> (usableBits / 2);
+ m_id = encodedIndex & ((quintptr(1) << (usableBits / 2)) - 1);
+
+ // walk up to the correct meta object if necessary
+ auto mo = static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(prop->object)->metaObject);
+ while (inheritanceDepth--)
+ mo = mo->parentVMEMetaObject();
+ m_metaObject = mo;
+ Q_ASSERT(m_metaObject);
+ Q_ASSERT(::strstr(m_metaObject->toDynamicMetaObject(prop->object)
+ ->property(m_metaObject->propOffset() + m_id)
+ .typeName(),
+ "QQmlListProperty"));
+ Q_ASSERT(m_metaObject->object == prop->object);
+
+ // readPropertyAsList() with checks transformed into Q_ASSERT
+ // and without allocation.
+ if (m_metaObject->propertyAndMethodStorage.isUndefined()
+ && m_metaObject->propertyAndMethodStorage.valueRef()) {
+ return;
+ }
+
+ if (auto *md = static_cast<QV4::MemberData *>(
+ m_metaObject->propertyAndMethodStorage.asManaged())) {
+ const QV4::Value *v = md->data() + m_id;
+ Q_ASSERT(v->as<QV4::Object>());
+ m_list = static_cast<QV4::Heap::Object *>(v->heapObject());
+ Q_ASSERT(m_list);
+ }
+}
+
+void QQmlVMEResolvedList::append(QObject *o) const
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- list->append(o);
- static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), nullptr);
+ QV4::Scope scope(m_list->internalClass->engine);
+ QV4::Heap::ArrayData *arrayData = m_list->arrayData;
+
+ const uint length = arrayData->length();
+ if (Q_UNLIKELY(length == std::numeric_limits<uint>::max())) {
+ scope.engine->throwRangeError(QLatin1String("Too many elements."));
+ return;
+ }
+
+ QV4::ScopedObject object(scope, m_list);
+ QV4::ArrayData::realloc(object, QV4::Heap::ArrayData::Simple, length + 1, false);
+ arrayData->vtable()->put(
+ object, length, QV4::QObjectWrapper::wrap(scope.engine, o));
}
-static int list_count(QQmlListProperty<QObject> *prop)
+QObject *QQmlVMEResolvedList::at(qsizetype i) const
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- return list->count();
+ QV4::Scope scope(m_list->internalClass->engine);
+ QV4::Scoped<QV4::QObjectWrapper> result(scope, m_list->arrayData->get(i));
+ return result ? result->object() : nullptr;
}
-static QObject *list_at(QQmlListProperty<QObject> *prop, int index)
+void QQmlVMEResolvedList::replace(qsizetype i, QObject *o) const
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- return list->at(index);
+ QV4::Scope scope(m_list->internalClass->engine);
+ QV4::ScopedObject object(scope, m_list);
+ m_list->arrayData->vtable()->put(object, i, QV4::QObjectWrapper::wrap(scope.engine, o));
}
-static void list_clear(QQmlListProperty<QObject> *prop)
+QQmlVMEResolvedList::~QQmlVMEResolvedList() = default;
+
+void QQmlVMEResolvedList::activateSignal() const
{
- QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data);
- list->clear();
- static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), nullptr);
+ m_metaObject->activate(m_metaObject->object, int(m_id + m_metaObject->methodOffset()), nullptr);
}
-QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr()
- : QQmlGuard<QObject>(nullptr), m_target(nullptr), m_index(-1)
+void QQmlVMEMetaObject::list_append(QQmlListProperty<QObject> *prop, QObject *o)
+{
+ const QQmlVMEResolvedList resolved(prop);
+ resolved.append(o);
+ resolved.activateSignal();
+}
+
+void QQmlVMEMetaObject::list_append_nosignal(QQmlListProperty<QObject> *prop, QObject *o)
+{
+ QQmlVMEResolvedList(prop).append(o);
+}
+
+static qsizetype list_count(QQmlListProperty<QObject> *prop)
+{
+ return QQmlVMEResolvedList(prop).size();
+}
+
+static QObject *list_at(QQmlListProperty<QObject> *prop, qsizetype index)
{
+ return QQmlVMEResolvedList(prop).at(index);
}
-QQmlVMEVariantQObjectPtr::~QQmlVMEVariantQObjectPtr()
+void QQmlVMEMetaObject::list_clear(QQmlListProperty<QObject> *prop)
{
+ const QQmlVMEResolvedList resolved(prop);
+ resolved.clear();
+ resolved.activateSignal();
}
-void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
+void QQmlVMEMetaObject::list_clear_nosignal(QQmlListProperty<QObject> *prop)
{
- if (!m_target || QQmlData::wasDeleted(m_target->object))
+ QQmlVMEResolvedList(prop).clear();
+}
+
+static void list_replace(QQmlListProperty<QObject> *prop, qsizetype index, QObject *o)
+{
+ const QQmlVMEResolvedList resolved(prop);
+ resolved.replace(index, o);
+ resolved.activateSignal();
+}
+
+static void list_removeLast(QQmlListProperty<QObject> *prop)
+{
+ const QQmlVMEResolvedList resolved(prop);
+ resolved.removeLast();
+ resolved.activateSignal();
+}
+
+QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr()
+ : QQmlGuard<QObject>(QQmlVMEVariantQObjectPtr::objectDestroyedImpl, nullptr), m_target(nullptr), m_index(-1)
+{
+}
+
+void QQmlVMEVariantQObjectPtr::objectDestroyedImpl(QQmlGuardImpl *guard)
+{
+ auto This = static_cast<QQmlVMEVariantQObjectPtr *>(guard);
+ if (!This->m_target || QQmlData::wasDeleted(This->m_target->object))
return;
- if (m_index >= 0) {
- QV4::ExecutionEngine *v4 = m_target->propertyAndMethodStorage.engine();
+ if (This->m_index >= 0) {
+ QV4::ExecutionEngine *v4 = This->m_target->propertyAndMethodStorage.engine();
if (v4) {
QV4::Scope scope(v4);
- QV4::Scoped<QV4::MemberData> sp(scope, m_target->propertyAndMethodStorage.value());
+ QV4::Scoped<QV4::MemberData> sp(scope, This->m_target->propertyAndMethodStorage.value());
if (sp) {
- QV4::PropertyIndex index{ sp->d(), sp->d()->values.values + m_index };
+ QV4::PropertyIndex index{ sp->d(), sp->d()->values.values + This->m_index };
index.set(v4, QV4::Value::nullValue());
}
}
- m_target->activate(m_target->object, m_target->methodOffset() + m_index, nullptr);
+ This->m_target->activate(This->m_target->object, This->m_target->methodOffset() + This->m_index, nullptr);
}
}
@@ -130,7 +188,12 @@ public:
QQmlVMEMetaObjectEndpoint();
void tryConnect();
- QFlagPointer<QQmlVMEMetaObject> metaObject;
+ enum Tag {
+ NoTag,
+ EndPointIsConnected
+ };
+
+ QTaggedPointer<QQmlVMEMetaObject, Tag> metaObject;
};
QQmlVMEMetaObjectEndpoint::QQmlVMEMetaObjectEndpoint()
@@ -149,29 +212,26 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
Q_ASSERT(metaObject->compiledObject);
int aliasId = this - metaObject->aliasEndpoints;
- if (metaObject.flag()) {
+ if (metaObject.tag() == EndPointIsConnected) {
// This is actually notify
int sigIdx = metaObject->methodOffset() + aliasId + metaObject->compiledObject->nProperties;
metaObject->activate(metaObject->object, sigIdx, nullptr);
} else {
const QV4::CompiledData::Alias *aliasData = &metaObject->compiledObject->aliasTable()[aliasId];
if (!aliasData->isObjectAlias()) {
- QQmlContextData *ctxt = metaObject->ctxt;
- QObject *target = ctxt->idValues[aliasData->targetObjectId].data();
+ QQmlRefPointer<QQmlContextData> ctxt = metaObject->ctxt;
+ QObject *target = ctxt->idValue(aliasData->targetObjectId());
if (!target)
return;
- QQmlData *targetDData = QQmlData::get(target, /*create*/false);
- if (!targetDData)
- return;
QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex);
int coreIndex = encodedIndex.coreIndex();
int valueTypeIndex = encodedIndex.valueTypeIndex();
- const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
- if (pd && valueTypeIndex != -1 && !QQmlValueTypeFactory::valueType(pd->propType())) {
+ const QQmlPropertyData *pd = QQmlData::ensurePropertyCache(target)->property(coreIndex);
+ if (pd && valueTypeIndex != -1 && !QQmlMetaType::valueType(pd->propType())) {
// deep alias
- QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(metaObject->compilationUnit->engine->qmlEngine());
- auto const *newPropertyCache = enginePriv->propertyCacheForType(pd->propType());
+ const QQmlPropertyCache::ConstPtr newPropertyCache
+ = QQmlMetaType::propertyCacheForType(pd->propType());
void *argv[1] = { &target };
QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex, argv);
Q_ASSERT(newPropertyCache);
@@ -180,20 +240,18 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
if (!pd)
return;
- if (pd->notifyIndex() != -1)
- connect(target, pd->notifyIndex(), ctxt->engine);
+ if (pd->notifyIndex() != -1 && ctxt->engine())
+ connect(target, pd->notifyIndex(), ctxt->engine());
}
- metaObject.setFlag();
+ metaObject.setTag(EndPointIsConnected);
}
}
-QQmlInterceptorMetaObject::QQmlInterceptorMetaObject(QObject *obj, const QQmlRefPointer<QQmlPropertyCache> &cache)
+QQmlInterceptorMetaObject::QQmlInterceptorMetaObject(QObject *obj, const QQmlPropertyCache::ConstPtr &cache)
: object(obj),
- cache(cache),
- interceptors(nullptr),
- hasAssignedMetaObjectData(false)
+ cache(cache)
{
QObjectPrivate *op = QObjectPrivate::get(obj);
@@ -216,6 +274,15 @@ QQmlInterceptorMetaObject::~QQmlInterceptorMetaObject()
void QQmlInterceptorMetaObject::registerInterceptor(QQmlPropertyIndex index, QQmlPropertyValueInterceptor *interceptor)
{
+ for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
+ if (Q_UNLIKELY(vi->m_propertyIndex.coreIndex() == index.coreIndex())) {
+ qWarning() << "Attempting to set another interceptor on "
+ << object->metaObject()->className() << "property"
+ << object->metaObject()->property(index.coreIndex()).name()
+ << "- unsupported";
+ }
+ }
+
interceptor->m_propertyIndex = index;
interceptor->m_next = interceptors;
interceptors = interceptor;
@@ -231,21 +298,31 @@ int QQmlInterceptorMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id,
return object->qt_metacall(c, id, a);
}
-bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a)
-{
- if (c == QMetaObject::WriteProperty && interceptors &&
- !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyData::BypassInterceptor)) {
-
- for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
- if (vi->m_propertyIndex.coreIndex() != id)
- continue;
-
- const int valueIndex = vi->m_propertyIndex.valueTypeIndex();
- int type = QQmlData::get(object)->propertyCache->property(id)->propType();
-
- if (type != QVariant::Invalid) {
- if (valueIndex != -1) {
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type);
+bool QQmlInterceptorMetaObject::doIntercept(QMetaObject::Call c, int id, void **a)
+{
+ for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) {
+ if (vi->m_propertyIndex.coreIndex() != id)
+ continue;
+
+ const int valueIndex = vi->m_propertyIndex.valueTypeIndex();
+ const QQmlData *data = QQmlData::get(object);
+ const QMetaType metaType = data->propertyCache->property(id)->propType();
+
+ if (metaType.isValid()) {
+ if (valueIndex != -1 && c == QMetaObject::WriteProperty) {
+
+ // If we didn't intend to change the property this interceptor cares about,
+ // then don't bother intercepting it. There may be an animation running on
+ // the property. We shouldn't disturb it.
+ const int changedProperty
+ = (*static_cast<int *>(a[3]) & QQmlPropertyData::HasInternalIndex)
+ ? *static_cast<int *>(a[4])
+ : QV4::ReferenceObject::AllProperties;
+ if (changedProperty == QV4::ReferenceObject::AllProperties
+ || changedProperty == valueIndex) {
+ // TODO: handle intercepting bindable properties for value types?
+ QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance(
+ data->context->engine(), metaType);
Q_ASSERT(valueType);
//
@@ -279,57 +356,65 @@ bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a)
// (7) Issue the interceptor call with the new component value.
//
- QMetaProperty valueProp = valueType->metaObject()->property(valueIndex);
- QVariant newValue(type, a[0]);
+ QMetaProperty valueProp = valueType->property(valueIndex);
+ QVariant newValue(metaType, a[0]);
valueType->read(object, id);
- QVariant prevComponentValue = valueProp.read(valueType);
+ QVariant prevComponentValue = valueType->readOnGadget(valueProp);
valueType->setValue(newValue);
- QVariant newComponentValue = valueProp.read(valueType);
+ QVariant newComponentValue = valueType->readOnGadget(valueProp);
- // Don't apply the interceptor if the intercepted value has not changed
- bool updated = false;
- if (newComponentValue != prevComponentValue) {
- valueProp.write(valueType, prevComponentValue);
- valueType->write(object, id, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
-
- vi->write(newComponentValue);
- updated = true;
- }
+ // If the intercepted value seemingly has not changed, we still need to
+ // invoke the interceptor. There may be a pending animation that will
+ // change the value soon. Such an animation needs to be canceled if the
+ // current value is explicitly set.
+ // So, we cannot return here if prevComponentValue == newComponentValue.
+ valueType->writeOnGadget(valueProp, std::move(prevComponentValue));
+ valueType->write(object, id, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor);
- if (updated)
- return true;
- } else {
- vi->write(QVariant(type, a[0]));
+ vi->write(newComponentValue);
return true;
}
+ } else if (c == QMetaObject::WriteProperty) {
+ vi->write(QVariant(metaType, a[0]));
+ return true;
+ } else {
+ object->qt_metacall(c, id, a);
+ QUntypedBindable target = *reinterpret_cast<QUntypedBindable *>(a[0]);
+ return vi->bindable(reinterpret_cast<QUntypedBindable *>(a[0]), target);
}
}
}
+
return false;
}
-
-QAbstractDynamicMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObject *o)
+static QMetaObject *stringCastMetaObject(QObject *o, const QMetaObject *top)
{
- if (!hasAssignedMetaObjectData) {
- *static_cast<QMetaObject *>(this) = *cache->createMetaObject();
+ for (const QMetaObject *mo = top; mo; mo = mo->superClass()) {
+ if (o->qt_metacast(mo->className()) != nullptr)
+ return const_cast<QMetaObject *>(mo);
+ }
+ return nullptr;
+}
- if (parent.isT1())
- this->d.superdata = parent.asT1()->toDynamicMetaObject(o);
- else
- this->d.superdata = parent.asT2();
+QMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObject *o)
+{
+ if (!metaObject)
+ metaObject = cache->createMetaObject();
- hasAssignedMetaObjectData = true;
- }
+ if (Q_UNLIKELY(metaObject.tag() == MetaObjectInvalid))
+ return stringCastMetaObject(o, metaObject->superClass());
- return this;
+ // ### Qt7: The const_cast is only due to toDynamicMetaObject having the wrong return type.
+ // It should be const QMetaObject *. Fix this.
+ return const_cast<QMetaObject *>(metaObject.data());
}
QQmlVMEMetaObject::QQmlVMEMetaObject(QV4::ExecutionEngine *engine,
QObject *obj,
- const QQmlRefPointer<QQmlPropertyCache> &cache, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlCompilationUnit, int qmlObjectId)
+ const QQmlPropertyCache::ConstPtr &cache, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlCompilationUnit, int qmlObjectId)
: QQmlInterceptorMetaObject(obj, cache),
engine(engine),
ctxt(QQmlData::get(obj, true)->outerContext),
@@ -345,6 +430,12 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QV4::ExecutionEngine *engine,
uint size = compiledObject->nProperties + compiledObject->nFunctions;
if (size) {
QV4::Heap::MemberData *data = QV4::MemberData::allocate(engine, size);
+ // we only have a weak reference below; if the VMEMetaObject is already marked
+ // (triggered by the allocate call above)
+ // we therefore might never mark the member data; consequently, mark it now
+ QV4::WriteBarrier::markCustom(engine, [data](QV4::MarkStack *ms) {
+ data->mark(ms);
+ });
propertyAndMethodStorage.set(engine, data);
std::fill(data->values.values, data->values.values + data->values.size, QV4::Encode::undefined());
}
@@ -401,57 +492,20 @@ void QQmlVMEMetaObject::writeProperty(int id, double v)
void QQmlVMEMetaObject::writeProperty(int id, const QString& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newString(v));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QDate& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
-}
-
-void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v)
-{
- QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
+ if (md) {
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::MemberData>(scope, md)->set(engine, id, engine->newString(v));
+ }
}
void QQmlVMEMetaObject::writeProperty(int id, QObject* v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
- if (md)
- md->set(engine, id, QV4::Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, v)));
+ if (md) {
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::MemberData>(scope, md)->set(engine, id, QV4::Value::fromReturnedValue(
+ QV4::QObjectWrapper::wrap(engine, v)));
+ }
QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id);
if (v && !guard) {
@@ -523,7 +577,7 @@ QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id) const
QV4::Scope scope(engine);
QV4::ScopedValue sv(scope, *(md->data() + id));
const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
- if (!v || v->d()->data().type() != QVariant::Url)
+ if (!v || v->d()->data().userType() != QMetaType::QUrl)
return QUrl();
return v->d()->data().value<QUrl>();
}
@@ -537,12 +591,26 @@ QDate QQmlVMEMetaObject::readPropertyAsDate(int id) const
QV4::Scope scope(engine);
QV4::ScopedValue sv(scope, *(md->data() + id));
const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
- if (!v || v->d()->data().type() != QVariant::Date)
+ if (!v || v->d()->data().userType() != QMetaType::QDate)
return QDate();
return v->d()->data().value<QDate>();
}
-QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id)
+QTime QQmlVMEMetaObject::readPropertyAsTime(int id) const
+{
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
+ if (!md)
+ return QTime();
+
+ QV4::Scope scope(engine);
+ QV4::ScopedValue sv(scope, *(md->data() + id));
+ const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
+ if (!v || v->d()->data().userType() != QMetaType::QTime)
+ return QTime();
+ return v->d()->data().value<QTime>();
+}
+
+QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id) const
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
@@ -551,11 +619,27 @@ QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id)
QV4::Scope scope(engine);
QV4::ScopedValue sv(scope, *(md->data() + id));
const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
- if (!v || v->d()->data().type() != QVariant::DateTime)
+ if (!v || v->d()->data().userType() != QMetaType::QDateTime)
return QDateTime();
return v->d()->data().value<QDateTime>();
}
+#if QT_CONFIG(regularexpression)
+QRegularExpression QQmlVMEMetaObject::readPropertyAsRegularExpression(int id) const
+{
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
+ if (!md)
+ return QRegularExpression();
+
+ QV4::Scope scope(engine);
+ QV4::ScopedValue sv(scope, *(md->data() + id));
+ const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
+ if (!v || v->d()->data().userType() != QMetaType::QRegularExpression)
+ return QRegularExpression();
+ return v->d()->data().value<QRegularExpression>();
+}
+#endif
+
QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) const
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
@@ -565,7 +649,7 @@ QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) const
QV4::Scope scope(engine);
QV4::ScopedValue sv(scope, *(md->data() + id));
const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
- if (!v || v->d()->data().type() != QVariant::SizeF)
+ if (!v || v->d()->data().userType() != QMetaType::QSizeF)
return QSizeF();
return v->d()->data().value<QSizeF>();
}
@@ -579,7 +663,7 @@ QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id) const
QV4::Scope scope(engine);
QV4::ScopedValue sv(scope, *(md->data() + id));
const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
- if (!v || v->d()->data().type() != QVariant::PointF)
+ if (!v || v->d()->data().userType() != QMetaType::QPointF)
return QPointF();
return v->d()->data().value<QPointF>();
}
@@ -598,20 +682,19 @@ QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) const
return wrapper->object();
}
-QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) const
+void QQmlVMEMetaObject::initPropertyAsList(int id) const
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
- return nullptr;
+ return;
QV4::Scope scope(engine);
- QV4::Scoped<QV4::VariantObject> v(scope, *(md->data() + id));
- if (!v || (int)v->d()->data().userType() != qMetaTypeId<QList<QObject *> >()) {
- QVariant variant(QVariant::fromValue(QList<QObject*>()));
- v = engine->newVariantObject(variant);
+ QV4::ScopedObject v(scope, *(md->data() + id));
+ if (!v) {
+ v = engine->newObject();
+ v->arrayCreate();
md->set(engine, id, v);
}
- return static_cast<QList<QObject *> *>(v->d()->data().data());
}
QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) const
@@ -623,14 +706,11 @@ QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) const
QV4::Scope scope(engine);
QV4::ScopedValue sv(scope, *(md->data() + id));
const QV4::VariantObject *v = sv->as<QV4::VariantObject>();
- if (!v || v->d()->data().type() != QVariant::RectF)
+ if (!v || v->d()->data().userType() != QMetaType::QRectF)
return QRectF();
return v->d()->data().value<QRectF>();
}
-#if defined(Q_OS_WINRT) && defined(_M_ARM)
-#pragma optimize("", off)
-#endif
int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void **a)
{
Q_ASSERT(o == object);
@@ -646,171 +726,301 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
const int signalCount = compiledObject ? int(compiledObject->nSignals) : 0;
const int methodCount = compiledObject ? int(compiledObject->nFunctions) : 0;
- if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) {
+ if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty || c == QMetaObject::BindableProperty) {
if (id >= propOffset()) {
id -= propOffset();
if (id < propertyCount) {
+ // if we reach this point, propertyCount must have been > 0, and thus compiledObject != nullptr
+ Q_ASSERT(compiledObject);
const QV4::CompiledData::Property &property = compiledObject->propertyTable()[id];
- const QV4::CompiledData::BuiltinType t = property.builtinType();
+ const QV4::CompiledData::CommonType t = property.commonType();
// the context can be null if accessing var properties from cpp after re-parenting an item.
- QQmlEnginePrivate *ep = (ctxt == nullptr || ctxt->engine == nullptr) ? nullptr : QQmlEnginePrivate::get(ctxt->engine);
-
- const int fallbackMetaType = QQmlPropertyCacheCreatorBase::metaTypeForPropertyType(t);
+ QQmlEnginePrivate *ep = (ctxt.isNull() || ctxt->engine() == nullptr)
+ ? nullptr
+ : QQmlEnginePrivate::get(ctxt->engine());
if (c == QMetaObject::ReadProperty) {
- switch (t) {
- case QV4::CompiledData::BuiltinType::Int:
- *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id);
- break;
- case QV4::CompiledData::BuiltinType::Bool:
- *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id);
- break;
- case QV4::CompiledData::BuiltinType::Real:
- *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id);
- break;
- case QV4::CompiledData::BuiltinType::String:
- *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id);
- break;
- case QV4::CompiledData::BuiltinType::Url:
- *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id);
- break;
- case QV4::CompiledData::BuiltinType::Date:
- *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id);
- break;
- case QV4::CompiledData::BuiltinType::DateTime:
- *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id);
- break;
- case QV4::CompiledData::BuiltinType::Rect:
- *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id);
- break;
- case QV4::CompiledData::BuiltinType::Size:
- *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id);
- break;
- case QV4::CompiledData::BuiltinType::Point:
- *reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id);
- break;
- case QV4::CompiledData::BuiltinType::Variant:
- *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
- break;
- case QV4::CompiledData::BuiltinType::Font:
- case QV4::CompiledData::BuiltinType::Time:
- case QV4::CompiledData::BuiltinType::Color:
- case QV4::CompiledData::BuiltinType::Vector2D:
- case QV4::CompiledData::BuiltinType::Vector3D:
- case QV4::CompiledData::BuiltinType::Vector4D:
- case QV4::CompiledData::BuiltinType::Matrix4x4:
- case QV4::CompiledData::BuiltinType::Quaternion:
- Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
- if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
- QVariant propertyAsVariant;
- if (const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>())
- propertyAsVariant = v->d()->data();
- QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType);
- }
- break;
- case QV4::CompiledData::BuiltinType::Var:
- if (ep) {
- *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
+ if (property.isList()) {
+ // _id because this is an absolute property ID.
+ const QQmlPropertyData *propertyData = cache->property(_id);
+ const QMetaType propType = propertyData->propType();
+
+ if (propType.flags().testFlag(QMetaType::IsQmlList)) {
+ // when reading from the list, we need to find the correct MetaObject,
+ // namely this. However, obejct->metaObject might point to any
+ // MetaObject down the inheritance hierarchy, so we need to store how
+ // far we have to go down
+ // To do this, we encode the hierarchy depth together with the id of the
+ // property in a single quintptr, with the first half storing the depth
+ // and the second half storing the property id
+ auto mo = static_cast<QQmlVMEMetaObject *>(
+ QObjectPrivate::get(object)->metaObject);
+ quintptr inheritanceDepth = 0u;
+ while (mo && mo != this) {
+ mo = mo->parentVMEMetaObject();
+ ++inheritanceDepth;
+ }
+ constexpr quintptr idBits = sizeof(quintptr) * CHAR_BIT / 2u;
+ if (Q_UNLIKELY(inheritanceDepth >= (quintptr(1) << idBits))) {
+ qmlWarning(object) << "Too many objects in inheritance hierarchy "
+ "for list property";
+ return -1;
+ }
+ if (Q_UNLIKELY(quintptr(id) >= (quintptr(1) << idBits))) {
+ qmlWarning(object) << "Too many properties in object "
+ "for list property";
+ return -1;
+ }
+ quintptr encodedIndex = (inheritanceDepth << idBits) + id;
+
+ initPropertyAsList(id);
+ *static_cast<QQmlListProperty<QObject> *>(a[0])
+ = QQmlListProperty<QObject>(
+ object, reinterpret_cast<void *>(quintptr(encodedIndex)),
+ list_append, list_count, list_at,
+ list_clear, list_replace, list_removeLast);
+ } else if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
+ // Value type list
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::Sequence> sequence(scope, *(md->data() + id));
+ const void *data = sequence
+ ? QV4::SequencePrototype::getRawContainerPtr(sequence, propType)
+ : nullptr;
+ propType.destruct(a[0]);
+ propType.construct(a[0], data);
} else {
- // if the context was disposed, we just return an invalid variant from read.
- *reinterpret_cast<QVariant *>(a[0]) = QVariant();
+ qmlWarning(object) << "Cannot find member data";
}
- break;
- case QV4::CompiledData::BuiltinType::InvalidBuiltin:
- if (property.isList) {
- QList<QObject *> *list = readPropertyAsList(id);
- QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]);
- *p = QQmlListProperty<QObject>(object, list,
- list_append, list_count, list_at,
- list_clear);
- p->dummy1 = this;
- p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id));
- } else {
- *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id);
+ } else {
+ switch (t) {
+ case QV4::CompiledData::CommonType::Void:
+ break;
+ case QV4::CompiledData::CommonType::Int:
+ *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id);
+ break;
+ case QV4::CompiledData::CommonType::Bool:
+ *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id);
+ break;
+ case QV4::CompiledData::CommonType::Real:
+ *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id);
+ break;
+ case QV4::CompiledData::CommonType::String:
+ *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id);
+ break;
+ case QV4::CompiledData::CommonType::Url:
+ *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id);
+ break;
+ case QV4::CompiledData::CommonType::Date:
+ *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id);
+ break;
+ case QV4::CompiledData::CommonType::DateTime:
+ *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id);
+ break;
+ case QV4::CompiledData::CommonType::RegExp:
+#if QT_CONFIG(regularexpression)
+ *reinterpret_cast<QRegularExpression *>(a[0])
+ = readPropertyAsRegularExpression(id);
+#endif
+ break;
+ case QV4::CompiledData::CommonType::Rect:
+ *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id);
+ break;
+ case QV4::CompiledData::CommonType::Size:
+ *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id);
+ break;
+ case QV4::CompiledData::CommonType::Point:
+ *reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id);
+ break;
+ case QV4::CompiledData::CommonType::Time:
+ *reinterpret_cast<QTime *>(a[0]) = readPropertyAsTime(id);
+ break;
+ case QV4::CompiledData::CommonType::Var:
+ if (ep) {
+ *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
+ } else {
+ // if the context was disposed,
+ // we just return an invalid variant from read.
+ *reinterpret_cast<QVariant *>(a[0]) = QVariant();
+ }
+ break;
+ case QV4::CompiledData::CommonType::Invalid:
+ if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
+ QV4::Scope scope(engine);
+ QV4::ScopedValue sv(scope, *(md->data() + id));
+
+ // _id because this is an absolute property ID.
+ const QQmlPropertyData *propertyData = cache->property(_id);
+
+ if (propertyData->isQObject()) {
+ if (const auto *wrap = sv->as<QV4::QObjectWrapper>())
+ *reinterpret_cast<QObject **>(a[0]) = wrap->object();
+ else
+ *reinterpret_cast<QObject **>(a[0]) = nullptr;
+ } else {
+ const QMetaType propType = propertyData->propType();
+ const void *data = nullptr;
+ if (const auto *v = sv->as<QV4::VariantObject>()) {
+ const QVariant &variant = v->d()->data();
+ if (variant.metaType() == propType)
+ data = variant.constData();
+ }
+ propType.destruct(a[0]);
+ propType.construct(a[0], data);
+ }
+ } else {
+ qmlWarning(object) << "Cannot find member data";
+ }
}
}
-
} else if (c == QMetaObject::WriteProperty) {
bool needActivate = false;
- switch (t) {
- case QV4::CompiledData::BuiltinType::Int:
- needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id);
- writeProperty(id, *reinterpret_cast<int *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::Bool:
- needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id);
- writeProperty(id, *reinterpret_cast<bool *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::Real:
- needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id);
- writeProperty(id, *reinterpret_cast<double *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::String:
- needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id);
- writeProperty(id, *reinterpret_cast<QString *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::Url:
- needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id);
- writeProperty(id, *reinterpret_cast<QUrl *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::Date:
- needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id);
- writeProperty(id, *reinterpret_cast<QDate *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::DateTime:
- needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id);
- writeProperty(id, *reinterpret_cast<QDateTime *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::Rect:
- needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id);
- writeProperty(id, *reinterpret_cast<QRectF *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::Size:
- needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id);
- writeProperty(id, *reinterpret_cast<QSizeF *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::Point:
- needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id);
- writeProperty(id, *reinterpret_cast<QPointF *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::Variant:
- writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::Font:
- case QV4::CompiledData::BuiltinType::Time:
- case QV4::CompiledData::BuiltinType::Color:
- case QV4::CompiledData::BuiltinType::Vector2D:
- case QV4::CompiledData::BuiltinType::Vector3D:
- case QV4::CompiledData::BuiltinType::Vector4D:
- case QV4::CompiledData::BuiltinType::Matrix4x4:
- case QV4::CompiledData::BuiltinType::Quaternion:
- Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
- if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
- const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
- if (!v) {
- md->set(engine, id, engine->newVariantObject(QVariant()));
- v = (md->data() + id)->as<QV4::VariantObject>();
- QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data());
+
+ if (property.isList()) {
+ // _id because this is an absolute property ID.
+ const QQmlPropertyData *propertyData = cache->property(_id);
+ const QMetaType propType = propertyData->propType();
+
+ if (propType.flags().testFlag(QMetaType::IsQmlList)) {
+ // Writing such a property is not supported. Content is added through
+ // the list property methods.
+ } else if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
+ // Value type list
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::Sequence> sequence(scope, *(md->data() + id));
+ void *data = sequence
+ ? QV4::SequencePrototype::getRawContainerPtr(sequence, propType)
+ : nullptr;
+ if (data) {
+ if (!propType.equals(data, a[0])) {
+ propType.destruct(data);
+ propType.construct(data, a[0]);
+ needActivate = true;
+ }
+ } else {
+ if (const QQmlType type = QQmlMetaType::qmlListType(propType);
+ type.isSequentialContainer()) {
+ sequence = QV4::SequencePrototype::fromData(
+ engine, propType, type.listMetaSequence(), a[0]);
+ } else if (QSequentialIterable iterable;
+ QMetaType::convert(
+ propType, a[0],
+ QMetaType::fromType<QSequentialIterable>(),
+ &iterable)) {
+ sequence = QV4::SequencePrototype::fromData(
+ engine, propType, iterable.metaContainer(), a[0]);
+ } else {
+ sequence = QV4::Encode::undefined();
+ }
+ md->set(engine, id, sequence);
+ if (sequence->isUndefined()) {
+ qmlWarning(object)
+ << "Could not create a QML sequence object for "
+ << propType.name();
+ }
+ needActivate = true;
}
- needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data());
- QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data());
- }
- break;
- case QV4::CompiledData::BuiltinType::Var:
- if (ep)
- writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
- break;
- case QV4::CompiledData::BuiltinType::InvalidBuiltin:
- if (property.isList) {
- // Writing such a property is not supported. Content is added through the list property
- // methods.
} else {
- needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id);
- writeProperty(id, *reinterpret_cast<QObject **>(a[0]));
+ qmlWarning(object) << "Cannot find member data";
+ }
+ } else {
+ switch (t) {
+ case QV4::CompiledData::CommonType::Void:
+ break;
+ case QV4::CompiledData::CommonType::Int:
+ needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id);
+ writeProperty(id, *reinterpret_cast<int *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Bool:
+ needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id);
+ writeProperty(id, *reinterpret_cast<bool *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Real:
+ needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id);
+ writeProperty(id, *reinterpret_cast<double *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::String:
+ needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id);
+ writeProperty(id, *reinterpret_cast<QString *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Url:
+ needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id);
+ writeProperty(id, *reinterpret_cast<QUrl *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Date:
+ needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id);
+ writeProperty(id, *reinterpret_cast<QDate *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::DateTime:
+ needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id);
+ writeProperty(id, *reinterpret_cast<QDateTime *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::RegExp:
+#if QT_CONFIG(regularexpression)
+ needActivate = *reinterpret_cast<QRegularExpression *>(a[0])
+ != readPropertyAsRegularExpression(id);
+ writeProperty(id, *reinterpret_cast<QRegularExpression *>(a[0]));
+#endif
+ break;
+ case QV4::CompiledData::CommonType::Rect:
+ needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id);
+ writeProperty(id, *reinterpret_cast<QRectF *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Size:
+ needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id);
+ writeProperty(id, *reinterpret_cast<QSizeF *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Point:
+ needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id);
+ writeProperty(id, *reinterpret_cast<QPointF *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Time:
+ needActivate = *reinterpret_cast<QTime *>(a[0]) != readPropertyAsTime(id);
+ writeProperty(id, *reinterpret_cast<QTime *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Var:
+ if (ep)
+ writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
+ break;
+ case QV4::CompiledData::CommonType::Invalid:
+ if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
+ QV4::Scope scope(engine);
+ QV4::ScopedValue sv(scope, *(md->data() + id));
+
+ // _id because this is an absolute property ID.
+ const QQmlPropertyData *propertyData = cache->property(_id);
+
+ if (propertyData->isQObject()) {
+ QObject *arg = *reinterpret_cast<QObject **>(a[0]);
+ if (const auto *wrap = sv->as<QV4::QObjectWrapper>())
+ needActivate = wrap->object() != arg;
+ else if (arg != nullptr || !sv->isNull())
+ needActivate = true;
+ if (needActivate)
+ writeProperty(id, arg);
+ } else {
+ const QMetaType propType = propertyData->propType();
+ if (const auto *v = sv->as<QV4::VariantObject>()) {
+ QVariant &variant = v->d()->data();
+ if (variant.metaType() != propType) {
+ needActivate = true;
+ variant = QVariant(propType, a[0]);
+ } else if (!propType.equals(variant.constData(), a[0])) {
+ needActivate = true;
+ propType.destruct(variant.data());
+ propType.construct(variant.data(), a[0]);
+ }
+ } else {
+ needActivate = true;
+ md->set(engine, id, engine->newVariantObject(
+ propType, a[0]));
+ }
+ }
+ } else {
+ qmlWarning(object) << "Cannot find member data";
+ }
}
-
}
if (needActivate)
@@ -825,18 +1035,18 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
if (id < aliasCount) {
const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[id];
- if ((aliasData->flags & QV4::CompiledData::Alias::AliasPointsToPointerObject) && c == QMetaObject::ReadProperty)
- *reinterpret_cast<void **>(a[0]) = nullptr;
+ if (aliasData->hasFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject)
+ && c == QMetaObject::ReadProperty){
+ *reinterpret_cast<void **>(a[0]) = nullptr;
+ }
- if (!ctxt) return -1;
+ if (ctxt.isNull())
+ return -1;
- while (aliasData->aliasToLocalAlias)
+ while (aliasData->isAliasToLocalAlias())
aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
- QQmlContext *context = ctxt->asQQmlContext();
- QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);
-
- QObject *target = ctxtPriv->data->idValues[aliasData->targetObjectId].data();
+ QObject *target = ctxt->idValue(aliasData->targetObjectId());
if (!target)
return -1;
@@ -855,39 +1065,50 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
int coreIndex = encodedIndex.coreIndex();
const int valueTypePropertyIndex = encodedIndex.valueTypeIndex();
- // Remove binding (if any) on write
- if(c == QMetaObject::WriteProperty) {
- int flags = *reinterpret_cast<int*>(a[3]);
- if (flags & QQmlPropertyData::RemoveBindingOnAliasWrite) {
- QQmlData *targetData = QQmlData::get(target);
- if (targetData && targetData->hasBindingBit(coreIndex))
- QQmlPropertyPrivate::removeBinding(target, encodedIndex);
+ const auto removePendingBinding
+ = [c, a](QObject *target, int coreIndex, QQmlPropertyIndex encodedIndex) {
+ // Remove binding (if any) on write
+ if (c == QMetaObject::WriteProperty) {
+ int flags = *reinterpret_cast<int*>(a[3]);
+ if (flags & QQmlPropertyData::RemoveBindingOnAliasWrite) {
+ QQmlData *targetData = QQmlData::get(target);
+ if (targetData && targetData->hasBindingBit(coreIndex)) {
+ QQmlPropertyPrivate::removeBinding(target, encodedIndex);
+ targetData->clearBindingBit(coreIndex);
+ }
+ }
}
- }
+ };
if (valueTypePropertyIndex != -1) {
if (!targetDData->propertyCache)
return -1;
const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
// Value type property or deep alias
- QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType());
+ QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance(
+ ctxt->engine(), pd->propType());
if (valueType) {
-
+ removePendingBinding(target, coreIndex, encodedIndex);
valueType->read(target, coreIndex);
int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a);
if (c == QMetaObject::WriteProperty)
- valueType->write(target, coreIndex, nullptr);
+ valueType->write(target, coreIndex, QQmlPropertyData::HasInternalIndex,
+ valueTypePropertyIndex);
return rv;
} else {
// deep alias
void *argv[1] = { &target };
QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex, argv);
+ removePendingBinding(
+ target, valueTypePropertyIndex,
+ QQmlPropertyIndex(valueTypePropertyIndex));
return QMetaObject::metacall(target, c, valueTypePropertyIndex, a);
}
} else {
+ removePendingBinding(target, coreIndex, encodedIndex);
return QMetaObject::metacall(target, c, coreIndex, a);
}
@@ -910,7 +1131,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
id -= plainSignals;
if (id < methodCount) {
- QQmlEngine *engine = ctxt->engine;
+ QQmlEngine *engine = ctxt->engine();
if (!engine)
return -1; // We can't run the method
@@ -927,10 +1148,10 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
// are not rewritten correctly but this bug is deemed out-of-scope to fix for
// performance reasons; see QTBUG-24064) and thus compilation will have failed.
QQmlError e;
- e.setDescription(QLatin1String("Exception occurred during compilation of "
- "function: ")
- + QString::fromUtf8(QMetaObject::method(_id)
- .methodSignature()));
+ e.setDescription(
+ QStringLiteral(
+ "Exception occurred during compilation of function: ")
+ + QString::fromUtf8(metaObject->method(_id).methodSignature()));
ep->warning(e);
return -1; // The dynamic method with that id is not available.
}
@@ -938,35 +1159,20 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
auto methodData = cache->method(_id);
auto arguments = methodData->hasArguments() ? methodData->arguments() : nullptr;
- const unsigned int parameterCount = (arguments && arguments->names) ? arguments->names->count() : 0;
- Q_ASSERT(parameterCount == function->formalParameterCount());
-
- QV4::JSCallData jsCallData(scope, parameterCount);
- *jsCallData->thisObject = v4->global();
-
- for (uint ii = 0; ii < parameterCount; ++ii) {
- jsCallData->args[ii] = scope.engine->metaTypeToJS(arguments->arguments[ii + 1], a[ii + 1]);
+ if (arguments && arguments->names) {
+ const quint32 parameterCount = arguments->names->size();
+ Q_ASSERT(parameterCount == function->formalParameterCount());
+ function->call(object, a, arguments->types, parameterCount);
+ } else {
+ Q_ASSERT(function->formalParameterCount() == 0);
+ const QMetaType returnType = methodData->propType();
+ function->call(object, a, &returnType, 0);
}
- const int returnType = methodData->propType();
- QV4::ScopedValue result(scope, function->call(jsCallData));
if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
if (error.isValid())
ep->warning(error);
- if (a[0]) {
- QMetaType::destruct(returnType, a[0]);
- QMetaType::construct(returnType, a[0], nullptr);
- }
- } else {
- if (a[0]) {
- // When the return type is QVariant, JS objects are to be returned as QJSValue wrapped in
- // QVariant.
- if (returnType == QMetaType::QVariant)
- *(QVariant *)a[0] = scope.engine->toVariant(result, 0);
- else
- scope.engine->metaTypeFromJS(result, returnType, a[0]);
- }
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
@@ -981,13 +1187,10 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
else
return object->qt_metacall(c, _id, a);
}
-#if defined(Q_OS_WINRT) && defined(_M_ARM)
-#pragma optimize("", on)
-#endif
QV4::ReturnedValue QQmlVMEMetaObject::method(int index) const
{
- if (!ctxt || !ctxt->isValid() || !compiledObject) {
+ if (ctxt.isNull() || !ctxt->isValid() || !compiledObject) {
qWarning("QQmlVMEMetaObject: Internal error - attempted to evaluate a function in an invalid context");
return QV4::Encode::undefined();
}
@@ -1001,7 +1204,7 @@ QV4::ReturnedValue QQmlVMEMetaObject::method(int index) const
QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id) const
{
- Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var);
+ Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].commonType() == QV4::CompiledData::CommonType::Var);
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
@@ -1019,14 +1222,14 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) const
const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
if (v)
return v->d()->data();
- return engine->toVariant(*(md->data() + id), -1);
+ return QV4::ExecutionEngine::toVariant(*(md->data() + id), QMetaType {});
}
return QVariant();
}
void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
{
- Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var);
+ Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].commonType() == QV4::CompiledData::CommonType::Var);
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
@@ -1045,6 +1248,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
// automatically released by the engine until no other references to it exist.
if (QV4::VariantObject *v = const_cast<QV4::VariantObject*>(value.as<QV4::VariantObject>())) {
v->addVmePropertyReference();
+ md->set(engine, id, value);
} else if (QV4::QObjectWrapper *wrapper = const_cast<QV4::QObjectWrapper*>(value.as<QV4::QObjectWrapper>())) {
// We need to track this QObject to signal its deletion
valueObject = wrapper->object();
@@ -1054,19 +1258,39 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
guard = new QQmlVMEVariantQObjectPtr();
varObjectGuards.append(guard);
}
+ md->set(engine, id, value);
+ } else if (const QV4::Sequence *sequence = value.as<QV4::Sequence>()) {
+ QV4::Heap::Sequence *p = sequence->d();
+ if (p->enforcesLocation()) {
+ // If the sequence enforces its location, we don't want it to be updated anymore after
+ // being written to a property.
+ md->set(engine, id, QV4::ReferenceObject::detached(p));
+ } else {
+ // Otherwise, make sure the reference carries some value so that we can still call
+ // toVariant() on it (see note in QV4::SequencePrototype::toVariant).
+ if (!p->hasData())
+ QV4::ReferenceObject::readReference(p);
+ md->set(engine, id, p);
+ }
+ } else if (const QV4::QQmlValueTypeWrapper *wrapper = value.as<QV4::QQmlValueTypeWrapper>()) {
+ // If the value type enforces its location, we don't want it to be updated anymore after
+ // being written to a property.
+ QV4::Heap::QQmlValueTypeWrapper *p = wrapper->d();
+ md->set(engine, id, p->enforcesLocation() ? QV4::ReferenceObject::detached(p) : p);
+ } else {
+ md->set(engine, id, value);
}
if (guard)
guard->setGuardedValue(valueObject, this, id);
- // Write the value and emit change signal as appropriate.
- md->set(engine, id, value);
+ // Emit change signal as appropriate.
activate(object, methodOffset() + id, nullptr);
}
void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
{
- if (compiledObject && compiledObject->propertyTable()[id].builtinType() == QV4::CompiledData::BuiltinType::Var) {
+ if (compiledObject && compiledObject->propertyTable()[id].commonType() == QV4::CompiledData::CommonType::Var) {
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return;
@@ -1105,7 +1329,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
v->d()->data() != value);
if (v)
v->removeVmePropertyReference();
- md->set(engine, id, engine->newVariantObject(value));
+ md->set(engine, id, engine->newVariantObject(value.metaType(), value.constData()));
v = static_cast<const QV4::VariantObject *>(md->data() + id);
v->addVmePropertyReference();
}
@@ -1170,12 +1394,12 @@ void QQmlVMEMetaObject::setVMEProperty(int index, const QV4::Value &v)
void QQmlVMEMetaObject::ensureQObjectWrapper()
{
Q_ASSERT(cache);
- QV4::QObjectWrapper::wrap(engine, object);
+ QV4::QObjectWrapper::ensureWrapper(engine, object);
}
void QQmlVMEMetaObject::mark(QV4::MarkStack *markStack)
{
- if (engine != markStack->engine)
+ if (engine != markStack->engine())
return;
propertyAndMethodStorage.markOnce(markStack);
@@ -1192,14 +1416,14 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex,
*coreIndex = -1;
*valueTypeIndex = -1;
- if (!ctxt)
+ if (ctxt.isNull())
return false;
const int aliasId = index - propOffset() - compiledObject->nProperties;
const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId];
- while (aliasData->aliasToLocalAlias)
+ while (aliasData->isAliasToLocalAlias())
aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
- *target = ctxt->idValues[aliasData->targetObjectId].data();
+ *target = ctxt->idValue(aliasData->targetObjectId());
if (!*target)
return false;
@@ -1227,7 +1451,7 @@ void QQmlVMEMetaObject::connectAlias(int aliasId)
}
endpoint->metaObject = this;
- endpoint->connect(&ctxt->idValues[aliasData->targetObjectId].bindings);
+ endpoint->connect(ctxt->idValueBindings(aliasData->targetObjectId()));
endpoint->tryConnect();
}
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 5025987586..d37c20a41b 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 BasysKom GmbH.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 BasysKom GmbH.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLVMEMETAOBJECT_P_H
#define QQMLVMEMETAOBJECT_P_H
@@ -52,57 +16,102 @@
// We mean it.
//
-#include "qqml.h"
+#include <private/qbipointer_p.h>
+#include <private/qqmlguard_p.h>
+#include <private/qqmlguardedcontextdata_p.h>
+#include <private/qqmlpropertyvalueinterceptor_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4value_p.h>
-#include <QtCore/QMetaObject>
-#include <QtCore/QBitArray>
-#include <QtCore/QPair>
-#include <QtCore/QDate>
-#include <QtCore/qlist.h>
+#include <QtCore/private/qobject_p.h>
+
+#if QT_CONFIG(regularexpression)
+#include <QtCore/qregularexpression.h>
+#endif
+
+#include <QtCore/qbitarray.h>
+#include <QtCore/qdatetime.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qpair.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlVMEMetaObject;
+class QQmlVMEResolvedList
+{
+ Q_DISABLE_COPY_MOVE(QQmlVMEResolvedList)
-#include <private/qobject_p.h>
+public:
+ QQmlVMEResolvedList(QQmlListProperty<QObject> *prop);
+ ~QQmlVMEResolvedList();
-#include "qqmlguard_p.h"
-#include "qqmlcontext_p.h"
+ QQmlVMEMetaObject *metaObject() const { return m_metaObject; }
+ QV4::Heap::Object *list() const { return m_list; }
+ quintptr id() const { return m_id; }
-#include <private/qflagpointer_p.h>
+ void append(QObject *o) const;
+ void replace(qsizetype i, QObject *o) const;
+ QObject *at(qsizetype i) const;
-#include <private/qv4object_p.h>
-#include <private/qv4value_p.h>
-#include <private/qqmlpropertyvalueinterceptor_p.h>
+ qsizetype size() const { return m_list->arrayData->length(); }
-QT_BEGIN_NAMESPACE
+ void clear() const
+ {
+ QV4::Scope scope(m_list->internalClass->engine);
+ QV4::ScopedObject object(scope, m_list);
+ m_list->arrayData->vtable()->truncate(object, 0);
+ }
+
+ void removeLast() const
+ {
+ const uint length = m_list->arrayData->length();
+ if (length == 0)
+ return;
+
+ QV4::Scope scope(m_list->internalClass->engine);
+ QV4::ScopedObject object(scope, m_list);
+ m_list->arrayData->vtable()->truncate(object, length - 1);
+ }
+
+ void activateSignal() const;
+
+private:
+ QQmlVMEMetaObject *m_metaObject = nullptr;
+ QV4::Heap::Object *m_list = nullptr;
+ quintptr m_id = 0;
+};
-class QQmlVMEMetaObject;
class QQmlVMEVariantQObjectPtr : public QQmlGuard<QObject>
{
public:
inline QQmlVMEVariantQObjectPtr();
- inline ~QQmlVMEVariantQObjectPtr() override;
- inline void objectDestroyed(QObject *) override;
inline void setGuardedValue(QObject *obj, QQmlVMEMetaObject *target, int index);
QQmlVMEMetaObject *m_target;
int m_index;
+
+private:
+ static void objectDestroyedImpl(QQmlGuardImpl *guard);
};
-class Q_QML_PRIVATE_EXPORT QQmlInterceptorMetaObject : public QAbstractDynamicMetaObject
+class Q_QML_EXPORT QQmlInterceptorMetaObject : public QDynamicMetaObjectData
{
public:
- QQmlInterceptorMetaObject(QObject *obj, const QQmlRefPointer<QQmlPropertyCache> &cache);
+ QQmlInterceptorMetaObject(QObject *obj, const QQmlPropertyCache::ConstPtr &cache);
~QQmlInterceptorMetaObject() override;
void registerInterceptor(QQmlPropertyIndex index, QQmlPropertyValueInterceptor *interceptor);
static QQmlInterceptorMetaObject *get(QObject *obj);
- QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *o) override;
+ QMetaObject *toDynamicMetaObject(QObject *o) override;
// Used by auto-tests for inspection
- QQmlPropertyCache *propertyCache() const { return cache.data(); }
+ QQmlPropertyCache::ConstPtr propertyCache() const { return cache; }
bool intercepts(QQmlPropertyIndex propertyIndex) const
{
@@ -115,17 +124,40 @@ public:
return false;
}
+ void invalidate() { metaObject.setTag(MetaObjectInvalid); }
+
+ QObject *object = nullptr;
+ QQmlPropertyCache::ConstPtr cache;
+
protected:
int metaCall(QObject *o, QMetaObject::Call c, int id, void **a) override;
- bool intercept(QMetaObject::Call c, int id, void **a);
+ bool intercept(QMetaObject::Call c, int id, void **a)
+ {
+ if (!interceptors)
+ return false;
+
+ switch (c) {
+ case QMetaObject::WriteProperty:
+ if (*reinterpret_cast<int*>(a[3]) & QQmlPropertyData::BypassInterceptor)
+ return false;
+ break;
+ case QMetaObject::BindableProperty:
+ break;
+ default:
+ return false;
+ }
+
+ return doIntercept(c, id, a);
+ }
-public:
- QObject *object;
- QQmlRefPointer<QQmlPropertyCache> cache;
QBiPointer<QDynamicMetaObjectData, const QMetaObject> parent;
- QQmlPropertyValueInterceptor *interceptors;
- bool hasAssignedMetaObjectData;
+ enum MetaObjectValidity { MetaObjectValid, MetaObjectInvalid };
+ QTaggedPointer<const QMetaObject, MetaObjectValidity> metaObject;
+
+private:
+ bool doIntercept(QMetaObject::Call c, int id, void **a);
+ QQmlPropertyValueInterceptor *interceptors = nullptr;
};
inline QQmlInterceptorMetaObject *QQmlInterceptorMetaObject::get(QObject *obj)
@@ -141,10 +173,13 @@ inline QQmlInterceptorMetaObject *QQmlInterceptorMetaObject::get(QObject *obj)
}
class QQmlVMEMetaObjectEndpoint;
-class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject
+class Q_QML_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject
{
public:
- QQmlVMEMetaObject(QV4::ExecutionEngine *engine, QObject *obj, const QQmlRefPointer<QQmlPropertyCache> &cache, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlCompilationUnit, int qmlObjectId);
+ QQmlVMEMetaObject(QV4::ExecutionEngine *engine, QObject *obj,
+ const QQmlPropertyCache::ConstPtr &cache,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlCompilationUnit,
+ int qmlObjectId);
~QQmlVMEMetaObject() override;
bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const;
@@ -160,6 +195,11 @@ public:
static QQmlVMEMetaObject *getForMethod(QObject *o, int coreIndex);
static QQmlVMEMetaObject *getForSignal(QObject *o, int coreIndex);
+ static void list_append(QQmlListProperty<QObject> *prop, QObject *o);
+ static void list_clear(QQmlListProperty<QObject> *prop);
+ static void list_append_nosignal(QQmlListProperty<QObject> *prop, QObject *o);
+ static void list_clear_nosignal(QQmlListProperty<QObject> *prop);
+
protected:
int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override;
@@ -185,21 +225,34 @@ public:
QPointF readPropertyAsPointF(int id) const;
QUrl readPropertyAsUrl(int id) const;
QDate readPropertyAsDate(int id) const;
- QDateTime readPropertyAsDateTime(int id);
+ QTime readPropertyAsTime(int id) const;
+ QDateTime readPropertyAsDateTime(int id) const;
+
+#if QT_CONFIG(regularexpression)
+ QRegularExpression readPropertyAsRegularExpression(int id) const;
+#endif
+
QRectF readPropertyAsRectF(int id) const;
QObject *readPropertyAsQObject(int id) const;
- QList<QObject *> *readPropertyAsList(int id) const;
+ void initPropertyAsList(int id) const;
void writeProperty(int id, int v);
void writeProperty(int id, bool v);
void writeProperty(int id, double v);
void writeProperty(int id, const QString& v);
- void writeProperty(int id, const QPointF& v);
- void writeProperty(int id, const QSizeF& v);
- void writeProperty(int id, const QUrl& v);
- void writeProperty(int id, const QDate& v);
- void writeProperty(int id, const QDateTime& v);
- void writeProperty(int id, const QRectF& v);
+
+ template<typename VariantCompatible>
+ void writeProperty(int id, const VariantCompatible &v)
+ {
+ QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
+ if (md) {
+ QV4::Scope scope(engine);
+ QV4::Scoped<QV4::MemberData>(scope, md)->set(
+ engine, id, engine->newVariantObject(
+ QMetaType::fromType<VariantCompatible>(), &v));
+ }
+ }
+
void writeProperty(int id, QObject *v);
void ensureQObjectWrapper();
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 4db0562c0e..c5d18860db 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlxmlhttprequest_p.h"
@@ -43,7 +7,6 @@
#include "qqmlengine_p.h"
#include <private/qqmlrefcount_p.h>
#include "qqmlengine_p.h"
-#include "qqmlexpression_p.h"
#include "qqmlglobal_p.h"
#include <private/qv4domerrors_p.h>
#include <private/qv4engine_p.h>
@@ -54,8 +17,11 @@
#include <QtCore/qobject.h>
#include <QtQml/qjsvalue.h>
#include <QtQml/qjsengine.h>
+#include <QtQml/qqmlfile.h>
#include <QtNetwork/qnetworkreply.h>
-#include <QtCore/qtextcodec.h>
+
+#include <QtCore/qpointer.h>
+#include <QtCore/qstringconverter.h>
#include <QtCore/qxmlstream.h>
#include <QtCore/qstack.h>
#include <QtCore/qdebug.h>
@@ -77,6 +43,8 @@ using namespace QV4;
QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP);
+DEFINE_BOOL_CONFIG_OPTION(xhrFileWrite, QML_XHR_ALLOW_FILE_WRITE);
+DEFINE_BOOL_CONFIG_OPTION(xhrFileRead, QML_XHR_ALLOW_FILE_READ);
struct QQmlXMLHttpRequestData {
QQmlXMLHttpRequestData();
@@ -150,11 +118,12 @@ public:
QList<NodeImpl *> attributes;
};
-class DocumentImpl : public QQmlRefCount, public NodeImpl
+class DocumentImpl final : public QQmlRefCounted<DocumentImpl>, public NodeImpl
{
+ using Base1 = QQmlRefCounted<DocumentImpl>;
public:
DocumentImpl() : root(nullptr) { type = Document; }
- virtual ~DocumentImpl() {
+ ~DocumentImpl() override {
delete root;
}
@@ -164,8 +133,8 @@ public:
NodeImpl *root;
- void addref() { QQmlRefCount::addref(); }
- void release() { QQmlRefCount::release(); }
+ void addref() { Base1::addref(); }
+ void release() { Base1::release(); }
};
namespace Heap {
@@ -537,7 +506,7 @@ ReturnedValue NodePrototype::method_get_previousSibling(const FunctionObject *b,
if (!r->d()->d->parent)
RETURN_RESULT(Encode::null());
- for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) {
+ for (int ii = 0; ii < r->d()->d->parent->children.size(); ++ii) {
if (r->d()->d->parent->children.at(ii) == r->d()->d) {
if (ii == 0)
return Encode::null();
@@ -559,9 +528,9 @@ ReturnedValue NodePrototype::method_get_nextSibling(const FunctionObject *b, con
if (!r->d()->d->parent)
RETURN_RESULT(Encode::null());
- for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) {
+ for (int ii = 0; ii < r->d()->d->parent->children.size(); ++ii) {
if (r->d()->d->parent->children.at(ii) == r->d()->d) {
- if ((ii + 1) == r->d()->d->parent->children.count())
+ if ((ii + 1) == r->d()->d->parent->children.size())
return Encode::null();
else
return Node::create(scope.engine, r->d()->d->parent->children.at(ii + 1));
@@ -699,7 +668,7 @@ ReturnedValue CharacterData::method_length(const FunctionObject *b, const Value
if (!r)
RETURN_UNDEFINED();
- return Encode(r->d()->d->data.length());
+ return Encode(int(r->d()->d->data.size()));
}
ReturnedValue CharacterData::prototype(ExecutionEngine *v4)
@@ -725,7 +694,7 @@ ReturnedValue Text::method_isElementContentWhitespace(const FunctionObject *b, c
if (!r)
RETURN_UNDEFINED();
- return Encode(QStringRef(&r->d()->d->data).trimmed().isEmpty());
+ return Encode(QStringView(r->d()->d->data).trimmed().isEmpty());
}
ReturnedValue Text::method_wholeText(const FunctionObject *b, const Value *thisObject, const Value *, int)
@@ -892,7 +861,7 @@ ReturnedValue NamedNodeMap::virtualGet(const Managed *m, PropertyKey id, const V
if (id.isArrayIndex()) {
uint index = id.asArrayIndex();
- if ((int)index < r->d()->list().count()) {
+ if ((int)index < r->d()->list().size()) {
if (hasProperty)
*hasProperty = true;
return Node::create(v4, r->d()->list().at(index));
@@ -906,10 +875,10 @@ ReturnedValue NamedNodeMap::virtualGet(const Managed *m, PropertyKey id, const V
return Object::virtualGet(m, id, receiver, hasProperty);
if (id == v4->id_length()->propertyKey())
- return Value::fromInt32(r->d()->list().count()).asReturnedValue();
+ return Value::fromInt32(r->d()->list().size()).asReturnedValue();
QString str = id.toQString();
- for (int ii = 0; ii < r->d()->list().count(); ++ii) {
+ for (int ii = 0; ii < r->d()->list().size(); ++ii) {
if (r->d()->list().at(ii)->name == str) {
if (hasProperty)
*hasProperty = true;
@@ -935,7 +904,7 @@ ReturnedValue NodeList::virtualGet(const Managed *m, PropertyKey id, const Value
if (id.isArrayIndex()) {
uint index = id.asArrayIndex();
- if ((int)index < r->d()->d->children.count()) {
+ if ((int)index < r->d()->d->children.size()) {
if (hasProperty)
*hasProperty = true;
return Node::create(v4, r->d()->d->children.at(index));
@@ -946,7 +915,7 @@ ReturnedValue NodeList::virtualGet(const Managed *m, PropertyKey id, const Value
}
if (id == v4->id_length()->propertyKey())
- return Value::fromInt32(r->d()->d->children.count()).asReturnedValue();
+ return Value::fromInt32(r->d()->d->children.size()).asReturnedValue();
return Object::virtualGet(m, id, receiver, hasProperty);
}
@@ -1003,9 +972,13 @@ public:
AsynchronousLoad,
SynchronousLoad
};
- enum State { Unsent = 0,
- Opened = 1, HeadersReceived = 2,
- Loading = 3, Done = 4 };
+ enum State {
+ Unsent = 0,
+ Opened = 1,
+ HeadersReceived = 2,
+ Loading = 3,
+ Done = 4
+ };
QQmlXMLHttpRequest(QNetworkAccessManager *manager, QV4::ExecutionEngine *v4);
virtual ~QQmlXMLHttpRequest();
@@ -1017,7 +990,8 @@ public:
QString replyStatusText() const;
ReturnedValue open(Object *thisObject, const QString &, const QUrl &, LoadType);
- ReturnedValue send(Object *thisObject, QQmlContextData *context, const QByteArray &);
+ ReturnedValue send(Object *thisObject, const QQmlRefPointer<QQmlContextData> &context,
+ const QByteArray &);
ReturnedValue abort(Object *thisObject);
void addHeader(const QString &, const QString &);
@@ -1027,9 +1001,15 @@ public:
QString responseBody();
const QByteArray & rawResponseBody() const;
bool receivedXml() const;
+ QUrl url() const;
const QString & responseType() const;
void setResponseType(const QString &);
+ void setOverrideMimeType(QStringView mimeType) { m_overrideMime = mimeType.toUtf8(); }
+ void setOverrideCharset(QStringView charset) { m_overrideCharset = charset.toUtf8(); }
+
+ const QByteArray mimeType() const;
+ const QByteArray charset() const;
QV4::ReturnedValue jsonResponseBody(QV4::ExecutionEngine*);
QV4::ReturnedValue xmlResponseBody(QV4::ExecutionEngine*);
@@ -1058,14 +1038,14 @@ private:
bool m_gotXml;
QByteArray m_mime;
QByteArray m_charset;
- QTextCodec *m_textCodec;
-#if QT_CONFIG(textcodec)
- QTextCodec* findTextCodec() const;
-#endif
+ QByteArray m_overrideMime;
+ QByteArray m_overrideCharset;
+
+ QStringDecoder findTextDecoder() const;
void readEncoding();
PersistentValue m_thisObject;
- QQmlContextDataRef m_qmlContext;
+ QQmlRefPointer<QQmlContextData> m_qmlContext;
bool m_wasConstructedWithQmlContext = true;
void dispatchCallbackNow(Object *thisObj);
@@ -1088,11 +1068,9 @@ private:
QQmlXMLHttpRequest::QQmlXMLHttpRequest(QNetworkAccessManager *manager, QV4::ExecutionEngine *v4)
: m_state(Unsent), m_errorFlag(false), m_sendFlag(false)
- , m_redirectCount(0), m_gotXml(false), m_textCodec(nullptr), m_network(nullptr), m_nam(manager)
- , m_responseType()
- , m_parsedDocument()
+ , m_redirectCount(0), m_gotXml(false), m_network(nullptr), m_nam(manager)
{
- m_wasConstructedWithQmlContext = v4->callingQmlContext() != nullptr;
+ m_wasConstructedWithQmlContext = !v4->callingQmlContext().isNull();
}
QQmlXMLHttpRequest::~QQmlXMLHttpRequest()
@@ -1169,7 +1147,7 @@ QString QQmlXMLHttpRequest::headers() const
QString ret;
for (const HeaderPair &header : m_headersList) {
- if (ret.length())
+ if (ret.size())
ret.append(QLatin1String("\r\n"));
ret += QString::fromUtf8(header.first) + QLatin1String(": ")
+ QString::fromUtf8(header.second);
@@ -1194,7 +1172,30 @@ void QQmlXMLHttpRequest::fillHeadersList()
void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
{
+ m_url = url;
QNetworkRequest request = m_request;
+
+ if (QQmlFile::isLocalFile(url)) {
+ if (m_method == QLatin1String("PUT"))
+ {
+ if (!xhrFileWrite()) {
+ qWarning("XMLHttpRequest: Using PUT on a local file is disabled by default.\n"
+ "Set QML_XHR_ALLOW_FILE_WRITE to 1 to enable this feature.");
+ return;
+ }
+ } else if (m_method == QLatin1String("GET")) {
+ if (!xhrFileRead()) {
+ qWarning("XMLHttpRequest: Using GET on a local file is disabled by default.\n"
+ "Set QML_XHR_ALLOW_FILE_READ to 1 to enable this feature.");
+ return;
+ }
+ } else {
+ qWarning("XMLHttpRequest: Unsupported method used on a local file");
+ return;
+ }
+ }
+
+ request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy);
request.setUrl(url);
if(m_method == QLatin1String("POST") ||
m_method == QLatin1String("PUT")) {
@@ -1211,7 +1212,7 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
int n = 0;
int semiColon = str.indexOf(QLatin1Char(';'), charsetIdx);
if (semiColon == -1) {
- n = str.length() - charsetIdx;
+ n = str.size() - charsetIdx;
} else {
n = semiColon - charsetIdx;
}
@@ -1266,14 +1267,15 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
} else {
QObject::connect(m_network, SIGNAL(readyRead()),
this, SLOT(readyRead()));
- QObject::connect(m_network, SIGNAL(error(QNetworkReply::NetworkError)),
+ QObject::connect(m_network, SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
this, SLOT(error(QNetworkReply::NetworkError)));
QObject::connect(m_network, SIGNAL(finished()),
this, SLOT(finished()));
}
}
-ReturnedValue QQmlXMLHttpRequest::send(Object *thisObject, QQmlContextData *context, const QByteArray &data)
+ReturnedValue QQmlXMLHttpRequest::send(
+ Object *thisObject, const QQmlRefPointer<QQmlContextData> &context, const QByteArray &data)
{
m_errorFlag = false;
m_sendFlag = true;
@@ -1319,7 +1321,7 @@ void QQmlXMLHttpRequest::readyRead()
// ### We assume if this is called the headers are now available
if (m_state < HeadersReceived) {
m_state = HeadersReceived;
- fillHeadersList ();
+ fillHeadersList();
dispatchCallbackSafely();
}
@@ -1389,13 +1391,17 @@ void QQmlXMLHttpRequest::finished()
QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (redirect.isValid()) {
QUrl url = m_network->url().resolved(redirect.toUrl());
- if (url.scheme() != QLatin1String("file")) {
+ if (!QQmlFile::isLocalFile(url)) {
// See http://www.ietf.org/rfc/rfc2616.txt, section 10.3.4 "303 See Other":
// Result of 303 redirection should be a new "GET" request.
const QVariant code = m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (code.isValid() && code.toInt() == 303 && m_method != QLatin1String("GET"))
m_method = QStringLiteral("GET");
destroyNetwork();
+
+ // Discard redirect response body
+ m_responseEntityBody = QByteArray();
+
requestFromUrl(url);
return;
}
@@ -1434,13 +1440,13 @@ void QQmlXMLHttpRequest::finished()
dispatchCallbackSafely();
m_thisObject.clear();
- m_qmlContext.setContextData(nullptr);
+ m_qmlContext.reset();
}
void QQmlXMLHttpRequest::readEncoding()
{
- for (const HeaderPair &header : qAsConst(m_headersList)) {
+ for (const HeaderPair &header : std::as_const(m_headersList)) {
if (header.first == "content-type") {
int separatorIdx = header.second.indexOf(';');
if (separatorIdx == -1) {
@@ -1451,14 +1457,15 @@ void QQmlXMLHttpRequest::readEncoding()
if (charsetIdx != -1) {
charsetIdx += 8;
separatorIdx = header.second.indexOf(';', charsetIdx);
- m_charset = header.second.mid(charsetIdx, separatorIdx >= 0 ? separatorIdx : header.second.length());
+ m_charset = header.second.mid(charsetIdx, separatorIdx >= 0 ? separatorIdx : header.second.size());
}
}
break;
}
}
- if (m_mime.isEmpty() || m_mime == "text/xml" || m_mime == "application/xml" || m_mime.endsWith("+xml"))
+ const auto mime = mimeType();
+ if (mime.isEmpty() || mime == "text/xml" || mime == "application/xml" || mime.endsWith("+xml"))
m_gotXml = true;
}
@@ -1467,6 +1474,25 @@ bool QQmlXMLHttpRequest::receivedXml() const
return m_gotXml;
}
+QUrl QQmlXMLHttpRequest::url() const
+{
+ return m_url;
+}
+
+const QByteArray QQmlXMLHttpRequest::mimeType() const
+{
+ // Final MIME type is the override MIME type unless that is null in which
+ // case it is the response MIME type.
+ return m_overrideMime.isEmpty() ? m_mime : m_overrideMime;
+}
+
+const QByteArray QQmlXMLHttpRequest::charset() const
+{
+ // Final charset is the override charset unless that is null in which case
+ // it is the response charset.
+ return m_overrideCharset.isEmpty() ? m_charset : m_overrideCharset;
+}
+
const QString & QQmlXMLHttpRequest::responseType() const
{
return m_responseType;
@@ -1484,7 +1510,7 @@ QV4::ReturnedValue QQmlXMLHttpRequest::jsonResponseBody(QV4::ExecutionEngine* en
QJsonParseError error;
const QString& jtext = responseBody();
- JsonParser parser(scope.engine, jtext.constData(), jtext.length());
+ JsonParser parser(scope.engine, jtext.constData(), jtext.size());
ScopedValue jsonObject(scope, parser.parse(&error));
if (error.error != QJsonParseError::NoError)
return engine->throwSyntaxError(QStringLiteral("JSON.parse: Parse error"));
@@ -1504,43 +1530,38 @@ QV4::ReturnedValue QQmlXMLHttpRequest::xmlResponseBody(QV4::ExecutionEngine* eng
return m_parsedDocument.value();
}
-#if QT_CONFIG(textcodec)
-QTextCodec* QQmlXMLHttpRequest::findTextCodec() const
+QStringDecoder QQmlXMLHttpRequest::findTextDecoder() const
{
- QTextCodec *codec = nullptr;
+ QStringDecoder decoder;
- if (!m_charset.isEmpty())
- codec = QTextCodec::codecForName(m_charset);
+ if (!charset().isEmpty())
+ decoder = QStringDecoder(charset());
- if (!codec && m_gotXml) {
+ if (!decoder.isValid() && m_gotXml) {
QXmlStreamReader reader(m_responseEntityBody);
reader.readNext();
- codec = QTextCodec::codecForName(reader.documentEncoding().toString().toUtf8());
+ decoder = QStringDecoder(reader.documentEncoding().toString().toUtf8());
}
- if (!codec && m_mime == "text/html")
- codec = QTextCodec::codecForHtml(m_responseEntityBody, nullptr);
+ if (!decoder.isValid() && mimeType() == "text/html")
+ decoder = QStringDecoder::decoderForHtml(m_responseEntityBody);
+
+ if (!decoder.isValid()) {
+ auto encoding = QStringConverter::encodingForData(m_responseEntityBody);
+ if (encoding)
+ decoder = QStringDecoder(*encoding);
+ }
- if (!codec)
- codec = QTextCodec::codecForUtfText(m_responseEntityBody, nullptr);
+ if (!decoder.isValid())
+ decoder = QStringDecoder(QStringDecoder::Utf8);
- if (!codec)
- codec = QTextCodec::codecForName("UTF-8");
- return codec;
+ return decoder;
}
-#endif
-
QString QQmlXMLHttpRequest::responseBody()
{
-#if QT_CONFIG(textcodec)
- if (!m_textCodec)
- m_textCodec = findTextCodec();
- if (m_textCodec)
- return m_textCodec->toUnicode(m_responseEntityBody);
-#endif
-
- return QString::fromUtf8(m_responseEntityBody);
+ QStringDecoder toUtf16 = findTextDecoder();
+ return toUtf16(m_responseEntityBody);
}
const QByteArray &QQmlXMLHttpRequest::rawResponseBody() const
@@ -1565,10 +1586,10 @@ void QQmlXMLHttpRequest::dispatchCallbackNow(Object *thisObj, bool done, bool er
if (!callback)
return;
- QV4::JSCallData jsCallData(scope);
+ QV4::JSCallArguments jsCallData(scope);
callback->call(jsCallData);
- if (scope.engine->hasException) {
+ if (scope.hasException()) {
QQmlError error = scope.engine->catchExceptionAsQmlError();
QQmlEnginePrivate *qmlEnginePrivate = scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : nullptr;
QQmlEnginePrivate::warning(qmlEnginePrivate, error);
@@ -1587,12 +1608,13 @@ void QQmlXMLHttpRequest::dispatchCallbackNow(Object *thisObj, bool done, bool er
void QQmlXMLHttpRequest::dispatchCallbackSafely()
{
- if (m_wasConstructedWithQmlContext && !m_qmlContext.contextData())
+ if (m_wasConstructedWithQmlContext && m_qmlContext.isNull()) {
// if the calling context object is no longer valid, then it has been
// deleted explicitly (e.g., by a Loader deleting the itemContext when
// the source is changed). We do nothing in this case, as the evaluation
// cannot succeed.
return;
+ }
dispatchCallbackNow(m_thisObject.as<Object>());
}
@@ -1626,7 +1648,7 @@ struct QQmlXMLHttpRequestWrapper : Object {
Member(class, Pointer, Object *, proto)
DECLARE_HEAP_OBJECT(QQmlXMLHttpRequestCtor, FunctionObject) {
- DECLARE_MARKOBJECTS(QQmlXMLHttpRequestCtor);
+ DECLARE_MARKOBJECTS(QQmlXMLHttpRequestCtor)
void init(ExecutionEngine *engine);
};
@@ -1638,6 +1660,7 @@ struct QQmlXMLHttpRequestWrapper : public Object
V4_NEEDS_DESTROY
};
+// https://xhr.spec.whatwg.org/
struct QQmlXMLHttpRequestCtor : public FunctionObject
{
V4_OBJECT2(QQmlXMLHttpRequestCtor, FunctionObject)
@@ -1647,7 +1670,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
Scope scope(f->engine());
const QQmlXMLHttpRequestCtor *ctor = static_cast<const QQmlXMLHttpRequestCtor *>(f);
- QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->qmlEngine()->networkAccessManager(), scope.engine);
+ QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->networkAccessManager(scope.engine), scope.engine);
Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocate<QQmlXMLHttpRequestWrapper>(r));
ScopedObject proto(scope, ctor->d()->proto);
w->setPrototypeUnchecked(proto);
@@ -1666,6 +1689,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
static ReturnedValue method_abort(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_getResponseHeader(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_getAllResponseHeaders(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_overrideMimeType(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get_readyState(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get_status(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
@@ -1675,6 +1699,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
static ReturnedValue method_get_response(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get_responseType(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_set_responseType(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_get_responseURL(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
};
}
@@ -1687,11 +1712,12 @@ void Heap::QQmlXMLHttpRequestCtor::init(ExecutionEngine *engine)
Scope scope(engine);
Scoped<QV4::QQmlXMLHttpRequestCtor> ctor(scope, this);
- ctor->defineReadonlyProperty(QStringLiteral("UNSENT"), Value::fromInt32(0));
- ctor->defineReadonlyProperty(QStringLiteral("OPENED"), Value::fromInt32(1));
- ctor->defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), Value::fromInt32(2));
- ctor->defineReadonlyProperty(QStringLiteral("LOADING"), Value::fromInt32(3));
- ctor->defineReadonlyProperty(QStringLiteral("DONE"), Value::fromInt32(4));
+ ctor->defineReadonlyProperty(QStringLiteral("UNSENT"), Value::fromInt32(QQmlXMLHttpRequest::Unsent));
+ ctor->defineReadonlyProperty(QStringLiteral("OPENED"), Value::fromInt32(QQmlXMLHttpRequest::Opened));
+ ctor->defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), Value::fromInt32(QQmlXMLHttpRequest::HeadersReceived));
+ ctor->defineReadonlyProperty(QStringLiteral("LOADING"), Value::fromInt32(QQmlXMLHttpRequest::Loading));
+ ctor->defineReadonlyProperty(QStringLiteral("DONE"), Value::fromInt32(QQmlXMLHttpRequest::Done));
+
if (!ctor->d()->proto)
ctor->setupProto();
ScopedString s(scope, engine->id_prototype());
@@ -1714,6 +1740,7 @@ void QQmlXMLHttpRequestCtor::setupProto()
p->defineDefaultProperty(QStringLiteral("abort"), method_abort);
p->defineDefaultProperty(QStringLiteral("getResponseHeader"), method_getResponseHeader);
p->defineDefaultProperty(QStringLiteral("getAllResponseHeaders"), method_getAllResponseHeaders);
+ p->defineDefaultProperty(QStringLiteral("overrideMimeType"), method_overrideMimeType);
// Read-only properties
p->defineAccessorProperty(QStringLiteral("readyState"), method_get_readyState, nullptr);
@@ -1722,6 +1749,7 @@ void QQmlXMLHttpRequestCtor::setupProto()
p->defineAccessorProperty(QStringLiteral("responseText"),method_get_responseText, nullptr);
p->defineAccessorProperty(QStringLiteral("responseXML"),method_get_responseXML, nullptr);
p->defineAccessorProperty(QStringLiteral("response"),method_get_response, nullptr);
+ p->defineAccessorProperty(QStringLiteral("responseURL"),method_get_responseURL, nullptr);
// Read-write properties
p->defineAccessorProperty(QStringLiteral("responseType"), method_get_responseType, method_set_responseType);
@@ -1763,8 +1791,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(const FunctionObject *b, const
QUrl url = QUrl(argv[1].toQStringNoThrow());
if (url.isRelative()) {
- QQmlContextData *qmlContextData = scope.engine->callingQmlContext();
- if (qmlContextData)
+ if (QQmlRefPointer<QQmlContextData> qmlContextData = scope.engine->callingQmlContext())
url = qmlContextData->resolvedUrl(url);
else
url = scope.engine->resolvedUrl(url.url());
@@ -1829,7 +1856,6 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(const FunctionObje
nameUpper == QLatin1String("TRAILER") ||
nameUpper == QLatin1String("TRANSFER-ENCODING") ||
nameUpper == QLatin1String("UPGRADE") ||
- nameUpper == QLatin1String("USER-AGENT") ||
nameUpper == QLatin1String("VIA") ||
nameUpper.startsWith(QLatin1String("PROXY-")) ||
nameUpper.startsWith(QLatin1String("SEC-")))
@@ -2049,6 +2075,71 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_set_responseType(const FunctionObje
return Encode::undefined();
}
+ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseURL(const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ Scope scope(b);
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->d()->request;
+
+ if (r->readyState() != QQmlXMLHttpRequest::Loading &&
+ r->readyState() != QQmlXMLHttpRequest::Done) {
+ return Encode(scope.engine->newString(QString()));
+ } else {
+ QUrl url = r->url();
+ url.setFragment(QString());
+ return Encode(scope.engine->newString(url.toString()));
+ }
+}
+
+ReturnedValue QQmlXMLHttpRequestCtor::method_overrideMimeType(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, thisObject->as<QQmlXMLHttpRequestWrapper>());
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->d()->request;
+
+ if (argc != 1)
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+
+ // If state is loading or done, throw an InvalidStateError exception.
+ if (r->readyState() == QQmlXMLHttpRequest::Loading ||
+ r->readyState() == QQmlXMLHttpRequest::Done)
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+
+ // Set override MIME type to `application/octet-stream`.
+ r->setOverrideMimeType(QStringLiteral("application/octet-stream"));
+ const auto parts = argv[0].toQStringNoThrow().split(QLatin1Char(';'));
+ const auto type = parts.at(0).trimmed();
+
+ const auto mimeInvalidCharacter = [](QChar uni) {
+ if (uni.unicode() > 127) // Only accept ASCII
+ return true;
+ const char ch = char(uni.unicode());
+ return !(ch == '-' || ch == '/' || isAsciiLetterOrNumber(ch));
+ };
+
+ // If mime is a parsable MIME type, ...
+ if (type.count(QLatin1Char('/')) == 1
+ && std::find_if(type.begin(), type.end(), mimeInvalidCharacter) == type.end()) {
+ // ... then set override MIME type to its MIME type portion.
+ r->setOverrideMimeType(type);
+ }
+ for (const auto &part : parts) {
+ const QLatin1String charset("charset=");
+ // If override MIME type has a `charset` parameter, ...
+ if (part.trimmed().startsWith(charset)) {
+ // ... then set override charset to its value.
+ const int offset(part.indexOf(charset) + charset.size());
+ r->setOverrideCharset(part.sliced(offset).trimmed());
+ }
+ }
+
+ return Encode::undefined();
+}
+
void qt_rem_qmlxmlhttprequest(ExecutionEngine * /* engine */, void *d)
{
QQmlXMLHttpRequestData *data = (QQmlXMLHttpRequestData *)d;
diff --git a/src/qml/qml/qqmlxmlhttprequest_p.h b/src/qml/qml/qqmlxmlhttprequest_p.h
index 7515ef8dcc..886cf7038e 100644
--- a/src/qml/qml/qqmlxmlhttprequest_p.h
+++ b/src/qml/qml/qqmlxmlhttprequest_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLXMLHTTPREQUEST_P_H
#define QQMLXMLHTTPREQUEST_P_H
@@ -53,7 +17,7 @@
//
#include <QtCore/qglobal.h>
-#include <private/qqmlglobal_p.h>
+#include <private/qtqmlglobal_p.h>
QT_REQUIRE_CONFIG(qml_xml_http_request);
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
deleted file mode 100644
index d87b83ba10..0000000000
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLBUILTINFUNCTIONS_P_H
-#define QQMLBUILTINFUNCTIONS_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <private/qqmlglobal_p.h>
-#include <private/qv4functionobject_p.h>
-#include <private/qjsengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlEngine;
-
-namespace QV4 {
-
-namespace Heap {
-
-struct QtObject : Object {
- void init(QQmlEngine *qmlEngine);
- QObject *platform;
- QObject *application;
-
- enum { Finished = -1 };
- int enumeratorIterator;
- int keyIterator;
-
- bool isComplete() const
- { return enumeratorIterator == Finished; }
-};
-
-struct ConsoleObject : Object {
- void init();
-};
-
-#define QQmlBindingFunctionMembers(class, Member) \
- Member(class, Pointer, FunctionObject *, bindingFunction)
-DECLARE_HEAP_OBJECT(QQmlBindingFunction, FunctionObject) {
- DECLARE_MARKOBJECTS(QQmlBindingFunction)
- void init(const QV4::FunctionObject *bindingFunction);
-};
-
-}
-
-struct QtObject : Object
-{
- V4_OBJECT2(QtObject, Object)
-
- static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
- static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
-
- static ReturnedValue method_isQtObject(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_rgba(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_hsla(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_hsva(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_colorEqual(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_font(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_rect(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_point(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_size(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_vector2d(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_vector3d(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_vector4d(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_quaternion(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_matrix4x4(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_lighter(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_darker(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_tint(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_formatDate(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_formatTime(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_formatDateTime(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_openUrlExternally(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_fontFamilies(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_md5(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_btoa(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_atob(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_quit(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_exit(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_resolvedUrl(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_createQmlObject(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_createComponent(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-#if QT_CONFIG(qml_locale)
- static ReturnedValue method_locale(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-#endif
- static ReturnedValue method_binding(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-
- static ReturnedValue method_get_platform(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_get_application(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_get_inputMethod(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_get_styleHints(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-
- static ReturnedValue method_callLater(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
-
-private:
- void addAll();
- ReturnedValue findAndAdd(const QString *name, bool &foundProperty) const;
-};
-
-struct ConsoleObject : Object
-{
- V4_OBJECT2(ConsoleObject, Object)
-
- static ReturnedValue method_error(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_log(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_info(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_profile(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_profileEnd(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_time(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_timeEnd(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_count(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_trace(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_warn(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_assert(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_exception(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-
-};
-
-struct Q_QML_PRIVATE_EXPORT GlobalExtensions {
- static void init(Object *globalObject, QJSEngine::Extensions extensions);
-
-#if QT_CONFIG(translation)
- static ReturnedValue method_qsTranslate(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_qsTranslateNoOp(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_qsTr(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_qsTrNoOp(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_qsTrId(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_qsTrIdNoOp(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-#endif
- static ReturnedValue method_gc(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-
- // on String:prototype
- static ReturnedValue method_string_arg(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
-
-};
-
-struct QQmlBindingFunction : public QV4::FunctionObject
-{
- V4_OBJECT2(QQmlBindingFunction, FunctionObject)
-
- Heap::FunctionObject *bindingFunction() const { return d()->bindingFunction; }
- QQmlSourceLocation currentLocation() const; // from caller stack trace
-};
-
-inline bool FunctionObject::isBinding() const
-{
- return d()->vtable() == QQmlBindingFunction::staticVTable();
-}
-
-}
-
-QT_END_NAMESPACE
-
-#endif // QQMLBUILTINFUNCTIONS_P_H
diff --git a/src/qml/qml/v8/qv4domerrors_p.h b/src/qml/qml/v8/qv4domerrors_p.h
deleted file mode 100644
index 1842e46a9c..0000000000
--- a/src/qml/qml/v8/qv4domerrors_p.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV8DOMERRORS_P_H
-#define QV8DOMERRORS_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-// From DOM-Level-3-Core spec
-// http://www.w3.org/TR/DOM-Level-3-Core/core.html
-#define DOMEXCEPTION_INDEX_SIZE_ERR 1
-#define DOMEXCEPTION_DOMSTRING_SIZE_ERR 2
-#define DOMEXCEPTION_HIERARCHY_REQUEST_ERR 3
-#define DOMEXCEPTION_WRONG_DOCUMENT_ERR 4
-#define DOMEXCEPTION_INVALID_CHARACTER_ERR 5
-#define DOMEXCEPTION_NO_DATA_ALLOWED_ERR 6
-#define DOMEXCEPTION_NO_MODIFICATION_ALLOWED_ERR 7
-#define DOMEXCEPTION_NOT_FOUND_ERR 8
-#define DOMEXCEPTION_NOT_SUPPORTED_ERR 9
-#define DOMEXCEPTION_INUSE_ATTRIBUTE_ERR 10
-#define DOMEXCEPTION_INVALID_STATE_ERR 11
-#define DOMEXCEPTION_SYNTAX_ERR 12
-#define DOMEXCEPTION_INVALID_MODIFICATION_ERR 13
-#define DOMEXCEPTION_NAMESPACE_ERR 14
-#define DOMEXCEPTION_INVALID_ACCESS_ERR 15
-#define DOMEXCEPTION_VALIDATION_ERR 16
-#define DOMEXCEPTION_TYPE_MISMATCH_ERR 17
-
-#define THROW_DOM(error, string) { \
- QV4::ScopedValue v(scope, scope.engine->newString(QStringLiteral(string))); \
- QV4::ScopedObject ex(scope, scope.engine->newErrorObject(v)); \
- ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, QV4::Value::fromInt32(error))); \
- return scope.engine->throwError(ex); \
-}
-
-namespace QV4 {
-struct ExecutionEngine;
-}
-
-
-void qt_add_domexceptions(QV4::ExecutionEngine *e);
-
-QT_END_NAMESPACE
-
-#endif // QV8DOMERRORS_P_H
diff --git a/src/qml/qml/v8/qv4sqlerrors.cpp b/src/qml/qml/v8/qv4sqlerrors.cpp
deleted file mode 100644
index 3f1744a687..0000000000
--- a/src/qml/qml/v8/qv4sqlerrors.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4sqlerrors_p.h"
-#include "private/qv4engine_p.h"
-#include "private/qv4object_p.h"
-
-QT_BEGIN_NAMESPACE
-
-using namespace QV4;
-
-void qt_add_sqlexceptions(QV4::ExecutionEngine *engine)
-{
- Scope scope(engine);
- ScopedObject sqlexception(scope, engine->newObject());
- sqlexception->defineReadonlyProperty(QStringLiteral("UNKNOWN_ERR"), Value::fromInt32(SQLEXCEPTION_UNKNOWN_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("DATABASE_ERR"), Value::fromInt32(SQLEXCEPTION_DATABASE_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("VERSION_ERR"), Value::fromInt32(SQLEXCEPTION_VERSION_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("TOO_LARGE_ERR"), Value::fromInt32(SQLEXCEPTION_TOO_LARGE_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("QUOTA_ERR"), Value::fromInt32(SQLEXCEPTION_QUOTA_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("SYNTAX_ERR"), Value::fromInt32(SQLEXCEPTION_SYNTAX_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("CONSTRAINT_ERR"), Value::fromInt32(SQLEXCEPTION_CONSTRAINT_ERR));
- sqlexception->defineReadonlyProperty(QStringLiteral("TIMEOUT_ERR"), Value::fromInt32(SQLEXCEPTION_TIMEOUT_ERR));
- engine->globalObject->defineDefaultProperty(QStringLiteral("SQLException"), sqlexception);
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv4sqlerrors_p.h b/src/qml/qml/v8/qv4sqlerrors_p.h
deleted file mode 100644
index 51dcb286de..0000000000
--- a/src/qml/qml/v8/qv4sqlerrors_p.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV8SQLERRORS_P_H
-#define QV8SQLERRORS_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-#define SQLEXCEPTION_UNKNOWN_ERR 1
-#define SQLEXCEPTION_DATABASE_ERR 2
-#define SQLEXCEPTION_VERSION_ERR 3
-#define SQLEXCEPTION_TOO_LARGE_ERR 4
-#define SQLEXCEPTION_QUOTA_ERR 5
-#define SQLEXCEPTION_SYNTAX_ERR 6
-#define SQLEXCEPTION_CONSTRAINT_ERR 7
-#define SQLEXCEPTION_TIMEOUT_ERR 8
-
-namespace QV4 {
-struct ExecutionEngine;
-}
-
-void qt_add_sqlexceptions(QV4::ExecutionEngine *engine);
-
-QT_END_NAMESPACE
-
-#endif // QV8SQLERRORS_P_H
diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri
deleted file mode 100644
index fbcc47de0c..0000000000
--- a/src/qml/qml/v8/v8.pri
+++ /dev/null
@@ -1,9 +0,0 @@
-HEADERS += \
- $$PWD/qv4domerrors_p.h \
- $$PWD/qv4sqlerrors_p.h \
- $$PWD/qqmlbuiltinfunctions_p.h
-
-SOURCES += \
- $$PWD/qv4domerrors.cpp \
- $$PWD/qv4sqlerrors.cpp \
- $$PWD/qqmlbuiltinfunctions.cpp
diff --git a/src/qml/qml_compile_hash_p.h.in b/src/qml/qml_compile_hash_p.h.in
new file mode 100644
index 0000000000..3316da16d6
--- /dev/null
+++ b/src/qml/qml_compile_hash_p.h.in
@@ -0,0 +1,15 @@
+// Generated file, DO NOT EDIT
+
+//
+// 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.
+//
+
+#define QML_COMPILE_HASH "${QML_COMPILE_HASH}"
+#define QML_COMPILE_HASH_LENGTH ${QML_COMPILE_HASH_LENGTH}
diff --git a/src/qml/qmldirparser/qmldirparser.pri b/src/qml/qmldirparser/qmldirparser.pri
deleted file mode 100644
index fefe2e75be..0000000000
--- a/src/qml/qmldirparser/qmldirparser.pri
+++ /dev/null
@@ -1,8 +0,0 @@
-INCLUDEPATH += $$PWD
-INCLUDEPATH += $$OUT_PWD
-
-HEADERS += \
- $$PWD/qqmldirparser_p.h
-
-SOURCES += \
- $$PWD/qqmldirparser.cpp
diff --git a/src/qml/qmldirparser/qqmldirparser.cpp b/src/qml/qmldirparser/qqmldirparser.cpp
index 6e925ba515..e6a5691d3d 100644
--- a/src/qml/qmldirparser/qqmldirparser.cpp
+++ b/src/qml/qmldirparser/qqmldirparser.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmldirparser_p.h"
@@ -43,34 +7,49 @@
QT_BEGIN_NAMESPACE
-static int parseInt(const QStringRef &str, bool *ok)
+static int parseInt(QStringView str, bool *ok)
{
int pos = 0;
int number = 0;
- while (pos < str.length() && str.at(pos).isDigit()) {
+ while (pos < str.size() && str.at(pos).isDigit()) {
if (pos != 0)
number *= 10;
number += str.at(pos).unicode() - '0';
++pos;
}
- if (pos != str.length())
+ if (pos != str.size())
*ok = false;
else
*ok = true;
return number;
}
-static bool parseVersion(const QString &str, int *major, int *minor)
+static QTypeRevision parseVersion(const QString &str)
{
const int dotIndex = str.indexOf(QLatin1Char('.'));
if (dotIndex != -1 && str.indexOf(QLatin1Char('.'), dotIndex + 1) == -1) {
bool ok = false;
- *major = parseInt(QStringRef(&str, 0, dotIndex), &ok);
- if (ok)
- *minor = parseInt(QStringRef(&str, dotIndex + 1, str.length() - dotIndex - 1), &ok);
- return ok;
+ const int major = parseInt(QStringView(str).left(dotIndex), &ok);
+ if (!ok) return QTypeRevision();
+ const int minor = parseInt(QStringView(str).mid(dotIndex + 1, str.size() - dotIndex - 1), &ok);
+ return ok ? QTypeRevision::fromVersion(major, minor) : QTypeRevision();
}
- return false;
+ return QTypeRevision();
+}
+
+void QQmlDirParser::clear()
+{
+ _errors.clear();
+ _typeNamespace.clear();
+ _components.clear();
+ _dependencies.clear();
+ _imports.clear();
+ _scripts.clear();
+ _plugins.clear();
+ _designerSupported = false;
+ _typeInfos.clear();
+ _classNames.clear();
+ _linkTarget.clear();
}
inline static void scanSpace(const QChar *&ch) {
@@ -93,16 +72,53 @@ inline static void scanWord(const QChar *&ch) {
*/
bool QQmlDirParser::parse(const QString &source)
{
- _errors.clear();
- _plugins.clear();
- _components.clear();
- _scripts.clear();
- _designerSupported = false;
- _className.clear();
-
quint16 lineNumber = 0;
bool firstLine = true;
+ auto readImport = [&](const QString *sections, int sectionCount, Import::Flags flags) {
+ Import import;
+ if (sectionCount == 2) {
+ import = Import(sections[1], QTypeRevision(), flags);
+ } else if (sectionCount == 3) {
+ if (sections[2] == QLatin1String("auto")) {
+ import = Import(sections[1], QTypeRevision(), flags | Import::Auto);
+ } else {
+ const auto version = parseVersion(sections[2]);
+ if (version.isValid()) {
+ import = Import(sections[1], version, flags);
+ } else {
+ reportError(lineNumber, 0,
+ QStringLiteral("invalid version %1, expected <major>.<minor>")
+ .arg(sections[2]));
+ return false;
+ }
+ }
+ } else {
+ reportError(lineNumber, 0,
+ QStringLiteral("%1 requires 1 or 2 arguments, but %2 were provided")
+ .arg(sections[0]).arg(sectionCount - 1));
+ return false;
+ }
+ if (sections[0] == QStringLiteral("import"))
+ _imports.append(import);
+ else
+ _dependencies.append(import);
+ return true;
+ };
+
+ auto readPlugin = [&](const QString *sections, int sectionCount, bool isOptional) {
+ if (sectionCount < 2 || sectionCount > 3) {
+ reportError(lineNumber, 0, QStringLiteral("plugin directive requires one or two "
+ "arguments, but %1 were provided")
+ .arg(sectionCount - 1));
+ return false;
+ }
+
+ const Plugin entry(sections[1], sections[2], isOptional);
+ _plugins.append(entry);
+ return true;
+ };
+
const QChar *ch = source.constData();
while (!ch->isNull()) {
++lineNumber;
@@ -169,17 +185,43 @@ bool QQmlDirParser::parse(const QString &source)
_typeNamespace = sections[1];
} else if (sections[0] == QLatin1String("plugin")) {
- if (sectionCount < 2 || sectionCount > 3) {
- reportError(lineNumber, 0,
- QStringLiteral("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1));
-
+ if (!readPlugin(sections, sectionCount, false))
+ continue;
+ } else if (sections[0] == QLatin1String("optional")) {
+ if (sectionCount < 2) {
+ reportError(lineNumber, 0, QStringLiteral("optional directive requires further "
+ "arguments, but none were provided."));
continue;
}
- const Plugin entry(sections[1], sections[2]);
-
- _plugins.append(entry);
-
+ if (sections[1] == QStringLiteral("plugin")) {
+ if (!readPlugin(sections + 1, sectionCount - 1, true))
+ continue;
+ } else if (sections[1] == QLatin1String("import")) {
+ if (!readImport(sections + 1, sectionCount - 1, Import::Optional))
+ continue;
+ } else {
+ reportError(lineNumber, 0, QStringLiteral("only import and plugin can be optional, "
+ "not %1.").arg(sections[1]));
+ continue;
+ }
+ } else if (sections[0] == QLatin1String("default")) {
+ if (sectionCount < 2) {
+ reportError(lineNumber, 0,
+ QStringLiteral("default directive requires further "
+ "arguments, but none were provided."));
+ continue;
+ }
+ if (sections[1] == QLatin1String("import")) {
+ if (!readImport(sections + 1, sectionCount - 1,
+ Import::Flags({ Import::Optional, Import::OptionalDefault })))
+ continue;
+ } else {
+ reportError(lineNumber, 0,
+ QStringLiteral("only optional imports can have a default, "
+ "not %1.")
+ .arg(sections[1]));
+ }
} else if (sections[0] == QLatin1String("classname")) {
if (sectionCount < 2) {
reportError(lineNumber, 0,
@@ -188,17 +230,31 @@ bool QQmlDirParser::parse(const QString &source)
continue;
}
- _className = sections[1];
+ _classNames.append(sections[1]);
} else if (sections[0] == QLatin1String("internal")) {
- if (sectionCount != 3) {
+ if (sectionCount == 3) {
+ Component entry(sections[1], sections[2], QTypeRevision());
+ entry.internal = true;
+ _components.insert(entry.typeName, entry);
+ } else if (sectionCount == 4) {
+ const QTypeRevision version = parseVersion(sections[2]);
+ if (version.isValid()) {
+ Component entry(sections[1], sections[3], version);
+ entry.internal = true;
+ _components.insert(entry.typeName, entry);
+ } else {
+ reportError(lineNumber, 0,
+ QStringLiteral("invalid version %1, expected <major>.<minor>")
+ .arg(sections[2]));
+ continue;
+ }
+ } else {
reportError(lineNumber, 0,
- QStringLiteral("internal types require 2 arguments, but %1 were provided").arg(sectionCount - 1));
+ QStringLiteral("internal types require 2 or 3 arguments, "
+ "but %1 were provided").arg(sectionCount - 1));
continue;
}
- Component entry(sections[1], sections[2], -1, -1);
- entry.internal = true;
- _components.insertMulti(entry.typeName, entry);
} else if (sections[0] == QLatin1String("singleton")) {
if (sectionCount < 3 || sectionCount > 4) {
reportError(lineNumber, 0,
@@ -207,18 +263,18 @@ bool QQmlDirParser::parse(const QString &source)
} else if (sectionCount == 3) {
// handle qmldir directory listing case where singleton is defined in the following pattern:
// singleton TestSingletonType TestSingletonType.qml
- Component entry(sections[1], sections[2], -1, -1);
+ Component entry(sections[1], sections[2], QTypeRevision());
entry.singleton = true;
- _components.insertMulti(entry.typeName, entry);
+ _components.insert(entry.typeName, entry);
} else {
// handle qmldir module listing case where singleton is defined in the following pattern:
// singleton TestSingletonType 2.0 TestSingletonType20.qml
- int major, minor;
- if (parseVersion(sections[2], &major, &minor)) {
+ const QTypeRevision version = parseVersion(sections[2]);
+ if (version.isValid()) {
const QString &fileName = sections[3];
- Component entry(sections[1], fileName, major, minor);
+ Component entry(sections[1], fileName, version);
entry.singleton = true;
- _components.insertMulti(entry.typeName, entry);
+ _components.insert(entry.typeName, entry);
} else {
reportError(lineNumber, 0, QStringLiteral("invalid version %1, expected <major>.<minor>").arg(sections[2]));
}
@@ -229,54 +285,82 @@ bool QQmlDirParser::parse(const QString &source)
QStringLiteral("typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1));
continue;
}
-#ifdef QT_CREATOR
- TypeInfo typeInfo(sections[1]);
- _typeInfos.append(typeInfo);
-#endif
-
+ _typeInfos.append(sections[1]);
} else if (sections[0] == QLatin1String("designersupported")) {
if (sectionCount != 1)
reportError(lineNumber, 0, QStringLiteral("designersupported does not expect any argument"));
else
_designerSupported = true;
- } else if (sections[0] == QLatin1String("depends")) {
- if (sectionCount != 3) {
+ } else if (sections[0] == QLatin1String("static")) {
+ if (sectionCount != 1)
+ reportError(lineNumber, 0, QStringLiteral("static does not expect any argument"));
+ else
+ _isStaticModule = true;
+ } else if (sections[0] == QLatin1String("system")) {
+ if (sectionCount != 1)
+ reportError(lineNumber, 0, QStringLiteral("system does not expect any argument"));
+ else
+ _isSystemModule = true;
+ } else if (sections[0] == QLatin1String("import")
+ || sections[0] == QLatin1String("depends")) {
+ if (!readImport(sections, sectionCount, Import::Default))
+ continue;
+ } else if (sections[0] == QLatin1String("prefer")) {
+ if (sectionCount < 2) {
reportError(lineNumber, 0,
- QStringLiteral("depends requires 2 arguments, but %1 were provided").arg(sectionCount - 1));
+ QStringLiteral("prefer directive requires one argument, "
+ "but %1 were provided").arg(sectionCount - 1));
continue;
}
- int major, minor;
- if (parseVersion(sections[2], &major, &minor)) {
- Component entry(sections[1], QString(), major, minor);
- entry.internal = true;
- _dependencies.insert(entry.typeName, entry);
- } else {
- reportError(lineNumber, 0, QStringLiteral("invalid version %1, expected <major>.<minor>").arg(sections[2]));
+ if (!_preferredPath.isEmpty()) {
+ reportError(lineNumber, 0, QStringLiteral(
+ "only one prefer directive may be defined in a qmldir file"));
+ continue;
}
- } else if (sections[0] == QLatin1String("import")) {
- if (sectionCount != 2) {
+
+ if (!sections[1].endsWith(u'/')) {
+ // Yes. People should realize it's a directory.
+ reportError(lineNumber, 0, QStringLiteral(
+ "the preferred directory has to end with a '/'"));
+ continue;
+ }
+
+ _preferredPath = sections[1];
+ } else if (sections[0] == QLatin1String("linktarget")) {
+ if (sectionCount < 2) {
reportError(lineNumber, 0,
- QStringLiteral("import requires 2 arguments, but %1 were provided").arg(sectionCount - 1));
+ QStringLiteral("linktarget directive requires an argument, "
+ "but %1 were provided")
+ .arg(sectionCount - 1));
+ continue;
+ }
+
+ if (!_linkTarget.isEmpty()) {
+ reportError(
+ lineNumber, 0,
+ QStringLiteral(
+ "only one linktarget directive may be defined in a qmldir file"));
continue;
}
- _imports << sections[1];
+
+ _linkTarget = 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);
- _components.insertMulti(entry.typeName, entry);
+ const Component entry(sections[0], sections[1], QTypeRevision());
+ _components.insert(entry.typeName, entry);
} else if (sectionCount == 3) {
- int major, minor;
- if (parseVersion(sections[1], &major, &minor)) {
+ const QTypeRevision version = parseVersion(sections[1]);
+ if (version.isValid()) {
const QString &fileName = sections[2];
if (fileName.endsWith(QLatin1String(".js")) || fileName.endsWith(QLatin1String(".mjs"))) {
// A 'js' extension indicates a namespaced script import
- const Script entry(sections[0], fileName, major, minor);
+ const Script entry(sections[0], fileName, version);
_scripts.append(entry);
} else {
- const Component entry(sections[0], fileName, major, minor);
- _components.insertMulti(entry.typeName, entry);
+ const Component entry(sections[0], fileName, version);
+ _components.insert(entry.typeName, entry);
}
} else {
reportError(lineNumber, 0, QStringLiteral("invalid version %1, expected <major>.<minor>").arg(sections[1]));
@@ -292,103 +376,170 @@ bool QQmlDirParser::parse(const QString &source)
return hasError();
}
-void QQmlDirParser::reportError(quint16 line, quint16 column, const QString &description)
+/* removes all file selector occurrences in path
+ firstPlus is the position of the initial '+' in the path
+ which we always have as we check for '+' to decide whether
+ we need to do some work at all
+*/
+static QString pathWithoutFileSelectors(QString path, // we want a copy of path
+ qsizetype firstPlus)
{
- QQmlJS::DiagnosticMessage error;
- error.line = line;
- error.column = column;
- error.message = description;
- _errors.append(error);
+ do {
+ Q_ASSERT(path.at(firstPlus) == u'+');
+ const auto eos = path.size();
+ qsizetype terminatingSlashPos = firstPlus + 1;
+ while (terminatingSlashPos != eos && path.at(terminatingSlashPos) != u'/')
+ ++terminatingSlashPos;
+ path.remove(firstPlus, terminatingSlashPos - firstPlus + 1);
+ firstPlus = path.indexOf(u'+', firstPlus);
+ } while (firstPlus != -1);
+ return path;
}
-bool QQmlDirParser::hasError() const
+static bool canDisambiguate(
+ const QString &fileName1, const QString &fileName2, QString *correctedFileName)
{
- if (! _errors.isEmpty())
+ // If the entries are exactly the same we can delete one without losing anything.
+ if (fileName1 == fileName2)
return true;
- return false;
-}
+ // If we detect conflicting paths, we check if they agree when we remove anything
+ // looking like a file selector.
-void QQmlDirParser::setError(const QQmlJS::DiagnosticMessage &e)
-{
- _errors.clear();
- reportError(e.line, e.column, e.message);
-}
+ // ugly heuristic to deal with file selectors
+ const qsizetype file2PotentialFileSelectorPos = fileName2.indexOf(u'+');
+ const bool file2MightHaveFileSelector = file2PotentialFileSelectorPos != -1;
-QList<QQmlJS::DiagnosticMessage> QQmlDirParser::errors(const QString &uri) const
-{
- QList<QQmlJS::DiagnosticMessage> errors;
- const int numErrors = _errors.size();
- errors.reserve(numErrors);
- for (int i = 0; i < numErrors; ++i) {
- QQmlJS::DiagnosticMessage e = _errors.at(i);
- e.message.replace(QLatin1String("$$URI$$"), uri);
- errors << e;
+ if (const qsizetype fileSelectorPos1 = fileName1.indexOf(u'+'); fileSelectorPos1 != -1) {
+ // existing entry was file selector entry, fix it up
+ // it could also be the case that _both_ are using file selectors
+ const QString baseName = file2MightHaveFileSelector
+ ? pathWithoutFileSelectors(fileName2, file2PotentialFileSelectorPos)
+ : fileName2;
+
+ if (pathWithoutFileSelectors(fileName1, fileSelectorPos1) != baseName)
+ return false;
+
+ *correctedFileName = baseName;
+ return true;
}
- return errors;
-}
-QString QQmlDirParser::typeNamespace() const
-{
- return _typeNamespace;
-}
+ // new entry contains file selector (and we know that fileName1 did not)
+ if (file2MightHaveFileSelector
+ && pathWithoutFileSelectors(fileName2, file2PotentialFileSelectorPos) == fileName1) {
+ *correctedFileName = fileName1;
+ return true;
+ }
-void QQmlDirParser::setTypeNamespace(const QString &s)
-{
- _typeNamespace = s;
+ return false;
}
-QList<QQmlDirParser::Plugin> QQmlDirParser::plugins() const
+static void disambiguateFileSelectedComponents(QQmlDirComponents *components)
{
- return _plugins;
-}
+ using ConstIterator = QQmlDirComponents::const_iterator;
-QHash<QString, QQmlDirParser::Component> QQmlDirParser::components() const
-{
- return _components;
-}
+ // end iterator may get invalidated by the erasing below.
+ // Therefore, refetch it on each iteration.
+ for (ConstIterator cit = components->constBegin(); cit != components->constEnd();) {
-QHash<QString, QQmlDirParser::Component> QQmlDirParser::dependencies() const
-{
- return _dependencies;
+ // We can erase and re-assign cit if we immediately forget cit2.
+ // But we cannot erase cit2 without potentially invalidating cit.
+
+ bool doErase = false;
+ const ConstIterator cend = components->constEnd();
+ for (ConstIterator cit2 = ++ConstIterator(cit); cit2 != cend; ++cit2) {
+ if (cit2.key() != cit.key())
+ break;
+
+ Q_ASSERT(cit2->typeName == cit->typeName);
+
+ if (cit2->version != cit->version
+ || cit2->internal != cit->internal
+ || cit2->singleton != cit->singleton) {
+ continue;
+ }
+
+ // The two components may differ only by fileName now.
+
+ if (canDisambiguate(cit->fileName, cit2->fileName, &(cit2->fileName))) {
+ doErase = true;
+ break;
+ }
+ }
+
+ if (doErase)
+ cit = components->erase(cit);
+ else
+ ++cit;
+ }
}
-QStringList QQmlDirParser::imports() const
+static void disambiguateFileSelectedScripts(QQmlDirScripts *scripts)
{
- return _imports;
+ using Iterator = QQmlDirScripts::iterator;
+
+ Iterator send = scripts->end();
+
+ for (Iterator sit = scripts->begin(); sit != send; ++sit) {
+ send = std::remove_if(++Iterator(sit), send, [sit](const QQmlDirParser::Script &script2) {
+ if (sit->nameSpace != script2.nameSpace || sit->version != script2.version)
+ return false;
+
+ // The two scripts may differ only by fileName now.
+ return canDisambiguate(sit->fileName, script2.fileName, &(sit->fileName));
+ });
+ }
+
+ scripts->erase(send, scripts->end());
}
-QList<QQmlDirParser::Script> QQmlDirParser::scripts() const
+void QQmlDirParser::disambiguateFileSelectors()
{
- return _scripts;
+ disambiguateFileSelectedComponents(&_components);
+ disambiguateFileSelectedScripts(&_scripts);
}
-QList<QQmlDirParser::TypeInfo> QQmlDirParser::typeInfos() const
+void QQmlDirParser::reportError(quint16 line, quint16 column, const QString &description)
{
- return _typeInfos;
+ QQmlJS::DiagnosticMessage error;
+ error.loc.startLine = line;
+ error.loc.startColumn = column;
+ error.message = description;
+ _errors.append(error);
}
-bool QQmlDirParser::designerSupported() const
+void QQmlDirParser::setError(const QQmlJS::DiagnosticMessage &e)
{
- return _designerSupported;
+ _errors.clear();
+ reportError(e.loc.startLine, e.loc.startColumn, e.message);
}
-QString QQmlDirParser::className() const
+QList<QQmlJS::DiagnosticMessage> QQmlDirParser::errors(const QString &uri) const
{
- return _className;
+ QList<QQmlJS::DiagnosticMessage> errors;
+ const int numErrors = _errors.size();
+ errors.reserve(numErrors);
+ for (int i = 0; i < numErrors; ++i) {
+ QQmlJS::DiagnosticMessage e = _errors.at(i);
+ e.message.replace(QLatin1String("$$URI$$"), uri);
+ errors << e;
+ }
+ return errors;
}
QDebug &operator<< (QDebug &debug, const QQmlDirParser::Component &component)
{
- const QString output = QStringLiteral("{%1 %2.%3}").
- arg(component.typeName).arg(component.majorVersion).arg(component.minorVersion);
+ const QString output = QStringLiteral("{%1 %2.%3}")
+ .arg(component.typeName).arg(component.version.majorVersion())
+ .arg(component.version.minorVersion());
return debug << qPrintable(output);
}
QDebug &operator<< (QDebug &debug, const QQmlDirParser::Script &script)
{
- const QString output = QStringLiteral("{%1 %2.%3}").
- arg(script.nameSpace).arg(script.majorVersion).arg(script.minorVersion);
+ const QString output = QStringLiteral("{%1 %2.%3}")
+ .arg(script.nameSpace).arg(script.version.majorVersion())
+ .arg(script.version.minorVersion());
return debug << qPrintable(output);
}
diff --git a/src/qml/qmldirparser/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h
index c9d77532c8..deef8f2dcf 100644
--- a/src/qml/qmldirparser/qqmldirparser_p.h
+++ b/src/qml/qmldirparser/qqmldirparser_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLDIRPARSER_P_H
#define QQMLDIRPARSER_P_H
@@ -54,28 +18,30 @@
#include <QtCore/QUrl>
#include <QtCore/QHash>
#include <QtCore/QDebug>
+#include <QtCore/QTypeRevision>
#include <private/qtqmlcompilerglobal_p.h>
-#include <private/qqmljsengine_p.h>
#include <private/qqmljsdiagnosticmessage_p.h>
QT_BEGIN_NAMESPACE
class QQmlEngine;
-class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlDirParser
+class Q_QML_COMPILER_EXPORT QQmlDirParser
{
public:
+ void clear();
bool parse(const QString &source);
+ void disambiguateFileSelectors();
- bool hasError() const;
+ bool hasError() const { return !_errors.isEmpty(); }
void setError(const QQmlJS::DiagnosticMessage &);
QList<QQmlJS::DiagnosticMessage> errors(const QString &uri) const;
- QString typeNamespace() const;
- void setTypeNamespace(const QString &s);
+ QString typeNamespace() const { return _typeNamespace; }
+ void setTypeNamespace(const QString &s) { _typeNamespace = s; }
static void checkNonRelative(const char *item, const QString &typeName, const QString &fileName)
{
- if (fileName.startsWith(QLatin1Char('/')) || fileName.contains(QLatin1Char(':'))) {
+ if (fileName.startsWith(QLatin1Char('/'))) {
qWarning() << item << typeName
<< "is specified with non-relative URL" << fileName << "in a qmldir file."
<< "URLs in qmldir files should be relative to the qmldir file's directory.";
@@ -86,22 +52,23 @@ public:
{
Plugin() = default;
- Plugin(const QString &name, const QString &path)
- : name(name), path(path)
+ Plugin(const QString &name, const QString &path, bool optional)
+ : name(name), path(path), optional(optional)
{
checkNonRelative("Plugin", name, path);
}
QString name;
QString path;
+ bool optional = false;
};
struct Component
{
Component() = default;
- Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion)
- : typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion),
+ Component(const QString &typeName, const QString &fileName, QTypeRevision version)
+ : typeName(typeName), fileName(fileName), version(version),
internal(false), singleton(false)
{
checkNonRelative("Component", typeName, fileName);
@@ -109,8 +76,7 @@ public:
QString typeName;
QString fileName;
- int majorVersion = 0;
- int minorVersion = 0;
+ QTypeRevision version = QTypeRevision::zero();
bool internal = false;
bool singleton = false;
};
@@ -119,37 +85,57 @@ public:
{
Script() = default;
- Script(const QString &nameSpace, const QString &fileName, int majorVersion, int minorVersion)
- : nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion)
+ Script(const QString &nameSpace, const QString &fileName, QTypeRevision version)
+ : nameSpace(nameSpace), fileName(fileName), version(version)
{
checkNonRelative("Script", nameSpace, fileName);
}
QString nameSpace;
QString fileName;
- int majorVersion = 0;
- int minorVersion = 0;
+ QTypeRevision version = QTypeRevision::zero();
};
- QHash<QString,Component> components() const;
- QHash<QString,Component> dependencies() const;
- QStringList imports() const;
- QList<Script> scripts() const;
- QList<Plugin> plugins() const;
- bool designerSupported() const;
-
- struct TypeInfo
+ struct Import
{
- TypeInfo() = default;
- TypeInfo(const QString &fileName)
- : fileName(fileName) {}
+ enum Flag {
+ Default = 0x0,
+ Auto = 0x1, // forward the version of the importing module
+ Optional = 0x2, // is not automatically imported but only a tooling hint
+ OptionalDefault =
+ 0x4, // tooling hint only, denotes this entry should be imported by tooling
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ Import() = default;
+ Import(QString module, QTypeRevision version, Flags flags)
+ : module(module), version(version), flags(flags)
+ {
+ }
- QString fileName;
+ QString module;
+ QTypeRevision version; // invalid version is latest version, unless Flag::Auto
+ Flags flags;
+
+ friend bool operator==(const Import &a, const Import &b)
+ {
+ return a.module == b.module && a.version == b.version && a.flags == b.flags;
+ }
};
- QList<TypeInfo> typeInfos() const;
+ QMultiHash<QString,Component> components() const { return _components; }
+ QList<Import> dependencies() const { return _dependencies; }
+ QList<Import> imports() const { return _imports; }
+ QList<Script> scripts() const { return _scripts; }
+ QList<Plugin> plugins() const { return _plugins; }
+ bool designerSupported() const { return _designerSupported; }
+ bool isStaticModule() const { return _isStaticModule; }
+ bool isSystemModule() const { return _isSystemModule; }
- QString className() const;
+ QStringList typeInfos() const { return _typeInfos; }
+ QStringList classNames() const { return _classNames; }
+ QString preferredPath() const { return _preferredPath; }
+ QString linkTarget() const { return _linkTarget; }
private:
bool maybeAddComponent(const QString &typeName, const QString &fileName, const QString &version, QHash<QString,Component> &hash, int lineNumber = -1, bool multi = true);
@@ -158,19 +144,24 @@ private:
private:
QList<QQmlJS::DiagnosticMessage> _errors;
QString _typeNamespace;
- QHash<QString,Component> _components; // multi hash
- QHash<QString,Component> _dependencies;
- QStringList _imports;
+ QString _preferredPath;
+ QMultiHash<QString,Component> _components;
+ QList<Import> _dependencies;
+ QList<Import> _imports;
QList<Script> _scripts;
QList<Plugin> _plugins;
bool _designerSupported = false;
- QList<TypeInfo> _typeInfos;
- QString _className;
+ bool _isStaticModule = false;
+ bool _isSystemModule = false;
+ QStringList _typeInfos;
+ QStringList _classNames;
+ QString _linkTarget;
};
-using QQmlDirComponents = QHash<QString,QQmlDirParser::Component>;
+using QQmlDirComponents = QMultiHash<QString,QQmlDirParser::Component>;
using QQmlDirScripts = QList<QQmlDirParser::Script>;
using QQmlDirPlugins = QList<QQmlDirParser::Plugin>;
+using QQmlDirImports = QList<QQmlDirParser::Import>;
QDebug &operator<< (QDebug &, const QQmlDirParser::Component &);
QDebug &operator<< (QDebug &, const QQmlDirParser::Script &);
diff --git a/src/qml/qmldirparser/qqmlimportresolver.cpp b/src/qml/qmldirparser/qqmlimportresolver.cpp
new file mode 100644
index 0000000000..15ec7765b0
--- /dev/null
+++ b/src/qml/qmldirparser/qqmlimportresolver.cpp
@@ -0,0 +1,86 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmlimportresolver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+enum ImportVersion { FullyVersioned, PartiallyVersioned, Unversioned };
+
+/*
+ Forms complete paths to a module, from a list of base paths,
+ a module URI and version specification.
+
+ For example, QtQml.Models 2.0:
+ - base/QtQml/Models.2.0
+ - base/QtQml.2.0/Models
+ - base/QtQml/Models.2
+ - base/QtQml.2/Models
+ - base/QtQml/Models
+*/
+QStringList qQmlResolveImportPaths(QStringView uri, const QStringList &basePaths,
+ QTypeRevision version)
+{
+ static const QLatin1Char Slash('/');
+ static const QLatin1Char Backslash('\\');
+
+ const QVector<QStringView> parts = uri.split(u'.', Qt::SkipEmptyParts);
+
+ QStringList importPaths;
+ // fully & partially versioned parts + 1 unversioned for each base path
+ importPaths.reserve(2 * parts.size() + 1);
+
+ auto versionString = [](QTypeRevision version, ImportVersion mode)
+ {
+ if (mode == FullyVersioned) {
+ // extension with fully encoded version number (eg. MyModule.3.2)
+ return QString::fromLatin1(".%1.%2").arg(version.majorVersion())
+ .arg(version.minorVersion());
+ }
+ if (mode == PartiallyVersioned) {
+ // extension with encoded version major (eg. MyModule.3)
+ return QString::fromLatin1(".%1").arg(version.majorVersion());
+ }
+ // else extension without version number (eg. MyModule)
+ return QString();
+ };
+
+ auto joinStringRefs = [](const QVector<QStringView> &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;
+ };
+
+ const ImportVersion initial = (version.hasMinorVersion())
+ ? FullyVersioned
+ : (version.hasMajorVersion() ? PartiallyVersioned : Unversioned);
+ for (int mode = initial; mode <= Unversioned; ++mode) {
+ const QString ver = versionString(version, ImportVersion(mode));
+
+ for (const QString &path : basePaths) {
+ QString dir = path;
+ if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
+ dir += Slash;
+
+ // append to the end
+ importPaths += dir + joinStringRefs(parts, Slash) + ver;
+
+ if (mode != Unversioned) {
+ // insert in the middle
+ for (int index = parts.size() - 2; index >= 0; --index) {
+ importPaths += dir + joinStringRefs(parts.mid(0, index + 1), Slash)
+ + ver + Slash
+ + joinStringRefs(parts.mid(index + 1), Slash);
+ }
+ }
+ }
+ }
+
+ return importPaths;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qmldirparser/qqmlimportresolver_p.h b/src/qml/qmldirparser/qqmlimportresolver_p.h
new file mode 100644
index 0000000000..1fa85e67b7
--- /dev/null
+++ b/src/qml/qmldirparser/qqmlimportresolver_p.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLIMPORTRESOLVER_P_H
+#define QQMLIMPORTRESOLVER_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/qtqmlcompilerglobal_p.h>
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qversionnumber.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_QML_COMPILER_EXPORT QStringList qQmlResolveImportPaths(QStringView uri, const QStringList &basePaths,
+ QTypeRevision version);
+
+QT_END_NAMESPACE
+
+#endif // QQMLIMPORTRESOLVER_P_H
diff --git a/src/qml/qmltc/qqmltcobjectcreationhelper.cpp b/src/qml/qmltc/qqmltcobjectcreationhelper.cpp
new file mode 100644
index 0000000000..bab86de1b9
--- /dev/null
+++ b/src/qml/qmltc/qqmltcobjectcreationhelper.cpp
@@ -0,0 +1,63 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmltcobjectcreationhelper_p.h"
+
+#include <private/qqmlmetatype_p.h>
+#include <private/qmetaobjectbuilder_p.h>
+#include <private/qobject_p.h>
+#include <private/qqmltype_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void qmltcCreateDynamicMetaObject(QObject *object, const QmltcTypeData &data)
+{
+ // TODO: when/if qmltc-compiled types would be registered via
+ // qmltyperegistrar, instead of creating a dummy QQmlTypePrivate, fetch the
+ // good QQmlType via QQmlMetaType::qmlType(). to do it correctly, one needs,
+ // along with the meta object, module name and revision. all that should be
+ // available ahead-of-time to qmltc.
+ auto qmlTypePrivate = new QQmlTypePrivate(data.regType);
+
+ // tie qmlTypePrivate destruction to objects's destruction. the type's
+ // content is not needed once the associated object is deleted
+ QObject::connect(object, &QObject::destroyed, object,
+ [qmlTypePrivate](QObject *) { qmlTypePrivate->release(); },
+ Qt::DirectConnection);
+
+ // initialize QQmlType::QQmlCppTypeData
+ Q_ASSERT(data.regType == QQmlType::CppType);
+ qmlTypePrivate->extraData.cppTypeData->allocationSize = data.allocationSize;
+ qmlTypePrivate->extraData.cppTypeData->newFunc = nullptr;
+ qmlTypePrivate->extraData.cppTypeData->userdata = nullptr;
+ qmlTypePrivate->extraData.cppTypeData->noCreationReason =
+ QStringLiteral("Qmltc-compiled type is not creatable via QQmlType");
+ qmlTypePrivate->extraData.cppTypeData->createValueTypeFunc = nullptr;
+ qmlTypePrivate->extraData.cppTypeData->parserStatusCast = -1;
+ qmlTypePrivate->extraData.cppTypeData->extFunc = nullptr;
+ qmlTypePrivate->extraData.cppTypeData->extMetaObject = nullptr;
+ qmlTypePrivate->extraData.cppTypeData->customParser = nullptr;
+ qmlTypePrivate->extraData.cppTypeData->attachedPropertiesFunc = nullptr;
+ qmlTypePrivate->extraData.cppTypeData->attachedPropertiesType = nullptr;
+ qmlTypePrivate->extraData.cppTypeData->propertyValueSourceCast = -1;
+ qmlTypePrivate->extraData.cppTypeData->propertyValueInterceptorCast = -1;
+ qmlTypePrivate->extraData.cppTypeData->finalizerCast = -1;
+ qmlTypePrivate->extraData.cppTypeData->registerEnumClassesUnscoped = false;
+ qmlTypePrivate->extraData.cppTypeData->registerEnumsFromRelatedTypes = false;
+
+ qmlTypePrivate->baseMetaObject = data.metaObject;
+
+ QQmlType qmlType(qmlTypePrivate);
+ Q_ASSERT(qmlType.isValid());
+
+ QObjectPrivate *op = QObjectPrivate::get(object);
+ // ### inefficient - rather, call this function only once for the leaf type
+ if (op->metaObject) {
+ delete op->metaObject;
+ op->metaObject = nullptr;
+ }
+
+ qmlType.createProxy(object);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qmltc/qqmltcobjectcreationhelper_p.h b/src/qml/qmltc/qqmltcobjectcreationhelper_p.h
new file mode 100644
index 0000000000..fe0cdcfed2
--- /dev/null
+++ b/src/qml/qmltc/qqmltcobjectcreationhelper_p.h
@@ -0,0 +1,125 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLTCOBJECTCREATIONHELPER_P_H
+#define QQMLTCOBJECTCREATIONHELPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQml/qqml.h>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qversionnumber.h>
+#include <private/qtqmlglobal_p.h>
+#include <private/qqmltype_p.h>
+
+#include <array>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+
+ (Kind of) type-erased object creation utility that can be used throughout
+ the generated C++ code. By nature it shows relative data to the current QML
+ document and allows to get and set object pointers.
+ */
+class QQmltcObjectCreationHelper
+{
+ QObject **m_data = nullptr; // QObject* array
+ const qsizetype m_size = 0; // size of m_data array, exists for bounds checking
+ const qsizetype m_offset = 0; // global offset into m_data array
+
+ qsizetype offset() const { return m_offset; }
+
+public:
+ /*!
+ Constructs initial "view" from basic data. Supposed to only be called
+ once from QQmltcObjectCreationBase.
+ */
+ QQmltcObjectCreationHelper(QObject **data, qsizetype size) : m_data(data), m_size(size)
+ {
+ Q_UNUSED(m_size);
+ }
+
+ /*!
+ Constructs new "view" from \a base view, adding \a localOffset to the
+ offset of that base.
+ */
+ QQmltcObjectCreationHelper(const QQmltcObjectCreationHelper *base, qsizetype localOffset)
+ : m_data(base->m_data), m_size(base->m_size), m_offset(base->m_offset + localOffset)
+ {
+ }
+
+ template<typename T>
+ T *get(qsizetype i) const
+ {
+ Q_ASSERT(m_data);
+ Q_ASSERT(i >= 0 && i + offset() < m_size);
+ Q_ASSERT(qobject_cast<T *>(m_data[i + offset()]) != nullptr);
+ // Note: perform cheap cast as we know *exactly* the real type of the
+ // object
+ return static_cast<T *>(m_data[i + offset()]);
+ }
+
+ void set(qsizetype i, QObject *object)
+ {
+ Q_ASSERT(m_data);
+ Q_ASSERT(i >= 0 && i + offset() < m_size);
+ Q_ASSERT(m_data[i + offset()] == nullptr); // prevent accidental resets
+ m_data[i + offset()] = object;
+ }
+
+ template<typename T>
+ static constexpr uint typeCount() noexcept
+ {
+ return T::q_qmltc_typeCount();
+ }
+};
+
+/*!
+ \internal
+
+ Base helper for qmltc-generated types that linearly stores pointers to all
+ the to-be-created objects for fast access during object creation.
+ */
+template<typename QmltcGeneratedType>
+class QQmltcObjectCreationBase
+{
+ // Note: +1 for the document root itself
+ std::array<QObject *, QmltcGeneratedType::q_qmltc_typeCount() + 1> m_objects = {};
+
+public:
+ QQmltcObjectCreationHelper view()
+ {
+ return QQmltcObjectCreationHelper(m_objects.data(), m_objects.size());
+ }
+};
+
+struct QmltcTypeData
+{
+ QQmlType::RegistrationType regType = QQmlType::CppType;
+ int allocationSize = 0;
+ const QMetaObject *metaObject = nullptr;
+
+ template<typename QmltcGeneratedType>
+ QmltcTypeData(QmltcGeneratedType *)
+ : allocationSize(sizeof(QmltcGeneratedType)),
+ metaObject(&QmltcGeneratedType::staticMetaObject)
+ {
+ }
+};
+
+Q_QML_EXPORT void qmltcCreateDynamicMetaObject(QObject *object, const QmltcTypeData &data);
+
+QT_END_NAMESPACE
+
+#endif // QQMLTCOBJECTCREATIONHELPER_P_H
diff --git a/src/qml/qmltc/supportlibrary/qqmlcppbinding.cpp b/src/qml/qmltc/supportlibrary/qqmlcppbinding.cpp
new file mode 100644
index 0000000000..fdea993124
--- /dev/null
+++ b/src/qml/qmltc/supportlibrary/qqmlcppbinding.cpp
@@ -0,0 +1,163 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmlcppbinding_p.h"
+
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtCore/qmetaobject.h>
+
+#include <private/qqmltypedata_p.h>
+#include <private/qqmlpropertybinding_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmlbinding_p.h>
+
+QT_BEGIN_NAMESPACE
+
+template<typename CreateBinding>
+inline decltype(auto) createBindingInScope(QObject *thisObject, CreateBinding create)
+{
+ QQmlEngine *qmlengine = qmlEngine(thisObject);
+ Q_ASSERT(qmlengine);
+ QV4::ExecutionEngine *v4 = qmlengine->handle();
+ Q_ASSERT(v4);
+
+ QQmlData *ddata = QQmlData::get(thisObject);
+ Q_ASSERT(ddata && ddata->outerContext);
+ QQmlRefPointer<QQmlContextData> ctxtdata = QQmlRefPointer<QQmlContextData>(ddata->outerContext);
+
+ QV4::Scope scope(v4);
+ QV4::ExecutionContext *executionCtx = v4->scriptContext();
+ QV4::Scoped<QV4::QmlContext> qmlContext(
+ scope, QV4::QmlContext::create(executionCtx, ctxtdata, thisObject));
+
+ return create(ctxtdata, qmlContext);
+}
+
+QUntypedPropertyBinding
+QQmlCppBinding::createBindingForBindable(const QV4::ExecutableCompilationUnit *unit,
+ QObject *thisObject, qsizetype functionIndex,
+ QObject *bindingTarget, int metaPropertyIndex,
+ int valueTypePropertyIndex, const QString &propertyName)
+{
+ Q_UNUSED(propertyName);
+
+ QV4::Function *v4Function = unit->runtimeFunctions.value(functionIndex, nullptr);
+ if (!v4Function) {
+ // TODO: align with existing logging of such
+ qCritical() << "invalid JavaScript function index (internal error)";
+ return QUntypedPropertyBinding();
+ }
+ if (metaPropertyIndex < 0) {
+ // TODO: align with existing logging of such
+ qCritical() << "invalid meta property index (internal error)";
+ return QUntypedPropertyBinding();
+ }
+
+ const QMetaObject *mo = bindingTarget->metaObject();
+ Q_ASSERT(mo);
+ QMetaProperty property = mo->property(metaPropertyIndex);
+ Q_ASSERT(valueTypePropertyIndex == -1 || QString::fromUtf8(property.name()) == propertyName);
+
+ return createBindingInScope(
+ thisObject,
+ [&](const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope) {
+ auto index = QQmlPropertyIndex(property.propertyIndex(), valueTypePropertyIndex);
+ return QQmlPropertyBinding::create(property.metaType(), v4Function, thisObject,
+ ctxt, scope, bindingTarget, index);
+ });
+}
+
+void QQmlCppBinding::createBindingForNonBindable(const QV4::ExecutableCompilationUnit *unit,
+ QObject *thisObject, qsizetype functionIndex,
+ QObject *bindingTarget, int metaPropertyIndex,
+ int valueTypePropertyIndex,
+ const QString &propertyName)
+{
+ Q_UNUSED(propertyName);
+
+ QV4::Function *v4Function = unit->runtimeFunctions.value(functionIndex, nullptr);
+ if (!v4Function) {
+ // TODO: align with existing logging of such
+ qCritical() << "invalid JavaScript function index (internal error)";
+ return;
+ }
+ if (metaPropertyIndex < 0) {
+ // TODO: align with existing logging of such
+ qCritical() << "invalid meta property index (internal error)";
+ return;
+ }
+
+ const QMetaObject *mo = bindingTarget->metaObject();
+ Q_ASSERT(mo);
+ QMetaProperty property = mo->property(metaPropertyIndex);
+ Q_ASSERT(valueTypePropertyIndex != -1 || QString::fromUtf8(property.name()) == propertyName);
+
+ createBindingInScope(
+ thisObject,
+ [&](const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope) -> void {
+ QQmlBinding *binding = QQmlBinding::create(property.metaType(), v4Function,
+ thisObject, ctxt, scope);
+ // almost as in qv4objectwrapper.cpp:535
+ Q_ASSERT(!property.isAlias()); // we convert aliases to (almost) real properties
+ binding->setTarget(bindingTarget, property.propertyIndex(), false,
+ valueTypePropertyIndex);
+ QQmlPropertyPrivate::setBinding(binding);
+ });
+}
+
+QUntypedPropertyBinding QQmlCppBinding::createTranslationBindingForBindable(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, QObject *bindingTarget,
+ int metaPropertyIndex, const QQmlTranslation &translationData, const QString &propertyName)
+{
+ Q_UNUSED(propertyName);
+
+ if (metaPropertyIndex < 0) {
+ // TODO: align with existing logging of such
+ qCritical() << "invalid meta property index (internal error)";
+ return QUntypedPropertyBinding();
+ }
+
+ const QMetaObject *mo = bindingTarget->metaObject();
+ Q_ASSERT(mo);
+ QMetaProperty property = mo->property(metaPropertyIndex);
+ Q_ASSERT(QString::fromUtf8(property.name()) == propertyName);
+
+ return QQmlTranslationPropertyBinding::create(property.metaType(), unit, translationData);
+}
+
+void QQmlCppBinding::createTranslationBindingForNonBindable(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QQmlSourceLocation &location, const QQmlTranslation &translationData,
+ QObject *thisObject, QObject *bindingTarget, int metaPropertyIndex,
+ const QString &propertyName, int valueTypePropertyIndex)
+{
+ Q_UNUSED(propertyName);
+
+ if (metaPropertyIndex < 0) {
+ // TODO: align with existing logging of such
+ qCritical() << "invalid meta property index (internal error)";
+ return;
+ }
+
+ const QMetaObject *mo = bindingTarget->metaObject();
+ Q_ASSERT(mo);
+ QMetaProperty property = mo->property(metaPropertyIndex);
+ Q_ASSERT(QString::fromUtf8(property.name()) == propertyName);
+
+ createBindingInScope(
+ thisObject,
+ [&](const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *) -> void {
+ QQmlBinding *binding = QQmlBinding::createTranslationBinding(
+ unit, ctxt, propertyName, translationData, location, thisObject);
+ // almost as in qv4objectwrapper.cpp:535
+ Q_ASSERT(!property.isAlias()); // we convert aliases to (almost) real properties
+ binding->setTarget(bindingTarget, property.propertyIndex(), false,
+ valueTypePropertyIndex);
+ QQmlPropertyPrivate::setBinding(binding);
+ });
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qmltc/supportlibrary/qqmlcppbinding_p.h b/src/qml/qmltc/supportlibrary/qqmlcppbinding_p.h
new file mode 100644
index 0000000000..a1c60012bc
--- /dev/null
+++ b/src/qml/qmltc/supportlibrary/qqmlcppbinding_p.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLCPPBINDING_P_H
+#define QQMLCPPBINDING_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qobject.h>
+#include <QtCore/qproperty.h>
+#include <QtCore/qurl.h>
+
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtCore/qmetaobject.h>
+
+#include <private/qqmltypedata_p.h>
+#include <private/qqmlpropertybinding_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmlbinding_p.h>
+
+QT_BEGIN_NAMESPACE
+
+struct Q_QML_EXPORT QQmlCppBinding
+{
+ // TODO: this might instead be put into the QQmlEngine or QQmlAnyBinding?
+ static QUntypedPropertyBinding
+ createBindingForBindable(const QV4::ExecutableCompilationUnit *unit, QObject *thisObject,
+ qsizetype functionIndex, QObject *bindingTarget, int metaPropertyIndex,
+ int valueTypePropertyIndex, const QString &propertyName);
+
+ static void createBindingForNonBindable(const QV4::ExecutableCompilationUnit *unit,
+ QObject *thisObject, qsizetype functionIndex,
+ QObject *bindingTarget, int metaPropertyIndex,
+ int valueTypePropertyIndex,
+ const QString &propertyName);
+
+ static QUntypedPropertyBinding
+ createTranslationBindingForBindable(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ QObject *bindingTarget, int metaPropertyIndex,
+ const QQmlTranslation &translationData,
+ const QString &propertyName);
+
+ static void createTranslationBindingForNonBindable(
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
+ const QQmlSourceLocation &location, const QQmlTranslation &translationData,
+ QObject *thisObject, QObject *bindingTarget, int metaPropertyIndex,
+ const QString &propertyName, int valueTypePropertyIndex);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLCPPBINDING_P_H
diff --git a/src/qml/qmltc/supportlibrary/qqmlcpponassignment.cpp b/src/qml/qmltc/supportlibrary/qqmlcpponassignment.cpp
new file mode 100644
index 0000000000..e6f170fe25
--- /dev/null
+++ b/src/qml/qmltc/supportlibrary/qqmlcpponassignment.cpp
@@ -0,0 +1,20 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmlcpponassignment_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QQmlCppOnAssignmentHelper::set(QQmlPropertyValueInterceptor *interceptor,
+ const QQmlProperty &property)
+{
+ interceptor->setTarget(property);
+}
+
+void QQmlCppOnAssignmentHelper::set(QQmlPropertyValueSource *valueSource,
+ const QQmlProperty &property)
+{
+ valueSource->setTarget(property);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qmltc/supportlibrary/qqmlcpponassignment_p.h b/src/qml/qmltc/supportlibrary/qqmlcpponassignment_p.h
new file mode 100644
index 0000000000..cd8014895f
--- /dev/null
+++ b/src/qml/qmltc/supportlibrary/qqmlcpponassignment_p.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLCPPONASSIGNMENT_P_H
+#define QQMLCPPONASSIGNMENT_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/qqmlpropertyvalueinterceptor_p.h>
+#include <QtQml/qqmlpropertyvaluesource.h>
+
+QT_BEGIN_NAMESPACE
+
+/*! \internal
+
+ Helper class that provides setTarget() functionality for both value
+ interceptors and value sources.
+
+ Property value sources could be problematic because QQuickAbstractAnimation
+ changes access specifier of QQmlPropertyValueSource::setTarget() to private
+ (unintentionally?). This API allows to avoid manual casts to base types as
+ the C++ compiler would implicitly cast derived classes in this case.
+*/
+struct Q_QML_EXPORT QQmlCppOnAssignmentHelper
+{
+ // TODO: in theory, this API might just accept QObject * and int that would
+ // give the QMetaProperty. using the meta property, one could create
+ // QQmlProperty with a call to QQmlProperty::restore() (if there's an
+ // overload that takes QMetaProperty instead of QQmlPropertyData - which is
+ // also possible to add by using QQmlPropertyData::load())
+ static void set(QQmlPropertyValueInterceptor *interceptor, const QQmlProperty &property);
+ static void set(QQmlPropertyValueSource *valueSource, const QQmlProperty &property);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLCPPONASSIGNMENT_P_H
diff --git a/src/qml/qmltc/supportlibrary/qqmlcpptypehelpers_p.h b/src/qml/qmltc/supportlibrary/qqmlcpptypehelpers_p.h
new file mode 100644
index 0000000000..2470d87efe
--- /dev/null
+++ b/src/qml/qmltc/supportlibrary/qqmlcpptypehelpers_p.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLCPPTYPEHELPERS_H
+#define QQMLCPPTYPEHELPERS_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 <type_traits>
+
+/*! \internal
+ Used by Qmltc to decide when value types should be passed by value or reference.
+ */
+template<typename T>
+using passByConstRefOrValue =
+ std::conditional_t<((sizeof(T) > 3 * sizeof(void *)) || !std::is_trivial_v<T>), const T &,
+ T>;
+
+#endif // QQMLCPPTYPEHELPERS_H
diff --git a/src/qml/qqmlbuiltins_p.h b/src/qml/qqmlbuiltins_p.h
new file mode 100644
index 0000000000..187e11d5da
--- /dev/null
+++ b/src/qml/qqmlbuiltins_p.h
@@ -0,0 +1,407 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLBUILTINS_H
+#define QQMLBUILTINS_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.
+//
+
+// QmlBuiltins does not link QtQml - rather the other way around. Still, we can use the QtQml
+// headers here. This works because we explicitly include the QtQml include directories in the
+// manual moc call.
+#include <private/qqmlcomponentattached_p.h>
+#include <QtQml/qjsvalue.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlscriptstring.h>
+
+#include <QtQmlIntegration/qqmlintegration.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qtmetamacros.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariantmap.h>
+#include <QtCore/qtypes.h>
+#include <QtCore/qchar.h>
+#include <QtCore/qjsonobject.h>
+
+#include <climits>
+
+#if QT_CONFIG(regularexpression)
+#include <QtCore/qregularexpression.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+// moc doesn't do 64bit constants, so we have to determine the size of qsizetype indirectly.
+// We assume that qsizetype is always the same size as a pointer. I haven't seen a platform
+// where this is not the case.
+// Furthermore moc is wrong about pretty much everything on 64bit windows. We need to hardcode
+// the size there.
+// Likewise, we also have to determine the size of long and ulong indirectly.
+
+#if defined(Q_OS_WIN64)
+
+static_assert(sizeof(long) == 4);
+#define QML_LONG_IS_32BIT
+static_assert(sizeof(qsizetype) == 8);
+#define QML_SIZE_IS_64BIT
+
+#elif QT_POINTER_SIZE == 4
+
+static_assert(sizeof(long) == 4);
+#define QML_LONG_IS_32BIT
+static_assert(sizeof(qsizetype) == 4);
+#define QML_SIZE_IS_32BIT
+
+#else
+
+static_assert(sizeof(long) == 8);
+#define QML_LONG_IS_64BIT
+static_assert(sizeof(qsizetype) == 8);
+#define QML_SIZE_IS_64BIT
+
+#endif
+
+#define QML_EXTENDED_JAVASCRIPT(EXTENDED_TYPE) \
+ Q_CLASSINFO("QML.Extended", #EXTENDED_TYPE) \
+ Q_CLASSINFO("QML.ExtensionIsJavaScript", "true")
+
+template<typename A> struct QQmlPrimitiveAliasFriend {};
+
+#define QML_PRIMITIVE_ALIAS(PRIMITIVE_ALIAS) \
+ Q_CLASSINFO("QML.PrimitiveAlias", #PRIMITIVE_ALIAS) \
+ friend QQmlPrimitiveAliasFriend<PRIMITIVE_ALIAS>;
+
+struct QQmlVoidForeign
+{
+ Q_GADGET
+ QML_VALUE_TYPE(void)
+ QML_EXTENDED_JAVASCRIPT(undefined)
+#if !QT_CONFIG(regularexpression)
+ QML_VALUE_TYPE(regexp)
+#endif
+ QML_FOREIGN(void)
+};
+
+struct QQmlVarForeign
+{
+ Q_GADGET
+ QML_VALUE_TYPE(var)
+ QML_VALUE_TYPE(variant)
+ QML_FOREIGN(QVariant)
+ QML_EXTENDED(QQmlVarForeign)
+};
+
+struct QQmlQtObjectForeign
+{
+ Q_GADGET
+ QML_NAMED_ELEMENT(QtObject)
+ QML_EXTENDED_JAVASCRIPT(Object)
+ QML_FOREIGN(QObject)
+ Q_CLASSINFO("QML.Root", "true")
+};
+
+struct QQmlIntForeign
+{
+ Q_GADGET
+ QML_VALUE_TYPE(int)
+ QML_EXTENDED_JAVASCRIPT(Number)
+ QML_FOREIGN(int)
+ QML_PRIMITIVE_ALIAS(qint32)
+ QML_PRIMITIVE_ALIAS(int32_t)
+#ifdef QML_SIZE_IS_32BIT
+ QML_PRIMITIVE_ALIAS(qsizetype)
+#endif
+#ifdef QML_LONG_IS_32BIT
+ QML_PRIMITIVE_ALIAS(long)
+#endif
+};
+
+struct QQmlDoubleForeign
+{
+ Q_GADGET
+ QML_VALUE_TYPE(real)
+ QML_VALUE_TYPE(double)
+ QML_EXTENDED_JAVASCRIPT(Number)
+ QML_FOREIGN(double)
+#if !defined(QT_COORD_TYPE) || defined(QT_COORD_TYPE_IS_DOUBLE)
+ QML_PRIMITIVE_ALIAS(qreal)
+#endif
+};
+
+struct QQmlStringForeign
+{
+ Q_GADGET
+ QML_VALUE_TYPE(string)
+ QML_EXTENDED_JAVASCRIPT(String)
+ QML_FOREIGN(QString)
+};
+
+struct QQmlAnyStringViewForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_EXTENDED_JAVASCRIPT(String)
+ QML_FOREIGN(QAnyStringView)
+};
+
+struct QQmlBoolForeign
+{
+ Q_GADGET
+ QML_VALUE_TYPE(bool)
+ QML_EXTENDED_JAVASCRIPT(Boolean)
+ QML_FOREIGN(bool)
+};
+
+struct QQmlDateForeign
+{
+ Q_GADGET
+ QML_VALUE_TYPE(date)
+ QML_EXTENDED_JAVASCRIPT(Date)
+ QML_FOREIGN(QDateTime)
+};
+
+struct QQmlUrlForeign
+{
+ Q_GADGET
+ QML_VALUE_TYPE(url)
+ QML_EXTENDED_JAVASCRIPT(URL)
+ QML_FOREIGN(QUrl)
+};
+
+#if QT_CONFIG(regularexpression)
+struct QQmlRegexpForeign
+{
+ Q_GADGET
+ QML_VALUE_TYPE(regexp)
+ QML_EXTENDED_JAVASCRIPT(RegExp)
+ QML_FOREIGN(QRegularExpression)
+};
+#endif
+
+struct QQmlNullForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(std::nullptr_t)
+ QML_EXTENDED(QQmlNullForeign)
+};
+
+struct QQmlQVariantMapForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QVariantMap)
+ QML_EXTENDED_JAVASCRIPT(Object)
+};
+
+struct QQmlQint8Foreign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_EXTENDED_JAVASCRIPT(Number)
+ QML_FOREIGN(qint8)
+ QML_PRIMITIVE_ALIAS(int8_t)
+#if CHAR_MAX == SCHAR_MAX
+ QML_PRIMITIVE_ALIAS(char)
+#endif
+};
+
+struct QQmlQuint8Foreign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_EXTENDED_JAVASCRIPT(Number)
+ QML_FOREIGN(quint8)
+ QML_PRIMITIVE_ALIAS(uint8_t)
+ QML_PRIMITIVE_ALIAS(uchar)
+#if CHAR_MAX == UCHAR_MAX
+ QML_PRIMITIVE_ALIAS(char)
+#endif
+};
+
+struct QQmlShortForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_EXTENDED_JAVASCRIPT(Number)
+ QML_FOREIGN(short)
+ QML_PRIMITIVE_ALIAS(qint16)
+ QML_PRIMITIVE_ALIAS(int16_t)
+};
+
+struct QQmlUshortForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_EXTENDED_JAVASCRIPT(Number)
+ QML_FOREIGN(ushort)
+ QML_PRIMITIVE_ALIAS(quint16)
+ QML_PRIMITIVE_ALIAS(uint16_t)
+};
+
+struct QQmlUintForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_EXTENDED_JAVASCRIPT(Number)
+ QML_FOREIGN(uint)
+ QML_PRIMITIVE_ALIAS(quint32)
+ QML_PRIMITIVE_ALIAS(uint32_t)
+#ifdef QML_LONG_IS_32BIT
+ QML_PRIMITIVE_ALIAS(ulong)
+#endif
+};
+
+struct QQmlQlonglongForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_EXTENDED_JAVASCRIPT(Number)
+ QML_FOREIGN(qlonglong)
+ QML_PRIMITIVE_ALIAS(qint64)
+ QML_PRIMITIVE_ALIAS(int64_t)
+#ifdef QML_LONG_IS_64BIT
+ QML_PRIMITIVE_ALIAS(long)
+#endif
+#ifdef QML_SIZE_IS_64BIT
+ QML_PRIMITIVE_ALIAS(qsizetype)
+#endif
+};
+
+struct QQmlQulonglongForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_EXTENDED_JAVASCRIPT(Number)
+ QML_FOREIGN(qulonglong)
+ QML_PRIMITIVE_ALIAS(quint64)
+ QML_PRIMITIVE_ALIAS(uint64_t)
+#ifdef QML_LONG_IS_64BIT
+ QML_PRIMITIVE_ALIAS(ulong)
+#endif
+};
+
+struct QQmlFloatForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_EXTENDED_JAVASCRIPT(Number)
+ QML_FOREIGN(float)
+#if defined(QT_COORD_TYPE) && defined(QT_COORD_TYPE_IS_FLOAT)
+ QML_PRIMITIVE_ALIAS(qreal)
+#endif
+};
+
+struct QQmlQCharForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QChar)
+ QML_EXTENDED_JAVASCRIPT(String)
+};
+
+struct QQmlQDateForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QDate)
+ QML_EXTENDED_JAVASCRIPT(Date)
+};
+
+struct QQmlQTimeForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QTime)
+ QML_EXTENDED_JAVASCRIPT(Date)
+};
+
+struct QQmlQByteArrayForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_EXTENDED_JAVASCRIPT(ArrayBuffer)
+ QML_FOREIGN(QByteArray)
+};
+
+struct QQmlQStringListForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QStringList)
+ QML_SEQUENTIAL_CONTAINER(QString)
+};
+
+struct QQmlQVariantListForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QVariantList)
+ QML_SEQUENTIAL_CONTAINER(QVariant)
+};
+
+struct QQmlQObjectListForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QObjectList)
+ QML_SEQUENTIAL_CONTAINER(QObject*)
+ QML_PRIMITIVE_ALIAS(QList<QObject*>)
+};
+
+struct QQmlQJSValueForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QJSValue)
+ QML_EXTENDED(QQmlQJSValueForeign)
+};
+
+struct QQmlComponentForeign
+{
+ Q_GADGET
+ QML_NAMED_ELEMENT(Component)
+ QML_FOREIGN(QQmlComponent)
+ QML_ATTACHED(QQmlComponentAttached)
+};
+
+struct QQmlScriptStringForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQmlScriptString)
+};
+
+struct QQmlV4FunctionPtrForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQmlV4FunctionPtr)
+ QML_EXTENDED(QQmlV4FunctionPtrForeign)
+};
+
+struct QQmlQJsonObjectForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QJsonObject)
+ QML_EXTENDED_JAVASCRIPT(Object)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLBUILTINS_H
diff --git a/src/qml/qt_cmdline.cmake b/src/qml/qt_cmdline.cmake
new file mode 100644
index 0000000000..ce03d0f64c
--- /dev/null
+++ b/src/qml/qt_cmdline.cmake
@@ -0,0 +1,2 @@
+qt_commandline_option(qml-network TYPE boolean)
+qt_commandline_option(qml-debug TYPE boolean)
diff --git a/src/qml/qtqml.tracepoints b/src/qml/qtqml.tracepoints
deleted file mode 100644
index 841748f201..0000000000
--- a/src/qml/qtqml.tracepoints
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-namespace QV4 {
-class ExecutionEngine;
-namespace CompiledData {
-class CompilationUnit;
-class Object;
-} // CompiledData
-} // QV4
-}
-
-QQmlObjectCreator_createInstance_entry(const QV4::CompiledData::CompilationUnit *compilationUnit, const QV4::CompiledData::Object *object, const QUrl &url)
-QQmlObjectCreator_createInstance_exit(const QString &typeName)
-QQmlV4_function_call_entry(const QV4::ExecutionEngine *engine, const QString &function, const QString &fileName, int line, int column)
-QQmlV4_function_call_exit()
diff --git a/src/qml/qtqmlcompilerglobal.h b/src/qml/qtqmlcompilerglobal.h
index 850d413372..d175e820c4 100644
--- a/src/qml/qtqmlcompilerglobal.h
+++ b/src/qml/qtqmlcompilerglobal.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTQMLCOMPILERGLOBAL_H
#define QTQMLCOMPILERGLOBAL_H
@@ -44,13 +8,13 @@
QT_BEGIN_NAMESPACE
-#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) || defined(QT_STATIC)
-# define Q_QMLCOMPILER_EXPORT
+#if defined(QT_STATIC)
+# define Q_QML_COMPILER_EXPORT
#else
# if defined(QT_BUILD_QML_LIB)
-# define Q_QMLCOMPILER_EXPORT Q_DECL_EXPORT
+# define Q_QML_COMPILER_EXPORT Q_DECL_EXPORT
# else
-# define Q_QMLCOMPILER_EXPORT Q_DECL_IMPORT
+# define Q_QML_COMPILER_EXPORT Q_DECL_IMPORT
# endif
#endif
diff --git a/src/qml/qtqmlcompilerglobal_p.h b/src/qml/qtqmlcompilerglobal_p.h
index 9c8bce23d3..f21c63d4a0 100644
--- a/src/qml/qtqmlcompilerglobal_p.h
+++ b/src/qml/qtqmlcompilerglobal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTQMLCOMPILERGLOBAL_P_H
#define QTQMLCOMPILERGLOBAL_P_H
@@ -54,6 +18,4 @@
#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/qtqmlglobal.h b/src/qml/qtqmlglobal.h
index 3e275c6359..373a79afac 100644
--- a/src/qml/qtqmlglobal.h
+++ b/src/qml/qtqmlglobal.h
@@ -1,74 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTQMLGLOBAL_H
#define QTQMLGLOBAL_H
-#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
-# define QT_QML_BOOTSTRAPPED
-#endif
#include <QtCore/qglobal.h>
-#ifndef QT_QML_BOOTSTRAPPED
-# include <QtQml/qtqml-config.h>
-# if QT_CONFIG(qml_network)
-# include <QtNetwork/qtnetworkglobal.h>
-# endif
-#else
-# define QT_FEATURE_qml_debug -1
-# define QT_FEATURE_qml_sequence_object 1
-# define QT_FEATURE_qml_jit -1
-# define QT_FEATURE_qml_worker_script -1
-# define QT_FEATURE_qml_xml_http_request -1
+#include <QtQml/qtqml-config.h>
+#if QT_CONFIG(qml_network)
+# include <QtNetwork/qtnetworkglobal.h>
#endif
-QT_BEGIN_NAMESPACE
-
-#if !defined(QT_QML_BOOTSTRAPPED) && !defined(QT_STATIC)
-# if defined(QT_BUILD_QML_LIB)
-# define Q_QML_EXPORT Q_DECL_EXPORT
-# else
-# define Q_QML_EXPORT Q_DECL_IMPORT
-# endif
-#else
-# define Q_QML_EXPORT
-#endif
+# include <QtQml/qtqmlexports.h>
-QT_END_NAMESPACE
#endif // QTQMLGLOBAL_H
diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h
index 9ca0cf2abe..6c5c3967ed 100644
--- a/src/qml/qtqmlglobal_p.h
+++ b/src/qml/qtqmlglobal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTQMLGLOBAL_P_H
#define QTQMLGLOBAL_P_H
@@ -53,17 +17,15 @@
#include <QtCore/private/qglobal_p.h>
#include <QtQml/qtqmlglobal.h>
-#ifndef QT_QML_BOOTSTRAPPED
-# include <QtQml/private/qtqml-config_p.h>
-#endif
-#include <private/qqmlapiversion_p.h>
+#include <QtQml/private/qtqml-config_p.h>
+#include <QtQml/qtqmlexports.h>
-#define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT
+#define Q_QML_AUTOTEST_EXPORT Q_AUTOTEST_EXPORT
-#if !defined(QT_QMLDEVTOOLS_LIB) && !defined(QT_BUILD_QMLDEVTOOLS_LIB)
-# define Q_QML_AUTOTEST_EXPORT Q_AUTOTEST_EXPORT
+#ifdef QT_NO_DEBUG
+#define QML_NEARLY_ALWAYS_INLINE Q_ALWAYS_INLINE
#else
-# define Q_QML_AUTOTEST_EXPORT
+#define QML_NEARLY_ALWAYS_INLINE inline
#endif
#endif // QTQMLGLOBAL_P_H
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 6d762401d0..bc06d4ed51 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -1,117 +1,331 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlbind_p.h"
-#include <private/qqmlnullablevalue_p.h>
-#include <private/qqmlproperty_p.h>
+#include <private/qqmlanybinding_p.h>
#include <private/qqmlbinding_p.h>
+#include <private/qqmlcomponent_p.h>
#include <private/qqmlmetatype_p.h>
+#include <private/qqmlnullablevalue_p.h>
+#include <private/qqmlproperty_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qv4persistent_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qv4resolvedtypereference_p.h>
-#include <qqmlengine.h>
-#include <qqmlcontext.h>
-#include <qqmlproperty.h>
-#include <qqmlinfo.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/qqmlproperty.h>
+#include <QtQml/qqmlpropertymap.h>
+
+#include <QtCore/private/qobject_p.h>
-#include <QtCore/qfile.h>
#include <QtCore/qdebug.h>
-#include <QtCore/qtimer.h>
+#include <QtCore/qfile.h>
#include <QtCore/qloggingcategory.h>
-
-#include <private/qobject_p.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qtimer.h>
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
+enum class QQmlBindEntryKind: quint8 {
+ V4Value,
+ Variant,
+ Binding,
+ None
+};
+
+/*!
+ * \internal
+ * QQmlBindEntryContent can store one of QV4::Value, QVariant, QQmlAnyBinding, or nothing,
+ * as denoted by QQmlBindEntryKind. It expects the calling code to know what is stored at
+ * any time. On each method invocation, the current kind has to be passed as last parameter
+ * and the new kind is returned.
+ */
+union QQmlBindEntryContent {
+ Q_DISABLE_COPY_MOVE(QQmlBindEntryContent)
+public:
+ QQmlBindEntryContent() {}
+ ~QQmlBindEntryContent() {}
+
+ [[nodiscard]] QQmlBindEntryKind set(
+ QQmlBindEntryContent &&other, QQmlBindEntryKind newKind, QQmlBindEntryKind oldKind)
+ {
+ silentDestroy(oldKind);
+ switch (newKind) {
+ case QQmlBindEntryKind::V4Value:
+ new (&v4Value) QV4::PersistentValue(std::move(other.v4Value));
+ break;
+ case QQmlBindEntryKind::Variant:
+ new (&variant) QVariant(std::move(other.variant));
+ break;
+ case QQmlBindEntryKind::Binding:
+ new (&binding) QQmlAnyBinding(std::move(other.binding));
+ break;
+ case QQmlBindEntryKind::None:
+ break;
+ }
+ return newKind;
+ }
+
+ [[nodiscard]] QQmlBindEntryKind set(
+ const QQmlBindEntryContent &other, QQmlBindEntryKind newKind, QQmlBindEntryKind oldKind)
+ {
+ silentDestroy(oldKind);
+ switch (newKind) {
+ case QQmlBindEntryKind::V4Value:
+ new (&v4Value) QV4::PersistentValue(other.v4Value);
+ break;
+ case QQmlBindEntryKind::Variant:
+ new (&variant) QVariant(other.variant);
+ break;
+ case QQmlBindEntryKind::Binding:
+ new (&binding) QQmlAnyBinding(other.binding);
+ break;
+ case QQmlBindEntryKind::None:
+ break;
+ }
+ return newKind;
+ }
+
+ [[nodiscard]] QQmlBindEntryKind destroy(QQmlBindEntryKind kind)
+ {
+ switch (kind) {
+ case QQmlBindEntryKind::V4Value:
+ v4Value.~PersistentValue();
+ break;
+ case QQmlBindEntryKind::Variant:
+ variant.~QVariant();
+ break;
+ case QQmlBindEntryKind::Binding:
+ binding.~QQmlAnyBinding();
+ break;
+ case QQmlBindEntryKind::None:
+ break;
+ }
+ return QQmlBindEntryKind::None;
+ }
+
+ [[nodiscard]] QQmlBindEntryKind set(QVariant v, QQmlBindEntryKind oldKind)
+ {
+ silentDestroy(oldKind);
+ new (&variant) QVariant(std::move(v));
+ return QQmlBindEntryKind::Variant;
+ }
+
+ [[nodiscard]] QQmlBindEntryKind set(QV4::PersistentValue v, QQmlBindEntryKind oldKind)
+ {
+ silentDestroy(oldKind);
+ new (&v4Value) QV4::PersistentValue(std::move(v));
+ return QQmlBindEntryKind::V4Value;
+ }
+
+ [[nodiscard]] QQmlBindEntryKind set(QQmlAnyBinding v, QQmlBindEntryKind oldKind)
+ {
+ silentDestroy(oldKind);
+ new (&binding) QQmlAnyBinding(std::move(v));
+ return QQmlBindEntryKind::Binding;
+ }
+
+ QV4::PersistentValue v4Value;
+ QVariant variant;
+ QQmlAnyBinding binding;
+
+private:
+ void silentDestroy(QQmlBindEntryKind oldKind)
+ {
+ const QQmlBindEntryKind dead = destroy(oldKind);
+ Q_ASSERT(dead == QQmlBindEntryKind::None);
+ Q_UNUSED(dead);
+ }
+};
+
+/*!
+ * \internal
+ * QQmlBindEntry holds two QQmlBindEntryContent members, along with their kinds.
+ * The \l current content is the value or binding the Binding element installs on
+ * the target if enabled (that is, if \l{when}). The \l previous content is what
+ * the target holds before the Binding element installs its binding or value. It
+ * is restored if !\l{when}. The \l prop member holds the target property.
+ */
+struct QQmlBindEntry
+{
+ QQmlBindEntry() = default;
+ QQmlBindEntry(QQmlBindEntry &&other) noexcept : prop(std::move(other.prop))
+ {
+ currentKind = current.set(std::move(other.current), other.currentKind, currentKind);
+ previousKind = previous.set(std::move(other.previous), other.previousKind, previousKind);
+ }
+
+ QQmlBindEntry(const QQmlBindEntry &other)
+ : prop(other.prop)
+ {
+ currentKind = current.set(other.current, other.currentKind, currentKind);
+ previousKind = previous.set(other.previous, other.previousKind, previousKind);
+ }
+
+ ~QQmlBindEntry()
+ {
+ currentKind = current.destroy(currentKind);
+ previousKind = previous.destroy(previousKind);
+ }
+
+ QQmlBindEntry &operator=(QQmlBindEntry &&other) noexcept
+ {
+ if (this == &other)
+ return *this;
+ prop = std::move(other.prop);
+ currentKind = current.set(std::move(other.current), other.currentKind, currentKind);
+ previousKind = previous.set(std::move(other.previous), other.previousKind, previousKind);
+ return *this;
+ }
+
+ QQmlBindEntry &operator=(const QQmlBindEntry &other)
+ {
+ if (this == &other)
+ return *this;
+ prop = other.prop;
+ currentKind = current.set(other.current, other.currentKind, currentKind);
+ previousKind = previous.set(other.previous, other.previousKind, previousKind);
+ return *this;
+ }
+
+
+ QQmlBindEntryContent current;
+ QQmlBindEntryContent previous;
+ QQmlProperty prop;
+ QQmlBindEntryKind currentKind = QQmlBindEntryKind::None;
+ QQmlBindEntryKind previousKind = QQmlBindEntryKind::None;
+
+ void validate(QQmlBind *q) const;
+ void clearPrev();
+ void setTarget(QQmlBind *q, const QQmlProperty &p);
+};
+
class QQmlBindPrivate : public QObjectPrivate
{
public:
QQmlBindPrivate()
- : obj(nullptr)
- , prevBind(QQmlAbstractBinding::Ptr())
- , prevIsVariant(false)
+ : when(true)
, componentComplete(true)
, delayed(false)
, pendingEval(false)
, restoreBinding(true)
, restoreValue(true)
, writingProperty(false)
- {}
+ , lastIsTarget(false)
+ {
+ }
~QQmlBindPrivate() { }
- QQmlNullableValue<bool> when;
+ // There can be multiple entries when using the generalized grouped
+ // property syntax. One is used for target/property/value.
+ QVarLengthArray<QQmlBindEntry, 1> entries;
+
+ // The target object if using the \l target property
QPointer<QObject> obj;
+
+ // Any values we need to create a proxy for. This is necessary when
+ // using the \l delayed member on generalized grouped properties. See
+ // the note on \l delayed.
+ std::unique_ptr<QQmlPropertyMap> delayedValues;
+
+ // The property name if using the \l property property.
QString propName;
- QQmlNullableValue<QJSValue> value;
- QQmlProperty prop;
- QQmlAbstractBinding::Ptr prevBind;
- QV4::PersistentValue v4Value;
- QVariant prevValue;
- bool prevIsVariant:1;
+
+ // Whether the binding is enabled.
+ bool when: 1;
+
+ // Whether we have already parsed any generalized grouped properties
+ // we might need.
bool componentComplete:1;
+
+ // Whether we should run in "delayed" mode and proxy all values before
+ // applying them to the target.
bool delayed:1;
+
+ // In delayed mode, when using the target/property mode, the \l value
+ // is the proxy. Then pendingEval denotes that a timer is active to
+ // apply the value. We should not start another timer then.
bool pendingEval:1;
+
+ // Whether we should restore bindings on !when.
+ // TODO: Deprecate this and always do.
bool restoreBinding:1;
+
+ // Whether we should restore values on !when.
+ // TODO: Deprecate this and always do.
bool restoreValue:1;
- bool writingProperty: 1;
- void validate(QObject *binding) const;
- void clearPrev();
+ // writingProperty tracks whether we are updating the target property
+ // when using target/property/value. We use this information to warn about
+ // binding removal if we detect the target property to be updated while we
+ // are not writing it. This doesn't remove the Binding after all.
+ // For generalized grouped properties, we don't have to do this as writing
+ // the target property does remove the binding, just like it removes any
+ // other binding.
+ bool writingProperty:1;
+
+ // Whether the last entry is the the target property referred to by the
+ // \l target object and the \l property property. This will generally be
+ // the case when using \l target and \l property.
+ bool lastIsTarget:1;
+
+ QQmlBindEntry *targetEntry();
+ void validate(QQmlBind *binding) const;
+ void decodeBinding(
+ QQmlBind *q, const QString &propertyPrefix, QQmlData::DeferredData *deferredData,
+ const QV4::CompiledData::Binding *binding,
+ QQmlComponentPrivate::ConstructionState *immediateState);
+ void createDelayedValues();
+ void onDelayedValueChanged(QString delayedName);
+ void evalDelayed();
+ void buildBindEntries(QQmlBind *q, QQmlComponentPrivate::DeferredState *deferredState);
};
-void QQmlBindPrivate::validate(QObject *binding) const
+void QQmlBindEntry::validate(QQmlBind *q) const
{
- if (!obj || (when.isValid() && !when))
- return;
+ if (!prop.isWritable()) {
+ qmlWarning(q) << "Property '" << prop.name() << "' on "
+ << QQmlMetaType::prettyTypeName(prop.object()) << " is read-only.";
+ }
+}
- if (!prop.isValid()) {
- qmlWarning(binding) << "Property '" << propName << "' does not exist on " << QQmlMetaType::prettyTypeName(obj) << ".";
- return;
+QQmlBindEntry *QQmlBindPrivate::targetEntry()
+{
+ if (!lastIsTarget) {
+ entries.append(QQmlBindEntry());
+ lastIsTarget = true;
}
+ return &entries.last();
+}
- if (!prop.isWritable()) {
- qmlWarning(binding) << "Property '" << propName << "' on " << QQmlMetaType::prettyTypeName(obj) << " is read-only.";
+void QQmlBindPrivate::validate(QQmlBind *q) const
+{
+ if (!when)
return;
+
+ qsizetype iterationEnd = entries.size();
+ if (lastIsTarget) {
+ if (obj) {
+ Q_ASSERT(!entries.isEmpty());
+ const QQmlBindEntry &last = entries.last();
+ if (!last.prop.isValid()) {
+ qmlWarning(q) << "Property '" << propName << "' does not exist on "
+ << QQmlMetaType::prettyTypeName(obj) << ".";
+ --iterationEnd;
+ }
+ } else {
+ --iterationEnd;
+ }
}
+
+ for (qsizetype i = 0; i < iterationEnd; ++i)
+ entries[i].validate(q);
}
/*!
@@ -134,10 +348,10 @@ void QQmlBindPrivate::validate(QObject *binding) const
For example, in a C++ application that maps an "app.enteredText" property
into QML, you can use Binding to update the enteredText property.
- \code
+ \qml
TextEdit { id: myTextField; text: "Please type here..." }
- Binding { target: app; property: "enteredText"; value: myTextField.text }
- \endcode
+ Binding { app.enteredText: myTextField.text }
+ \endqml
When \c{text} changes, the C++ property \c{enteredText} will update
automatically.
@@ -170,29 +384,25 @@ void QQmlBindPrivate::validate(QObject *binding) const
The Binding type restores any previously set direct bindings on the
property.
- \sa {Qt QML}
+ \sa {Qt Qml}
*/
QQmlBind::QQmlBind(QObject *parent)
: QObject(*(new QQmlBindPrivate), parent)
{
}
-QQmlBind::~QQmlBind()
-{
-}
-
/*!
\qmlproperty bool QtQml::Binding::when
This property holds when the binding is active.
This should be set to an expression that evaluates to true when you want the binding to be active.
- \code
+ \qml
Binding {
- target: contactName; property: 'text'
- value: name; when: list.ListView.isCurrentItem
+ contactName.text: name
+ when: list.ListView.isCurrentItem
}
- \endcode
+ \endqml
By default, any binding or value that was set perviously is restored when the binding becomes
inactive. You can customize the restoration behavior using the \l restoreMode property.
@@ -208,7 +418,7 @@ bool QQmlBind::when() const
void QQmlBind::setWhen(bool v)
{
Q_D(QQmlBind);
- if (!d->when.isNull && d->when == v)
+ if (d->when == v)
return;
d->when = v;
@@ -218,9 +428,26 @@ void QQmlBind::setWhen(bool v)
}
/*!
- \qmlproperty Object QtQml::Binding::target
+ \qmlproperty QtObject QtQml::Binding::target
- The object to be updated.
+ The object to be updated. You need to use this property if the binding target
+ does not have an \c id attribute (for example, when the target is a singleton).
+ Otherwise, the following two pieces of code are equivalent:
+
+ \qml
+ Binding { contactName.text: name }
+ \endqml
+
+ \qml
+ Binding {
+ target: contactName
+ property: "text"
+ value: name
+ }
+ \endqml
+
+ The former one is much more compact, but you cannot replace the target
+ object or property at run time. With the latter one you can.
*/
QObject *QQmlBind::object()
{
@@ -231,17 +458,33 @@ QObject *QQmlBind::object()
void QQmlBind::setObject(QObject *obj)
{
Q_D(QQmlBind);
- if (d->obj && d->when.isValid() && d->when) {
+ if (d->obj && d->when) {
/* if we switch the object at runtime, we need to restore the
previous binding on the old object before continuing */
d->when = false;
eval();
d->when = true;
}
+ /* if "when" and "target" depend on the same property, we might
+ end up here before we could have updated "when". So reevaluate
+ when manually here.
+ */
+ const QQmlProperty whenProp(this, QLatin1StringView("when"));
+ const auto potentialWhenBinding = QQmlAnyBinding::ofProperty(whenProp);
+ if (auto abstractBinding = potentialWhenBinding.asAbstractBinding()) {
+ QQmlBinding *binding = static_cast<QQmlBinding *>(abstractBinding);
+ if (binding->hasValidContext()) {
+ const auto boolType = QMetaType::fromType<bool>();
+ bool when;
+ binding->evaluate(&when, boolType);
+ d->when = when;
+ }
+ }
d->obj = obj;
if (d->componentComplete) {
setTarget(QQmlProperty(d->obj, d->propName, qmlContext(this)));
- d->validate(this);
+ if (d->when)
+ d->validate(this);
}
eval();
}
@@ -252,7 +495,7 @@ void QQmlBind::setObject(QObject *obj)
The property to be updated.
This can be a group property if the expression results in accessing a
- property of a \l {QML Basic Types}{value type}. For example:
+ property of a \l {QML Value Types}{value type}. For example:
\qml
Item {
@@ -267,6 +510,14 @@ void QQmlBind::setObject(QObject *obj)
value: 100
}
\endqml
+
+ You only need to use this property if you can't supply the binding target
+ declaratively. The following snippet of code is equivalent to the above
+ binding, but more compact:
+
+ \qml
+ Binding { item.rectangle.x: 100 }
+ \endqml
*/
QString QQmlBind::property() const
{
@@ -277,7 +528,7 @@ QString QQmlBind::property() const
void QQmlBind::setProperty(const QString &p)
{
Q_D(QQmlBind);
- if (!d->propName.isEmpty() && d->when.isValid() && d->when) {
+ if (!d->propName.isEmpty() && d->when) {
/* if we switch the property name at runtime, we need to restore the
previous binding on the old object before continuing */
d->when = false;
@@ -287,27 +538,35 @@ void QQmlBind::setProperty(const QString &p)
d->propName = p;
if (d->componentComplete) {
setTarget(QQmlProperty(d->obj, d->propName, qmlContext(this)));
- d->validate(this);
+ if (d->when)
+ d->validate(this);
}
eval();
}
/*!
- \qmlproperty any QtQml::Binding::value
+ \qmlproperty var QtQml::Binding::value
The value to be set on the target object and property. This can be a
constant (which isn't very useful), or a bound expression.
+
+ You only need to use this property if you can't supply the binding target
+ declaratively. Otherwise you can directly bind to the target.
*/
-QJSValue QQmlBind::value() const
+QVariant QQmlBind::value() const
{
Q_D(const QQmlBind);
- return d->value.value;
+ if (!d->lastIsTarget)
+ return QVariant();
+ Q_ASSERT(d->entries.last().currentKind == QQmlBindEntryKind::Variant);
+ return d->entries.last().current.variant;
}
-void QQmlBind::setValue(const QJSValue &v)
+void QQmlBind::setValue(const QVariant &v)
{
Q_D(QQmlBind);
- d->value = v;
+ QQmlBindEntry *targetEntry = d->targetEntry();
+ targetEntry->currentKind = targetEntry->current.set(v, targetEntry->currentKind);
prepareEval();
}
@@ -323,11 +582,19 @@ void QQmlBind::setValue(const QJSValue &v)
\code
Binding {
- target: contactName; property: 'text'
- value: givenName + " " + familyName; when: list.ListView.isCurrentItem
+ contactName.text.value: givenName + " " + familyName
+ when: list.ListView.isCurrentItem
delayed: true
}
\endcode
+
+ \note Using the \l delayed property incurs a run time cost as the Binding
+ element has to create a proxy for the value, so that it can delay its
+ application to the actual target. When using the \l target and
+ \l property properties, this cost is lower because the \l value
+ property can be re-used as proxy. When using the form shown above,
+ Binding will allocate a separate object with a dynamic meta-object to
+ hold the proxy values.
*/
bool QQmlBind::delayed() const
{
@@ -342,6 +609,28 @@ void QQmlBind::setDelayed(bool delayed)
return;
d->delayed = delayed;
+ if (!d->componentComplete)
+ return;
+
+ d->delayedValues.reset();
+
+ QVarLengthArray<QQmlBindEntry, 1> oldEntries = std::move(d->entries);
+ d->entries.clear();
+ d->buildBindEntries(this, nullptr);
+
+ if (d->lastIsTarget) {
+ d->entries.append(std::move(oldEntries.last()));
+ oldEntries.pop_back();
+ }
+
+ for (qsizetype i = 0, end = oldEntries.size(); i < end; ++i) {
+ QQmlBindEntry &newEntry = d->entries[i];
+ QQmlBindEntry &oldEntry = oldEntries[i];
+ newEntry.previousKind = newEntry.previous.set(
+ std::move(oldEntry.previous), oldEntry.previousKind, newEntry.previousKind);
+ if (d->delayed && oldEntry.currentKind == QQmlBindEntryKind::Binding)
+ QQmlAnyBinding::removeBindingFrom(oldEntry.prop);
+ }
if (!d->delayed)
eval();
@@ -355,23 +644,18 @@ void QQmlBind::setDelayed(bool delayed)
be restored when the binding is disabled.
The possible values are:
- \list
- \li Binding.RestoreNone The original value is not restored at all
- \li Binding.RestoreBinding The original value is restored if it was another
- binding. In that case the old binding is in effect again.
- \li Binding.RestoreValue The original value is restored if it was a plain
- value rather than a binding.
- \li Binding.RestoreBindingOrValue The original value is always restored.
- \endlist
- The default value is \c Binding.RestoreBindingOrValue.
+ \value Binding.RestoreNone The original value is not restored at all
+ \value Binding.RestoreBinding The original value is restored if it was another binding.
+ In that case the old binding is in effect again.
+ \value Binding.RestoreValue The original value is restored if it was a plain
+ value rather than a binding.
+ \value Binding.RestoreBindingOrValue The original value is always restored.
- If you rely on any specific behavior regarding the restoration of plain
- values when bindings get disabled you should migrate to explicitly set the
- restoreMode.
+ The default value is \c Binding.RestoreBindingOrValue.
- Reliance on a restoreMode that doesn't restore the previous binding or value
- for a specific property results in a run-time warning.
+ \note This property exists for backwards compatibility with earlier versions
+ of Qt. Don't use it in new code.
*/
QQmlBind::RestorationMode QQmlBind::restoreMode() const
{
@@ -397,20 +681,24 @@ void QQmlBind::setRestoreMode(RestorationMode newMode)
void QQmlBind::setTarget(const QQmlProperty &p)
{
Q_D(QQmlBind);
+ d->targetEntry()->setTarget(this, p);
+}
+void QQmlBindEntry::setTarget(QQmlBind *q, const QQmlProperty &p)
+{
if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
- if (QObject *oldObject = d->prop.object()) {
- QMetaProperty prop = oldObject->metaObject()->property(d->prop.index());
- if (prop.hasNotifySignal()) {
- QByteArray signal('2' + prop.notifySignal().methodSignature());
+ if (QObject *oldObject = prop.object()) {
+ QMetaProperty metaProp = oldObject->metaObject()->property(prop.index());
+ if (metaProp.hasNotifySignal()) {
+ QByteArray signal('2' + metaProp.notifySignal().methodSignature());
QObject::disconnect(oldObject, signal.constData(),
- this, SLOT(targetValueChanged()));
+ q, SLOT(targetValueChanged()));
}
}
- p.connectNotifySignal(this, SLOT(targetValueChanged()));
+ p.connectNotifySignal(q, SLOT(targetValueChanged()));
}
- d->prop = p;
+ prop = p;
}
void QQmlBind::classBegin()
@@ -419,14 +707,285 @@ void QQmlBind::classBegin()
d->componentComplete = false;
}
+static QQmlAnyBinding createBinding(
+ const QQmlProperty &prop, const QV4::CompiledData::Binding *binding,
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QQmlRefPointer<QQmlContextData> &contextData,
+ QObject *scopeObject)
+{
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Translation:
+ case QV4::CompiledData::Binding::Type_TranslationById:
+ return QQmlAnyBinding::createTranslationBinding(prop, compilationUnit, binding, scopeObject);
+ case QV4::CompiledData::Binding::Type_Script: {
+ const QQmlBinding::Identifier id = binding->value.compiledScriptIndex;
+ if (id == QQmlBinding::Invalid) {
+ return QQmlAnyBinding::createFromCodeString(
+ prop, compilationUnit->bindingValueAsString(binding), scopeObject,
+ contextData, compilationUnit->finalUrlString(), binding->location.line());
+ }
+ QV4::Scope scope(contextData->engine()->handle());
+ QV4::Scoped<QV4::QmlContext> qmlCtxt(
+ scope, QV4::QmlContext::create(
+ scope.engine->rootContext(), contextData, scopeObject));
+ return QQmlAnyBinding::createFromFunction(
+ prop, compilationUnit->runtimeFunctions.at(id), scopeObject, contextData,
+ qmlCtxt);
+ }
+ default:
+ break;
+ }
+ return QQmlAnyBinding();
+}
+
+static void initCreator(
+ QQmlData::DeferredData *deferredData,
+ const QQmlRefPointer<QQmlContextData> &contextData,
+ QQmlComponentPrivate::ConstructionState *immediateState)
+{
+ if (!immediateState->hasCreator()) {
+ immediateState->setCompletePending(true);
+ immediateState->initCreator(
+ deferredData->context->parent(), deferredData->compilationUnit,
+ contextData);
+ immediateState->creator()->beginPopulateDeferred(deferredData->context);
+ }
+}
+
+void QQmlBindPrivate::decodeBinding(
+ QQmlBind *q, const QString &propertyPrefix,
+ QQmlData::DeferredData *deferredData,
+ const QV4::CompiledData::Binding *binding,
+ QQmlComponentPrivate::ConstructionState *immediateState)
+{
+ const QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
+ = deferredData->compilationUnit;
+ const QString propertySuffix = compilationUnit->stringAt(binding->propertyNameIndex);
+ const QString propertyName = propertyPrefix + propertySuffix;
+
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ if (propertyPrefix.isEmpty()) {
+ // Top-level attached properties cannot be generalized grouped properties.
+ // Treat them as regular properties.
+ // ... unless we're not supposed to handle regular properties. Then ignore them.
+ if (!immediateState)
+ return;
+
+ Q_ASSERT(compilationUnit->stringAt(compilationUnit->objectAt(binding->value.objectIndex)
+ ->inheritedTypeNameIndex).isEmpty());
+
+ const QV4::ResolvedTypeReference *typeReference
+ = compilationUnit->resolvedType(binding->propertyNameIndex);
+ Q_ASSERT(typeReference);
+ QQmlType attachedType = typeReference->type();
+ if (!attachedType.isValid()) {
+ if (QQmlTypeLoader *typeLoader = compilationUnit->engine->typeLoader()) {
+ const QQmlTypeNameCache::Result result
+ = deferredData->context->imports()->query(propertySuffix, typeLoader);
+ if (!result.isValid()) {
+ qmlWarning(q).nospace()
+ << "Unknown name " << propertySuffix << ". The binding is ignored.";
+ return;
+ }
+ attachedType = result.type;
+ }
+ }
+
+ QQmlContext *context = qmlContext(q);
+ QObject *attachedObject = qmlAttachedPropertiesObject(
+ q, attachedType.attachedPropertiesFunction(
+ QQmlEnginePrivate::get(context->engine())));
+ if (!attachedObject) {
+ qmlWarning(q).nospace() <<"Could not create attached properties object '"
+ << attachedType.typeName() << "'";
+ return;
+ }
+
+ initCreator(deferredData, QQmlContextData::get(context), immediateState);
+ immediateState->creator()->populateDeferredInstance(
+ q, deferredData->deferredIdx, binding->value.objectIndex, attachedObject,
+ attachedObject, /*value type property*/ nullptr, binding);
+ return;
+ }
+ Q_FALLTHROUGH();
+ case QV4::CompiledData::Binding::Type_GroupProperty: {
+ const QString pre = propertyName + u'.';
+ const QV4::CompiledData::Object *subObj
+ = compilationUnit->objectAt(binding->value.objectIndex);
+ const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
+ for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding)
+ decodeBinding(q, pre, deferredData, subBinding, immediateState);
+ return;
+ }
+ default:
+ break;
+ }
+
+ QQmlBindEntry entry;
+ QQmlContext *context = qmlContext(q);
+ const QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(context);
+ entry.prop = QQmlPropertyPrivate::create(nullptr, propertyName, contextData,
+ QQmlPropertyPrivate::InitFlag::AllowId);
+ if (!entry.prop.isValid()) {
+ // Try again in the context of this object. If that works, it's a regular property.
+ // ... unless we're not supposed to handle regular properties. Then ignore it.
+ if (!immediateState)
+ return;
+
+ QQmlProperty property = QQmlPropertyPrivate::create(
+ q, propertyName, contextData, QQmlPropertyPrivate::InitFlag::AllowSignal);
+ if (property.isValid()) {
+ initCreator(deferredData, contextData, immediateState);
+ immediateState->creator()->populateDeferredBinding(
+ property, deferredData->deferredIdx, binding);
+ } else {
+ qmlWarning(q).nospace() << "Unknown name " << propertyName
+ << ". The binding is ignored.";
+ }
+ return;
+ }
+
+ const auto setVariant = [&entry](QVariant var) {
+ entry.currentKind = entry.current.set(std::move(var), entry.currentKind);
+ };
+
+ const auto setBinding = [&entry](QQmlAnyBinding binding) {
+ entry.currentKind = entry.current.set(binding, entry.currentKind);
+ };
+
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ Q_UNREACHABLE(); // Handled above
+ break;
+ case QV4::CompiledData::Binding::Type_Translation:
+ case QV4::CompiledData::Binding::Type_TranslationById:
+ case QV4::CompiledData::Binding::Type_Script:
+ if (delayed) {
+ if (!delayedValues)
+ createDelayedValues();
+ const QString delayedName = QString::number(entries.size());
+ delayedValues->insert(delayedName, QVariant());
+ QQmlProperty bindingTarget = QQmlProperty(delayedValues.get(), delayedName);
+ Q_ASSERT(bindingTarget.isValid());
+ QQmlAnyBinding anyBinding = createBinding(
+ bindingTarget, binding, compilationUnit, contextData, q);
+ anyBinding.installOn(bindingTarget);
+ } else {
+ setBinding(createBinding(entry.prop, binding, compilationUnit, contextData, q));
+ }
+ break;
+ case QV4::CompiledData::Binding::Type_String:
+ setVariant(compilationUnit->bindingValueAsString(binding));
+ break;
+ case QV4::CompiledData::Binding::Type_Number:
+ setVariant(compilationUnit->bindingValueAsNumber(binding));
+ break;
+ case QV4::CompiledData::Binding::Type_Boolean:
+ setVariant(binding->valueAsBoolean());
+ break;
+ case QV4::CompiledData::Binding::Type_Null:
+ setVariant(QVariant::fromValue(nullptr));
+ break;
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_Invalid:
+ break;
+ }
+
+ entries.append(std::move(entry));
+}
+
+void QQmlBindPrivate::createDelayedValues()
+{
+ delayedValues = std::make_unique<QQmlPropertyMap>();
+ QObject::connect(
+ delayedValues.get(), &QQmlPropertyMap::valueChanged,
+ delayedValues.get(), [this](QString delayedName, const QVariant &value) {
+ Q_UNUSED(value);
+ onDelayedValueChanged(std::move(delayedName));
+ }
+ );
+}
+
+void QQmlBindPrivate::onDelayedValueChanged(QString delayedName)
+{
+ Q_ASSERT(delayed);
+ Q_ASSERT(delayedValues);
+ const QString pendingName = QStringLiteral("pending");
+ QStringList pending = qvariant_cast<QStringList>((*delayedValues)[pendingName]);
+ if (componentComplete && pending.size() == 0)
+ QTimer::singleShot(0, delayedValues.get(), [this]() { evalDelayed(); });
+ else if (pending.contains(delayedName))
+ return;
+
+ pending.append(std::move(delayedName));
+ (*delayedValues)[pendingName].setValue(std::move(pending));
+}
+
+void QQmlBindPrivate::evalDelayed()
+{
+ if (!when || !delayedValues)
+ return;
+
+ const QString pendingName = QStringLiteral("pending");
+ const QStringList pending = qvariant_cast<QStringList>((*delayedValues)[pendingName]);
+ for (const QString &delayedName : pending) {
+ bool ok;
+ const int delayedIndex = delayedName.toInt(&ok);
+ Q_ASSERT(ok);
+ Q_ASSERT(delayedIndex >= 0 && delayedIndex < entries.size());
+ entries[delayedIndex].prop.write((*delayedValues)[delayedName]);
+ }
+ (*delayedValues)[pendingName].setValue(QStringList());
+}
+
+void QQmlBindPrivate::buildBindEntries(QQmlBind *q, QQmlComponentPrivate::DeferredState *deferredState)
+{
+ QQmlData *data = QQmlData::get(q);
+ if (data && !data->deferredData.isEmpty()) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
+ for (QQmlData::DeferredData *deferredData : data->deferredData) {
+ QMultiHash<int, const QV4::CompiledData::Binding *> *bindings = &deferredData->bindings;
+ if (deferredState) {
+ QQmlComponentPrivate::ConstructionState constructionState;
+ for (auto it = bindings->cbegin(); it != bindings->cend(); ++it)
+ decodeBinding(q, QString(), deferredData, *it, &constructionState);
+
+
+ if (constructionState.hasCreator()) {
+ ++ep->inProgressCreations;
+ constructionState.creator()->finalizePopulateDeferred();
+ constructionState.appendCreatorErrors();
+ deferredState->push_back(std::move(constructionState));
+ }
+ } else {
+ for (auto it = bindings->cbegin(); it != bindings->cend(); ++it)
+ decodeBinding(q, QString(), deferredData, *it, nullptr);
+ }
+ }
+
+ if (deferredState) {
+ data->releaseDeferredData();
+ if (!deferredState->empty())
+ QQmlComponentPrivate::completeDeferred(ep, deferredState);
+ }
+ }
+}
+
void QQmlBind::componentComplete()
{
Q_D(QQmlBind);
+ QQmlComponentPrivate::DeferredState deferredState;
+ d->buildBindEntries(this, &deferredState);
d->componentComplete = true;
- if (!d->prop.isValid()) {
- setTarget(QQmlProperty(d->obj, d->propName, qmlContext(this)));
- d->validate(this);
+ if (!d->propName.isEmpty() || d->obj) {
+ QQmlBindEntry *target = d->targetEntry();
+ if (!target->prop.isValid())
+ target->setTarget(this, QQmlProperty(d->obj, d->propName, qmlContext(this)));
}
+ d->validate(this);
+ d->evalDelayed();
eval();
}
@@ -442,72 +1001,110 @@ void QQmlBind::prepareEval()
}
}
-void QQmlBindPrivate::clearPrev()
+void QQmlBindEntry::clearPrev()
{
- prevBind = nullptr;
- v4Value.clear();
- prevValue.clear();
- prevIsVariant = false;
+ previousKind = previous.destroy(previousKind);
}
void QQmlBind::eval()
{
Q_D(QQmlBind);
d->pendingEval = false;
- if (!d->prop.isValid() || d->value.isNull || !d->componentComplete)
+ if (!d->componentComplete)
return;
- if (d->when.isValid()) {
+ for (QQmlBindEntry &entry : d->entries) {
+ if (!entry.prop.isValid() || (entry.currentKind == QQmlBindEntryKind::None))
+ continue;
+
if (!d->when) {
//restore any previous binding
- if (d->prevBind) {
+ switch (entry.previousKind) {
+ case QQmlBindEntryKind::Binding:
if (d->restoreBinding) {
- QQmlAbstractBinding::Ptr p = d->prevBind;
- d->clearPrev(); // Do that before setBinding(), as setBinding() may recurse.
- QQmlPropertyPrivate::setBinding(p.data());
+ QQmlAnyBinding p = std::move(entry.previous.binding);
+ entry.clearPrev(); // Do that before setBinding(), as setBinding() may recurse.
+ p.installOn(entry.prop);
}
- } else if (!d->v4Value.isEmpty()) {
+ break;
+ case QQmlBindEntryKind::V4Value:
if (d->restoreValue) {
- auto propPriv = QQmlPropertyPrivate::get(d->prop);
+ QQmlAnyBinding::takeFrom(entry.prop); // we don't want to have a binding active
+ auto propPriv = QQmlPropertyPrivate::get(entry.prop);
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
Q_ASSERT(vmemo);
- vmemo->setVMEProperty(propPriv->core.coreIndex(), *d->v4Value.valueRef());
- d->clearPrev();
+ vmemo->setVMEProperty(propPriv->core.coreIndex(),
+ *entry.previous.v4Value.valueRef());
+ entry.clearPrev();
}
- } else if (d->prevIsVariant) {
+ break;
+ case QQmlBindEntryKind::Variant:
if (d->restoreValue) {
- d->prop.write(d->prevValue);
- d->clearPrev();
+ QQmlAnyBinding::takeFrom(entry.prop); // we don't want to have a binding active
+ entry.prop.write(entry.previous.variant);
+ entry.clearPrev();
}
+ break;
+ case QQmlBindEntryKind::None:
+ break;
}
- return;
+ continue;
}
//save any set binding for restoration
- if (!d->prevBind && d->v4Value.isEmpty() && !d->prevIsVariant) {
- // try binding first
- d->prevBind = QQmlPropertyPrivate::binding(d->prop);
-
- if (!d->prevBind) { // nope, try a V4 value next
- auto propPriv = QQmlPropertyPrivate::get(d->prop);
+ if (entry.previousKind == QQmlBindEntryKind::None) {
+ // try binding first; we need to use takeFrom to properly unlink the binding
+ QQmlAnyBinding prevBind = QQmlAnyBinding::takeFrom(entry.prop);
+ if (prevBind) {
+ entry.previousKind = entry.previous.set(std::move(prevBind), entry.previousKind);
+ } else {
+ // nope, try a V4 value next
+ auto propPriv = QQmlPropertyPrivate::get(entry.prop);
auto propData = propPriv->core;
if (!propPriv->valueTypeData.isValid() && propData.isVarProperty()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
Q_ASSERT(vmemo);
auto retVal = vmemo->vmeProperty(propData.coreIndex());
- d->v4Value = QV4::PersistentValue(vmemo->engine, retVal);
- } else { // nope, use the meta object to get a QVariant
- d->prevValue = d->prop.read();
- d->prevIsVariant = true;
+ entry.previousKind = entry.previous.set(
+ QV4::PersistentValue(vmemo->engine, retVal), entry.previousKind);
+ } else {
+ // nope, use the meta object to get a QVariant
+ entry.previousKind = entry.previous.set(entry.prop.read(), entry.previousKind);
}
}
}
- QQmlPropertyPrivate::removeBinding(d->prop);
+ // NOTE: removeBinding has no effect on QProperty classes, but
+ // we already used takeBinding to remove it
+ QQmlPropertyPrivate::removeBinding(entry.prop);
}
+ if (!d->when)
+ return;
+
d->writingProperty = true;
- d->prop.write(d->value.value.toVariant());
+ for (qsizetype i = 0, end = d->entries.size(); i != end; ++i) {
+ QQmlBindEntry &entry = d->entries[i];
+ if (!entry.prop.isValid())
+ continue;
+ switch (entry.currentKind) {
+ case QQmlBindEntryKind::Variant:
+ entry.prop.write(entry.current.variant);
+ break;
+ case QQmlBindEntryKind::Binding:
+ Q_ASSERT(!d->delayed);
+ entry.current.binding.installOn(entry.prop);
+ break;
+ case QQmlBindEntryKind::V4Value: {
+ auto propPriv = QQmlPropertyPrivate::get(entry.prop);
+ QQmlVMEMetaObject::get(propPriv->object)->setVMEProperty(
+ propPriv->core.coreIndex(), *entry.current.v4Value.valueRef());
+ break;
+ }
+ case QQmlBindEntryKind::None:
+ break;
+ }
+ }
d->writingProperty = false;
}
@@ -517,7 +1114,7 @@ void QQmlBind::targetValueChanged()
if (d->writingProperty)
return;
- if (d->when.isValid() && !d->when)
+ if (!d->when)
return;
QUrl url;
diff --git a/src/qml/types/qqmlbind_p.h b/src/qml/types/qqmlbind_p.h
index c709224c23..aaefbc0618 100644
--- a/src/qml/types/qqmlbind_p.h
+++ b/src/qml/types/qqmlbind_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLBIND_H
#define QQMLBIND_H
@@ -51,14 +15,15 @@
// We mean it.
//
-#include <qqml.h>
+#include <private/qtqmlglobal_p.h>
+#include <QtQml/qqml.h>
#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
class QQmlBindPrivate;
-class Q_AUTOTEST_EXPORT QQmlBind : public QObject, public QQmlPropertyValueSource, public QQmlParserStatus
+class Q_QML_EXPORT QQmlBind : public QObject, public QQmlPropertyValueSource, public QQmlParserStatus
{
public:
enum RestorationMode {
@@ -75,17 +40,18 @@ private:
Q_INTERFACES(QQmlPropertyValueSource)
Q_PROPERTY(QObject *target READ object WRITE setObject)
Q_PROPERTY(QString property READ property WRITE setProperty)
- Q_PROPERTY(QJSValue value READ value WRITE setValue)
+ Q_PROPERTY(QVariant value READ value WRITE setValue)
Q_PROPERTY(bool when READ when WRITE setWhen)
- Q_PROPERTY(bool delayed READ delayed WRITE setDelayed REVISION 8)
+ Q_PROPERTY(bool delayed READ delayed WRITE setDelayed REVISION(2, 8))
Q_PROPERTY(RestorationMode restoreMode READ restoreMode WRITE setRestoreMode
- NOTIFY restoreModeChanged REVISION 14)
+ NOTIFY restoreModeChanged REVISION(2, 14))
Q_ENUM(RestorationMode)
QML_NAMED_ELEMENT(Binding)
+ QML_ADDED_IN_VERSION(2, 0)
+ Q_CLASSINFO("ImmediatePropertyNames", "objectName,target,property,value,when,delayed,restoreMode");
public:
QQmlBind(QObject *parent=nullptr);
- ~QQmlBind();
bool when() const;
void setWhen(bool);
@@ -96,8 +62,8 @@ public:
QString property() const;
void setProperty(const QString &);
- QJSValue value() const;
- void setValue(const QJSValue &);
+ QVariant value() const;
+ void setValue(const QVariant &);
bool delayed() const;
void setDelayed(bool);
@@ -123,6 +89,4 @@ private Q_SLOTS:
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlBind)
-
#endif
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 1e801641e5..19363f9f76 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -1,71 +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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlconnections_p.h"
-#include <private/qqmlexpression_p.h>
-#include <private/qqmlproperty_p.h>
#include <private/qqmlboundsignal_p.h>
-#include <qqmlcontext.h>
#include <private/qqmlcontext_p.h>
+#include <private/qqmlexpression_p.h>
+#include <private/qqmlproperty_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <private/qqmlvmemetaobject_p.h>
-#include <qqmlinfo.h>
+#include <private/qv4jscall_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlinfo.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qstringlist.h>
#include <private/qobject_p.h>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQmlConnections, "qt.qml.connections")
+
+// This is the equivalent of QQmlBoundSignal for C++ methods as as slots.
+// If a type derived from QQmlConnnections is compiled using qmltc, the
+// JavaScript functions it contains are turned into C++ methods and we cannot
+// use QQmlBoundSignal to connect to those.
+struct QQmlConnectionSlotDispatcher : public QtPrivate::QSlotObjectBase
+{
+ QV4::ExecutionEngine *v4 = nullptr;
+ QObject *receiver = nullptr;
+
+ // Signals rarely have more than one argument.
+ QQmlMetaObject::ArgTypeStorage<2> signalMetaTypes;
+ QQmlMetaObject::ArgTypeStorage<2> slotMetaTypes;
+
+ QMetaObject::Connection connection;
+
+ int slotIndex = -1;
+ bool enabled = true;
+
+ QQmlConnectionSlotDispatcher(
+ QV4::ExecutionEngine *v4, QObject *sender, int signalIndex,
+ QObject *receiver, int slotIndex, bool enabled)
+ : QtPrivate::QSlotObjectBase(&impl)
+ , v4(v4)
+ , receiver(receiver)
+ , slotIndex(slotIndex)
+ , enabled(enabled)
+ {
+ QMetaMethod signal = sender->metaObject()->method(signalIndex);
+ QQmlMetaObject::methodReturnAndParameterTypes(signal, &signalMetaTypes, nullptr);
+
+ QMetaMethod slot = receiver->metaObject()->method(slotIndex);
+ QQmlMetaObject::methodReturnAndParameterTypes(slot, &slotMetaTypes, nullptr);
+ }
+
+ template<typename ArgTypeStorage>
+ struct TypedFunction
+ {
+ Q_DISABLE_COPY_MOVE(TypedFunction)
+ public:
+ TypedFunction(const ArgTypeStorage *storage) : storage(storage) {}
+
+ QMetaType returnMetaType() const { return storage->at(0); }
+ qsizetype parameterCount() const { return storage->size() - 1; }
+ QMetaType parameterMetaType(qsizetype i) const { return storage->at(i + 1); }
+
+ private:
+ const ArgTypeStorage *storage;
+ };
+
+ static void impl(int which, QSlotObjectBase *base, QObject *, void **metaArgs, bool *ret)
+ {
+ switch (which) {
+ case Destroy: {
+ delete static_cast<QQmlConnectionSlotDispatcher *>(base);
+ break;
+ }
+ case Call: {
+ QQmlConnectionSlotDispatcher *self = static_cast<QQmlConnectionSlotDispatcher *>(base);
+ QV4::ExecutionEngine *v4 = self->v4;
+ if (!v4)
+ break;
+
+ if (!self->enabled)
+ break;
+
+ TypedFunction typedFunction(&self->slotMetaTypes);
+ QV4::coerceAndCall(
+ v4, &typedFunction, metaArgs,
+ self->signalMetaTypes.data(), self->signalMetaTypes.size() - 1,
+ [&](void **argv, int) {
+ self->receiver->metaObject()->metacall(
+ self->receiver, QMetaObject::InvokeMetaMethod,
+ self->slotIndex, argv);
+ });
+
+ if (v4->hasException) {
+ QQmlError error = v4->catchExceptionAsQmlError();
+ if (QQmlEngine *qmlEngine = v4->qmlEngine()) {
+ QQmlEnginePrivate::get(qmlEngine)->warning(error);
+ } else {
+ QMessageLogger(
+ qPrintable(error.url().toString()), error.line(), nullptr)
+ .warning().noquote()
+ << error.toString();
+ }
+ }
+ break;
+ }
+ case Compare:
+ // We're not implementing the Compare protocol here. It's insane.
+ // QQmlConnectionSlotDispatcher compares false to anything. We use
+ // the regular QObject::disconnect with QMetaObject::Connection.
+ *ret = false;
+ break;
+ case NumOperations:
+ break;
+ }
+ };
+};
+
class QQmlConnectionsPrivate : public QObjectPrivate
{
public:
- QQmlConnectionsPrivate() : target(nullptr), enabled(true), targetSet(false), ignoreUnknownSignals(false), componentcomplete(true) {}
+ QList<QBiPointer<QQmlBoundSignal, QQmlConnectionSlotDispatcher>> boundsignals;
+ QQmlGuard<QObject> target;
- QList<QQmlBoundSignal*> boundsignals;
- QObject *target;
-
- bool enabled;
- bool targetSet;
- bool ignoreUnknownSignals;
- bool componentcomplete;
+ bool enabled = true;
+ bool targetSet = false;
+ bool ignoreUnknownSignals = false;
+ bool componentcomplete = true;
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
QList<const QV4::CompiledData::Binding *> bindings;
@@ -85,7 +154,7 @@ public:
\qml
MouseArea {
- onClicked: { foo(parameters) }
+ onClicked: (mouse)=> { foo(mouse) }
}
\endqml
@@ -127,7 +196,13 @@ public:
}
\endqml
- \sa {Qt QML}
+ \note For backwards compatibility you can also specify the signal handlers
+ without \c{function}, like you would specify them directly in the target
+ object. This is not recommended. If you specify one signal handler this way,
+ then all signal handlers specified as \c{function} in the same Connections
+ object are ignored.
+
+ \sa {Qt Qml}
*/
QQmlConnections::QQmlConnections(QObject *parent) :
QObject(*(new QQmlConnectionsPrivate), parent)
@@ -136,10 +211,22 @@ QQmlConnections::QQmlConnections(QObject *parent) :
QQmlConnections::~QQmlConnections()
{
+ Q_D(QQmlConnections);
+
+ // The slot dispatchers hold cyclic references to their connections. Clear them.
+ for (const auto &bound : std::as_const(d->boundsignals)) {
+ if (QQmlConnectionSlotDispatcher *dispatcher = bound.isT2() ? bound.asT2() : nullptr) {
+ // No need to explicitly disconnect anymore since 'this' is the receiver.
+ // But to be safe, explicitly break any cyclic references between the connection
+ // and the slot object.
+ dispatcher->connection = {};
+ dispatcher->destroyIfLastRef();
+ }
+ }
}
/*!
- \qmlproperty Object QtQml::Connections::target
+ \qmlproperty QtObject QtQml::Connections::target
This property holds the object that sends the signal.
If this property is not set, the \c target defaults to the parent of the Connection.
@@ -150,7 +237,7 @@ QQmlConnections::~QQmlConnections()
QObject *QQmlConnections::target() const
{
Q_D(const QQmlConnections);
- return d->targetSet ? d->target : parent();
+ return d->targetSet ? d->target.data() : parent();
}
class QQmlBoundSignalDeleter : public QObject
@@ -169,13 +256,19 @@ void QQmlConnections::setTarget(QObject *obj)
if (d->targetSet && d->target == obj)
return;
d->targetSet = true; // even if setting to 0, it is *set*
- for (QQmlBoundSignal *s : qAsConst(d->boundsignals)) {
+ for (const auto &bound : std::as_const(d->boundsignals)) {
// It is possible that target is being changed due to one of our signal
// handlers -> use deleteLater().
- if (s->isNotifying())
- (new QQmlBoundSignalDeleter(s))->deleteLater();
- else
- delete s;
+ if (QQmlBoundSignal *signal = bound.isT1() ? bound.asT1() : nullptr) {
+ if (signal->isNotifying())
+ (new QQmlBoundSignalDeleter(signal))->deleteLater();
+ else
+ delete signal;
+ } else {
+ QQmlConnectionSlotDispatcher *dispatcher = bound.asT2();
+ QObject::disconnect(std::exchange(dispatcher->connection, {}));
+ dispatcher->destroyIfLastRef();
+ }
}
d->boundsignals.clear();
d->target = obj;
@@ -205,8 +298,12 @@ void QQmlConnections::setEnabled(bool enabled)
d->enabled = enabled;
- for (QQmlBoundSignal *s : qAsConst(d->boundsignals))
- s->setEnabled(d->enabled);
+ for (const auto &bound : std::as_const(d->boundsignals)) {
+ if (QQmlBoundSignal *signal = bound.isT1() ? bound.asT1() : nullptr)
+ signal->setEnabled(d->enabled);
+ else
+ bound.asT2()->enabled = enabled;
+ }
emit enabledChanged();
}
@@ -234,26 +331,29 @@ void QQmlConnections::setIgnoreUnknownSignals(bool ignore)
void QQmlConnectionsParser::verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props)
{
- for (int ii = 0; ii < props.count(); ++ii) {
+ for (int ii = 0; ii < props.size(); ++ii) {
const QV4::CompiledData::Binding *binding = props.at(ii);
const QString &propName = compilationUnit->stringAt(binding->propertyNameIndex);
- if (!propName.startsWith(QLatin1String("on")) || (propName.length() < 3 || !propName.at(2).isUpper())) {
+ if (!QQmlSignalNames::isHandlerName(propName)) {
error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
return;
}
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Script)
+ continue;
+
+ if (binding->type() >= QV4::CompiledData::Binding::Type_Object) {
const QV4::CompiledData::Object *target = compilationUnit->objectAt(binding->value.objectIndex);
if (!compilationUnit->stringAt(target->inheritedTypeNameIndex).isEmpty())
error(binding, QQmlConnections::tr("Connections: nested objects not allowed"));
else
error(binding, QQmlConnections::tr("Connections: syntax error"));
return;
- } if (binding->type != QV4::CompiledData::Binding::Type_Script) {
- error(binding, QQmlConnections::tr("Connections: script expected"));
- return;
}
+
+ error(binding, QQmlConnections::tr("Connections: script expected"));
+ return;
}
}
@@ -274,10 +374,10 @@ void QQmlConnections::connectSignals()
if (d->bindings.isEmpty()) {
connectSignalsToMethods();
} else {
-#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
- qmlWarning(this) << tr("Implicitly defined onFoo properties in Connections are deprecated. "
- "Use this syntax instead: function onFoo(<arguments>) { ... }");
-#endif
+ if (lcQmlConnections().isWarningEnabled()) {
+ qmlWarning(this) << tr("Implicitly defined onFoo properties in Connections are deprecated. "
+ "Use this syntax instead: function onFoo(<arguments>) { ... }");
+ }
connectSignalsToBindings();
}
}
@@ -291,44 +391,52 @@ void QQmlConnections::connectSignalsToMethods()
if (!ddata)
return;
- QV4::ExecutionEngine *engine = ddata->context->engine->handle();
+ QV4::ExecutionEngine *engine = ddata->context->engine()->handle();
- QQmlContextData *ctxtdata = ddata->outerContext;
+ QQmlRefPointer<QQmlContextData> ctxtdata = ddata->outerContext;
for (int i = ddata->propertyCache->methodOffset(),
end = ddata->propertyCache->methodOffset() + ddata->propertyCache->methodCount();
i < end;
++i) {
- QQmlPropertyData *handler = ddata->propertyCache->method(i);
- if (!handler || !handler->isVMEFunction())
+ const QQmlPropertyData *handler = ddata->propertyCache->method(i);
+ if (!handler)
continue;
const QString propName = handler->name(this);
QQmlProperty prop(target, propName);
if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) {
- int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex();
- auto *signal = new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
- signal->setEnabled(d->enabled);
-
QV4::Scope scope(engine);
QV4::ScopedContext global(scope, engine->rootContext());
- QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(this);
- Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
-
- QV4::ScopedFunctionObject method(scope, vmeMetaObject->vmeMethod(handler->coreIndex()));
-
- QQmlBoundSignalExpression *expression =
- ctxtdata ? new QQmlBoundSignalExpression(
- target, signalIndex, ctxtdata, this,
- method->as<QV4::FunctionObject>()->function())
- : nullptr;
-
- signal->takeExpression(expression);
- d->boundsignals += signal;
+ if (QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(this)) {
+ int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex();
+ auto *signal = new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
+ signal->setEnabled(d->enabled);
+
+ QV4::ScopedFunctionObject method(
+ scope, vmeMetaObject->vmeMethod(handler->coreIndex()));
+
+ QQmlBoundSignalExpression *expression = ctxtdata
+ ? new QQmlBoundSignalExpression(
+ target, signalIndex, ctxtdata, this,
+ method->as<QV4::FunctionObject>()->function())
+ : nullptr;
+
+ signal->takeExpression(expression);
+ d->boundsignals += signal;
+ } else {
+ QQmlConnectionSlotDispatcher *slot = new QQmlConnectionSlotDispatcher(
+ scope.engine, target, prop.index(),
+ this, handler->coreIndex(), d->enabled);
+ slot->connection = QObjectPrivate::connect(
+ target, prop.index(), slot, Qt::AutoConnection);
+ slot->ref();
+ d->boundsignals += slot;
+ }
} else if (!d->ignoreUnknownSignals
- && propName.startsWith(QLatin1String("on")) && propName.length() > 2
+ && propName.startsWith(QLatin1String("on")) && propName.size() > 2
&& propName.at(2).isUpper()) {
qmlWarning(this) << tr("Detected function \"%1\" in Connections element. "
"This is probably intended to be a signal handler but no "
@@ -343,10 +451,10 @@ void QQmlConnections::connectSignalsToBindings()
Q_D(QQmlConnections);
QObject *target = this->target();
QQmlData *ddata = QQmlData::get(this);
- QQmlContextData *ctxtdata = ddata ? ddata->outerContext : nullptr;
+ QQmlRefPointer<QQmlContextData> ctxtdata = ddata ? ddata->outerContext : nullptr;
- for (const QV4::CompiledData::Binding *binding : qAsConst(d->bindings)) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
+ for (const QV4::CompiledData::Binding *binding : std::as_const(d->bindings)) {
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
QString propName = d->compilationUnit->stringAt(binding->propertyNameIndex);
QQmlProperty prop(target, propName);
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index 7bf688cf75..e0100aa452 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLCONNECTIONS_H
#define QQMLCONNECTIONS_H
@@ -62,19 +26,21 @@ QT_BEGIN_NAMESPACE
class QQmlBoundSignal;
class QQmlContext;
class QQmlConnectionsPrivate;
-class Q_AUTOTEST_EXPORT QQmlConnections : public QObject, public QQmlParserStatus
+class Q_QML_EXPORT QQmlConnections : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlConnections)
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
- Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged REVISION 3)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged REVISION(2, 3))
Q_PROPERTY(bool ignoreUnknownSignals READ ignoreUnknownSignals WRITE setIgnoreUnknownSignals)
QML_NAMED_ELEMENT(Connections)
+ QML_ADDED_IN_VERSION(2, 0)
+ QML_CUSTOMPARSER
public:
- QQmlConnections(QObject *parent=nullptr);
+ QQmlConnections(QObject *parent = nullptr);
~QQmlConnections();
QObject *target() const;
@@ -86,17 +52,18 @@ public:
bool ignoreUnknownSignals() const;
void setIgnoreUnknownSignals(bool ignore);
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
Q_SIGNALS:
void targetChanged();
- Q_REVISION(3) void enabledChanged();
+ Q_REVISION(2, 3) void enabledChanged();
private:
void connectSignals();
void connectSignalsToMethods();
void connectSignalsToBindings();
-
- void classBegin() override;
- void componentComplete() override;
};
// TODO: Drop this class as soon as we can
@@ -117,6 +84,4 @@ inline QQmlCustomParser *qmlCreateCustomParser<QQmlConnections>()
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlConnections)
-
#endif
diff --git a/src/qml/types/qqmlmodelindexvaluetype.cpp b/src/qml/types/qqmlmodelindexvaluetype.cpp
deleted file mode 100644
index cbf2fef348..0000000000
--- a/src/qml/types/qqmlmodelindexvaluetype.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlmodelindexvaluetype_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \internal
-*/
-QString QQmlModelIndexValueType::propertiesString(const QModelIndex &idx)
-{
- if (!idx.isValid())
- return QLatin1String("()");
- return QString(QLatin1String("(%1,%2,0x%3,%4(0x%5))"))
- .arg(idx.row()).arg(idx.column()).arg(idx.internalId(), 0, 16)
- .arg(QLatin1String(idx.model()->metaObject()->className())).arg(quintptr(idx.model()), 0, 16);
-}
-
-/*!
- \internal
-*/
-QString QQmlItemSelectionRangeValueType::toString() const
-{
- return QString(QLatin1String("QItemSelectionRange(%1,%2)"))
- .arg(reinterpret_cast<const QQmlPersistentModelIndexValueType *>(&v.topLeft())->toString())
- .arg(reinterpret_cast<const QQmlPersistentModelIndexValueType *>(&v.bottomRight())->toString());
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qqmlmodelindexvaluetype_p.cpp"
diff --git a/src/qml/types/qqmlmodelindexvaluetype_p.h b/src/qml/types/qqmlmodelindexvaluetype_p.h
deleted file mode 100644
index f5b1699574..0000000000
--- a/src/qml/types/qqmlmodelindexvaluetype_p.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLMODELINDEXVALUETYPE_P_H
-#define QQMLMODELINDEXVALUETYPE_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/qabstractitemmodel.h>
-#include <QtCore/qitemselectionmodel.h>
-
-QT_BEGIN_NAMESPACE
-
-struct QQmlModelIndexValueType
-{
- QModelIndex v;
-
- Q_PROPERTY(int row READ row CONSTANT FINAL)
- Q_PROPERTY(int column READ column CONSTANT FINAL)
- Q_PROPERTY(QModelIndex parent READ parent FINAL)
- Q_PROPERTY(bool valid READ isValid CONSTANT FINAL)
- Q_PROPERTY(QAbstractItemModel *model READ model CONSTANT FINAL)
- Q_PROPERTY(quint64 internalId READ internalId CONSTANT FINAL)
- Q_GADGET
-
-public:
- Q_INVOKABLE QString toString() const
- { return QLatin1String("QModelIndex") + propertiesString(v); }
-
- inline int row() const Q_DECL_NOTHROW { return v.row(); }
- inline int column() const Q_DECL_NOTHROW { return v.column(); }
- inline QModelIndex parent() const { return v.parent(); }
- inline bool isValid() const Q_DECL_NOTHROW { return v.isValid(); }
- inline QAbstractItemModel *model() const Q_DECL_NOTHROW
- { return const_cast<QAbstractItemModel *>(v.model()); }
- quint64 internalId() const { return v.internalId(); }
-
- static QString propertiesString(const QModelIndex &idx);
-
- static QPersistentModelIndex toPersistentModelIndex(const QModelIndex &index)
- { return QPersistentModelIndex(index); }
-};
-
-struct QQmlPersistentModelIndexValueType
-{
- QPersistentModelIndex v;
-
- Q_PROPERTY(int row READ row FINAL)
- Q_PROPERTY(int column READ column FINAL)
- Q_PROPERTY(QModelIndex parent READ parent FINAL)
- Q_PROPERTY(bool valid READ isValid FINAL)
- Q_PROPERTY(QAbstractItemModel *model READ model FINAL)
- Q_PROPERTY(quint64 internalId READ internalId FINAL)
- Q_GADGET
-
-public:
- Q_INVOKABLE QString toString() const
- { return QLatin1String("QPersistentModelIndex") + QQmlModelIndexValueType::propertiesString(v); }
-
- inline int row() const { return v.row(); }
- inline int column() const { return v.column(); }
- inline QModelIndex parent() const { return v.parent(); }
- inline bool isValid() const { return v.isValid(); }
- inline QAbstractItemModel *model() const { return const_cast<QAbstractItemModel *>(v.model()); }
- inline quint64 internalId() const { return v.internalId(); }
-
- static const QModelIndex &toModelIndex(const QPersistentModelIndex &index)
- { return index; }
-};
-
-struct QQmlItemSelectionRangeValueType
-{
- QItemSelectionRange v;
-
- Q_PROPERTY(int top READ top FINAL)
- Q_PROPERTY(int left READ left FINAL)
- Q_PROPERTY(int bottom READ bottom FINAL)
- Q_PROPERTY(int right READ right FINAL)
- Q_PROPERTY(int width READ width FINAL)
- Q_PROPERTY(int height READ height FINAL)
- Q_PROPERTY(QPersistentModelIndex topLeft READ topLeft FINAL)
- Q_PROPERTY(QPersistentModelIndex bottomRight READ bottomRight FINAL)
- Q_PROPERTY(QModelIndex parent READ parent FINAL)
- Q_PROPERTY(bool valid READ isValid FINAL)
- Q_PROPERTY(bool empty READ isEmpty FINAL)
- Q_PROPERTY(QAbstractItemModel *model READ model FINAL)
- Q_GADGET
-
-public:
- Q_INVOKABLE QString toString() const;
- Q_INVOKABLE inline bool contains(const QModelIndex &index) const
- { return v.contains(index); }
- Q_INVOKABLE inline bool contains(int row, int column, const QModelIndex &parentIndex) const
- { return v.contains(row, column, parentIndex); }
- Q_INVOKABLE inline bool intersects(const QItemSelectionRange &other) const
- { return v.intersects(other); }
- Q_INVOKABLE QItemSelectionRange intersected(const QItemSelectionRange &other) const
- { return v.intersected(other); }
-
- inline int top() const { return v.top(); }
- inline int left() const { return v.left(); }
- inline int bottom() const { return v.bottom(); }
- inline int right() const { return v.right(); }
- inline int width() const { return v.width(); }
- inline int height() const { return v.height(); }
- inline QPersistentModelIndex &topLeft() const { return const_cast<QPersistentModelIndex &>(v.topLeft()); }
- inline QPersistentModelIndex &bottomRight() const { return const_cast<QPersistentModelIndex &>(v.bottomRight()); }
- inline QModelIndex parent() const { return v.parent(); }
- inline QAbstractItemModel *model() const { return const_cast<QAbstractItemModel *>(v.model()); }
- inline bool isValid() const { return v.isValid(); }
- inline bool isEmpty() const { return v.isEmpty(); }
-};
-
-#undef QLISTVALUETYPE_INVOKABLE_API
-
-QT_END_NAMESPACE
-
-#endif // QQMLMODELINDEXVALUETYPE_P_H
-
diff --git a/src/qml/types/qqmltimer.cpp b/src/qml/types/qqmltimer.cpp
index af2ff56f2a..fb3c53e880 100644
--- a/src/qml/types/qqmltimer.cpp
+++ b/src/qml/types/qqmltimer.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmltimer_p.h"
@@ -313,8 +277,6 @@ void QQmlTimer::componentComplete()
\qmlsignal QtQml::Timer::triggered()
This signal is emitted when the Timer times out.
-
- The corresponding handler is \c onTriggered.
*/
void QQmlTimer::ticked()
{
diff --git a/src/qml/types/qqmltimer_p.h b/src/qml/types/qqmltimer_p.h
index 0cd93e4659..e75b8bbe9d 100644
--- a/src/qml/types/qqmltimer_p.h
+++ b/src/qml/types/qqmltimer_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLTIMER_H
#define QQMLTIMER_H
@@ -62,7 +26,7 @@ QT_REQUIRE_CONFIG(qml_animation);
QT_BEGIN_NAMESPACE
class QQmlTimerPrivate;
-class Q_QML_PRIVATE_EXPORT QQmlTimer : public QObject, public QQmlParserStatus
+class Q_QML_EXPORT QQmlTimer : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlTimer)
@@ -72,7 +36,9 @@ class Q_QML_PRIVATE_EXPORT QQmlTimer : public QObject, public QQmlParserStatus
Q_PROPERTY(bool repeat READ isRepeating WRITE setRepeating NOTIFY repeatChanged)
Q_PROPERTY(bool triggeredOnStart READ triggeredOnStart WRITE setTriggeredOnStart NOTIFY triggeredOnStartChanged)
Q_PROPERTY(QObject *parent READ parent CONSTANT)
+ Q_CLASSINFO("ParentProperty", "parent")
QML_NAMED_ELEMENT(Timer)
+ QML_ADDED_IN_VERSION(2, 0)
public:
QQmlTimer(QObject *parent=nullptr);
@@ -116,6 +82,4 @@ private Q_SLOTS:
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlTimer)
-
#endif
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
deleted file mode 100644
index 54cd8710b6..0000000000
--- a/src/qml/types/types.pri
+++ /dev/null
@@ -1,22 +0,0 @@
-SOURCES += \
- $$PWD/qqmlbind.cpp \
- $$PWD/qqmlconnections.cpp
-
-HEADERS += \
- $$PWD/qqmlbind_p.h \
- $$PWD/qqmlconnections_p.h
-
-qtConfig(qml-itemmodel) {
- SOURCES += \
- $$PWD/qqmlmodelindexvaluetype.cpp
- HEADERS += \
- $$PWD/qqmlmodelindexvaluetype_p.h
-}
-
-qtConfig(qml-animation) {
- SOURCES += \
- $$PWD/qqmltimer.cpp
-
- HEADERS += \
- $$PWD/qqmltimer_p.h
-}
diff --git a/src/qml/util/qqmlpropertymap.cpp b/src/qml/util/qqmlpropertymap.cpp
index 82f048d9d9..494bf4e744 100644
--- a/src/qml/util/qqmlpropertymap.cpp
+++ b/src/qml/util/qqmlpropertymap.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlpropertymap.h"
@@ -57,7 +21,6 @@ protected:
QVariant propertyWriteValue(int, const QVariant &) override;
void propertyWritten(int index) override;
void propertyCreated(int, QMetaPropertyBuilder &) override;
- int createProperty(const char *, const char *) override;
const QString &propertyName(int index);
@@ -130,13 +93,6 @@ void QQmlPropertyMapMetaObject::propertyCreated(int, QMetaPropertyBuilder &b)
priv->keys.append(QString::fromUtf8(b.name()));
}
-int QQmlPropertyMapMetaObject::createProperty(const char *name, const char *value)
-{
- if (!priv->validKeyName(QString::fromUtf8(name)))
- return -1;
- return QQmlOpenMetaObject::createProperty(name, value);
-}
-
/*!
\class QQmlPropertyMap
\brief The QQmlPropertyMap class allows you to set key-value pairs that can be used in QML bindings.
@@ -207,7 +163,24 @@ QQmlPropertyMap::~QQmlPropertyMap()
void QQmlPropertyMap::clear(const QString &key)
{
Q_D(QQmlPropertyMap);
- d->mo->setValue(key.toUtf8(), QVariant());
+ if (d->validKeyName(key))
+ d->mo->setValue(key.toUtf8(), QVariant());
+}
+
+/*!
+ \since 6.1
+
+ Disallows any further properties to be added to this property map.
+ Existing properties can be modified or cleared.
+
+ In turn, an internal cache is turned on for the existing properties, which
+ may result in faster access from QML.
+ */
+void QQmlPropertyMap::freeze()
+{
+ Q_D(QQmlPropertyMap);
+ d->mo->setAutoCreatesProperties(false);
+ d->mo->setCached(true);
}
/*!
@@ -241,6 +214,36 @@ void QQmlPropertyMap::insert(const QString &key, const QVariant &value)
}
/*!
+ \since 6.1
+
+ Inserts the \a values into the QQmlPropertyMap.
+
+ Keys that don't exist are automatically created.
+
+ This method is substantially faster than calling \c{insert(key, value)}
+ many times in a row.
+*/
+void QQmlPropertyMap::insert(const QVariantHash &values)
+{
+ Q_D(QQmlPropertyMap);
+
+ QHash<QByteArray, QVariant> checkedValues;
+ for (auto it = values.begin(), end = values.end(); it != end; ++it) {
+ const QString &key = it.key();
+ if (!d->validKeyName(key)) {
+ qWarning() << "Creating property with name"
+ << key
+ << "is not permitted, conflicts with internal symbols.";
+ return;
+ }
+
+ checkedValues.insert(key.toUtf8(), it.value());
+ }
+ d->mo->setValues(checkedValues);
+
+}
+
+/*!
Returns the list of keys.
Keys that have been cleared will still appear in this list, even though their
@@ -260,7 +263,7 @@ QStringList QQmlPropertyMap::keys() const
int QQmlPropertyMap::count() const
{
Q_D(const QQmlPropertyMap);
- return d->keys.count();
+ return d->keys.size();
}
/*!
@@ -337,7 +340,7 @@ QVariant QQmlPropertyMap::operator[](const QString &key) const
*/
QVariant QQmlPropertyMap::updateValue(const QString &key, const QVariant &input)
{
- Q_UNUSED(key)
+ Q_UNUSED(key);
return input;
}
@@ -370,3 +373,5 @@ QQmlPropertyMap::QQmlPropertyMap(const QMetaObject *staticMetaObject, QObject *p
*/
QT_END_NAMESPACE
+
+#include "moc_qqmlpropertymap.cpp"
diff --git a/src/qml/util/qqmlpropertymap.h b/src/qml/util/qqmlpropertymap.h
index cb7ada3d79..652cf4d11b 100644
--- a/src/qml/util/qqmlpropertymap.h
+++ b/src/qml/util/qqmlpropertymap.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLPROPERTYMAP_H
#define QQMLPROPERTYMAP_H
@@ -60,7 +24,9 @@ public:
QVariant value(const QString &key) const;
void insert(const QString &key, const QVariant &value);
+ void insert(const QVariantHash &values);
void clear(const QString &key);
+ void freeze();
Q_INVOKABLE QStringList keys() const;
@@ -82,7 +48,7 @@ protected:
QQmlPropertyMap(DerivedType *derived, QObject *parentObj)
: QQmlPropertyMap(&DerivedType::staticMetaObject, parentObj)
{
- Q_UNUSED(derived)
+ Q_UNUSED(derived);
}
private:
diff --git a/src/qml/util/util.pri b/src/qml/util/util.pri
deleted file mode 100644
index 3b121ba3cb..0000000000
--- a/src/qml/util/util.pri
+++ /dev/null
@@ -1,5 +0,0 @@
-SOURCES += \
- $$PWD/qqmlpropertymap.cpp
-
-HEADERS += \
- $$PWD/qqmlpropertymap.h