Merge tag 'v6.5.5-lts' into tqtc/lts-6.5-opensource

Qt 6.5.5-lts release

Conflicts solved:
	dependencies.yaml
	src/quick/doc/snippets/qml/treeview/qml-customdelegate.qml

Change-Id: Ifa297315fa0e6e70d9f26312f9183da4769d18fc
This commit is contained in:
Tarja Sundqvist 2025-01-29 16:12:28 +02:00
commit 7ac842cba1
378 changed files with 4187 additions and 1251 deletions

View File

@ -1,4 +1,4 @@
set(QT_REPO_MODULE_VERSION "6.5.4")
set(QT_REPO_MODULE_VERSION "6.5.5")
set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1")
set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_LEAN_HEADERS=1")

View File

@ -1,16 +1,16 @@
dependencies:
../tqtc-qtbase:
ref: 8ff0b254e4c3db81254782262d827f7831d15f6b
ref: fdf57f5df57e7d12cf871699d857a71acf272e0c
required: true
../tqtc-qtimageformats:
ref: 8170735657e6df87c1275b6ad7ca1e60ed0b9314
ref: 93317400471b1ef875471bfd719b00fe4fffc4fe
required: false
../tqtc-qtlanguageserver:
ref: c24ae032c6991321046bb47ba3b680ddac1c242c
ref: a4240e7eea774e7cc3019e3f1bf3168fd76612bc
required: false
../tqtc-qtshadertools:
ref: 5bf9de4a39fe2385998307c3e5ae16df6c0a5bd7
ref: 8191dce7e16f9bf42476c41a3b7aab9a62b26daa
required: false
../tqtc-qtsvg:
ref: 7c01c49a83d851196d990da86c08d59b3c7951f8
ref: c9ca482a2876fb7d37717e5146eb37f7e26f03da
required: false

View File

@ -45,7 +45,5 @@ install(TARGETS painteditemexample
include(../../shared/QtBundleQmlModuleForMacOS.cmake)
set(app_target "painteditemexample")
set(qml_plugin_target "qmltextballoon")
set(qml_module_uri "TextBalloon")
add_qml_module_to_macos_app_bundle(
"${app_target}" "${qml_plugin_target}" "${qml_module_uri}")
set(qml_module "qmltextballoon")
add_qml_module_to_macos_app_bundle("${app_target}" "${qml_module}")

View File

@ -1,5 +1,5 @@
<RCC>
<qresource prefix="/qt/qml/embeddedinwidgets">
<qresource prefix="/embeddedinwidgets">
<file>main.qml</file>
<file>reflect.frag.qsb</file>
</qresource>

View File

@ -9,6 +9,7 @@ TapHandler {
signal triggered(string text)
id: menuTap
acceptedButtons: Qt.RightButton
gesturePolicy: TapHandler.DragWithinBounds
onPressedChanged: if (pressed) {
impl.x = point.position.x - impl.width / 2
@ -22,7 +23,10 @@ TapHandler {
parent: menuTap.parent
width: 100
height: 100
scale: Math.min(1, Math.max(0, menuTap.timeHeld * 4))
// with touchscreen or stylus, long-press slowly expands the menu to size
// with mouse or touchpad right-click, it opens instantly
scale: menuTap.point.device.pointerType === PointerDevice.Generic ?
1 : Math.min(1, Math.max(0, menuTap.timeHeld * 4))
opacity: scale * 2
visible: menuTap.pressed
property Shape highlightedShape: null

View File

@ -63,14 +63,22 @@ MainWindow::MainWindow()
setCentralWidget(centralWidget);
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(tr("Grab framebuffer"), this, &MainWindow::grabFramebuffer);
fileMenu->addAction(tr("Render to pixmap"), this, &MainWindow::renderToPixmap);
fileMenu->addAction(tr("Grab via grabToImage"), this, &MainWindow::grabToImage);
auto grabAction = fileMenu->addAction(tr("Grab framebuffer"), this, &MainWindow::grabFramebuffer);
auto renderAction = fileMenu->addAction(tr("Render to pixmap"), this, &MainWindow::renderToPixmap);
auto grabToImageAction = fileMenu->addAction(tr("Grab via grabToImage"), this, &MainWindow::grabToImage);
fileMenu->addAction(tr("Quit"), qApp, &QCoreApplication::quit);
QMenu *windowMenu = menuBar()->addMenu(tr("&Window"));
windowMenu->addAction(tr("Add tab widget"), this,
[this, centralWidget] { createQuickWidgetsInTabs(centralWidget); });
connect(m_quickWidget, &QObject::destroyed, this,
[this, grabAction, renderAction, grabToImageAction] {
m_quickWidget = nullptr;
grabAction->setEnabled(false);
renderAction->setEnabled(false);
grabToImageAction->setEnabled(false);
});
}
void MainWindow::createQuickWidgetsInTabs(QMdiArea *mdiArea)
@ -123,6 +131,7 @@ void MainWindow::quickWidgetStatusChanged(QQuickWidget::Status status)
{
if (status == QQuickWidget::Error) {
QStringList errors;
Q_ASSERT(m_quickWidget);
const auto widgetErrors = m_quickWidget->errors();
for (const QQmlError &error : widgetErrors)
errors.append(error.toString());
@ -147,12 +156,14 @@ template<class T> void saveToFile(QWidget *parent, T *saveable)
void MainWindow::grabFramebuffer()
{
Q_ASSERT(m_quickWidget);
QImage image = m_quickWidget->grabFramebuffer();
saveToFile(this, &image);
}
void MainWindow::renderToPixmap()
{
Q_ASSERT(m_quickWidget);
QPixmap pixmap(m_quickWidget->size());
m_quickWidget->render(&pixmap);
saveToFile(this, &pixmap);
@ -165,6 +176,7 @@ void MainWindow::grabToImage()
fd.setDefaultSuffix("png");
fd.selectFile("test_grabToImage.png");
if (fd.exec() == QDialog::Accepted) {
Q_ASSERT(m_quickWidget);
QMetaObject::invokeMethod(m_quickWidget->rootObject(), "performLayerBasedGrab",
Q_ARG(QVariant, fd.selectedFiles().first()));
}

View File

@ -8,9 +8,9 @@
\ingroup qtquickexamples
\brief Shows how to implement a custom geometry in the Qt Quick Scene Graph.
The custom geometry example shows how to create a QQuickItem which
The custom geometry example shows how to create a \l QQuickItem that
uses the scene graph API to build a custom geometry for the scene
graph. It does this by creating a BezierCurve item which is made
graph. It does this by creating a \c BezierCurve item, which is made
part of the CustomGeometry module and makes use of this in a QML
file.
@ -115,7 +115,7 @@
\snippet scenegraph/customgeometry/beziercurve.cpp 6
The scene graph API provides a few commonly used material
implementations. In this example we use the QSGFlatColorMaterial
implementations. In this example we use the QSGFlatColorMaterial,
which will fill the shape defined by the geometry with a solid
color. Again we pass the ownership of the material to the node, so
it can be cleaned up by the scene graph.
@ -130,7 +130,7 @@
\snippet scenegraph/customgeometry/beziercurve.cpp 8
To fill the geometry, we first extract the vertex array from
To fill the geometry we first extract the vertex array from
it. Since we are using one of the default attribute sets, we can
use the convenience function QSGGeometry::vertexDataAsPoint2D().
Then we go through each segment and calculate its position and
@ -138,7 +138,7 @@
\snippet scenegraph/customgeometry/beziercurve.cpp 9
In the end of the function, we return the node so the scene graph
At the end of the function we return the node so the scene graph
can render it.
\section1 Application Entry-Point
@ -153,9 +153,26 @@
To make use of the BezierCurve item, we need to register it in the QML
engine, using the QML_ELEMENT macro. This gives it the name
BezierCurve and makes it part of the \c {CustomGeometry 1.0}
module as defined in the customgeometry.pro file:
module as defined in the project's build files:
\quotefile scenegraph/customgeometry/customgeometry.pro
\if defined(onlinedocs)
\tab {build-qt-app}{tab-cmake}{CMake}{checked}
\tab {build-qt-app}{tab-qmake}{qmake}{}
\tabcontent {tab-cmake}
\else
\section1 Using CMake
\endif
\quotefile scenegraph/customgeometry/CMakeLists.txt
\if defined(onlinedocs)
\endtabcontent
\tabcontent {tab-qmake}
\else
\section1 Using qmake
\endif
\quotefile scenegraph/customgeometry/customgeometry.pro
\if defined(onlinedocs)
\endtabcontent
\endif
As the bezier curve is drawn as line strips, we specify that
the view should be multisampled to get antialiasing. This is not

View File

@ -103,6 +103,11 @@ Item {
}
Button {
text: qsTr("Toggle custom item visibility")
onClicked: custom.visible = !custom.visible
}
CustomRender {
id: custom
width: Math.min(parent.width, parent.height)

View File

@ -42,10 +42,8 @@ include(QtBundleQmlModuleForMacOS.cmake)
# Puts the shared qml module plugin and qmldir into the macOS app bundle directory.
# Only call this function if your main project has the MACOSX_BUNDLE option set.
function(bundle_shared app_target)
set(qml_plugin_target "${PROJECT_NAME}_shared")
set(qml_module_uri "shared")
add_qml_module_to_macos_app_bundle(
"${app_target}" "${qml_plugin_target}" "${qml_module_uri}")
set(qml_module_target "${PROJECT_NAME}_shared")
add_qml_module_to_macos_app_bundle("${app_target}" "${qml_module_target}")
endfunction()
set(INSTALL_SHAREDDIR "${INSTALL_EXAMPLESDIR}/quick/${PROJECT_NAME}/shared")

View File

@ -174,9 +174,14 @@ Rectangle {
id: back
source: "images/back.png"
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 2
anchors.verticalCenterOffset: 1
anchors.left: parent.left
anchors.leftMargin: 16
anchors.leftMargin: 6
width: 38
height: 31
fillMode: Image.Pad
horizontalAlignment: Image.AlignHCenter
verticalAlignment: Image.AlignVCenter
TapHandler {
id: tapHandler
@ -188,10 +193,7 @@ Rectangle {
}
}
Rectangle {
anchors.centerIn: back
width: 38
height: 31
anchors.verticalCenterOffset: -1
anchors.fill: parent
opacity: tapHandler.pressed ? 1 : 0
Behavior on opacity { NumberAnimation{ duration: 100 }}
gradient: Gradient {

View File

@ -1,12 +1,18 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
function(add_qml_module_to_macos_app_bundle app_target qml_plugin_target qml_module_uri)
function(add_qml_module_to_macos_app_bundle app_target qml_module)
if(QT6_IS_SHARED_LIBS_BUILD AND APPLE)
# The application's main.cpp adds an explicit QML import path to look for qml module plugins
# under a PlugIns subdirectory of a macOS app bundle.
# Copy the qmldir and shared library qml plugin.
qt6_query_qml_module(${qml_module}
QMLDIR qmldir_file
PLUGIN_TARGET qml_plugin_target
URI qml_module_uri
)
# Ensure the executable depends on the plugin so the plugin is copied
# only after it was built.
add_dependencies(${app_target} ${qml_plugin_target})
@ -17,9 +23,6 @@ function(add_qml_module_to_macos_app_bundle app_target qml_plugin_target qml_mod
set(dest_module_dir_in_app_bundle "${app_dir}/../PlugIns/${escaped_uri}")
set(qml_plugin_dir "$<TARGET_FILE_DIR:${qml_plugin_target}>")
set(qmldir_file "${qml_plugin_dir}/qmldir")
add_custom_command(TARGET ${app_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${dest_module_dir_in_app_bundle}
COMMAND ${CMAKE_COMMAND} -E copy_if_different

View File

@ -9,7 +9,7 @@ Rectangle {
property Item exampleItem
width: ListView.view.width
height: button.implicitHeight + 22
height: col.implicitHeight + 22
signal clicked()
@ -22,10 +22,18 @@ Rectangle {
GradientStop {
position: 1
Behavior on color {ColorAnimation { duration: 100 }}
color: tapHandler.pressed ? "#e0e0e0" : button.containsMouse ? "#f5f5f5" : "#eee"
color: tapHandler.pressed ? "#e0e0e0" : hoverHandler.hovered ? "#f5f5f5" : "#eee"
}
}
TapHandler {
id: tapHandler
onTapped: container.clicked()
}
HoverHandler {
id: hoverHandler
}
Image {
id: image
opacity: 0.7
@ -36,53 +44,28 @@ Rectangle {
anchors.rightMargin: 16
}
Item {
id: button
anchors.top: parent.top
Column {
id: col
spacing: 2
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.right:image.left
implicitHeight: col.height
height: implicitHeight
width: buttonLabel.width + 20
property alias containsMouse: hoverHandler.hovered
TapHandler {
id: tapHandler
onTapped: container.clicked()
}
HoverHandler {
id: hoverHandler
}
Column {
spacing: 2
id: col
anchors.verticalCenter: parent.verticalCenter
anchors.margins: 10
anchors.verticalCenter: parent.verticalCenter
Text {
width: parent.width
Text {
id: buttonLabel
anchors.left: parent.left
anchors.leftMargin: 10
anchors.right: parent.right
anchors.rightMargin: 10
text: container.name
color: "black"
font.pixelSize: 22
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
styleColor: "white"
style: Text.Raised
}
Text {
id: buttonLabel2
anchors.left: parent.left
anchors.leftMargin: 10
text: container.description
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
color: "#666"
font.pixelSize: 12
}
text: container.name
color: "black"
font.pixelSize: 22
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
styleColor: "white"
style: Text.Raised
}
Text {
width: parent.width
text: container.description
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
color: "#666"
font.pixelSize: 12
}
}

View File

@ -46,7 +46,5 @@ install(TARGETS attachedstylepropertiesexample
include(../../quick/shared/QtBundleQmlModuleForMacOS.cmake)
set(app_target "attachedstylepropertiesexample")
set(qml_plugin_target "MyStyleplugin")
set(qml_module_uri "MyStyle")
add_qml_module_to_macos_app_bundle(
"${app_target}" "${qml_plugin_target}" "${qml_module_uri}")
set(qml_module_target "MyStyle")
add_qml_module_to_macos_app_bundle("${app_target}" "${qml_module_target}")

View File

@ -1,4 +1,4 @@
# Copyright (C) 2022 The Qt Company Ltd.
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
@ -28,7 +28,7 @@ qt_add_qml_module(contactlistexample
"ContactForm.ui.qml"
"ContactView.ui.qml"
"SectionDelegate.ui.qml"
"contactlist.qml"
"ContactList.qml"
"designer/Backend/ContactModel.qml"
)

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
@ -7,14 +7,18 @@ import QtQuick.Controls
ItemDelegate {
id: delegate
checkable: true
required property string fullName
required property string address
required property string city
required property string number
contentItem: ColumnLayout {
spacing: 10
Label {
text: fullName
text: delegate.fullName
font.bold: true
elide: Text.ElideRight
Layout.fillWidth: true
@ -34,7 +38,7 @@ ItemDelegate {
}
Label {
text: address
text: delegate.address
font.bold: true
elide: Text.ElideRight
Layout.fillWidth: true
@ -46,7 +50,7 @@ ItemDelegate {
}
Label {
text: city
text: delegate.city
font.bold: true
elide: Text.ElideRight
Layout.fillWidth: true
@ -58,7 +62,7 @@ ItemDelegate {
}
Label {
text: number
text: delegate.number
font.bold: true
elide: Text.ElideRight
Layout.fillWidth: true
@ -74,6 +78,7 @@ ItemDelegate {
PropertyChanges {
// TODO: When Qt Design Studio supports generalized grouped properties, change to:
// grid.visible: true
// qmllint disable Quick.property-changes-parsed
target: grid
visible: true
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
@ -41,5 +41,9 @@ Dialog {
id: form
}
onAccepted: finished(form.fullName.text, form.address.text, form.city.text, form.number.text)
onAccepted: {
if (form.fullName.text && form.address.text && form.city.text && form.number.text) {
finished(form.fullName.text, form.address.text, form.city.text, form.number.text);
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
@ -17,10 +17,10 @@ ApplicationWindow {
ContactDialog {
id: contactDialog
onFinished: function(fullName, address, city, number) {
if (currentContact === -1)
if (window.currentContact === -1)
contactView.model.append(fullName, address, city, number)
else
contactView.model.set(currentContact, fullName, address, city, number)
contactView.model.set(window.currentContact, fullName, address, city, number)
}
}
@ -35,23 +35,23 @@ ApplicationWindow {
font.bold: true
width: parent.width
horizontalAlignment: Qt.AlignHCenter
text: currentContact >= 0 ? contactView.model.get(currentContact).fullName : ""
text: window.currentContact >= 0 ? contactView.model.get(window.currentContact).fullName : ""
}
MenuItem {
text: qsTr("Edit...")
onTriggered: contactDialog.editContact(contactView.model.get(currentContact))
onTriggered: contactDialog.editContact(contactView.model.get(window.currentContact))
}
MenuItem {
text: qsTr("Remove")
onTriggered: contactView.model.remove(currentContact)
onTriggered: contactView.model.remove(window.currentContact)
}
}
ContactView {
id: contactView
anchors.fill: parent
onPressAndHold: {
currentContact = index
onPressAndHold: function(index) {
window.currentContact = index
contactMenu.open()
}
}
@ -63,7 +63,7 @@ ApplicationWindow {
anchors.right: parent.right
anchors.bottom: parent.bottom
onClicked: {
currentContact = -1
window.currentContact = -1
contactDialog.createContact()
}
}

View File

@ -1,9 +1,11 @@
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import Backend
import contactlist
ListView {
id: listView
@ -25,6 +27,9 @@ ListView {
delegate: ContactDelegate {
id: delegate
width: listView.width
required property int index
onPressAndHold: listView.pressAndHold(index)
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
@ -7,9 +7,11 @@ import QtQuick.Controls
ToolBar {
id: background
required property string section
Label {
id: label
text: section
text: background.section
anchors.fill: parent
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter

View File

@ -2,6 +2,12 @@ TEMPLATE = app
TARGET = contactlist
QT += quick
CONFIG += qmltypes
QML_IMPORT_PATH = $$pwd/.
QML_IMPORT_NAME = contactlist
QML_IMPORT_MAJOR_VERSION = 1
HEADERS += \
contactmodel.h
@ -9,15 +15,20 @@ SOURCES += \
main.cpp \
contactmodel.cpp
RESOURCES += \
qml_resources.files = \
qmldir \
ContactDelegate.ui.qml \
ContactDialog.qml \
ContactForm.ui.qml \
contactlist.qml \
ContactList.qml \
ContactView.ui.qml \
designer/Backend/ContactModel.qml \
SectionDelegate.ui.qml
qml_resources.prefix = /qt/qml/contactlist
RESOURCES += qml_resources
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH = $$PWD/designer

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "contactmodel.h"

View File

@ -1,14 +1,16 @@
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef CONTACTMODEL_H
#define CONTACTMODEL_H
#include <QAbstractListModel>
#include <QQmlEngine>
class ContactModel : public QAbstractListModel
{
Q_OBJECT
QML_ELEMENT
public:
enum ContactRole {

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick

View File

@ -1,19 +1,15 @@
// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "contactmodel.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<ContactModel>("Backend", 1, 0, "ContactModel");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/contactlist.qml")));
engine.loadFromModule("contactlist", "ContactList");
return app.exec();
}

View File

@ -0,0 +1,8 @@
module contactlist
ContactDelegate 1.0 ContactDelegate.ui.qml
ContactDialog 1.0 ContactDialog.qml
ContactForm 1.0 ContactForm.ui.qml
ContactList 1.0 ContactList.qml
ContactView 1.0 ContactView.ui.qml
SectionDelegate 1.0 SectionDelegate.ui.qml

View File

@ -54,6 +54,6 @@ install(TARGETS wearableexample
include(../../quick/shared/QtBundleQmlModuleForMacOS.cmake)
set(app_target "wearableexample")
add_qml_module_to_macos_app_bundle("${app_target}" "wearable" "Wearable")
add_qml_module_to_macos_app_bundle("${app_target}" "wearablesettings" "WearableSettings")
add_qml_module_to_macos_app_bundle("${app_target}" "wearablestyle" "WearableStyle")
add_qml_module_to_macos_app_bundle("${app_target}" "wearable")
add_qml_module_to_macos_app_bundle("${app_target}" "wearablesettings")
add_qml_module_to_macos_app_bundle("${app_target}" "wearablestyle")

View File

@ -8,17 +8,17 @@
"License": "BSD 2-clause \"Simplified\" License",
"LicenseId": "BSD-2-Clause",
"LicenseFile": "LICENSE",
"Copyright": "Copyright (C) 2003-2018 Apple Inc. All rights reserved.
Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
Copyright (C) 2007-2009 Torch Mobile, Inc. All rights reserved. (http://www.torchmobile.com/)
Copyright (C) 2009, 2010 University of Szeged
Copyright (C) 2009-2011 STMicroelectronics. All rights reserved.
Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved.
Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged
Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved.
Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved.
Copyright (C) 2011 Google Inc. All rights reserved.
Copyright (C) 2013 Samsung Electronics. All rights reserved.
Copyright (C) 2015 Cisco Systems, Inc. All rights reserved.
Copyright (c) 2002-2009 Vivek Thampi"
"Copyright": ["Copyright (C) 2003-2018 Apple Inc. All rights reserved.",
"Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)",
"Copyright (C) 2007-2009 Torch Mobile, Inc. All rights reserved. (http://www.torchmobile.com/)",
"Copyright (C) 2009, 2010 University of Szeged",
"Copyright (C) 2009-2011 STMicroelectronics. All rights reserved.",
"Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved.",
"Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged",
"Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved.",
"Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved.",
"Copyright (C) 2011 Google Inc. All rights reserved.",
"Copyright (C) 2013 Samsung Electronics. All rights reserved.",
"Copyright (C) 2015 Cisco Systems, Inc. All rights reserved.",
"Copyright (c) 2002-2009 Vivek Thampi"]
}

View File

@ -114,10 +114,7 @@ void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable,
if (result == MAP_FAILED)
CRASH();
while (madvise(result, bytes, MADV_DONTNEED)) {
if (errno != EAGAIN)
CRASH();
}
while (madvise(result, bytes, MADV_DONTNEED) == -1 && errno == EAGAIN) { }
if (fd != -1)
close(fd);
@ -250,8 +247,10 @@ void OSAllocator::decommit(void* address, size_t bytes)
mmap(address, bytes, PROT_NONE, MAP_FIXED | MAP_LAZY | MAP_PRIVATE | MAP_ANON, -1, 0);
#elif OS(LINUX)
while (madvise(address, bytes, MADV_DONTNEED)) {
if (errno != EAGAIN)
CRASH();
if (errno != EAGAIN) {
memset(address, 0, bytes); // We rely on madvise to zero-out the memory
break;
}
}
if (mprotect(address, bytes, PROT_NONE))
CRASH();

View File

@ -1,5 +1,5 @@
// 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
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#version 440

View File

@ -1,5 +1,5 @@
// 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
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#version 440

View File

@ -1662,6 +1662,10 @@ void QQuickMultiEffectPrivate::updateBlurItemsAmount(int blurLevel)
if (!m_shaderEffect)
return;
const auto engine = qmlEngine(q);
if (!engine)
return;
// Lowest blur level uses 3 items, highest 5 items.
int itemsAmount = blurLevel == 0 ? 0 : blurLevel + 2;
@ -1669,7 +1673,6 @@ void QQuickMultiEffectPrivate::updateBlurItemsAmount(int blurLevel)
// Add more blur items.
// Note that by design blur items are only added and never reduced
// during the lifetime of the effect component.
const auto engine = qmlEngine(q);
QUrl blurVs = QUrl(QStringLiteral("qrc:/data/shaders/bluritems.vert.qsb"));
QUrl blurFs = QUrl(QStringLiteral("qrc:/data/shaders/bluritems.frag.qsb"));
QQmlComponent blurComponent(engine, QUrl(QStringLiteral("qrc:/data/BlurItem.qml")));

View File

@ -1,5 +1,5 @@
// 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
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#version 440

View File

@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "quicklintplugin.h"
@ -761,11 +761,13 @@ void PropertyChangesValidatorPass::run(const QQmlSA::Element &element)
return;
QString targetId = u"<id>"_s;
const QString targetBinding = sourceCode(target->sourceLocation());
const auto targetLocation = target->sourceLocation();
const QString targetBinding = sourceCode(targetLocation);
const QQmlSA::Element targetElement = resolveIdToElement(targetBinding, element);
if (!targetElement.isNull())
targetId = targetBinding;
bool hadCustomParsedBindings = false;
for (auto it = bindings.begin(), end = bindings.end(); it != end; ++it) {
const QString name = it->propertyName();
if (element->hasProperty(name))
@ -783,12 +785,19 @@ void PropertyChangesValidatorPass::run(const QQmlSA::Element &element)
if (binding.length() > 16)
binding = binding.left(13) + "..."_L1;
hadCustomParsedBindings = true;
emitWarning(
"Property \"%1\" is custom-parsed in PropertyChanges. "
"You should phrase this binding as \"%2.%1: %3\""_L1
.arg(name, targetId, binding),
quickPropertyChangesParsed, bindingLocation);
}
if (hadCustomParsedBindings && !targetElement.isNull()) {
emitWarning("You should remove any bindings on the \"target\" property and avoid "
"custom-parsed bindings in PropertyChanges.",
quickPropertyChangesParsed, targetLocation);
}
}
QT_END_NAMESPACE

View File

@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QUICKLINTPLUGIN_H
#define QUICKLINTPLUGIN_H

View File

@ -226,6 +226,16 @@ function(_qt_internal_deploy_qml_imports_for_target)
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.

View File

@ -809,36 +809,68 @@ function(_qt_internal_target_enable_qmllint target)
_qt_internal_extend_qml_import_paths(import_args)
_qt_internal_get_tool_wrapper_script_path(tool_wrapper)
set(cmd
${tool_wrapper}
$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qmllint>
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 "$<${have_qmllint_files}:${cmd}>"
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})
set(lint_args "--json" "${CMAKE_BINARY_DIR}/${lint_target}.json")
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};${lint_args}>"
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>"
)
@ -849,18 +881,34 @@ function(_qt_internal_target_enable_qmllint target)
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
${tool_wrapper}
$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qmllint>
${import_args}
${qrc_args}
--module
${module_uri}
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>"
)
@ -935,28 +983,54 @@ function(_qt_internal_add_all_qmllint_target target_var default_target_name lint
if("${target_name}" STREQUAL "")
set(target_name ${default_target_name})
endif()
if(NOT TARGET ${target_name})
add_custom_target(${target_name})
_qt_internal_assign_to_qmllint_targets_folder(${target_name})
endif()
if(CMAKE_GENERATOR MATCHES "^Visual Studio ")
# For the Visual Studio generators we cannot use add_dependencies, because this would enable
# ${lint_target} in the default build of the solution. See QTBUG-115166 and upstream CMake
# issue #16668 for details. As a work-around, we run the ${lint_target} through 'cmake
# --build' as PRE_BUILD step of the all_qmllint target.
add_custom_command(
TARGET ${target_name} PRE_BUILD
COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" -t ${lint_target}
)
# issue #16668 for details. Instead, we record ${lint_target} and create an all_qmllint
# target at the end of the top-level directory scope.
if(${CMAKE_VERSION} VERSION_LESS "3.19.0")
if(NOT QT_NO_QMLLINT_CREATION_WARNING)
message(WARNING "Cannot create target ${target_name} with this CMake version. "
"Please upgrade to CMake 3.19.0 or newer. "
"Set QT_NO_QMLLINT_CREATION_WARNING to ON to disable this warning."
)
endif()
return()
endif()
set(property_name _qt_target_${target_name}_dependencies)
get_property(recorded_targets GLOBAL PROPERTY ${property_name})
if("${recorded_targets}" STREQUAL "")
cmake_language(EVAL CODE
"cmake_language(DEFER DIRECTORY \"${CMAKE_SOURCE_DIR}\" CALL _qt_internal_add_all_qmllint_target_deferred \"${target_name}\")"
)
endif()
set_property(GLOBAL APPEND PROPERTY ${property_name} ${lint_target})
# Exclude ${lint_target} from the solution's default build to avoid it being enabled should
# the user add a dependency to it.
set_property(TARGET ${lint_target} PROPERTY EXCLUDE_FROM_DEFAULT_BUILD ON)
else()
if(NOT TARGET ${target_name})
add_custom_target(${target_name})
_qt_internal_assign_to_qmllint_targets_folder(${target_name})
endif()
add_dependencies(${target_name} ${lint_target})
endif()
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 output_targets_var qmlcachegen)
set(output_targets)
@ -1507,6 +1581,35 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
endfunction()
endif()
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
@ -1752,6 +1855,8 @@ function(qt6_add_qml_plugin target)
)
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}")
@ -1848,8 +1953,9 @@ function(qt6_target_qml_sources target)
message(FATAL_ERROR "Unknown/unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
endif()
if (NOT arg_QML_FILES AND NOT arg_RESOURCES)
if(NOT arg_NO_LINT)
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()
@ -1868,7 +1974,6 @@ function(qt6_target_qml_sources target)
)
endif()
get_target_property(no_lint ${target} QT_QML_MODULE_NO_LINT)
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)

View File

@ -670,6 +670,8 @@ struct Binding
}
bool evaluatesToString() const { return type() == Type_String || isTranslationBinding(); }
bool isNumberBinding() const { return type() == Type_Number; }
bool valueAsBoolean() const
{
if (type() == Type_Boolean)

View File

@ -455,7 +455,7 @@
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_MINOR_VERSION(), \l QML_REMOVED_IN_MINOR_VERSION(),
\l QML_ATTACHED(), \l QML_EXTENDED(), or \l QML_EXTENDED_NAMESPACE() macros
\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
@ -469,6 +469,9 @@
the element will be named like the struct it is contained in, not the foreign type.
See the \l {Extension Objects} for an example.
\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()

View File

@ -254,13 +254,23 @@ The same declaration can also be given for C++-defined types. See
\section2 ComponentBehavior
With this pragma you can restrict components defined in this file to only
create objects within their original context. This holds for inline
components as well as Component elements explicitly or implicitly created
as properties. If a component is bound to its context, you can safely
use IDs from the rest of the file within the component. Otherwise, the
engine and the QML tooling cannot know in advance what type, if any, such
IDs will resolve to at run time.
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:
@ -269,8 +279,33 @@ argument:
pragma ComponentBehavior: Bound
\endqml
The default is \c{Unbound}. You can also specify it explicitly. In a
future version of Qt the default will change to \c{Bound}.
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

View File

@ -807,7 +807,7 @@ 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.

View File

@ -372,8 +372,11 @@ bool QJSValue::isError() const
}
/*!
Returns true if this QJSValue is an object of the URL class;
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
{
@ -635,8 +638,11 @@ QVariant QJSValue::toVariant(QJSValue::ObjectConversionBehavior behavior) const
if (val.isString())
return QVariant(val.toQString());
if (val.as<QV4::Managed>()) {
return QV4::ExecutionEngine::toVariant(
val, /*typeHint*/ QMetaType{}, behavior == RetainJSObjects);
if (behavior == RetainJSObjects)
return QV4::ExecutionEngine::toVariant(
val, /*typeHint*/ QMetaType{}, /*createJSValueForObjectsAndSymbols=*/ true);
else
return QV4::ExecutionEngine::toVariantLossy(val);
}
Q_ASSERT(false);

View File

@ -1478,11 +1478,13 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError()
// Variant conversion code
typedef QSet<QV4::Heap::Object *> V4ObjectSet;
enum class JSToQVariantConversionBehavior {Never, Safish, Aggressive };
static QVariant toVariant(
const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols,
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);
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 variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst);
static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst);
@ -1492,8 +1494,7 @@ static QV4::ReturnedValue variantToJS(QV4::ExecutionEngine *v4, const QVariant &
return v4->metaTypeToJS(value.metaType(), value.constData());
}
static QVariant toVariant(
const QV4::Value &value, QMetaType metaType, bool createJSValueForObjectsAndSymbols,
static QVariant toVariant(const QV4::Value &value, QMetaType metaType, JSToQVariantConversionBehavior conversionBehavior,
V4ObjectSet *visitedObjects)
{
Q_ASSERT (!value.isEmpty());
@ -1590,7 +1591,7 @@ static QVariant toVariant(
}
}
asVariant = toVariant(arrayValue, valueMetaType, false, visitedObjects);
asVariant = toVariant(arrayValue, valueMetaType, JSToQVariantConversionBehavior::Never, visitedObjects);
if (valueMetaType == QMetaType::fromType<QVariant>()) {
retnAsIterable.metaContainer().addValue(retn.data(), &asVariant);
} else {
@ -1655,7 +1656,7 @@ static QVariant toVariant(
if (const ArrayBuffer *d = value.as<ArrayBuffer>())
return d->asByteArray();
if (const Symbol *symbol = value.as<Symbol>()) {
return createJSValueForObjectsAndSymbols
return conversionBehavior == JSToQVariantConversionBehavior::Never
? QVariant::fromValue(QJSValuePrivate::fromReturnedValue(symbol->asReturnedValue()))
: symbol->descriptiveString();
}
@ -1676,20 +1677,27 @@ static QVariant toVariant(
return result;
}
if (createJSValueForObjectsAndSymbols)
if (conversionBehavior == JSToQVariantConversionBehavior::Never)
return QVariant::fromValue(QJSValuePrivate::fromReturnedValue(o->asReturnedValue()));
return objectToVariant(o, visitedObjects);
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)
{
return ::toVariant(value, typeHint, createJSValueForObjectsAndSymbols, nullptr);
auto behavior = createJSValueForObjectsAndSymbols ? JSToQVariantConversionBehavior::Never
: JSToQVariantConversionBehavior::Safish;
return ::toVariant(value, typeHint, behavior, nullptr);
}
static QVariantMap objectToVariantMap(const QV4::Object *o, V4ObjectSet *visitedObjects)
static QVariantMap objectToVariantMap(const QV4::Object *o, V4ObjectSet *visitedObjects,
JSToQVariantConversionBehavior conversionBehvior)
{
QVariantMap map;
QV4::Scope scope(o->engine());
@ -1704,12 +1712,13 @@ static QVariantMap objectToVariantMap(const QV4::Object *o, V4ObjectSet *visited
QString key = name->toQStringNoThrow();
map.insert(key, ::toVariant(
val, /*type hint*/ QMetaType {},
/*createJSValueForObjectsAndSymbols*/false, visitedObjects));
conversionBehvior, visitedObjects));
}
return map;
}
static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObjects)
static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObjects,
JSToQVariantConversionBehavior conversionBehvior)
{
Q_ASSERT(o);
@ -1737,13 +1746,20 @@ static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObject
int length = a->getLength();
for (int ii = 0; ii < length; ++ii) {
v = a->get(ii);
list << ::toVariant(v, QMetaType {}, /*createJSValueForObjectsAndSymbols*/false,
list << ::toVariant(v, QMetaType {}, conversionBehvior,
visitedObjects);
}
result = list;
} else if (o->getPrototypeOf() == o->engine()->objectPrototype()->d()) {
result = objectToVariantMap(o, visitedObjects);
} 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()));
@ -1974,7 +1990,7 @@ QVariantMap ExecutionEngine::variantMapFromJS(const Object *o)
Q_ASSERT(o);
V4ObjectSet visitedObjects;
visitedObjects.insert(o->d());
return objectToVariantMap(o, &visitedObjects);
return objectToVariantMap(o, &visitedObjects, JSToQVariantConversionBehavior::Safish);
}

View File

@ -644,6 +644,7 @@ public:
// variant conversions
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);

View File

@ -195,6 +195,11 @@ public:
return data->flags & CompiledData::Unit::ValueTypesCopied;
}
bool componentsAreBound() const
{
return data->flags & CompiledData::Unit::ComponentsBound;
}
int objectCount() const { return qmlData->nObjects; }
const CompiledObject *objectAt(int index) const
{

View File

@ -191,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 {
@ -208,6 +210,7 @@ struct PropertyAttributes
uchar configurable_set : 1;
};
};
QT_WARNING_POP
enum Type {
Data = 0,

View File

@ -155,10 +155,13 @@ ReturnedValue convertAndCall(
values[0] = nullptr;
}
if (const QV4::QObjectWrapper *cppThisObject = thisObject->as<QV4::QObjectWrapper>())
if (const QV4::QObjectWrapper *cppThisObject = thisObject
? thisObject->as<QV4::QObjectWrapper>()
: nullptr) {
call(cppThisObject->object(), values, types, argc);
else
} else {
call(nullptr, values, types, argc);
}
ReturnedValue result;
if (values[0]) {
@ -255,6 +258,156 @@ ReturnedValue coerceAndCall(
return result->asReturnedValue();
}
// 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;
}
// TODO: This is expensive. We might establish a direct C++-to-C++ type coercion, like we have
// will generate code that passes the right arguments.
// for JS-to-JS. However, we shouldn't need this very often. Most of the time the compiler
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

View File

@ -39,8 +39,11 @@ void Object::setInternalClass(Heap::InternalClass *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)));
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;

View File

@ -268,9 +268,33 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
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) {

View File

@ -1100,7 +1100,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
if (!v4)
break;
QQmlMetaObject::ArgTypeStorage storage;
QQmlMetaObject::ArgTypeStorage<9> storage;
QQmlMetaObject::methodParameterTypes(This->signal, &storage, nullptr);
int argCount = storage.size();
@ -1382,9 +1382,7 @@ void QObjectWrapper::destroyObject(bool lastCall)
if (!o->parent() && !ddata->indestructible) {
if (ddata && ddata->ownContext) {
Q_ASSERT(ddata->ownContext.data() == ddata->context);
ddata->ownContext->emitDestruction();
if (ddata->ownContext->contextObject() == o)
ddata->ownContext->setContextObject(nullptr);
ddata->ownContext->deepClearContextObject(o);
ddata->ownContext.reset();
ddata->context = nullptr;
}
@ -1803,7 +1801,7 @@ static ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQmlPro
if (data.hasArguments()) {
QQmlMetaObject::ArgTypeStorage storage;
QQmlMetaObject::ArgTypeStorage<9> storage;
bool ok = false;
if (data.isConstructor())
@ -1884,7 +1882,7 @@ static const QQmlPropertyData *ResolveOverloaded(
int sumMethodMatchScore = bestSumMatchScore;
if (!attempt->isV4Function()) {
QQmlMetaObject::ArgTypeStorage storage;
QQmlMetaObject::ArgTypeStorage<9> storage;
int methodArgumentCount = 0;
if (attempt->hasArguments()) {
if (attempt->isConstructor()) {

View File

@ -35,6 +35,8 @@ struct Q_QML_PRIVATE_EXPORT CppStackFrameBase
int originalArgumentsCount;
int instructionPointer;
QT_WARNING_PUSH
QT_WARNING_DISABLE_MSVC(4201) // nonstandard extension used: nameless struct/union
union {
struct {
Value *savedStackTop;
@ -57,6 +59,7 @@ struct Q_QML_PRIVATE_EXPORT CppStackFrameBase
bool returnValueIsUndefined;
};
};
QT_WARNING_POP
Kind kind;
};

View File

@ -1255,7 +1255,8 @@ void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType
storeResult = resetObjectProperty(&l, qmlScopeObject);
} else {
QVariant var(propType);
propType.convert(type, value, propType, var.data());
QV4::ExecutionEngine *v4 = engine->handle();
v4->metaTypeFromJS(v4->metaTypeToJS(type, value), propType, var.data());
storeResult = storeObjectProperty(&l, qmlScopeObject, var.data());
}
@ -1273,7 +1274,8 @@ void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType
storeResult = resetFallbackProperty(&l, qmlScopeObject);
} else {
QVariant var(propType);
propType.convert(type, value, propType, var.data());
QV4::ExecutionEngine *v4 = engine->handle();
v4->metaTypeFromJS(v4->metaTypeToJS(type, value), propType, var.data());
storeResult = storeFallbackProperty(&l, qmlScopeObject, var.data());
}
break;

View File

@ -179,7 +179,7 @@ void QQmlBoundSignalExpression::evaluate(void **a)
QMetaObjectPrivate::signal(targetMeta, m_index).methodIndex());
int argCount = metaMethod.parameterCount();
QQmlMetaObject::ArgTypeStorage storage;
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) {

View File

@ -1754,19 +1754,21 @@ enum ConsoleLogTypes {
static QString jsStack(QV4::ExecutionEngine *engine) {
QString stack;
QVector<QV4::StackFrame> stackTrace = engine->stackTrace(10);
for (int i = 0; i < stackTrace.size(); 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(qAbs(frame.line)), QString::number(frame.column));
if (f->isJSTypesFrame() && static_cast<JSTypesStackFrame *>(f)->isTailCalling()) {
stackFrame = QStringLiteral("[elided tail calls]");
} else {
stackFrame = QStringLiteral("%1 (%2:%3)").arg(
frame.function, frame.source, QString::number(qAbs(frame.line)));
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)

View File

@ -166,10 +166,7 @@ public:
QObject *createWithProperties(QObject *parent, const QVariantMap &properties,
QQmlContext *context, CreateBehavior behavior = CreateDefault);
bool isBound() const {
return compilationUnit
&& (compilationUnit->unitData()->flags & QV4::CompiledData::Unit::ComponentsBound);
}
bool isBound() const { return compilationUnit && (compilationUnit->componentsAreBound()); }
};
QQmlComponentPrivate::ConstructionState::~ConstructionState()

View File

@ -128,6 +128,28 @@ public:
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; }

View File

@ -215,23 +215,16 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
{
QObjectPrivate *p = QObjectPrivate::get(o);
if (QQmlData *d = QQmlData::get(p)) {
const auto invalidate = [](QQmlContextData *c) {c->invalidate();};
if (d->ownContext) {
for (QQmlRefPointer<QQmlContextData> lc = d->ownContext->linkedContext(); lc;
lc = lc->linkedContext()) {
lc->invalidate();
if (lc->contextObject() == o)
lc->setContextObject(nullptr);
}
d->ownContext->invalidate();
if (d->ownContext->contextObject() == o)
d->ownContext->setContextObject(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->setContextObject(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
@ -407,9 +400,7 @@ void QQmlData::setQueuedForDeletion(QObject *object)
if (QQmlData *ddata = QQmlData::get(object)) {
if (ddata->ownContext) {
Q_ASSERT(ddata->ownContext.data() == ddata->context);
ddata->context->emitDestruction();
if (ddata->ownContext->contextObject() == object)
ddata->ownContext->setContextObject(nullptr);
ddata->ownContext->deepClearContextObject(object);
ddata->ownContext.reset();
ddata->context = nullptr;
}

View File

@ -166,8 +166,20 @@ void QQmlEngineExtensionPlugin::initializeEngine(QQmlEngine *engine, const char
\since 6.2
\relates QQmlEngineExtensionPlugin
Ensures the plugin whose metadata-declaring class is named \a PluginName
is linked into static builds.
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
*/

View File

@ -78,42 +78,4 @@ QMetaType QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteAr
return QMetaType();
}
bool QQmlMetaObject::methodParameterTypes(int index, ArgTypeStorage *argStorage,
QByteArray *unknownTypeError) const
{
Q_ASSERT(_m && index >= 0);
QMetaMethod m = _m->method(index);
return methodParameterTypes(m, argStorage, unknownTypeError);
}
bool QQmlMetaObject::constructorParameterTypes(int index, ArgTypeStorage *dummy,
QByteArray *unknownTypeError) const
{
QMetaMethod m = _m->constructor(index);
return methodParameterTypes(m, dummy, unknownTypeError);
}
bool QQmlMetaObject::methodParameterTypes(const QMetaMethod &m, ArgTypeStorage *argStorage,
QByteArray *unknownTypeError)
{
Q_ASSERT(argStorage);
int argc = m.parameterCount();
argStorage->resize(argc);
for (int ii = 0; ii < argc; ++ii) {
QMetaType type = m.parameterMetaType(ii);
// we treat enumerations as int
if (type.flags().testFlag(QMetaType::IsEnumeration))
type = QMetaType::fromType<int>();
if (!type.isValid()) {
if (unknownTypeError)
*unknownTypeError = m.parameterTypeName(ii);
return false;
}
argStorage->operator[](ii) = type;
}
return true;
}
QT_END_NAMESPACE

View File

@ -34,7 +34,8 @@ class QQmlPropertyData;
class Q_QML_EXPORT QQmlMetaObject
{
public:
typedef QVarLengthArray<QMetaType, 9> ArgTypeStorage;
template<qsizetype Prealloc>
using ArgTypeStorage = QVarLengthArray<QMetaType, Prealloc>;
inline QQmlMetaObject() = default;
inline QQmlMetaObject(const QObject *);
@ -52,30 +53,116 @@ public:
inline const QMetaObject *metaObject() 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.
*/
bool methodParameterTypes(int index, ArgTypeStorage *argStorage,
QByteArray *unknownTypeError) const;
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.
*/
bool constructorParameterTypes(int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const;
template<typename ArgTypeStorage>
bool constructorParameterTypes(
int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const
{
QMetaMethod m = _m->constructor(index);
return methodParameterTypes(m, dummy, unknownTypeError);
}
static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
// 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 = QMetaType::fromType<int>();
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;
}
static bool methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage,
QByteArray *unknownTypeError);
protected:
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 int
if (type.flags().testFlag(QMetaType::IsEnumeration))
type = QMetaType::fromType<int>();
if (!type.isValid()) {
if (unknownTypeError)
*unknownTypeError = method.parameterTypeName(ii);
return false;
}
store(ii, std::move(type));
return true;
}
const QMetaObject *_m = nullptr;
};

View File

@ -154,7 +154,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
} else {
Q_ASSERT(subComponentIndex >= 0);
if (flags & CreationFlags::InlineComponent) {
if (compilationUnit->unitData()->flags & QV4::CompiledData::Unit::ComponentsBound
if (compilationUnit->componentsAreBound()
&& compilationUnit != parentContext->typeCompilationUnit()) {
recordError({}, tr("Cannot instantiate bound inline component in different file"));
phase = ObjectsCreated;
@ -164,7 +164,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
isComponentRoot = true;
} else {
Q_ASSERT(flags & CreationFlags::NormalObject);
if (compilationUnit->unitData()->flags & QV4::CompiledData::Unit::ComponentsBound
if (compilationUnit->componentsAreBound()
&& sharedState->creationContext != parentContext) {
recordError({}, tr("Cannot instantiate bound component "
"outside its creation context"));
@ -313,7 +313,10 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
QMetaType propertyType = property->propType();
if (property->isEnum()) {
if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum)) {
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 = QMetaType::fromType<int>();
} else {
// ### This should be resolved earlier at compile time and the binding value should be changed accordingly.

View File

@ -428,13 +428,14 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name,
if (result != end)
*result = result->toUpper();
qWarning()
<< terminalString
<< "is not a properly capitalized signal handler name."
<< handlerName
<< "would be correct.";
if (findSignalInMetaObject(signalName.toUtf8()))
if (findSignalInMetaObject(signalName.toUtf8())) {
qWarning()
<< terminalString
<< "is not a properly capitalized signal handler name."
<< handlerName
<< "would be correct.";
return;
}
}
if (ddata && ddata->propertyCache) {

View File

@ -864,10 +864,10 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
resettable = property->isResettable();
bindable = property->isBindable();
// Copy type flags
propertyFlags->copyPropertyTypeFlags(property->flags());
if (property->isVarProperty())
propertyFlags->type = QQmlPropertyData::Flags::QVariantType;
else
propertyFlags->copyPropertyTypeFlags(property->flags());
};
// for deep aliases, valueTypeIndex is always set

View File

@ -364,6 +364,11 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(
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);
QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex());
bool ok;

View File

@ -3,16 +3,19 @@
#include "qqmlconnections_p.h"
#include <private/qqmlboundsignal_p.h>
#include <private/qqmlcontext_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/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/qloggingcategory.h>
#include <QtCore/qdebug.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qstringlist.h>
#include <private/qobject_p.h>
@ -21,10 +24,110 @@ 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:
QList<QQmlBoundSignal*> boundsignals;
QList<QBiPointer<QQmlBoundSignal, QQmlConnectionSlotDispatcher>> boundsignals;
QQmlGuard<QObject> target;
bool enabled = true;
@ -105,6 +208,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 QtObject QtQml::Connections::target
This property holds the object that sends the signal.
@ -136,13 +255,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 : std::as_const(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;
@ -172,8 +297,12 @@ void QQmlConnections::setEnabled(bool enabled)
d->enabled = enabled;
for (QQmlBoundSignal *s : std::as_const(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();
}
@ -274,33 +403,41 @@ void QQmlConnections::connectSignalsToMethods()
++i) {
const QQmlPropertyData *handler = ddata->propertyCache->method(i);
if (!handler || !handler->isVMEFunction())
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
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()));
QV4::ScopedFunctionObject method(
scope, vmeMetaObject->vmeMethod(handler->coreIndex()));
QQmlBoundSignalExpression *expression =
ctxtdata ? new QQmlBoundSignalExpression(
target, signalIndex, ctxtdata, this,
method->as<QV4::FunctionObject>()->function())
: nullptr;
QQmlBoundSignalExpression *expression = ctxtdata
? new QQmlBoundSignalExpression(
target, signalIndex, ctxtdata, this,
method->as<QV4::FunctionObject>()->function())
: nullptr;
signal->takeExpression(expression);
d->boundsignals += signal;
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.size() > 2
&& propName.at(2).isUpper()) {

View File

@ -40,7 +40,8 @@ class Q_QML_PRIVATE_EXPORT QQmlConnections : public QObject, public QQmlParserSt
QML_CUSTOMPARSER
public:
QQmlConnections(QObject *parent=nullptr);
QQmlConnections(QObject *parent = nullptr);
~QQmlConnections();
QObject *target() const;
void setTarget(QObject *);

View File

@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qcoloroutput_p.h"

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QCOLOROUTPUT_H
#define QCOLOROUTPUT_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QDEFERREDPOINTER_P_H
#define QDEFERREDPOINTER_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljsannotation_p.h"

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSANNOTATION_P_H
#define QQMLJSANNOTATION_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljsbasicblocks_p.h"
@ -155,16 +155,6 @@ static bool containsAny(const ContainerA &container, const ContainerB &elements)
return false;
}
template<typename ContainerA, typename ContainerB>
static bool containsAll(const ContainerA &container, const ContainerB &elements)
{
for (const auto &element : elements) {
if (!container.contains(element))
return false;
}
return true;
}
template<class Key, class T, class Compare = std::less<Key>,
class KeyContainer = QList<Key>, class MappedContainer = QList<T>>
class NewFlatMap
@ -191,7 +181,7 @@ private:
struct PendingBlock
{
QList<int> conversions;
QQmlJSBasicBlocks::Conversions conversions;
int start = -1;
bool registerActive = false;
};
@ -278,7 +268,7 @@ void QQmlJSBasicBlocks::populateReaderLocations()
auto nextBlock = m_basicBlocks.find(block.start);
auto currentBlock = nextBlock++;
bool registerActive = block.registerActive;
QList<int> conversions = block.conversions;
Conversions conversions = block.conversions;
const auto blockEnd = (nextBlock == m_basicBlocks.end())
? m_annotations.end()
@ -290,7 +280,7 @@ void QQmlJSBasicBlocks::populateReaderLocations()
for (; blockInstr != blockEnd; ++blockInstr) {
if (registerActive
&& blockInstr->second.typeConversions.contains(writtenRegister)) {
conversions.append(blockInstr.key());
conversions.insert(blockInstr.key());
}
for (auto readIt = blockInstr->second.readRegisters.constBegin(),
@ -316,12 +306,26 @@ void QQmlJSBasicBlocks::populateReaderLocations()
// If we find that an already processed block has the register activated by this jump,
// we need to re-evaluate it. We also need to propagate any newly found conversions.
const auto processed = processedBlocks.find(blockStart);
if (processed == processedBlocks.end())
if (processed == processedBlocks.end()) {
blocks.append({conversions, blockStart, registerActive});
else if (registerActive && !processed->registerActive)
} else if (registerActive && !processed->registerActive) {
blocks.append({conversions, blockStart, registerActive});
else if (!containsAll(processed->conversions, conversions))
blocks.append({processed->conversions + conversions, blockStart, registerActive});
} else {
// TODO: Use unite() once it is fixed.
// We don't use unite() here since it would be more expensive. unite()
// effectively loops on only insert() and insert() does a number of checks
// each time. We trade those checks for calculating the hash twice on each
// iteration. Calculating the hash is very cheap for integers.
Conversions merged = processed->conversions;
for (const int conversion : std::as_const(conversions)) {
if (!merged.contains(conversion))
merged.insert(conversion);
}
if (merged.size() > processed->conversions.size())
blocks.append({std::move(merged), blockStart, registerActive});
}
};
if (!currentBlock->second.jumpIsUnconditional && nextBlock != m_basicBlocks.end())
@ -407,7 +411,7 @@ void QQmlJSBasicBlocks::adjustTypes()
valueType);
}
for (const QList<int> &conversions : std::as_const(it->registerReadersAndConversions)) {
for (const auto &conversions : std::as_const(it->registerReadersAndConversions)) {
for (int conversion : conversions)
liveConversions[conversion].append(it->trackedRegister);
}
@ -416,7 +420,7 @@ void QQmlJSBasicBlocks::adjustTypes()
}
for (auto it = m_readerLocations.begin(), end = m_readerLocations.end(); it != end; ++it) {
for (const QList<int> &conversions : std::as_const(it->registerReadersAndConversions)) {
for (const auto &conversions : std::as_const(it->registerReadersAndConversions)) {
for (int conversion : conversions)
liveConversions[conversion].append(it->trackedRegister);
}
@ -426,6 +430,11 @@ void QQmlJSBasicBlocks::adjustTypes()
if (it->trackedTypes.size() != 1)
continue;
// Don't adjust renamed values. We only adjust the originals.
const int writeLocation = it.key();
if (writeLocation >= 0 && m_annotations[writeLocation].isRename)
continue;
m_typeResolver->adjustTrackedType(it->trackedTypes[0], it->typeReaders.values());
}

View File

@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSBASICBLOCKS_P_H
#define QQMLJSBASICBLOCKS_P_H
@ -23,6 +23,8 @@ QT_BEGIN_NAMESPACE
class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSBasicBlocks : public QQmlJSCompilePass
{
public:
using Conversions = QSet<int>;
struct BasicBlock {
QList<int> jumpOrigins;
QList<int> readRegisters;
@ -46,7 +48,7 @@ private:
{
QList<QQmlJSScope::ConstPtr> trackedTypes;
QHash<int, QQmlJSScope::ConstPtr> typeReaders;
QHash<int, QList<int>> registerReadersAndConversions;
QHash<int, Conversions> registerReadersAndConversions;
int trackedRegister;
};

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljscodegenerator_p.h"
#include "qqmljsmetatypes_p.h"
@ -191,8 +191,8 @@ QT_WARNING_POP
result.code += registerIt->variableName + u" = "_s;
const QString originalValue = u"*static_cast<"_s + castTargetName(original)
+ u"*>(argumentsPtr["_s + QString::number(argumentIndex) + u"])"_s;
const QString originalValue = u"(*static_cast<"_s + castTargetName(original)
+ u"*>(argumentsPtr["_s + QString::number(argumentIndex) + u"]))"_s;
if (needsConversion)
result.code += conversion(original, argument, originalValue);
@ -2783,10 +2783,18 @@ void QQmlJSCodeGenerator::generateInPlaceOperation(const QString &cppOperator)
void QQmlJSCodeGenerator::generateLookup(const QString &lookup, const QString &initialization,
const QString &resultPreparation)
{
m_body += u"#ifndef QT_NO_DEBUG\n"_s;
generateSetInstructionPointer();
m_body += u"#endif\n"_s;
if (!resultPreparation.isEmpty())
m_body += resultPreparation + u";\n"_s;
m_body += u"while (!"_s + lookup + u") {\n"_s;
m_body += u"#ifdef QT_NO_DEBUG\n"_s;
generateSetInstructionPointer();
m_body += u"#endif\n"_s;
m_body += initialization + u";\n"_s;
generateExceptionCheck();
if (!resultPreparation.isEmpty())
@ -3003,7 +3011,7 @@ QString QQmlJSCodeGenerator::conversion(const QQmlJSScope::ConstPtr &from,
if (m_typeResolver->equals(to, m_typeResolver->uintType()))
return u"uint(QJSNumberCoercion::toInteger("_s + variable + u"))"_s;
if (m_typeResolver->equals(to, m_typeResolver->boolType()))
return u'(' + variable + u" && !std::isnan("_s + variable + u"))"_s;
return u"[](double moved){ return moved && !std::isnan(moved); }("_s + variable + u')';
}
if (isBoolOrNumber(from) && isBoolOrNumber(to))

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSCODEGENERATOR_P_H
#define QQMLJSCODEGENERATOR_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSCOMPILEPASS_P_H
#define QQMLJSCOMPILEPASS_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljscompiler_p.h"

View File

@ -1,5 +1,5 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSCOMPILER_P_H
#define QQMLJSCOMPILER_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljsfunctioninitializer_p.h"

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSFUNCTIONINITIALIAZER_P_H
#define QQMLJSFUNCTIONINITIALIAZER_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljsimporter_p.h"
#include "qqmljstypedescriptionreader_p.h"

View File

@ -1,5 +1,5 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSIMPORTER_P_H
#define QQMLJSIMPORTER_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljsimportvisitor_p.h"
#include "qqmljsmetatypes_p.h"

View File

@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSIMPORTEDMEMBERSVISITOR_P_H
#define QQMLJSIMPORTEDMEMBERSVISITOR_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljslinter_p.h"

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QMLJSLINTER_P_H
#define QMLJSLINTER_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljslintercodegen_p.h"

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSLINTERCODEGEN_P_H
#define QQMLJSLINTERCODEGEN_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljsliteralbindingcheck_p.h"

View File

@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSLITERALBINDINGCHECK_P_H
#define QQMLJSLITERALBINDINGCHECK_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljsloadergenerator_p.h"

View File

@ -1,5 +1,5 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSLOADERGENERATOR_P_H
#define QQMLJSLOADERGENERATOR_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include <qglobal.h>

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSLOGGER_P_H
#define QQMLJSLOGGER_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljsmetatypes_p.h"
#include "qqmljstyperesolver_p.h"

View File

@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSMETATYPES_P_H
#define QQMLJSMETATYPES_P_H
@ -120,7 +120,7 @@ public:
Const,
};
QQmlJSMetaParameter(const QString &name, const QString &typeName,
QQmlJSMetaParameter(const QString &name = QString(), const QString &typeName = QString(),
Constness typeQualifier = NonConst,
QWeakPointer<const QQmlJSScope> type = {})
: m_name(name), m_typeName(typeName), m_type(type), m_typeQualifier(typeQualifier)
@ -135,9 +135,13 @@ public:
void setType(QWeakPointer<const QQmlJSScope> type) { m_type = type; }
Constness typeQualifier() const { return m_typeQualifier; }
void setTypeQualifier(Constness typeQualifier) { m_typeQualifier = typeQualifier; }
bool isPointer() const { return m_isPointer; }
void setIsPointer(bool isPointer) { m_isPointer = isPointer; }
bool isList() const { return m_isList; }
void setIsList(bool isList) { m_isList = isList; }
friend bool operator==(const QQmlJSMetaParameter &a, const QQmlJSMetaParameter &b)
{
return a.m_name == b.m_name && a.m_typeName == b.m_typeName
@ -162,8 +166,11 @@ private:
QWeakPointer<const QQmlJSScope> m_type;
Constness m_typeQualifier = NonConst;
bool m_isPointer = false;
bool m_isList = false;
};
using QQmlJSMetaReturnType = QQmlJSMetaParameter;
class QQmlJSMetaMethod
{
public:
@ -191,20 +198,18 @@ public:
QQmlJSMetaMethod() = default;
explicit QQmlJSMetaMethod(QString name, QString returnType = QString())
: m_name(std::move(name))
, m_returnTypeName(std::move(returnType))
, m_returnType(QString(), std::move(returnType))
, m_methodType(Method)
{}
QString methodName() const { return m_name; }
void setMethodName(const QString &name) { m_name = name; }
QString returnTypeName() const { return m_returnTypeName; }
QSharedPointer<const QQmlJSScope> returnType() const { return m_returnType.toStrongRef(); }
void setReturnTypeName(const QString &type) { m_returnTypeName = type; }
void setReturnType(const QSharedPointer<const QQmlJSScope> &type)
{
m_returnType = type;
}
QQmlJSMetaReturnType returnValue() const { return m_returnType; }
void setReturnValue(const QQmlJSMetaReturnType returnValue) { m_returnType = returnValue; }
QString returnTypeName() const { return m_returnType.typeName(); }
QSharedPointer<const QQmlJSScope> returnType() const { return m_returnType.type(); }
void setReturnTypeName(const QString &type) { m_returnType.setTypeName(type); }
QList<QQmlJSMetaParameter> parameters() const { return m_parameters; }
@ -257,7 +262,7 @@ public:
friend bool operator==(const QQmlJSMetaMethod &a, const QQmlJSMetaMethod &b)
{
return a.m_name == b.m_name && a.m_returnTypeName == b.m_returnTypeName
return a.m_name == b.m_name && a.m_returnType == b.m_returnType
&& a.m_returnType == b.m_returnType && a.m_parameters == b.m_parameters
&& a.m_annotations == b.m_annotations && a.m_methodType == b.m_methodType
&& a.m_methodAccess == b.m_methodAccess && a.m_revision == b.m_revision
@ -274,8 +279,7 @@ public:
QtPrivate::QHashCombine combine;
seed = combine(seed, method.m_name);
seed = combine(seed, method.m_returnTypeName);
seed = combine(seed, method.m_returnType.toStrongRef().data());
seed = combine(seed, method.m_returnType);
seed = combine(seed, method.m_annotations);
seed = combine(seed, method.m_methodType);
seed = combine(seed, method.m_methodAccess);
@ -291,8 +295,8 @@ public:
private:
QString m_name;
QString m_returnTypeName;
QWeakPointer<const QQmlJSScope> m_returnType;
QQmlJSMetaReturnType m_returnType;
QList<QQmlJSMetaParameter> m_parameters;
QList<QQmlJSAnnotation> m_annotations;

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljsregistercontent_p.h"
#include "qqmljstyperesolver_p.h"

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSREGISTERCONTENT_P_H
#define QQMLJSREGISTERCONTENT_P_H

View File

@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#include "qqmljsresourcefilemapper_p.h"

View File

@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
#ifndef QQMLJSRESOURCEFILEMAPPER_P_H
#define QQMLJSRESOURCEFILEMAPPER_P_H

Some files were not shown because too many files have changed in this diff Show More