aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-03-18 11:44:13 +0100
committerUlf Hermann <ulf.hermann@qt.io>2020-03-18 12:37:04 +0100
commit13caf26b29283b544edc2974fa1ea0481c63b435 (patch)
treec06077293de36f69c42b5e1a38844e2b8bbe07c4
parent36fb7cf832e801a7b3718fa443ec2f1b83e0fea2 (diff)
parent869efe4a49c5286493d7f039325992725bcac6c3 (diff)
Merge remote-tracking branch 'origin/5.15' into dev
Conflicts: tools/qmllint/findunqualified.cpp Change-Id: I2593b5cc0db1d14e0c944aec4b88a80f46f5b0c1
-rw-r--r--src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp2
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp2
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp6
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h1
-rw-r--r--src/qml/qml/qqmlimport.cpp18
-rw-r--r--src/qml/qml/qqmlimport_p.h5
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp14
-rw-r--r--src/qmldebug/qqmldebugconnection.cpp4
-rw-r--r--src/quick/doc/src/advtutorial.qdoc4
-rw-r--r--src/quick/doc/src/dynamicview-tutorial.qdoc4
-rw-r--r--src/quick/doc/src/tutorial.qdoc3
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp86
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode_p.h9
-rw-r--r--tests/auto/qml/qmllint/data/ButtonLoader.qml10
-rw-r--r--tests/auto/qml/qmllint/data/Dialog.qml10
-rw-r--r--tests/auto/qml/qmllint/data/Drawer.qml5
-rw-r--r--tests/auto/qml/qmllint/data/Text.qml6
-rw-r--r--tests/auto/qml/qmllint/data/Things/plugins.qmltypes1
-rw-r--r--tests/auto/qml/qmllint/data/incompleteQmltypes.qml6
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp7
-rw-r--r--tests/auto/qml/qqmllanguage/data/inlineComponentDuplicateName.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/inlineComponentFoundBeforeOtherImports.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp25
-rw-r--r--tools/qmllint/findunqualified.cpp9
-rw-r--r--tools/qmllint/importedmembersvisitor.cpp11
-rw-r--r--tools/qmllint/scopetree.cpp66
27 files changed, 249 insertions, 82 deletions
diff --git a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp
index 1708166a8a..e641a901ad 100644
--- a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp
+++ b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp
@@ -133,7 +133,7 @@ bool QLocalClientConnection::connectToServer()
connect(m_socket, &QLocalSocket::connected,
this, &QLocalClientConnection::connectionEstablished);
connect(m_socket, static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(
- &QLocalSocket::error), m_socket, [this](QLocalSocket::LocalSocketError) {
+ &QLocalSocket::errorOccurred), m_socket, [this](QLocalSocket::LocalSocketError) {
m_socket->disconnectFromServer();
m_socket->connectToServer(m_filename);
}, Qt::QueuedConnection);
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index c6ace05b8f..82f3e53d68 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -45,8 +45,6 @@
#include "private/qqmlengine_p.h"
#include "private/qqmlglobal_p.h"
-#define DEFAULT_TIMER_INTERVAL 16
-
QT_BEGIN_NAMESPACE
#ifndef QT_NO_THREAD
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 0316e54c09..1f2e59b55e 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -549,6 +549,12 @@ bool IRBuilder::visit(QQmlJS::AST::UiInlineComponent *ast)
recordError(ast->firstSourceLocation(), QLatin1String("Nested inline components are not supported"));
return false;
}
+ if (inlineComponentsNames.contains(ast->name.toString())) {
+ recordError(ast->firstSourceLocation(), QLatin1String("Inline component names must be unique per file"));
+ return false;
+ } else {
+ inlineComponentsNames.insert(ast->name.toString());
+ }
{
QScopedValueRollback<bool> rollBack {insideInlineComponent, true};
if (!defineQMLObject(&idx, ast->component))
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 1f2c11f7f3..254d21001b 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -543,6 +543,7 @@ public:
QList<QQmlJS::DiagnosticMessage> errors;
QSet<QString> illegalNames;
+ QSet<QString> inlineComponentsNames;
QList<const QV4::CompiledData::Import *> _imports;
QList<Pragma*> _pragmas;
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 43a9435f83..08e43c1341 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1009,6 +1009,12 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
if (!typeRecursionDetected)
typeRecursionDetected = &localTypeRecursionDetected;
+ if (needsSorting()) {
+ std::stable_sort(imports.begin(), imports.end(), [](QQmlImportInstance *left, QQmlImportInstance *) {
+ return left->isInlineComponent;
+ });
+ setNeedsSorting(false);
+ }
for (int i=0; i<imports.count(); ++i) {
const QQmlImportInstance *import = imports.at(i);
if (import->resolveType(typeLoader, type, version_return, type_return, base,
@@ -1070,6 +1076,17 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
return false;
}
+bool QQmlImportNamespace::needsSorting() const
+{
+ return nextNamespace == this;
+}
+
+void QQmlImportNamespace::setNeedsSorting(bool needsSorting)
+{
+ Q_ASSERT(nextNamespace == this || nextNamespace == nullptr);
+ nextNamespace = needsSorting ? this : nullptr;
+}
+
QQmlImportsPrivate::QQmlImportsPrivate(QQmlTypeLoader *loader)
: ref(1), typeLoader(loader) {
}
@@ -1782,6 +1799,7 @@ bool QQmlImports::addInlineComponentImport(QQmlImportInstance *const importInsta
importInstance->version = QTypeRevision::zero();
importInstance->containingType = containingType;
d->unqualifiedset.imports.push_back(importInstance);
+ d->unqualifiedset.setNeedsSorting(true);
return true;
}
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index 7416bb7a4c..f7f5c32bf4 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -122,7 +122,12 @@ public:
QHashedString prefix;
// Used by QQmlImportsPrivate::qualifiedSets
+ // set to this in unqualifiedSet to indicate that the lists of imports needs
+ // to be sorted when an inline component import was added
+ // We can't use flag pointer, as that does not work with QFieldList
QQmlImportNamespace *nextNamespace;
+ bool needsSorting() const;
+ void setNeedsSorting(bool needsSorting);
};
class Q_QML_PRIVATE_EXPORT QQmlImports
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index ba5ba96cbe..aa7e28add0 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -192,7 +192,12 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *obj
r->d()->object = object;
r->d()->property = property;
r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
- r->d()->setValueType(QQmlValueTypeFactory::valueType(typeId));
+ auto valueType = QQmlValueTypeFactory::valueType(typeId);
+ if (!valueType) {
+ QMetaType metaType(typeId);
+ return engine->throwTypeError(QLatin1String("Type %1 is not a value type").arg(metaType.name()));
+ }
+ r->d()->setValueType(valueType);
r->d()->setGadgetPtr(nullptr);
return r->asReturnedValue();
}
@@ -204,7 +209,12 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVaria
Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>());
r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
- r->d()->setValueType(QQmlValueTypeFactory::valueType(typeId));
+ auto valueType = QQmlValueTypeFactory::valueType(typeId);
+ if (!valueType) {
+ QMetaType metaType(typeId);
+ return engine->throwTypeError(QLatin1String("Type %1 is not a value type").arg(metaType.name()));
+ }
+ r->d()->setValueType(valueType);
r->d()->setGadgetPtr(nullptr);
r->d()->setValue(value);
return r->asReturnedValue();
diff --git a/src/qmldebug/qqmldebugconnection.cpp b/src/qmldebug/qqmldebugconnection.cpp
index 15c56fc20d..9d495ce6e4 100644
--- a/src/qmldebug/qqmldebugconnection.cpp
+++ b/src/qmldebug/qqmldebugconnection.cpp
@@ -389,7 +389,7 @@ void QQmlDebugConnection::connectToHost(const QString &hostName, quint16 port)
connect(socket, &QAbstractSocket::disconnected, this, &QQmlDebugConnection::socketDisconnected);
connect(socket, &QAbstractSocket::connected, this, &QQmlDebugConnection::socketConnected);
connect(socket, static_cast<void(QAbstractSocket::*)(QAbstractSocket::SocketError)>(
- &QAbstractSocket::error), this, &QQmlDebugConnection::socketError);
+ &QAbstractSocket::errorOccurred), this, &QQmlDebugConnection::socketError);
connect(socket, &QAbstractSocket::stateChanged, this, &QQmlDebugConnection::socketStateChanged);
socket->connectToHost(hostName, port);
}
@@ -417,7 +417,7 @@ public:
connect(parent, &QLocalSocket::stateChanged,
this, &LocalSocketSignalTranslator::onStateChanged);
connect(parent, static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(
- &QLocalSocket::error), this, &LocalSocketSignalTranslator::onError);
+ &QLocalSocket::errorOccurred), this, &LocalSocketSignalTranslator::onError);
}
void onError(QLocalSocket::LocalSocketError error)
diff --git a/src/quick/doc/src/advtutorial.qdoc b/src/quick/doc/src/advtutorial.qdoc
index a18d4493ea..63c70067fd 100644
--- a/src/quick/doc/src/advtutorial.qdoc
+++ b/src/quick/doc/src/advtutorial.qdoc
@@ -64,7 +64,6 @@ directory.
/*!
\title QML Advanced Tutorial 1 - Creating the Game Canvas and Blocks
-\contentspage QML Advanced Tutorial
\previouspage QML Advanced Tutorial
\nextpage QML Advanced Tutorial 2 - Populating the Game Canvas
@@ -132,7 +131,6 @@ types to get started. Next, we will populate the game canvas with some blocks.
/*!
\title QML Advanced Tutorial 2 - Populating the Game Canvas
-\contentspage QML Advanced Tutorial
\previouspage QML Advanced Tutorial 1 - Creating the Game Canvas and Blocks
\nextpage QML Advanced Tutorial 3 - Implementing the Game Logic
@@ -206,7 +204,6 @@ Now, we have a screen of blocks, and we can begin to add the game mechanics.
/*!
\title QML Advanced Tutorial 3 - Implementing the Game Logic
-\contentspage QML Advanced Tutorial
\previouspage QML Advanced Tutorial 2 - Populating the Game Canvas
\nextpage QML Advanced Tutorial 4 - Finishing Touches
@@ -293,7 +290,6 @@ until the next chapter - where your application becomes alive!
/*!
\title QML Advanced Tutorial 4 - Finishing Touches
-\contentspage QML Advanced Tutorial
\previouspage QML Advanced Tutorial 3 - Implementing the Game Logic
\example tutorials/samegame/samegame4
diff --git a/src/quick/doc/src/dynamicview-tutorial.qdoc b/src/quick/doc/src/dynamicview-tutorial.qdoc
index 6f44ba1947..d221e2ae62 100644
--- a/src/quick/doc/src/dynamicview-tutorial.qdoc
+++ b/src/quick/doc/src/dynamicview-tutorial.qdoc
@@ -50,7 +50,6 @@ directory.
/*!
\title QML Dynamic View Ordering Tutorial 1 - A Simple ListView and Delegate
-\contentspage QML Dynamic View Ordering Tutorial
\previouspage QML Dynamic View Ordering Tutorial
\nextpage QML Dynamic View Ordering Tutorial 2 - Dragging View Items
@@ -85,7 +84,6 @@ The second part of the application is the ListView itself to which we bind the m
/*!
\title QML Dynamic View Ordering Tutorial 2 - Dragging View Items
-\contentspage QML Dynamic View Ordering Tutorial
\previouspage QML Dynamic View Ordering Tutorial 1 - A Simple ListView and Delegate
\nextpage QML Dynamic View Ordering Tutorial 3 - Moving Dragged Items
@@ -128,7 +126,6 @@ so that is above other items in the stacking order and isn't obscured as it is d
/*!
\title QML Dynamic View Ordering Tutorial 3 - Moving Dragged Items
-\contentspage QML Dynamic View Ordering Tutorial
\previouspage QML Dynamic View Ordering Tutorial 2 - Dragging View Items
\nextpage QML Dynamic View Ordering Tutorial 4 - Sorting Items
@@ -180,7 +177,6 @@ property of the view and bind the \l {DelegateModel::}{model} and
/*!
\title QML Dynamic View Ordering Tutorial 4 - Sorting Items
-\contentspage QML Dynamic View Ordering Tutorial
\previouspage QML Dynamic View Ordering Tutorial 3 - Moving Dragged Items
\example tutorials/dynamicview/dynamicview4
diff --git a/src/quick/doc/src/tutorial.qdoc b/src/quick/doc/src/tutorial.qdoc
index 20021f2432..7cb5f655e8 100644
--- a/src/quick/doc/src/tutorial.qdoc
+++ b/src/quick/doc/src/tutorial.qdoc
@@ -54,7 +54,6 @@ Tutorial chapters:
/*!
\page qml-tutorial1.html
\title QML Tutorial 1 - Basic Types
-\contentspage QML Tutorial
\previouspage QML Tutorial
\nextpage QML Tutorial 2 - QML Components
@@ -112,7 +111,6 @@ qmlscene tutorials/helloworld/tutorial1.qml
/*!
\page qml-tutorial2.html
\title QML Tutorial 2 - QML Components
-\contentspage QML Tutorial
\previouspage QML Tutorial 1 - Basic Types
\nextpage QML Tutorial 3 - States and Transitions
@@ -184,7 +182,6 @@ We can react to any signal of our component through a property of the name \e 'o
/*!
\page qml-tutorial3.html
\title QML Tutorial 3 - States and Transitions
-\contentspage QML Tutorial
\previouspage QML Tutorial 2 - QML Components
In this chapter, we make this example a little bit more dynamic by introducing states and transitions.
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index f9e6ba03a8..5a281cdd4a 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -1030,6 +1030,7 @@ Renderer::Renderer(QSGDefaultRenderContext *ctx)
? "static" : (m_bufferStrategy == GL_DYNAMIC_DRAW ? "dynamic" : "stream")));
}
+ static const bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER");
if (!m_rhi) {
// If rendering with an OpenGL Core profile context, we need to create a VAO
// to hold our vertex specification state.
@@ -1037,9 +1038,9 @@ Renderer::Renderer(QSGDefaultRenderContext *ctx)
m_vao = new QOpenGLVertexArrayObject(this);
m_vao->create();
}
-
- bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER");
m_useDepthBuffer = useDepth && ctx->openglContext()->format().depthBufferSize() > 0;
+ } else {
+ m_useDepthBuffer = useDepth;
}
}
@@ -1400,12 +1401,11 @@ void Renderer::nodeWasRemoved(Node *node)
m_elementsToDelete.add(e);
if (m_renderNodeElements.isEmpty()) {
- if (m_rhi) {
- m_useDepthBuffer = true;
- } else {
- static bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER");
+ static const bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER");
+ if (m_rhi)
+ m_useDepthBuffer = useDepth;
+ else
m_useDepthBuffer = useDepth && m_context->openglContext()->format().depthBufferSize() > 0;
- }
}
}
}
@@ -3716,7 +3716,7 @@ void Renderer::renderMergedBatch(PreparedRenderBatch *renderBatch) // split prep
{ batch->vbo.buf, quint32(draw.vertices) },
{ batch->vbo.buf, quint32(draw.zorders) }
};
- cb->setVertexInput(VERTEX_BUFFER_BINDING, 2, vbufBindings,
+ cb->setVertexInput(VERTEX_BUFFER_BINDING, m_useDepthBuffer ? 2 : 1, vbufBindings,
batch->ibo.buf, draw.indices,
m_uint32IndexForRhi ? QRhiCommandBuffer::IndexUInt32 : QRhiCommandBuffer::IndexUInt16);
cb->drawIndexed(draw.indexCount);
@@ -4052,8 +4052,8 @@ void Renderer::renderBatches()
m_pstate.viewportSet = false;
m_pstate.scissorSet = false;
- m_gstate.depthTest = true;
- m_gstate.depthWrite = true;
+ m_gstate.depthTest = m_useDepthBuffer;
+ m_gstate.depthWrite = m_useDepthBuffer;
m_gstate.depthFunc = QRhiGraphicsPipeline::Less;
m_gstate.blending = false;
@@ -4085,8 +4085,8 @@ void Renderer::renderBatches()
m_gstate.blending = true;
// factors never change, always set for premultiplied alpha based blending
- // depth test stays enabled but no need to write out depth from the
- // transparent (back-to-front) pass
+ // depth test stays enabled (if m_useDepthBuffer, that is) but no need
+ // to write out depth from the transparent (back-to-front) pass
m_gstate.depthWrite = false;
QVarLengthArray<PreparedRenderBatch, 64> alphaRenderBatches;
@@ -4507,6 +4507,35 @@ bool Renderer::prepareRhiRenderNode(Batch *batch, PreparedRenderBatch *renderBat
updateClipState(rd->m_clip_list, batch);
+ QSGNode *xform = e->renderNode->parent();
+ QMatrix4x4 matrix;
+ QSGNode *root = rootNode();
+ if (e->root) {
+ matrix = qsg_matrixForRoot(e->root);
+ root = e->root->sgNode;
+ }
+ while (xform != root) {
+ if (xform->type() == QSGNode::TransformNodeType) {
+ matrix = matrix * static_cast<QSGTransformNode *>(xform)->combinedMatrix();
+ break;
+ }
+ xform = xform->parent();
+ }
+ rd->m_matrix = &matrix;
+
+ QSGNode *opacity = e->renderNode->parent();
+ rd->m_opacity = 1.0;
+ while (opacity != rootNode()) {
+ if (opacity->type() == QSGNode::OpacityNodeType) {
+ rd->m_opacity = static_cast<QSGOpacityNode *>(opacity)->combinedOpacity();
+ break;
+ }
+ opacity = opacity->parent();
+ }
+
+ if (rd->m_prepareCallback)
+ rd->m_prepareCallback();
+
renderBatch->batch = batch;
renderBatch->sms = nullptr;
@@ -4535,38 +4564,15 @@ void Renderer::renderRhiRenderNode(const Batch *batch) // split prepare-render (
state.m_scissorEnabled = batch->clipState.type & ClipState::ScissorClip;
state.m_stencilEnabled = batch->clipState.type & ClipState::StencilClip;
- QSGNode *xform = e->renderNode->parent();
- QMatrix4x4 matrix;
- QSGNode *root = rootNode();
- if (e->root) {
- matrix = qsg_matrixForRoot(e->root);
- root = e->root->sgNode;
- }
- while (xform != root) {
- if (xform->type() == QSGNode::TransformNodeType) {
- matrix = matrix * static_cast<QSGTransformNode *>(xform)->combinedMatrix();
- break;
- }
- xform = xform->parent();
- }
- rd->m_matrix = &matrix;
-
- QSGNode *opacity = e->renderNode->parent();
- rd->m_opacity = 1.0;
- while (opacity != rootNode()) {
- if (opacity->type() == QSGNode::OpacityNodeType) {
- rd->m_opacity = static_cast<QSGOpacityNode *>(opacity)->combinedOpacity();
- break;
- }
- opacity = opacity->parent();
- }
-
const QSGRenderNode::StateFlags changes = e->renderNode->changedStates();
QRhiCommandBuffer *cb = commandBuffer();
- cb->beginExternal();
+ const bool needsExternal = rd->m_needsExternalRendering;
+ if (needsExternal)
+ cb->beginExternal();
e->renderNode->render(&state);
- cb->endExternal();
+ if (needsExternal)
+ cb->endExternal();
rd->m_matrix = nullptr;
rd->m_clip_list = nullptr;
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
index 519e3cd017..8112ed2da7 100644
--- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
@@ -77,6 +77,8 @@ QSGRenderNodePrivate::QSGRenderNodePrivate()
: m_matrix(nullptr)
, m_clip_list(nullptr)
, m_opacity(1)
+ , m_needsExternalRendering(true)
+ , m_prepareCallback(nullptr)
{
}
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode_p.h b/src/quick/scenegraph/coreapi/qsgrendernode_p.h
index 5c42e55689..534d630f15 100644
--- a/src/quick/scenegraph/coreapi/qsgrendernode_p.h
+++ b/src/quick/scenegraph/coreapi/qsgrendernode_p.h
@@ -51,12 +51,14 @@
// We mean it.
//
+#include <QtQuick/private/qtquickglobal_p.h>
#include <QtQuick/qsgnode.h>
#include <QtQuick/qsgrendernode.h>
+#include <functional>
QT_BEGIN_NAMESPACE
-class QSGRenderNodePrivate
+class Q_QUICK_PRIVATE_EXPORT QSGRenderNodePrivate
{
public:
QSGRenderNodePrivate();
@@ -66,6 +68,11 @@ public:
const QMatrix4x4 *m_matrix;
const QSGClipNode *m_clip_list;
qreal m_opacity;
+
+ // ### Qt 6: change this into a value for flags()
+ bool m_needsExternalRendering;
+ // ### Qt 6: change this into a virtual prepare() function
+ std::function<void()> m_prepareCallback;
};
QT_END_NAMESPACE
diff --git a/tests/auto/qml/qmllint/data/ButtonLoader.qml b/tests/auto/qml/qmllint/data/ButtonLoader.qml
new file mode 100644
index 0000000000..2721614735
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/ButtonLoader.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.12
+
+Item {
+ Text {
+ id: roundButton
+ Text {
+ font.pixelSize: roundButton.font.pixelSize * 0.5
+ }
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/Dialog.qml b/tests/auto/qml/qmllint/data/Dialog.qml
new file mode 100644
index 0000000000..bde8eae18b
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/Dialog.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.12
+
+Item {
+ id: control
+ property Text header
+ header: Text {
+ font.bold: true
+ padding: 12
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/Drawer.qml b/tests/auto/qml/qmllint/data/Drawer.qml
new file mode 100644
index 0000000000..db1d785c6c
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/Drawer.qml
@@ -0,0 +1,5 @@
+import QtQml 2.12 as T
+
+T.QtObject {
+ objectName: T.Component.objectName
+}
diff --git a/tests/auto/qml/qmllint/data/Text.qml b/tests/auto/qml/qmllint/data/Text.qml
new file mode 100644
index 0000000000..130578d1e3
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/Text.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.12 as T
+
+T.Text {
+ id: control
+ text: "'ello"
+}
diff --git a/tests/auto/qml/qmllint/data/Things/plugins.qmltypes b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes
index 00cda191cc..9d81c21070 100644
--- a/tests/auto/qml/qmllint/data/Things/plugins.qmltypes
+++ b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes
@@ -12,5 +12,6 @@ Module {
"CCC": 2
}
}
+ Property { name: "palette"; type: "QPalette" }
}
}
diff --git a/tests/auto/qml/qmllint/data/incompleteQmltypes.qml b/tests/auto/qml/qmllint/data/incompleteQmltypes.qml
new file mode 100644
index 0000000000..ab06bbd8b0
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/incompleteQmltypes.qml
@@ -0,0 +1,6 @@
+import Things 1.0
+
+SomethingEntirelyStrange {
+ id: self
+ property var a: self.palette.weDontKnowIt
+}
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index 1cd9f8b0d1..ed968d6623 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -160,6 +160,10 @@ void TestQmllint::dirtyQmlCode_data()
<< QStringLiteral("badTypeAssertion.qml")
<< QString("Warning: Property \"rrr\" not found on type \"Item\" at 5:39")
<< QString();
+ QTest::newRow("incompleteQmltypes")
+ << QStringLiteral("incompleteQmltypes.qml")
+ << QString("Warning: Type \"QPalette\" of member \"palette\" not found at 5:26")
+ << QString();
}
void TestQmllint::dirtyQmlCode()
@@ -192,6 +196,9 @@ void TestQmllint::cleanQmlCode_data()
QTest::newRow("goodParent") << QStringLiteral("goodParent.qml");
QTest::newRow("goodTypeAssertion") << QStringLiteral("goodTypeAssertion.qml");
QTest::newRow("AttachedProps") << QStringLiteral("AttachedProps.qml");
+ QTest::newRow("unknownBuiltinFont") << QStringLiteral("ButtonLoader.qml");
+ QTest::newRow("confusingImport") << QStringLiteral("Dialog.qml");
+ QTest::newRow("qualifiedAttached") << QStringLiteral("Drawer.qml");
}
void TestQmllint::cleanQmlCode()
diff --git a/tests/auto/qml/qqmllanguage/data/inlineComponentDuplicateName.qml b/tests/auto/qml/qqmllanguage/data/inlineComponentDuplicateName.qml
new file mode 100644
index 0000000000..12cc79cf14
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/inlineComponentDuplicateName.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.12
+Item
+{
+ component IC: Item {}
+ component IC: Item {}
+}
diff --git a/tests/auto/qml/qqmllanguage/data/inlineComponentFoundBeforeOtherImports.qml b/tests/auto/qml/qqmllanguage/data/inlineComponentFoundBeforeOtherImports.qml
new file mode 100644
index 0000000000..85903727fb
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/inlineComponentFoundBeforeOtherImports.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.12
+
+Item
+{
+ component Rectangle: Item {
+ Component.onCompleted: console.info("Created")
+ }
+ Rectangle {}
+}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index c6076410b2..6d932c2665 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -318,6 +318,8 @@ private slots:
void inlineComponentInSingleton();
void nonExistingInlineComponent_data();
void nonExistingInlineComponent();
+ void inlineComponentFoundBeforeOtherImports();
+ void inlineComponentDuplicateNameError();
void selfReference();
void selfReferencingSingleton();
@@ -5743,6 +5745,29 @@ void tst_qqmllanguage::nonExistingInlineComponent()
QCOMPARE(error.column(), column);
}
+void tst_qqmllanguage::inlineComponentFoundBeforeOtherImports()
+{
+ QQmlEngine engine;
+ QUrl url = testFileUrl("inlineComponentFoundBeforeOtherImports.qml");
+ QQmlComponent component(&engine, url);
+
+ QTest::ignoreMessage(QtMsgType::QtInfoMsg, "Created");
+ QScopedPointer<QObject> root {component.create()};
+}
+
+void tst_qqmllanguage::inlineComponentDuplicateNameError()
+{
+ QQmlEngine engine;
+ QUrl url = testFileUrl("inlineComponentDuplicateName.qml");
+ QQmlComponent component(&engine, url);
+
+ QString message = QLatin1String("%1:5 Inline component names must be unique per file\n").arg(url.toString());
+ QScopedPointer<QObject> root {component.create()};
+ QVERIFY(root.isNull());
+ QVERIFY(component.isError());
+ QCOMPARE(component.errorString(), message);
+}
+
class TestItem : public QObject
{
Q_OBJECT
diff --git a/tools/qmllint/findunqualified.cpp b/tools/qmllint/findunqualified.cpp
index 6155ea4637..305dd65c66 100644
--- a/tools/qmllint/findunqualified.cpp
+++ b/tools/qmllint/findunqualified.cpp
@@ -43,6 +43,7 @@
static const QString prefixedName(const QString &prefix, const QString &name)
{
+ Q_ASSERT(!prefix.endsWith('.'));
return prefix.isEmpty() ? name : (prefix + QLatin1Char('.') + name);
}
@@ -88,11 +89,9 @@ void FindUnqualifiedIDVisitor::parseHeaders(QQmlJS::AST::UiHeaderItemList *heade
uri = uri->next;
}
path.chop(1);
- QString prefix = QLatin1String("");
- if (import->asToken.isValid()) {
- prefix += import->importId + QLatin1Char('.');
- }
- importHelper(path, prefix, import->version->version);
+ importHelper(path,
+ import->asToken.isValid() ? import->importId.toString() : QString(),
+ import->version->version);
}
}
header = header->next;
diff --git a/tools/qmllint/importedmembersvisitor.cpp b/tools/qmllint/importedmembersvisitor.cpp
index 676903d135..c5214f2bb9 100644
--- a/tools/qmllint/importedmembersvisitor.cpp
+++ b/tools/qmllint/importedmembersvisitor.cpp
@@ -57,10 +57,13 @@ ScopeTree *ImportedMembersVisitor::result(const QString &scopeName) const
bool ImportedMembersVisitor::visit(UiObjectDefinition *definition)
{
ScopeTree::Ptr scope(new ScopeTree(ScopeType::QMLScope));
- auto qualifiedId = definition->qualifiedTypeNameId;
- while (qualifiedId && qualifiedId->next)
- qualifiedId = qualifiedId->next;
- scope->setSuperclassName(qualifiedId->name.toString());
+ QString superType;
+ for (auto segment = definition->qualifiedTypeNameId; segment; segment = segment->next) {
+ if (!superType.isEmpty())
+ superType.append('.');
+ superType.append(segment->name.toString());
+ }
+ scope->setSuperclassName(superType);
if (!m_rootObject)
m_rootObject = scope;
m_currentObjects.append(scope);
diff --git a/tools/qmllint/scopetree.cpp b/tools/qmllint/scopetree.cpp
index e7e0113f35..8c5358c7a5 100644
--- a/tools/qmllint/scopetree.cpp
+++ b/tools/qmllint/scopetree.cpp
@@ -134,6 +134,15 @@ private:
QStringRef m_afterText;
};
+static const QStringList unknownBuiltins = {
+ // TODO: "string" should be added to builtins.qmltypes, and the special handling below removed
+ QStringLiteral("alias"), // TODO: we cannot properly resolve aliases, yet
+ QStringLiteral("QRectF"), // TODO: should be added to builtins.qmltypes
+ QStringLiteral("QFont"), // TODO: should be added to builtins.qmltypes
+ QStringLiteral("QJSValue"), // We cannot say anything intelligent about untyped JS values.
+ QStringLiteral("variant"), // Same for generic variants
+};
+
bool ScopeTree::checkMemberAccess(
const QString &code,
FieldMemberList *members,
@@ -169,10 +178,31 @@ bool ScopeTree::checkMemberAccess(
}
return true;
}
- const ScopeTree *type = (scopeIt->type() && access->m_parentType.isEmpty())
- ? scopeIt->type()
- : types.value(typeName).get();
- return checkMemberAccess(code, access.get(), type, types, colorOut);
+
+ if (!access->m_child)
+ return true;
+
+ if (const ScopeTree *type = scopeIt->type()) {
+ if (access->m_parentType.isEmpty())
+ return checkMemberAccess(code, access.get(), type, types, colorOut);
+ }
+
+ if (unknownBuiltins.contains(typeName))
+ return true;
+
+ const auto it = types.find(typeName);
+ if (it != types.end())
+ return checkMemberAccess(code, access.get(), it->get(), types, colorOut);
+
+ colorOut.write("Warning: ", Warning);
+ colorOut.write(
+ QString::fromLatin1("Type \"%1\" of member \"%2\" not found at %3:%4.\n")
+ .arg(typeName)
+ .arg(access->m_name)
+ .arg(access->m_location.startLine)
+ .arg(access->m_location.startColumn), Normal);
+ printContext(colorOut, code, access->m_location);
+ return false;
}
const auto scopeMethodIt = scope->m_methods.find(access->m_name);
@@ -251,13 +281,6 @@ bool ScopeTree::checkMemberAccess(
return false;
}
-static const QStringList unknownBuiltins = {
- QStringLiteral("alias"), // TODO: we cannot properly resolve aliases, yet
- QStringLiteral("QRectF"), // TODO: should be added to builtins.qmltypes
- QStringLiteral("QJSValue"), // We cannot say anything intelligent about untyped JS values.
- QStringLiteral("variant"), // Same for generic variants
-};
-
bool ScopeTree::recheckIdentifiers(
const QString &code,
const QHash<QString, const ScopeTree *> &qmlIDs,
@@ -287,9 +310,24 @@ bool ScopeTree::recheckIdentifiers(
auto it = qmlIDs.find(memberAccessTree->m_name);
if (it != qmlIDs.end()) {
- if (!checkMemberAccess(code, memberAccessTree.get(), *it, types, colorOut))
- noUnqualifiedIdentifier = false;
- continue;
+ if (*it != nullptr) {
+ if (!checkMemberAccess(code, memberAccessTree.get(), *it, types, colorOut))
+ noUnqualifiedIdentifier = false;
+ continue;
+ } else if (memberAccessTree->m_child
+ && memberAccessTree->m_child->m_name.front().isUpper()) {
+ // It could be a qualified type name
+ const QString qualified = memberAccessTree->m_name + QLatin1Char('.')
+ + memberAccessTree->m_child->m_name;
+ const auto typeIt = types.find(qualified);
+ if (typeIt != types.end()) {
+ if (!checkMemberAccess(code, memberAccessTree->m_child.get(), typeIt->get(),
+ types, colorOut)) {
+ noUnqualifiedIdentifier = false;
+ }
+ continue;
+ }
+ }
}
auto qmlScope = currentScope->currentQMLScope();