diff options
author | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2023-03-01 22:03:58 +0200 |
---|---|---|
committer | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2023-03-01 22:03:58 +0200 |
commit | 15292659b7e77073ab19748199fdde06f27987b3 (patch) | |
tree | 4cc12fb1ce7d517e303620ab2028dea2e9406463 /src/qml | |
parent | 22b7e9c79182420ce1ff877d6636c0bdffde602d (diff) | |
parent | 7f07dae966bdd059b1dd1cb11c74ab5b89855396 (diff) |
Merge remote-tracking branch 'origin/tqtc/lts-6.2.6' into tqtc/lts-6.2-opensource
Change-Id: Ie5a87ae61d8ed0429225353ad46e5232d60f4daa
Diffstat (limited to 'src/qml')
44 files changed, 771 insertions, 438 deletions
diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt index 45a1b274e6..1cacf0d889 100644 --- a/src/qml/CMakeLists.txt +++ b/src/qml/CMakeLists.txt @@ -510,7 +510,7 @@ qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_debug debugger/qqmldebug.cpp debugger/qqmldebugconnector.cpp debugger/qqmldebugpluginmanager_p.h - debugger/qqmldebugserver_p.h + debugger/qqmldebugserver.cpp debugger/qqmldebugserver_p.h debugger/qqmldebugserverconnection_p.h debugger/qqmldebugservice.cpp debugger/qqmldebugservice_p.h debugger/qqmldebugservicefactory_p.h diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake index 4f3cf714b9..d26f183f5d 100644 --- a/src/qml/Qt6QmlMacros.cmake +++ b/src/qml/Qt6QmlMacros.cmake @@ -2000,7 +2000,7 @@ but this file does not exist. Possible reasons include: ") endif() - # Find QML import paths. + # Find Qt provided QML import paths. if("${_qt_additional_packages_prefix_paths}" STREQUAL "") # We have one installation prefix for all Qt modules. Add the "<prefix>/qml" directory. set(qml_import_paths "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_QML}") @@ -2008,7 +2008,9 @@ but this file does not exist. Possible reasons include: # We have multiple installation prefixes: one per Qt repository (conan). Add those that have # a "qml" subdirectory. set(qml_import_paths) - foreach(root IN ITEMS "${QT6_INSTALL_PREFIX};${_qt_additional_packages_prefix_paths}") + __qt_internal_prefix_paths_to_roots( + additional_root_paths "${_qt_additional_packages_prefix_paths}") + foreach(root IN ITEMS ${QT6_INSTALL_PREFIX} ${additional_root_paths}) set(candidate "${root}/${QT6_INSTALL_QML}") if(IS_DIRECTORY "${candidate}") list(APPEND qml_import_paths "${candidate}") @@ -2016,11 +2018,6 @@ but this file does not exist. Possible reasons include: endforeach() endif() - # Construct the -importPath arguments. - set(import_path_arguments) - foreach(path IN LISTS qml_import_paths) - list(APPEND import_path_arguments -importPath ${path}) - endforeach() # Small macro to avoid duplicating code in two different loops. macro(_qt6_QmlImportScanner_parse_entry) @@ -2044,7 +2041,6 @@ but this file does not exist. Possible reasons include: set(cmd_args -rootPath "${arg_PATH_TO_SCAN}" -cmake-output - ${import_path_arguments} ) get_target_property(qml_import_path ${target} QT_QML_IMPORT_PATH) @@ -2055,18 +2051,26 @@ but this file does not exist. Possible reasons include: # 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 cmd_args "${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 cmd_args "${QT_QML_OUTPUT_DIRECTORY}") + list(APPEND qml_import_paths "${QT_QML_OUTPUT_DIRECTORY}") endif() else() - list(APPEND cmd_args "${CMAKE_CURRENT_BINARY_DIR}") + list(APPEND qml_import_paths "${CMAKE_CURRENT_BINARY_DIR}") endif() + # Construct the -importPath arguments. + set(import_path_arguments) + foreach(path IN LISTS qml_import_paths) + list(APPEND import_path_arguments -importPath ${path}) + 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 diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h index f4c41f69f8..3f33743ecf 100644 --- a/src/qml/common/qv4compileddata_p.h +++ b/src/qml/common/qv4compileddata_p.h @@ -129,7 +129,7 @@ struct TableIterator struct Location { Location() : m_data(QSpecialIntegerBitfieldZero) {} - Location(quint32 l, quint32 c) + Location(quint32 l, quint32 c) : Location() { m_data.set<LineField>(l); m_data.set<ColumnField>(c); @@ -182,7 +182,7 @@ struct RegExp }; RegExp() : m_data(QSpecialIntegerBitfieldZero) {} - RegExp(quint32 flags, quint32 stringIndex) + RegExp(quint32 flags, quint32 stringIndex) : RegExp() { m_data.set<FlagsField>(flags); m_data.set<StringIndexField>(stringIndex); @@ -211,7 +211,7 @@ struct Lookup quint32 nameIndex() const { return m_data.get<NameIndexField>(); } Lookup() : m_data(QSpecialIntegerBitfieldZero) {} - Lookup(Type type, quint32 nameIndex) + Lookup(Type type, quint32 nameIndex) : Lookup() { m_data.set<TypeAndFlagsField>(type); m_data.set<NameIndexField>(nameIndex); diff --git a/src/qml/debugger/qqmldebugconnector_p.h b/src/qml/debugger/qqmldebugconnector_p.h index d1ad90adfd..4f7b013160 100644 --- a/src/qml/debugger/qqmldebugconnector_p.h +++ b/src/qml/debugger/qqmldebugconnector_p.h @@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE class Q_QML_PRIVATE_EXPORT QQmlDebugConnector { + virtual ~QQmlDebugConnector() = default; // don't break 'override' on ~QQmlDebugServer public: static QQmlDebugConnector *instance() { return nullptr; } diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp new file mode 100644 index 0000000000..5119fc4209 --- /dev/null +++ b/src/qml/debugger/qqmldebugserver.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** 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 "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..c99155051c 100644 --- a/src/qml/debugger/qqmldebugserver_p.h +++ b/src/qml/debugger/qqmldebugserver_p.h @@ -62,6 +62,7 @@ class Q_QML_PRIVATE_EXPORT QQmlDebugServer : public QQmlDebugConnector { Q_OBJECT public: + ~QQmlDebugServer() override; virtual void setDevice(QIODevice *socket) = 0; }; diff --git a/src/qml/doc/src/cmake/qt_add_qml_module.qdoc b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc index 810f45b127..a66aa27561 100644 --- a/src/qml/doc/src/cmake/qt_add_qml_module.qdoc +++ b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc @@ -73,6 +73,9 @@ qt_add_qml_module( \versionlessCMakeCommandsNote qt6_add_qml_module() +See \l {Building a QML application} and \l {Building a reusable QML module} +for examples that define QML modules. + \section1 Description This command defines a QML module that can consist of C++ sources, \c{.qml} @@ -126,6 +129,10 @@ 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. +\note +When using static linking, it migt be necessary to use +\c 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 diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc index d5c1d3e0c9..40e0627e6d 100644 --- a/src/qml/doc/src/cppintegration/definetypes.qdoc +++ b/src/qml/doc/src/cppintegration/definetypes.qdoc @@ -334,10 +334,9 @@ 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 diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc index 99aa4cd058..943da5cbef 100644 --- a/src/qml/doc/src/javascript/hostenvironment.qdoc +++ b/src/qml/doc/src/javascript/hostenvironment.qdoc @@ -42,7 +42,8 @@ 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} (since Qt 5.15) and \l{Optional Chaining} (since Qt 6.2) are also implemented in the QML runtime. +\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 diff --git a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc index 718b0c25ac..562b262271 100644 --- a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc +++ b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc @@ -53,8 +53,12 @@ The type name has the following requirements: 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. +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 diff --git a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc index 95e8a179de..be1908f7cd 100644 --- a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc +++ b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc @@ -43,278 +43,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 -[optional] plugin <Name> [<Path>] - \endcode - \li 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; 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{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. - - \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 -import <ModuleIdentifier> [<Version>] - \endcode - \li 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. - - \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. - - \row - \li - \code -prefer <Path> - \endcode - - \li 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. - -\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 diff --git a/src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc b/src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc index b1fce12dc3..834977994f 100644 --- a/src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc +++ b/src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc @@ -26,6 +26,14 @@ 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. +\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. + 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 diff --git a/src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc b/src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc index 7ec8a4ff34..0623dd9934 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc @@ -109,6 +109,11 @@ a file system path. 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 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/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc index 6ddd9f30d0..8b3ff59ecc 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc @@ -56,6 +56,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 @@ -686,8 +687,8 @@ 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. -\sa {QQmlComponent::createWithInitialProperties}, {QQmlApplicationEngine::setInitialProperties} -and {QQuickView::setInitialProperties} for ways to initialize required properties from C++. +See \l{QQmlComponent::createWithInitialProperties}, \l{QQmlApplicationEngine::setInitialProperties} +and \l{QQuickView::setInitialProperties} for ways to initialize required properties from C++. \section3 Read-Only Properties diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 6f91f0151b..8eb7d8982d 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -356,6 +356,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) if (ok && envMaxGCStackSize > 0) m_maxGCStackSize = envMaxGCStackSize; + // We allocate guard pages around our stacks. + const size_t guardPages = 2 * WTF::pageSize(); + memoryManager = new QV4::MemoryManager(this); if (maxCallDepth == -1) { @@ -368,6 +371,8 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) #if defined(QT_NO_DEBUG) && !defined(__SANITIZE_ADDRESS__) && !__has_feature(address_sanitizer) #ifdef Q_OS_QNX maxCallDepth = 640; // QNX's stack is only 512k by default +#elif defined(Q_OS_WIN) + maxCallDepth = 640; // We've seen crashes around 750. #else maxCallDepth = 1234; #endif @@ -383,9 +388,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) // 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( + m_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); @@ -393,9 +398,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) jsStackTop = jsStackBase; - *gcStack = WTF::PageAllocation::allocate(m_maxGCStackSize, WTF::OSAllocator::JSVMStackPages, - /* writable */ true, /* executable */ false, - /* includesGuardPages */ true); + *gcStack = WTF::PageAllocation::allocate( + m_maxGCStackSize + guardPages, WTF::OSAllocator::JSVMStackPages, + /* writable */ true, /* executable */ false, /* includesGuardPages */ true); { ok = false; @@ -2192,7 +2197,7 @@ void ExecutionEngine::setQmlEngine(QQmlEngine *engine) 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); @@ -2301,6 +2306,8 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi case QMetaType::QByteArray: if (const ArrayBuffer *ab = value.as<ArrayBuffer>()) *reinterpret_cast<QByteArray*>(data) = ab->asByteArray(); + else if (const String *string = value.as<String>()) + *reinterpret_cast<QByteArray*>(data) = string->toQString().toUtf8(); else *reinterpret_cast<QByteArray*>(data) = QByteArray(); return true; diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 1493456853..0abdd76c96 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -307,7 +307,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/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 4287563c94..eabb220c50 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -178,7 +178,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()); @@ -265,6 +265,13 @@ 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); @@ -273,13 +280,6 @@ void InternalClass::init(ExecutionEngine *engine) 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 @@ -300,10 +300,8 @@ void InternalClass::init(Heap::InternalClass *other) 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); @@ -365,7 +363,99 @@ 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. + std::vector<InternalClassTransition> 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; + 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 +471,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 +484,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 +494,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 +505,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; @@ -427,8 +519,7 @@ Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto) newClass->prototype = proto; t.lookup = newClass; - - return newClass; + return prototype ? cleanInternalClass(newClass) : newClass; } Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt) @@ -449,12 +540,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 +556,7 @@ 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); @@ -500,7 +593,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 +646,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 +670,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 +679,7 @@ Heap::InternalClass *InternalClass::sealed() s->propertyData.set(i, attrs); } } - s->isSealed = true; + s->flags |= Sealed; t.lookup = s; return s; @@ -592,14 +687,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 +711,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 +735,7 @@ InternalClass *InternalClass::cryopreserved() bool InternalClass::isImplicitlyFrozen() const { - if (isFrozen) + if (isFrozen()) return true; for (uint i = 0; i < size; ++i) { @@ -656,7 +751,7 @@ bool InternalClass::isImplicitlyFrozen() const Heap::InternalClass *InternalClass::asProtoClass() { - if (isUsedAsProto) + if (isUsedAsProto()) return this; Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::ProtoClass }; @@ -665,7 +760,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 +780,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 +793,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 c18133f4cd..37dbeded6f 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -173,7 +173,7 @@ struct SharedInternalClassDataPrivate<PropertyAttributes> { 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]; } + PropertyAttributes at(uint i) const { Q_ASSERT(data && i < m_alloc); return data[i]; } void set(uint i, PropertyAttributes t) { Q_ASSERT(data && i < m_alloc); data[i] = t; } void mark(MarkStack *) {} @@ -198,7 +198,7 @@ struct SharedInternalClassDataPrivate<PropertyKey> { 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); @@ -289,24 +289,33 @@ 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), }; 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, + }; + enum { MaxRedundantTransitions = 255 }; + ExecutionEngine *engine; const VTable *vtable; quintptr protoId; // unique across the engine, gets changed whenever the proto chain changes @@ -322,10 +331,13 @@ struct InternalClass : Base { 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; } void init(ExecutionEngine *engine); void init(InternalClass *other); diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h index c6d320ac20..70ddaf59c5 100644 --- a/src/qml/jsruntime/qv4jscall_p.h +++ b/src/qml/jsruntime/qv4jscall_p.h @@ -146,10 +146,12 @@ struct ScopedStackFrame { return; frame.jsFrame = reinterpret_cast<CallData *>(scope.alloc(sizeof(CallData)/sizeof(Value))); frame.jsFrame->context = context; - if (auto *parent = frame.parentFrame()) + if (auto *parent = frame.parentFrame()) { frame.v4Function = parent->v4Function; - else + frame.instructionPointer = parent->instructionPointer; + } else { frame.v4Function = nullptr; + } scope.engine->currentStackFrame = &frame; } ~ScopedStackFrame() { diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index a3ffdb5431..994d9a79a0 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -646,6 +646,28 @@ 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 m_callDepthRecorder; +}; + static QString quote(const QString &str) { QString product; @@ -776,10 +798,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); @@ -836,10 +857,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()); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index c10f1b46c3..564cd47203 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -61,17 +61,52 @@ 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) + newMembers->set(scope.engine, i, get(ic->nameMap.at(i))); + + 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)); + } + } + } + + if (ic->isUsedAsProto()) + ic->updateProtoUsage(p); + } void Object::getProperty(const InternalClassEntry &entry, Property *p) const @@ -958,7 +993,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) @@ -982,7 +1017,7 @@ bool Object::virtualSetPrototypeOf(Managed *m, const Object *proto) Heap::Object *protod = proto ? proto->d() : nullptr; if (current == protod) return true; - if (!o->internalClass()->extensible) + if (!o->internalClass()->isExtensible()) return false; Heap::Object *p = protod; while (p) { diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp index 83bfba9b11..e155f2c3ba 100644 --- a/src/qml/jsruntime/qv4promiseobject.cpp +++ b/src/qml/jsruntime/qv4promiseobject.cpp @@ -116,6 +116,8 @@ struct ResolveThenableEvent : public QEvent } // namespace QV4 QT_END_NAMESPACE +#include "moc_qv4promiseobject_p.cpp" + ReactionHandler::ReactionHandler(QObject *parent) : QObject(parent) {} diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h index b5dca2d2ac..bb93dc518d 100644 --- a/src/qml/jsruntime/qv4propertykey_p.h +++ b/src/qml/jsruntime/qv4propertykey_p.h @@ -51,6 +51,7 @@ // #include <private/qv4global_p.h> +#include <QtCore/qhashfunctions.h> QT_BEGIN_NAMESPACE @@ -145,6 +146,7 @@ public: 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; } + friend size_t qHash(const PropertyKey &key, size_t seed = 0) { return qHash(key.val, seed); } }; } diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 21ac5e448a..c897c63024 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -777,7 +777,7 @@ bool QObjectWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, QObjectWrapper *that = static_cast<QObjectWrapper*>(m); ScopedString name(scope, id.asStringOrSymbol()); - if (that->internalClass()->isFrozen) { + if (that->internalClass()->isFrozen()) { QString error = QLatin1String("Cannot assign to property \"") + name->toQString() + QLatin1String("\" of read-only object"); scope.engine->throwError(error); diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 01edfd5964..b0268afedd 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -709,3 +709,5 @@ int SequencePrototype::metaTypeForSequence(const QV4::Object *object) } QT_END_NAMESPACE + +#include "moc_qv4sequenceobject_p.cpp" diff --git a/src/qml/jsruntime/qv4stackframe.cpp b/src/qml/jsruntime/qv4stackframe.cpp index a716c53aea..0a060e81a7 100644 --- a/src/qml/jsruntime/qv4stackframe.cpp +++ b/src/qml/jsruntime/qv4stackframe.cpp @@ -53,7 +53,7 @@ QString CppStackFrame::function() const int CppStackFrame::lineNumber() const { - if (!v4Function) + if (!v4Function || instructionPointer <= 0) return -1; auto findLine = [](const CompiledData::CodeOffsetToLine &entry, uint offset) { @@ -61,9 +61,9 @@ int CppStackFrame::lineNumber() const }; const QV4::CompiledData::Function *cf = v4Function->compiledFunction; - uint offset = instructionPointer; + const uint offset = instructionPointer; const CompiledData::CodeOffsetToLine *lineNumbers = cf->lineNumberTable(); - uint nLineNumbers = cf->nLineNumbers; + const uint nLineNumbers = cf->nLineNumbers; const CompiledData::CodeOffsetToLine *line = std::lower_bound(lineNumbers, lineNumbers + nLineNumbers, offset, findLine) - 1; return line->line; } diff --git a/src/qml/qml/ftw/qintrusivelist_p.h b/src/qml/qml/ftw/qintrusivelist_p.h index 8992be9f93..40dc45095f 100644 --- a/src/qml/qml/ftw/qintrusivelist_p.h +++ b/src/qml/qml/ftw/qintrusivelist_p.h @@ -241,7 +241,12 @@ typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::end() template<class N, QIntrusiveListNode N::*member> N *QIntrusiveList<N, member>::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 } QIntrusiveListNode::QIntrusiveListNode() diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 9a15fa5358..064eddc76a 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -833,8 +833,16 @@ QObject *QQmlComponent::create(QQmlContext *context) Q_D(QQmlComponent); QObject *rv = d->doBeginCreate(this, context); - if (rv) + if (rv) { completeCreate(); + } else if (d->state.completePending) { + // overridden completCreate might assume that + // the object has actually been created + ++creationDepth.localData(); + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(d->engine); + d->complete(ep, &d->state); + --creationDepth.localData(); + } if (rv && !d->requiredProperties().empty()) { delete rv; return nullptr; @@ -1793,3 +1801,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/qqmlcomponentattached_p.h b/src/qml/qml/qqmlcomponentattached_p.h index b94d474d1f..2e63289c2d 100644 --- a/src/qml/qml/qqmlcomponentattached_p.h +++ b/src/qml/qml/qqmlcomponentattached_p.h @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE +// implemented in qqmlcomponent.cpp class Q_QML_PRIVATE_EXPORT QQmlComponentAttached : public QObject { Q_OBJECT diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 080ecfe323..3a2f678419 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -2290,4 +2290,6 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */) QT_END_NAMESPACE +#include "moc_qqmlengine_p.cpp" + #include "moc_qqmlengine.cpp" diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp index a14ecdc471..22846a84dc 100644 --- a/src/qml/qml/qqmlextensionplugin.cpp +++ b/src/qml/qml/qqmlextensionplugin.cpp @@ -169,7 +169,7 @@ void QQmlEngineExtensionPlugin::initializeEngine(QQmlEngine *engine, const char /*! \macro Q_IMPORT_QML_PLUGIN(PluginName) \since 6.2 - \relates QQmlExtensionPlugin + \relates QQmlEngineExtensionPlugin Ensures the plugin whose metadata-declaring class is named \a PluginName is linked into static builds. diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 3c89246870..a61cf4adea 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -226,7 +226,8 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el } 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()); @@ -243,40 +244,41 @@ void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo, } } - // 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); + 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); - // More complex - need to search name - QByteArray name = method.name(); + // More complex - need to search name + QByteArray name = method.name(); + bool found = false; - bool found = false; + for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount(); + !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount(); ++ii) { - for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount(); - !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount(); - ++ii) { + QMetaMethod other = ignoreEnd->method(ii); - QMetaMethod other = ignoreEnd->method(ii); + found = name == other.name(); + } - found = name == other.name(); + QMetaMethodBuilder m = builder.addMethod(method); + if (found) // SKIP + m.setAccess(QMetaMethod::Private); } - QMetaMethodBuilder m = builder.addMethod(method); - if (found) // SKIP - m.setAccess(QMetaMethod::Private); - } - - // Clone Q_PROPERTY - for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) { - QMetaProperty property = mo->property(ii); + // Clone Q_PROPERTY + for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) { + QMetaProperty property = mo->property(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); + 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); + } } } @@ -1521,7 +1523,8 @@ QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject return; QMetaObjectBuilder builder; - clone(builder, extMetaObject, superdataBaseMetaObject, baseMetaObject); + clone(builder, extMetaObject, superdataBaseMetaObject, baseMetaObject, + extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly); builder.setFlags(MetaObjectFlag::DynamicMetaObject); QMetaObject *mmo = builder.toMetaObject(); mmo->d.superdata = baseMetaObject; diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index bd7e07373c..dc08263511 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -245,8 +245,13 @@ 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); diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index a9c9c03c3d..372103b94f 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1799,3 +1799,5 @@ void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index) } QT_END_NAMESPACE + +#include "moc_qqmlproperty.cpp" diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index a4b61cc22a..b03b8e937a 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -1067,6 +1067,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) property.setWritable(data->isWritable()); property.setResettable(data->isResettable()); property.setBindable(data->isBindable()); + property.setAlias(data->isAlias()); } for (int ii = 0; ii < methods.count(); ++ii) { diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp index 2aab66b933..5c88761d78 100644 --- a/src/qml/qml/qqmlpropertycachecreator.cpp +++ b/src/qml/qml/qqmlpropertycachecreator.cpp @@ -149,6 +149,11 @@ void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(QQmlEnginePr if (propertyCaches->at(groupPropertyObjectIndex)) continue; + if (!pendingBinding.referencingObjectPropertyCache) { + pendingBinding.referencingObjectPropertyCache + = propertyCaches->at(pendingBinding.referencingObjectIndex); + } + if (!pendingBinding.resolveInstantiatingProperty()) continue; diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h index c57d805dea..f4845ec27b 100644 --- a/src/qml/qml/qqmlpropertycachecreator_p.h +++ b/src/qml/qml/qqmlpropertycachecreator_p.h @@ -341,24 +341,24 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur } } - 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); - - QQmlError error = buildMetaObjectRecursively(binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe); - if (error.isValid()) - return error; - } + 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 (!thisCache || !context.resolveInstantiatingProperty()) + pendingGroupPropertyBindings->append(context); + + QQmlError error = buildMetaObjectRecursively(binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe); + if (error.isValid()) + return error; + } } QQmlError noError; @@ -901,10 +901,16 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor } const auto referencedType = typeRef->type(); - if (referencedType.isValid()) + if (referencedType.isValid()) { *type = referencedType.typeId(); - else + if (!type->isValid() && referencedType.isInlineComponentType()) { + int objectId = referencedType.inlineComponentId(); + *type = objectContainer->typeIdsForComponent(objectId).id; + Q_ASSERT(type->isValid()); + } + } else { *type = typeRef->compilationUnit()->typeIds.id; + } *version = typeRef->version(); diff --git a/src/qml/qml/qqmlproxymetaobject.cpp b/src/qml/qml/qqmlproxymetaobject.cpp index 21d3c7ed05..6f48146fa3 100644 --- a/src/qml/qml/qqmlproxymetaobject.cpp +++ b/src/qml/qml/qqmlproxymetaobject.cpp @@ -68,11 +68,8 @@ QQmlProxyMetaObject::~QQmlProxyMetaObject() QObject *QQmlProxyMetaObject::getProxy(int index) { if (!proxies) { - if (!proxies) { - proxies = new QObject*[metaObjects->count()]; - ::memset(proxies, 0, - sizeof(QObject *) * metaObjects->count()); - } + proxies = new QObject *[metaObjects->count()]; + ::memset(proxies, 0, sizeof(QObject *) * metaObjects->count()); } if (!proxies[index]) { @@ -112,6 +109,7 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void const int globalPropertyOffset = metaObjects->at(ii).propertyOffset; if (id >= globalPropertyOffset) { QObject *proxy = getProxy(ii); + Q_ASSERT(proxy); const int localProxyOffset = proxy->metaObject()->propertyOffset(); const int localProxyId = id - globalPropertyOffset + localProxyOffset; @@ -129,7 +127,7 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void const int globalMethodOffset = metaObjects->at(ii).methodOffset; if (id >= globalMethodOffset) { QObject *proxy = getProxy(ii); - + Q_ASSERT(proxy); const int localMethodOffset = proxy->metaObject()->methodOffset(); const int localMethodId = id - globalMethodOffset + localMethodOffset; diff --git a/src/qml/qml/qqmlscriptstring.cpp b/src/qml/qml/qqmlscriptstring.cpp index 3230e69b6d..4df3a63785 100644 --- a/src/qml/qml/qqmlscriptstring.cpp +++ b/src/qml/qml/qqmlscriptstring.cpp @@ -220,3 +220,5 @@ bool QQmlScriptString::booleanLiteral(bool *ok) const QT_END_NAMESPACE +#include "moc_qqmlscriptstring.cpp" + diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp index 811ff668c6..c283f7c718 100644 --- a/src/qml/qml/qqmltype.cpp +++ b/src/qml/qml/qqmltype.cpp @@ -216,16 +216,15 @@ void QQmlTypePrivate::init() const return; } - auto setupExtendedMetaObject = [&]( - const QMetaObject *extMetaObject, - QObject *(*extFunc)(QObject *)) { - + auto setupExtendedMetaObject = [&](const QMetaObject *extMetaObject, + QObject *(*extFunc)(QObject *)) { if (!extMetaObject) return; // XXX - very inefficient QMetaObjectBuilder builder; - QQmlMetaType::clone(builder, extMetaObject, extMetaObject, extMetaObject); + QQmlMetaType::clone(builder, extMetaObject, extMetaObject, extMetaObject, + extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly); builder.setFlags(MetaObjectFlag::DynamicMetaObject); QMetaObject *mmo = builder.toMetaObject(); mmo->d.superdata = mo; diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp index af97643163..bcc5306cf8 100644 --- a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp +++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp @@ -72,3 +72,5 @@ void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply) } QT_END_NAMESPACE + +#include "moc_qqmltypeloadernetworkreplyproxy_p.cpp" diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index c2bbd7f498..2cba0375e7 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -281,10 +281,27 @@ PropertyAttributes QQmlValueTypeWrapper::virtualGetOwnProperty(const Managed *m, { if (id.isString()) { const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m); - QQmlPropertyData result = r->dataForPropertyKey(id); - if (p && result.isValid()) - p->value = getGadgetProperty(r->engine(), r->d(), result.propType(), result.coreIndex(), result.isFunction(), result.isEnum()); - return result.isValid() ? 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 + + const QQmlValueTypeReference *ref = r->as<const QQmlValueTypeReference>(); + if (!ref || ref->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); diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 8e45350982..f13a39946d 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -130,6 +130,12 @@ public: } \endqml + \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) : diff --git a/src/qml/util/qqmlpropertymap.cpp b/src/qml/util/qqmlpropertymap.cpp index 2bf8ab0190..23bf1b307c 100644 --- a/src/qml/util/qqmlpropertymap.cpp +++ b/src/qml/util/qqmlpropertymap.cpp @@ -409,3 +409,5 @@ QQmlPropertyMap::QQmlPropertyMap(const QMetaObject *staticMetaObject, QObject *p */ QT_END_NAMESPACE + +#include "moc_qqmlpropertymap.cpp" |