aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2017-09-20 18:57:07 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2017-09-20 18:57:07 +0000
commit112d668c0fded8c6ab7bf40fd3800cf43e005f95 (patch)
treeb23889851a0d8c779bd7f2f3605375f8adc1cb05
parentae805cafde1f327c9252b9d08449a08f052746d4 (diff)
parent55a671ea73fbe657f360befa221e2c0c15ed4b0e (diff)
Merge "Merge remote-tracking branch 'origin/5.9' into 5.10" into refs/staging/5.10
-rw-r--r--dist/changes-5.6.378
-rw-r--r--src/imports/settings/qqmlsettings.cpp9
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp32
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h2
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp7
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp9
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h1
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator_p.h12
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator.cpp12
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp28
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h2
-rw-r--r--src/qml/compiler/qv4compileddata.cpp36
-rw-r--r--src/qml/compiler/qv4compileddata_p.h34
-rw-r--r--src/qml/compiler/qv4compiler.cpp1
-rw-r--r--src/qml/jsruntime/qv4engine.cpp30
-rw-r--r--src/qml/jsruntime/qv4engine_p.h10
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp1
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp9
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h13
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp8
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp9
-rw-r--r--src/qml/jsruntime/qv4regexp_p.h13
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp13
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h8
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp7
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp7
-rw-r--r--src/qml/qml.pro13
-rw-r--r--src/qml/qml/qqmlcontext.cpp61
-rw-r--r--src/qml/qml/qqmlcontext_p.h132
-rw-r--r--src/qml/qml/qqmldata_p.h36
-rw-r--r--src/qml/qml/qqmlengine.cpp22
-rw-r--r--src/qml/qml/qqmlimport.cpp11
-rw-r--r--src/qml/qml/qqmlmetatype.cpp22
-rw-r--r--src/qml/qml/qqmlmetatype_p.h3
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp6
-rw-r--r--src/qml/qml/qqmltypeloader.cpp21
-rw-r--r--src/qml/qml/qqmltypeloader_p.h17
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp2
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp4
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp30
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h2
-rw-r--r--src/qml/types/qqmllistmodel.cpp30
-rw-r--r--src/qml/types/qqmllistmodel_p_p.h2
-rw-r--r--src/qmltest/quicktest.cpp2
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp37
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture_p.h1
-rw-r--r--src/quick/items/qquickanimatedimage.cpp22
-rw-r--r--src/quick/items/qquickanimatedimage_p.h3
-rw-r--r--src/quick/items/qquickanimatedimage_p_p.h1
-rw-r--r--src/quick/items/qquickdrag.cpp1
-rw-r--r--src/quick/items/qquickflickable.cpp2
-rw-r--r--src/quick/items/qquicktextedit.cpp2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp2
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp23
-rw-r--r--tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp35
-rw-r--r--tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp61
-rw-r--r--tests/auto/qml/qqmlcontext/data/Singleton.qml5
-rw-r--r--tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml14
-rw-r--r--tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp28
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.cpp9
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.h5
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp22
-rw-r--r--tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro2
-rw-r--r--tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp59
-rw-r--r--tests/auto/qml/qqmllanguage/data/MyLazyDeferredSubObject.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/lazyDeferredSubObject.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp2
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h20
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp18
-rw-r--r--tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp23
-rw-r--r--tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp4
-rw-r--r--tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp10
-rw-r--r--tests/auto/quick/qquickgridview/tst_qquickgridview.cpp2
-rw-r--r--tests/auto/quick/qquicklistview/data/programmaticFlickAtBounds3.qml19
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp30
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml40
-rw-r--r--tests/auto/quick/qquickpathview/tst_qquickpathview.cpp2
-rw-r--r--tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp13
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp36
-rw-r--r--tools/qmlimportscanner/main.cpp2
-rw-r--r--tools/qmlplugindump/main.cpp2
83 files changed, 1065 insertions, 314 deletions
diff --git a/dist/changes-5.6.3 b/dist/changes-5.6.3
new file mode 100644
index 0000000000..3dfc21eb39
--- /dev/null
+++ b/dist/changes-5.6.3
@@ -0,0 +1,78 @@
+Qt 5.6.3 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.6.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+ http://doc.qt.io/qt-5/index.html
+
+The Qt version 5.6 series is binary compatible with the 5.5.x series.
+Applications compiled for 5.5 will continue to run with 5.6.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+ https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+QQuickWindow
+------------
+
+ - The relevant child item is now sent a hover event when the window
+ receives a QEnterEvent, making sure hovering is recognized without
+ waiting for mouse movement.
+ - [QTBUG-56075] Wheel events retain their timestamps during delivery.
+
+QtQml
+-----
+
+ - Fixed reading of enum properties from gadgets / value types when the
+ enum was registered with qRegisterMetaType().
+ - [QTBUG-56271] Fixed a crash on big-endian architecture.
+ - [QTBUG-50592] JSON.stringify() uses QVariant::toString() so that URLs
+ and other types which are stored as variants will not be omitted.
+ - [QTBUG-56658] Fixed a crash in the Qt Quick compiler.
+ - [QTBUG-56830] Fixed conversion of long numeric strings to integers.
+ - [QTBUG-52356] Fixed binding re-evaluation when list model properties change.
+ - [QTBUG-58133] Fixed a crash when emitting a signal with an undefined QJSValue.
+ - [QTBUG-57633][QTBUG-46263] Fix crash with QObjects exposed to multiple QML engines.
+ - [QTBUG-58271] Fix PropertyChanges element to restore bindings on aliases.
+ - [QTBUG-56499] Fix Connection element not disconnecting when target became null.
+ - Work around crashes with gcc 5/6 caused by dead-store eliminations.
+ - Fix memory leak with QQmlExpression.
+ - [QTBUG-53261] Fix memory corruption when changing JS object properties in
+ certain ways.
+ - [QTBUG-39888] Fix crash with QQuickItem objects that do not have a parent but
+ should be kept alive by the JS garbage collector.
+ - [QTBUG-54822] Fix support for address space configurations where the kernel uses
+ more bits in pointer addressing
+ - [QTBUG-56551] Fix crash with Connection element and non-existent objects
+
+QtQuick
+-------
+
+ - [QTBUG-39888] Fixed crash with QQuickItems created via JavaScript being
+ garbage collected sometimes when they're not assigned to a window.
+ - [QTBUG-44038] TextInput no longer emits editingFinished twice on iOS.
+ - [QTBUG-55871][QTBUG-55886] Flickable::movementEnding and movementEnded
+ are emitted reliably at the right times on macOS.
+ - [QTBUG-55779] Text padding now has the proper effect on height when
+ there is more than one line of text.
+ - [QTBUG-37095] Canvas is rendered at high resolution if the scene is
+ initially rendered on a high-DPI screen.
+ - [QTBUG-56657] Fixed a bug resulting in invisible images in some cases.
+ - [QTBUG-58852] Large amounts of text are now rendered properly with
+ Text.NativeRendering.
+
+QuickTest
+---------
+ - [QTBUG-56223] Mouse events now include timestamps.
+
+QtWidgets
+---------
+
+ - [QTBUG-42074][QTBUG-57003] Support characters in Private Use Area, as
+ well as zero-width joiners and zero-width non-joiners in input in
+ TextInput and TextEdit.
diff --git a/src/imports/settings/qqmlsettings.cpp b/src/imports/settings/qqmlsettings.cpp
index ed2f58e7c1..f6040e7a64 100644
--- a/src/imports/settings/qqmlsettings.cpp
+++ b/src/imports/settings/qqmlsettings.cpp
@@ -189,6 +189,9 @@ QT_BEGIN_NAMESPACE
only provides a cleaner settings structure, but also prevents possible
conflicts between setting keys.
+ If several categories are required, use several Settings objects, each with
+ their own category:
+
\qml
Item {
id: panel
@@ -200,6 +203,12 @@ QT_BEGIN_NAMESPACE
property alias visible: panel.visible
// ...
}
+
+ Settings {
+ category: "General"
+ property alias fontSize: fontSizeSpinBox.value
+ // ...
+ }
}
\endqml
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
index 510c745d4e..d676731ba7 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
@@ -44,24 +44,36 @@
QT_BEGIN_NAMESPACE
-QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine) :
- next(0)
+QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine)
{
- setService(service);
engine->profiler = new QQmlProfiler;
+ init(service, engine->profiler);
+}
+
+QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlTypeLoader *loader)
+{
+ QQmlProfiler *profiler = new QQmlProfiler;
+ loader->setProfiler(profiler);
+ init(service, profiler);
+}
+
+void QQmlProfilerAdapter::init(QQmlProfilerService *service, QQmlProfiler *profiler)
+{
+ next = 0;
+ setService(service);
connect(this, &QQmlProfilerAdapter::profilingEnabled,
- engine->profiler, &QQmlProfiler::startProfiling);
+ profiler, &QQmlProfiler::startProfiling);
connect(this, &QQmlAbstractProfilerAdapter::profilingEnabledWhileWaiting,
- engine->profiler, &QQmlProfiler::startProfiling, Qt::DirectConnection);
+ profiler, &QQmlProfiler::startProfiling, Qt::DirectConnection);
connect(this, &QQmlAbstractProfilerAdapter::profilingDisabled,
- engine->profiler, &QQmlProfiler::stopProfiling);
+ profiler, &QQmlProfiler::stopProfiling);
connect(this, &QQmlAbstractProfilerAdapter::profilingDisabledWhileWaiting,
- engine->profiler, &QQmlProfiler::stopProfiling, Qt::DirectConnection);
+ profiler, &QQmlProfiler::stopProfiling, Qt::DirectConnection);
connect(this, &QQmlAbstractProfilerAdapter::dataRequested,
- engine->profiler, &QQmlProfiler::reportData);
+ profiler, &QQmlProfiler::reportData);
connect(this, &QQmlAbstractProfilerAdapter::referenceTimeKnown,
- engine->profiler, &QQmlProfiler::setTimer);
- connect(engine->profiler, &QQmlProfiler::dataReady,
+ profiler, &QQmlProfiler::setTimer);
+ connect(profiler, &QQmlProfiler::dataReady,
this, &QQmlProfilerAdapter::receiveData);
}
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h
index 1fee5c389f..7531cd1dff 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h
@@ -60,6 +60,7 @@ class QQmlProfilerAdapter : public QQmlAbstractProfilerAdapter {
Q_OBJECT
public:
QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine);
+ QQmlProfilerAdapter(QQmlProfilerService *service, QQmlTypeLoader *loader);
qint64 sendMessages(qint64 until, QList<QByteArray> &messages,
bool trackLocations) Q_DECL_OVERRIDE;
@@ -67,6 +68,7 @@ public:
const QQmlProfiler::LocationHash &locations);
private:
+ void init(QQmlProfilerService *service, QQmlProfiler *profiler);
QVector<QQmlProfilerData> data;
QQmlProfiler::LocationHash locations;
int next;
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
index edeb364f60..4176ede40e 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp
@@ -119,9 +119,12 @@ void QQmlProfilerServiceImpl::engineAboutToBeAdded(QJSEngine *engine)
QMutexLocker lock(&m_configMutex);
if (QQmlEngine *qmlEngine = qobject_cast<QQmlEngine *>(engine)) {
- QQmlProfilerAdapter *qmlAdapter =
- new QQmlProfilerAdapter(this, QQmlEnginePrivate::get(qmlEngine));
+ QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(qmlEngine);
+ QQmlProfilerAdapter *qmlAdapter = new QQmlProfilerAdapter(this, enginePrivate);
addEngineProfiler(qmlAdapter, engine);
+ QQmlProfilerAdapter *compileAdapter
+ = new QQmlProfilerAdapter(this, &(enginePrivate->typeLoader));
+ addEngineProfiler(compileAdapter, engine);
}
QV4ProfilerAdapter *v4Adapter = new QV4ProfilerAdapter(this, QV8Engine::getV4(engine->handle()));
addEngineProfiler(v4Adapter, engine);
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index a26c80e093..57121e5460 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -317,7 +317,6 @@ void Document::removeScriptPragmas(QString &script)
Document::Document(bool debugMode)
: jsModule(debugMode)
, program(0)
- , indexOfRootObject(0)
, jsGenerator(&jsModule)
{
}
@@ -421,7 +420,10 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, Documen
QQmlJS::AST::UiObjectDefinition *rootObject = QQmlJS::AST::cast<QQmlJS::AST::UiObjectDefinition*>(program->members->member);
Q_ASSERT(rootObject);
- defineQMLObject(&output->indexOfRootObject, rootObject);
+ int rootObjectIndex = -1;
+ if (defineQMLObject(&rootObjectIndex, rootObject)) {
+ Q_ASSERT(rootObjectIndex == 0);
+ }
qSwap(_imports, output->imports);
qSwap(_pragmas, output->pragmas);
@@ -1468,7 +1470,6 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4:
qmlUnit->nImports = output.imports.count();
qmlUnit->offsetToObjects = unitSize + importSize;
qmlUnit->nObjects = output.objects.count();
- qmlUnit->indexOfRootObject = output.indexOfRootObject;
qmlUnit->offsetToStringTable = totalSize - output.jsGenerator.stringTable.sizeOfTableAndData();
qmlUnit->stringTableSize = output.jsGenerator.stringTable.stringCount();
@@ -2216,8 +2217,6 @@ void IRLoader::load()
output->pragmas << p;
}
- output->indexOfRootObject = unit->indexOfRootObject;
-
for (uint i = 0; i < unit->nObjects; ++i) {
const QV4::CompiledData::Object *serializedObject = unit->objectAt(i);
QmlIR::Object *object = loadObject(serializedObject);
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 4c29e0b9f5..a5b4815745 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -457,7 +457,6 @@ struct Q_QML_PRIVATE_EXPORT Document
QList<const QV4::CompiledData::Import *> imports;
QList<Pragma*> pragmas;
QQmlJS::AST::UiProgram *program;
- int indexOfRootObject;
QVector<Object*> objects;
QV4::Compiler::JSUnitGenerator jsGenerator;
diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h
index b33deac045..5d6a5c177a 100644
--- a/src/qml/compiler/qqmlpropertycachecreator_p.h
+++ b/src/qml/compiler/qqmlpropertycachecreator_p.h
@@ -108,7 +108,7 @@ template <typename ObjectContainer>
inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
{
QQmlBindingInstantiationContext context;
- return buildMetaObjectRecursively(objectContainer->rootObjectIndex(), context);
+ return buildMetaObjectRecursively(/*root object*/0, context);
}
template <typename ObjectContainer>
@@ -278,7 +278,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
QByteArray newClassName;
- if (objectIndex == objectContainer->rootObjectIndex()) {
+ if (objectIndex == /*root object*/0) {
const QString path = objectContainer->url().path();
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
if (lastSlash > -1) {
@@ -576,7 +576,9 @@ inline QQmlPropertyCacheAliasCreator<ObjectContainer>::QQmlPropertyCacheAliasCre
template <typename ObjectContainer>
inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertiesToMetaObjects()
{
- for (int i = 0; i < objectContainer->objectCount(); ++i) {
+ // skip the root object (index 0) as that one does not have a first object index originating
+ // from a binding.
+ for (int i = 1; i < objectContainer->objectCount(); ++i) {
const CompiledObject &component = *objectContainer->objectAt(i);
if (!(component.flags & QV4::CompiledData::Object::IsComponent))
continue;
@@ -585,7 +587,7 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertie
appendAliasPropertiesInMetaObjectsWithinComponent(component, rootBinding->value.objectIndex);
}
- const int rootObjectIndex = objectContainer->rootObjectIndex();
+ const int rootObjectIndex = 0;
appendAliasPropertiesInMetaObjectsWithinComponent(*objectContainer->objectAt(rootObjectIndex), rootObjectIndex);
}
@@ -648,7 +650,7 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAl
objectsWithAliases->append(objectIndex);
// Stop at Component boundary
- if (object.flags & QV4::CompiledData::Object::IsComponent && objectIndex != objectContainer->rootObjectIndex())
+ if (object.flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0)
return;
auto binding = object.bindingsBegin();
diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp
index 4ac7aad553..7ea89b378d 100644
--- a/src/qml/compiler/qqmlpropertyvalidator.cpp
+++ b/src/qml/compiler/qqmlpropertyvalidator.cpp
@@ -58,7 +58,7 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, c
QVector<QQmlCompileError> QQmlPropertyValidator::validate()
{
- return validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0);
+ return validateObject(/*root object*/0, /*instantiatingBinding*/0);
}
typedef QVarLengthArray<const QV4::CompiledData::Binding *, 8> GroupPropertyVector;
@@ -94,16 +94,6 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex,
if (!propertyCache)
return QVector<QQmlCompileError>();
- QStringList deferredPropertyNames;
- {
- const QMetaObject *mo = propertyCache->firstCppMetaObject();
- const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
- if (namesIndex != -1) {
- QMetaClassInfo classInfo = mo->classInfo(namesIndex);
- deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
- }
- }
-
QQmlCustomParser *customParser = 0;
if (auto typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
if (typeRef->type.isValid())
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 9058a6c78f..697690984f 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -228,15 +228,10 @@ QVector<QmlIR::Object *> *QQmlTypeCompiler::qmlObjects() const
return &document->objects;
}
-int QQmlTypeCompiler::rootObjectIndex() const
-{
- return document->indexOfRootObject;
-}
-
void QQmlTypeCompiler::setPropertyCaches(QQmlPropertyCacheVector &&caches)
{
m_propertyCaches = std::move(caches);
- Q_ASSERT(m_propertyCaches.count() >= document->indexOfRootObject);
+ Q_ASSERT(m_propertyCaches.count() > 0);
}
const QQmlPropertyCacheVector *QQmlTypeCompiler::propertyCaches() const
@@ -703,7 +698,7 @@ QQmlCustomParserScriptIndexer::QQmlCustomParserScriptIndexer(QQmlTypeCompiler *t
void QQmlCustomParserScriptIndexer::annotateBindingsWithScriptStrings()
{
- scanObjectRecursively(compiler->rootObjectIndex());
+ scanObjectRecursively(/*root object*/0);
}
void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool annotateScriptBindings)
@@ -798,7 +793,6 @@ QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *t
, enginePrivate(typeCompiler->enginePrivate())
, pool(typeCompiler->memoryPool())
, qmlObjects(typeCompiler->qmlObjects())
- , indexOfRootObject(typeCompiler->rootObjectIndex())
, resolvedTypes(&typeCompiler->resolvedTypes)
, propertyCaches(std::move(typeCompiler->takePropertyCaches()))
{
@@ -936,9 +930,9 @@ bool QQmlComponentAndAliasResolver::resolve()
if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
- // We are going to collect ids/aliases and resolve them for the root object as a separate
+ // For the root object, we are going to collect ids/aliases and resolve them for as a separate
// last pass.
- if (i != indexOfRootObject)
+ if (i != 0)
componentRoots.append(i);
}
@@ -964,12 +958,12 @@ bool QQmlComponentAndAliasResolver::resolve()
_idToObjectIndex.clear();
_objectsWithAliases.clear();
- collectIdsAndAliases(indexOfRootObject);
+ collectIdsAndAliases(/*root object*/0);
- QmlIR::Object *rootComponent = qmlObjects->at(indexOfRootObject);
+ QmlIR::Object *rootComponent = qmlObjects->at(/*root object*/0);
rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
- if (!resolveAliases(indexOfRootObject))
+ if (!resolveAliases(/*root object*/0))
return false;
// Implicit component insertion may have added objects and thus we also need
@@ -997,7 +991,7 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
_objectsWithAliases.append(objectIndex);
// Stop at Component boundary
- if (obj->flags & QV4::CompiledData::Object::IsComponent && objectIndex != compiler->rootObjectIndex())
+ if (obj->flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0)
return true;
for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
@@ -1188,7 +1182,7 @@ QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingSca
bool QQmlDeferredAndCustomParserBindingScanner::scanObject()
{
- return scanObject(compiler->rootObjectIndex());
+ return scanObject(/*root object*/0);
}
bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
@@ -1274,7 +1268,7 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
_seenObjectWithId |= seenSubObjectWithId;
}
- if (!seenSubObjectWithId
+ if (!seenSubObjectWithId && binding->type != QV4::CompiledData::Binding::Type_GroupProperty
&& !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding;
@@ -1314,7 +1308,7 @@ bool QQmlJSCodeGenerator::generateCodeForComponents()
return false;
}
- return compileComponent(compiler->rootObjectIndex());
+ return compileComponent(/*root object*/0);
}
bool QQmlJSCodeGenerator::compileComponent(int contextObject)
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 76aa422fc5..4878a90641 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -119,7 +119,6 @@ public:
QQmlEnginePrivate *enginePrivate() const { return engine; }
const QQmlImports *imports() const;
QVector<QmlIR::Object *> *qmlObjects() const;
- int rootObjectIndex() const;
void setPropertyCaches(QQmlPropertyCacheVector &&caches);
const QQmlPropertyCacheVector *propertyCaches() const;
QQmlPropertyCacheVector &&takePropertyCaches();
@@ -282,7 +281,6 @@ protected:
QQmlJS::MemoryPool *pool;
QVector<QmlIR::Object*> *qmlObjects;
- const int indexOfRootObject;
// indices of the objects that are actually Component {}
QVector<quint32> componentRoots;
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 6b20557076..d0b2e4f08a 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -46,6 +46,7 @@
#include <private/qv4objectproto_p.h>
#include <private/qv4lookup_p.h>
#include <private/qv4regexpobject_p.h>
+#include <private/qv4regexp_p.h>
#include <private/qqmlpropertycache_p.h>
#include <private/qqmltypeloader_p.h>
#include <private/qqmlengine_p.h>
@@ -136,15 +137,16 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
memset(runtimeRegularExpressions, 0, data->regexpTableSize * sizeof(QV4::Value));
for (uint i = 0; i < data->regexpTableSize; ++i) {
const CompiledData::RegExp *re = data->regexpAt(i);
- int flags = 0;
+ bool global = false;
+ bool multiline = false;
+ bool ignoreCase = false;
if (re->flags & CompiledData::RegExp::RegExp_Global)
- flags |= IR::RegExp::RegExp_Global;
+ global = true;
if (re->flags & CompiledData::RegExp::RegExp_IgnoreCase)
- flags |= IR::RegExp::RegExp_IgnoreCase;
+ ignoreCase = true;
if (re->flags & CompiledData::RegExp::RegExp_Multiline)
- flags |= IR::RegExp::RegExp_Multiline;
- QV4::Heap::RegExpObject *ro = engine->newRegExpObject(data->stringAt(re->stringIndex), flags);
- runtimeRegularExpressions[i] = ro;
+ multiline = true;
+ runtimeRegularExpressions[i] = QV4::RegExp::create(engine, data->stringAt(re->stringIndex), ignoreCase, multiline, global);
}
if (data->lookupTableSize) {
@@ -211,7 +213,7 @@ void CompilationUnit::unlink()
engine->compilationUnits.erase(engine->compilationUnits.find(this));
if (isRegisteredWithEngine) {
- Q_ASSERT(data && quint32(propertyCaches.count()) > data->indexOfRootObject && propertyCaches.at(data->indexOfRootObject));
+ Q_ASSERT(data && propertyCaches.count() > 0 && propertyCaches.at(/*root object*/0));
if (qmlEngine)
qmlEngine->unregisterInternalCompositeType(this);
QQmlMetaType::unregisterInternalCompositeType(this);
@@ -287,11 +289,11 @@ void CompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine)
this->qmlEngine = qmlEngine;
// Add to type registry of composites
- if (propertyCaches.needsVMEMetaObject(data->indexOfRootObject)) {
+ if (propertyCaches.needsVMEMetaObject(/*root object*/0)) {
QQmlMetaType::registerInternalCompositeType(this);
qmlEngine->registerInternalCompositeType(this);
} else {
- const QV4::CompiledData::Object *obj = objectAt(data->indexOfRootObject);
+ const QV4::CompiledData::Object *obj = objectAt(/*root object*/0);
auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
Q_ASSERT(typeRef);
if (typeRef->compilationUnit) {
@@ -730,8 +732,6 @@ void ResolvedTypeReference::doDynamicTypeCheck()
isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
}
-#if defined(QT_BUILD_INTERNAL)
-
static QByteArray ownLibraryChecksum()
{
static QByteArray libraryChecksum;
@@ -739,7 +739,10 @@ static QByteArray ownLibraryChecksum()
if (checksumInitialized)
return libraryChecksum;
checksumInitialized = true;
-#if !defined(QT_NO_DYNAMIC_CAST) && QT_CONFIG(dlopen)
+#if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_DYNAMIC_CAST) && QT_CONFIG(dlopen)
+ // This is a bit of a hack to make development easier. When hacking on the code generator
+ // the cache files may end up being re-used. To avoid that we also add the checksum of
+ // the QtQml library.
Dl_info libInfo;
if (dladdr(reinterpret_cast<const void *>(&ownLibraryChecksum), &libInfo) != 0) {
QFile library(QFile::decodeName(libInfo.dli_fname));
@@ -749,14 +752,14 @@ static QByteArray ownLibraryChecksum()
libraryChecksum = hash.result();
}
}
+#elif defined(QML_COMPILE_HASH)
+ libraryChecksum = QByteArray(QT_STRINGIFY(QML_COMPILE_HASH));
#else
// Not implemented.
#endif
return libraryChecksum;
}
-#endif
-
bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *engine) const
{
for (auto it = constBegin(), end = constEnd(); it != end; ++it) {
@@ -764,12 +767,7 @@ bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *e
return false;
}
- // This is a bit of a hack to make development easier. When hacking on the code generator
- // the cache files may end up being re-used. To avoid that we also add the checksum of
- // the QtQml library.
-#if defined(QT_BUILD_INTERNAL)
hash->addData(ownLibraryChecksum());
-#endif
return true;
}
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index cc4a96d5c0..ce54e4fae4 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -71,7 +71,7 @@
QT_BEGIN_NAMESPACE
// Bump this whenever the compiler data structures change in an incompatible way.
-#define QV4_DATA_STRUCTURE_VERSION 0x11
+#define QV4_DATA_STRUCTURE_VERSION 0x13
class QIODevice;
class QQmlPropertyCache;
@@ -115,10 +115,6 @@ struct TableIterator
bool operator!=(const TableIterator &rhs) const { return index != rhs.index; }
};
-#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
-#pragma pack(push, 1)
-#endif
-
struct Location
{
union {
@@ -134,6 +130,7 @@ struct Location
(line == other.line && column < other.column);
}
};
+static_assert(sizeof(Location) == 4, "Location structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct RegExp
{
@@ -150,6 +147,7 @@ struct RegExp
RegExp() : _dummy(0) { }
};
+static_assert(sizeof(RegExp) == 4, "RegExp structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Lookup
{
@@ -169,6 +167,7 @@ struct Lookup
Lookup() : _dummy(0) { }
};
+static_assert(sizeof(Lookup) == 4, "Lookup structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct JSClassMember
{
@@ -180,6 +179,7 @@ struct JSClassMember
JSClassMember() : _dummy(0) { }
};
+static_assert(sizeof(JSClassMember) == 4, "JSClassMember structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct JSClass
{
@@ -188,6 +188,7 @@ struct JSClass
static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
};
+static_assert(sizeof(JSClass) == 4, "JSClass structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct String
{
@@ -198,6 +199,7 @@ struct String
return (sizeof(String) + str.length() * sizeof(quint16) + 7) & ~0x7;
}
};
+static_assert(sizeof(String) == 4, "String structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
// Function is aligned on an 8-byte boundary to make sure there are no bus errors or penalties
// for unaligned access. The ordering of the fields is also from largest to smallest.
@@ -241,6 +243,8 @@ struct Function
// Keep all unaligned data at the end
quint8 flags;
+ quint8 padding1;
+ quint16_le padding2;
const quint32_le *formalsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + formalsOffset); }
const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
@@ -259,6 +263,7 @@ struct Function
return (sizeof(Function) + (nFormals + nLocals + nInnerfunctions + nIdObjectDependencies + 2 * nPropertyDependencies) * sizeof(quint32) + 7) & ~0x7;
}
};
+static_assert(sizeof(Function) == 72, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
// Qml data structures
@@ -266,6 +271,7 @@ struct Q_QML_EXPORT TranslationData {
quint32_le commentIndex;
qint32_le number;
};
+static_assert(sizeof(TranslationData) == 8, "TranslationData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Q_QML_PRIVATE_EXPORT Binding
{
@@ -312,6 +318,8 @@ struct Q_QML_PRIVATE_EXPORT Binding
Location location;
Location valueLocation;
+ quint32_le padding;
+
bool isValueBinding() const
{
if (type == Type_AttachedProperty
@@ -391,6 +399,8 @@ struct Q_QML_PRIVATE_EXPORT Binding
};
+static_assert(sizeof(Binding) == 32, "Binding structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+
struct EnumValue
{
quint32_le nameIndex;
@@ -428,6 +438,7 @@ struct Parameter
quint32_le customTypeNameIndex;
Location location;
};
+static_assert(sizeof(Parameter) == 16, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Signal
{
@@ -452,6 +463,7 @@ struct Signal
int parameterCount() const { return nParameters; }
// ---
};
+static_assert(sizeof(Signal) == 12, "Signal structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Property
{
@@ -472,6 +484,7 @@ struct Property
quint32_le customTypeNameIndex; // If type >= Custom
Location location;
};
+static_assert(sizeof(Property) == 16, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Alias {
enum Flags : unsigned int {
@@ -501,6 +514,7 @@ struct Alias {
return encodedMetaPropertyIndex == -1;
}
};
+static_assert(sizeof(Alias) == 20, "Alias structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Object
{
@@ -623,6 +637,7 @@ struct Object
int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
// ---
};
+static_assert(sizeof(Object) == 80, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Import
{
@@ -643,6 +658,7 @@ struct Import
Import() { type = 0; uriIndex = 0; qualifierIndex = 0; majorVersion = 0; minorVersion = 0; }
};
+static_assert(sizeof(Import) == 24, "Import structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
static const char magic_str[] = "qv4cdata";
@@ -693,7 +709,6 @@ struct Unit
quint32_le offsetToImports;
quint32_le nObjects;
quint32_le offsetToObjects;
- quint32_le indexOfRootObject;
const Import *importAt(int idx) const {
return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
@@ -759,9 +774,7 @@ struct Unit
}
};
-#if defined(Q_CC_MSVC) || defined(Q_CC_GNU)
-#pragma pack(pop)
-#endif
+static_assert(sizeof(Unit) == 144, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct TypeReference
{
@@ -881,7 +894,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase, public
// QML specific fields
QQmlPropertyCacheVector propertyCaches;
- QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(data->indexOfRootObject); }
+ QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(/*root object*/0); }
QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
@@ -918,7 +931,6 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase, public
// --- interface for QQmlPropertyCacheCreator
typedef Object CompiledObject;
int objectCount() const { return data->nObjects; }
- int rootObjectIndex() const { return data->indexOfRootObject; }
const Object *objectAt(int index) const { return data->objectAt(index); }
QString stringAt(int index) const { return data->stringAt(index); }
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 35825587b1..f02ee728c9 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -434,7 +434,6 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
unit.offsetToImports = 0;
unit.nObjects = 0;
unit.offsetToObjects = 0;
- unit.indexOfRootObject = 0;
unit.unitSize = nextOffset;
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 8ca6b03950..a5fc37b91b 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -142,10 +142,6 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
, m_engineId(engineSerial.fetchAndAddOrdered(1))
, regExpCache(0)
, m_multiplyWrappedQObjects(0)
-#ifndef QT_NO_QML_DEBUGGER
- , m_debugger(0)
- , m_profiler(0)
-#endif
{
memoryManager = new QV4::MemoryManager(this);
@@ -501,12 +497,6 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
ExecutionEngine::~ExecutionEngine()
{
-#ifndef QT_NO_QML_DEBUGGER
- delete m_debugger;
- m_debugger = 0;
- delete m_profiler;
- m_profiler = 0;
-#endif
delete m_multiplyWrappedQObjects;
m_multiplyWrappedQObjects = 0;
delete identifierTable;
@@ -534,13 +524,13 @@ ExecutionEngine::~ExecutionEngine()
void ExecutionEngine::setDebugger(Debugging::Debugger *debugger)
{
Q_ASSERT(!m_debugger);
- m_debugger = debugger;
+ m_debugger.reset(debugger);
}
void ExecutionEngine::setProfiler(Profiling::Profiler *profiler)
{
Q_ASSERT(!m_profiler);
- m_profiler = profiler;
+ m_profiler.reset(profiler);
}
#endif // QT_NO_QML_DEBUGGER
@@ -698,21 +688,17 @@ Heap::DateObject *ExecutionEngine::newDateObjectFromTime(const QTime &t)
Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
{
bool global = (flags & IR::RegExp::RegExp_Global);
- bool ignoreCase = false;
- bool multiline = false;
- if (flags & IR::RegExp::RegExp_IgnoreCase)
- ignoreCase = true;
- if (flags & IR::RegExp::RegExp_Multiline)
- multiline = true;
+ bool ignoreCase = (flags & IR::RegExp::RegExp_IgnoreCase);
+ bool multiline = (flags & IR::RegExp::RegExp_Multiline);
Scope scope(this);
- Scoped<RegExp> re(scope, RegExp::create(this, pattern, ignoreCase, multiline));
- return newRegExpObject(re, global);
+ Scoped<RegExp> re(scope, RegExp::create(this, pattern, ignoreCase, multiline, global));
+ return newRegExpObject(re);
}
-Heap::RegExpObject *ExecutionEngine::newRegExpObject(RegExp *re, bool global)
+Heap::RegExpObject *ExecutionEngine::newRegExpObject(RegExp *re)
{
- return memoryManager->allocObject<RegExpObject>(re, global);
+ return memoryManager->allocObject<RegExpObject>(re);
}
Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re)
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 16a043dda5..3b4212020d 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -349,8 +349,8 @@ public:
void setDebugger(Debugging::Debugger *) {}
void setProfiler(Profiling::Profiler *) {}
#else
- QV4::Debugging::Debugger *debugger() const { return m_debugger; }
- QV4::Profiling::Profiler *profiler() const { return m_profiler; }
+ QV4::Debugging::Debugger *debugger() const { return m_debugger.data(); }
+ QV4::Profiling::Profiler *profiler() const { return m_profiler.data(); }
void setDebugger(Debugging::Debugger *debugger);
void setProfiler(Profiling::Profiler *profiler);
@@ -387,7 +387,7 @@ public:
Heap::DateObject *newDateObjectFromTime(const QTime &t);
Heap::RegExpObject *newRegExpObject(const QString &pattern, int flags);
- Heap::RegExpObject *newRegExpObject(RegExp *re, bool global);
+ Heap::RegExpObject *newRegExpObject(RegExp *re);
Heap::RegExpObject *newRegExpObject(const QRegExp &re);
Heap::Object *newErrorObject(const Value &value);
@@ -458,8 +458,8 @@ private:
void failStackLimitCheck(Scope &scope);
#ifndef QT_NO_QML_DEBUGGER
- QV4::Debugging::Debugger *m_debugger;
- QV4::Profiling::Profiler *m_profiler;
+ QScopedPointer<QV4::Debugging::Debugger> m_debugger;
+ QScopedPointer<QV4::Profiling::Profiler> m_profiler;
#endif
};
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index 6fd1509d77..46230b5bc1 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -46,6 +46,7 @@
#include <QtCore/private/qnumeric_p.h>
#include <QtCore/qthreadstorage.h>
+#include <math.h>
#include <cmath>
using namespace QV4;
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index c483fdb7e7..8b9ef149d6 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -62,20 +62,17 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(QQmlContextWrapper);
DEFINE_MANAGED_VTABLE(QmlContext);
-void Heap::QQmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject, bool ownsContext)
+void Heap::QQmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject)
{
Object::init();
readOnly = true;
- this->ownsContext = ownsContext;
isNullWrapper = false;
- this->context = new QQmlGuardedContextData(context);
+ this->context = new QQmlContextDataRef(context);
this->scopeObject.init(scopeObject);
}
void Heap::QQmlContextWrapper::destroy()
{
- if (*context && ownsContext)
- (*context)->destroy();
delete context;
scopeObject.destroy();
Object::destroy();
@@ -318,7 +315,7 @@ Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, cons
context->isInternal = true;
context->isJSContext = true;
- Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QQmlContextWrapper>(context, (QObject*)0, true));
+ Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QQmlContextWrapper>(context, (QObject*)0));
qml->d()->isNullWrapper = true;
qml->setReadOnly(false);
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index 2f1dbabaf2..48c9ee2c36 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -67,13 +67,12 @@ struct QQmlContextWrapper;
namespace Heap {
struct QQmlContextWrapper : Object {
- void init(QQmlContextData *context, QObject *scopeObject, bool ownsContext = false);
+ void init(QQmlContextData *context, QObject *scopeObject);
void destroy();
bool readOnly;
- bool ownsContext;
bool isNullWrapper;
- QQmlGuardedContextData *context;
+ QQmlContextDataRef *context;
QQmlQPointer<QObject> scopeObject;
};
@@ -93,10 +92,6 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object
V4_OBJECT2(QQmlContextWrapper, Object)
V4_NEEDS_DESTROY
- void takeContextOwnership() {
- d()->ownsContext = true;
- }
-
inline QObject *getScopeObject() const { return d()->scopeObject; }
inline QQmlContextData *getContext() const { return *d()->context; }
@@ -119,10 +114,6 @@ struct Q_QML_EXPORT QmlContext : public ExecutionContext
QQmlContextData *qmlContext() const {
return *d()->qml->context;
}
-
- void takeContextOwnership() {
- d()->qml->ownsContext = true;
- }
};
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 72ad0ce7b7..fb3aa47d1b 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1040,8 +1040,12 @@ void QObjectWrapper::destroyObject(bool lastCall)
QQmlData *ddata = QQmlData::get(h->object(), false);
if (ddata) {
if (!h->object()->parent() && !ddata->indestructible) {
- if (ddata && ddata->ownContext && ddata->context)
- ddata->context->emitDestruction();
+ if (ddata && ddata->ownContext) {
+ Q_ASSERT(ddata->ownContext == ddata->context);
+ ddata->ownContext->emitDestruction();
+ ddata->ownContext = 0;
+ ddata->context = 0;
+ }
// This object is notionally destroyed now
ddata->isQueuedForDeletion = true;
if (lastCall)
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index 6778145ff1..162f0fba57 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -69,9 +69,9 @@ uint RegExp::match(const QString &string, int start, uint *matchOffsets)
return JSC::Yarr::interpret(byteCode(), s.characters16(), string.length(), start, matchOffsets);
}
-Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline)
+Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline, bool global)
{
- RegExpCacheKey key(pattern, ignoreCase, multiline);
+ RegExpCacheKey key(pattern, ignoreCase, multiline, global);
RegExpCache *cache = engine->regExpCache;
if (!cache)
@@ -82,7 +82,7 @@ Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bo
return result->d();
Scope scope(engine);
- Scoped<RegExp> result(scope, engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline));
+ Scoped<RegExp> result(scope, engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline, global));
result->d()->cache = cache;
cachedValue.set(engine, result);
@@ -90,12 +90,13 @@ Heap::RegExp *RegExp::create(ExecutionEngine* engine, const QString& pattern, bo
return result->d();
}
-void Heap::RegExp::init(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline)
+void Heap::RegExp::init(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline, bool global)
{
Base::init();
this->pattern = new QString(pattern);
this->ignoreCase = ignoreCase;
this->multiLine = multiline;
+ this->global = global;
const char* error = 0;
JSC::Yarr::YarrPattern yarrPattern(WTF::String(pattern), ignoreCase, multiline, &error);
diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h
index 7ab12fe245..998f6e3da3 100644
--- a/src/qml/jsruntime/qv4regexp_p.h
+++ b/src/qml/jsruntime/qv4regexp_p.h
@@ -76,7 +76,7 @@ struct RegExpCacheKey;
namespace Heap {
struct RegExp : Base {
- void init(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline);
+ void init(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline, bool global);
void destroy();
QString *pattern;
@@ -88,6 +88,7 @@ struct RegExp : Base {
int subPatternCount;
bool ignoreCase;
bool multiLine;
+ bool global;
int captureCount() const { return subPatternCount + 1; }
};
@@ -111,8 +112,9 @@ struct RegExp : public Managed
int subPatternCount() const { return d()->subPatternCount; }
bool ignoreCase() const { return d()->ignoreCase; }
bool multiLine() const { return d()->multiLine; }
+ bool global() const { return d()->global; }
- static Heap::RegExp *create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false);
+ static Heap::RegExp *create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false, bool global = false);
bool isValid() const { return d()->byteCode; }
@@ -125,27 +127,30 @@ struct RegExp : public Managed
struct RegExpCacheKey
{
- RegExpCacheKey(const QString &pattern, bool ignoreCase, bool multiLine)
+ RegExpCacheKey(const QString &pattern, bool ignoreCase, bool multiLine, bool global)
: pattern(pattern)
, ignoreCase(ignoreCase)
, multiLine(multiLine)
+ , global(global)
{ }
explicit inline RegExpCacheKey(const RegExp::Data *re);
bool operator==(const RegExpCacheKey &other) const
- { return pattern == other.pattern && ignoreCase == other.ignoreCase && multiLine == other.multiLine; }
+ { return pattern == other.pattern && ignoreCase == other.ignoreCase && multiLine == other.multiLine && global == other.global; }
bool operator!=(const RegExpCacheKey &other) const
{ return !operator==(other); }
QString pattern;
uint ignoreCase : 1;
uint multiLine : 1;
+ uint global : 1;
};
inline RegExpCacheKey::RegExpCacheKey(const RegExp::Data *re)
: pattern(*re->pattern)
, ignoreCase(re->ignoreCase)
, multiLine(re->multiLine)
+ , global(re->global)
{}
inline uint qHash(const RegExpCacheKey& key, uint seed = 0) Q_DECL_NOTHROW
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 735951e085..83bfe21c67 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -75,15 +75,13 @@ void Heap::RegExpObject::init()
Scope scope(internalClass->engine);
Scoped<QV4::RegExpObject> o(scope, this);
value.set(scope.engine, QV4::RegExp::create(scope.engine, QString(), false, false));
- global = false;
o->initProperties();
}
-void Heap::RegExpObject::init(QV4::RegExp *value, bool global)
+void Heap::RegExpObject::init(QV4::RegExp *value)
{
Object::init();
Scope scope(internalClass->engine);
- this->global = global;
this->value.set(scope.engine, value->d());
Scoped<QV4::RegExpObject> o(scope, this);
o->initProperties();
@@ -95,7 +93,6 @@ void Heap::RegExpObject::init(QV4::RegExp *value, bool global)
void Heap::RegExpObject::init(const QRegExp &re)
{
Object::init();
- global = false;
// Convert the pattern to a ECMAScript pattern.
QString pattern = QT_PREPEND_NAMESPACE(qt_regexp_toCanonical)(re.pattern(), re.patternSyntax());
@@ -232,7 +229,7 @@ void RegExpCtor::construct(const Managed *, Scope &scope, CallData *callData)
}
Scoped<RegExp> regexp(scope, re->value());
- scope.result = Encode(scope.engine->newRegExpObject(regexp, re->global()));
+ scope.result = Encode(scope.engine->newRegExpObject(regexp));
return;
}
@@ -268,13 +265,13 @@ void RegExpCtor::construct(const Managed *, Scope &scope, CallData *callData)
}
}
- Scoped<RegExp> regexp(scope, RegExp::create(scope.engine, pattern, ignoreCase, multiLine));
+ Scoped<RegExp> regexp(scope, RegExp::create(scope.engine, pattern, ignoreCase, multiLine, global));
if (!regexp->isValid()) {
scope.result = scope.engine->throwSyntaxError(QStringLiteral("Invalid regular expression"));
return;
}
- scope.result = Encode(scope.engine->newRegExpObject(regexp, global));
+ scope.result = Encode(scope.engine->newRegExpObject(regexp));
}
void RegExpCtor::call(const Managed *that, Scope &scope, CallData *callData)
@@ -410,8 +407,6 @@ void RegExpPrototype::method_compile(const BuiltinFunction *, Scope &scope, Call
Scoped<RegExpObject> re(scope, scope.result.asReturnedValue());
r->d()->value.set(scope.engine, re->value());
- r->d()->global = re->global();
- RETURN_UNDEFINED();
}
template <int index>
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 6f54a4ab92..cb2bcbab2d 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -60,6 +60,7 @@
#include "qv4managed_p.h"
#include "qv4property_p.h"
#include "qv4objectiterator_p.h"
+#include "qv4regexp_p.h"
#include <QtCore/QString>
#include <QtCore/QHash>
@@ -74,14 +75,13 @@ namespace QV4 {
namespace Heap {
#define RegExpObjectMembers(class, Member) \
- Member(class, Pointer, RegExp *, value) \
- Member(class, NoMark, bool, global)
+ Member(class, Pointer, RegExp *, value)
DECLARE_HEAP_OBJECT(RegExpObject, Object) {
DECLARE_MARK_TABLE(RegExpObject);
void init();
- void init(QV4::RegExp *value, bool global);
+ void init(QV4::RegExp *value);
void init(const QRegExp &re);
};
@@ -124,7 +124,7 @@ struct RegExpObject: Object {
};
Heap::RegExp *value() const { return d()->value; }
- bool global() const { return d()->global; }
+ bool global() const { return d()->value->global; }
void initProperties();
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 9737a18812..4b952bcbbc 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -51,6 +51,8 @@
#include "qv4lookup_p.h"
#include "qv4function_p.h"
#include "qv4numberobject_p.h"
+#include "qv4regexp_p.h"
+#include "qv4regexpobject_p.h"
#include "private/qlocale_tools_p.h"
#include "qv4scopedvalue_p.h"
#include <private/qv4qmlcontext_p.h>
@@ -1477,7 +1479,10 @@ ReturnedValue Runtime::method_getQmlContext(NoThrowEngine *engine)
ReturnedValue Runtime::method_regexpLiteral(ExecutionEngine *engine, int id)
{
- return static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->runtimeRegularExpressions[id].asReturnedValue();
+ Heap::RegExpObject *ro = engine->newRegExpObject(
+ static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)
+ ->runtimeRegularExpressions[id].as<RegExp>());
+ return ro->asReturnedValue();
}
ReturnedValue Runtime::method_getQmlQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 81f5c3566c..7c65c97d73 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -551,7 +551,7 @@ void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, Call
break;
}
nMatchOffsets += re->captureCount() * 2;
- if (!regExp->d()->global)
+ if (!regExp->global())
break;
offset = qMax(offset + 1, matchOffsets[oldSize + 1]);
}
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 7293630924..5749d0aef3 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -50,6 +50,8 @@
#include <private/qv4math_p.h>
#include <private/qv4scopedvalue_p.h>
#include <private/qv4lookup_p.h>
+#include <private/qv4regexp_p.h>
+#include <private/qv4regexpobject_p.h>
#include <private/qv4string_p.h>
#include <iostream>
@@ -457,7 +459,10 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
MOTH_BEGIN_INSTR(LoadRegExp)
// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData());
- VALUE(instr.result) = static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->runtimeRegularExpressions[instr.regExpId];
+ Heap::RegExpObject *ro = engine->newRegExpObject(
+ static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)
+ ->runtimeRegularExpressions[instr.regExpId].as<RegExp>());
+ VALUE(instr.result) = ro;
MOTH_END_INSTR(LoadRegExp)
MOTH_BEGIN_INSTR(LoadClosure)
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index be3956bb61..e9d7dcbd2d 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -16,6 +16,19 @@ gcc:isEqual(QT_ARCH, "mips"): QMAKE_CXXFLAGS += -fno-reorder-blocks
DEFINES += QT_NO_FOREACH
+tagFile=$$PWD/../../.tag
+tag=
+exists($$tagFile) {
+ tag=$$cat($$tagFile, singleline)
+ QMAKE_INTERNAL_INCLUDED_FILES += $$tagFile
+}
+!equals(tag, "$${LITERAL_DOLLAR}Format:%H$${LITERAL_DOLLAR}") {
+ DEFINES += QML_COMPILE_HASH="$$tag"
+} else:exists($$PWD/../../.git) {
+ commit=$$system(git describe --tags --always --long --dirty)
+ DEFINES += QML_COMPILE_HASH="$$commit"
+}
+
exists("qqml_enable_gcov") {
QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage -fno-elide-constructors
LIBS_PRIVATE += -lgcov
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 531d9ae457..37cb328b36 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -161,6 +161,7 @@ QQmlContext::QQmlContext(QQmlEngine *e, bool)
{
Q_D(QQmlContext);
d->data = new QQmlContextData(this);
+ ++d->data->refCount;
d->data->engine = e;
}
@@ -174,6 +175,7 @@ QQmlContext::QQmlContext(QQmlEngine *engine, QObject *parent)
{
Q_D(QQmlContext);
d->data = new QQmlContextData(this);
+ ++d->data->refCount;
d->data->setParent(engine?QQmlContextData::get(engine->rootContext()):0);
}
@@ -187,6 +189,7 @@ QQmlContext::QQmlContext(QQmlContext *parentContext, QObject *parent)
{
Q_D(QQmlContext);
d->data = new QQmlContextData(this);
+ ++d->data->refCount;
d->data->setParent(parentContext?QQmlContextData::get(parentContext):0);
}
@@ -199,6 +202,7 @@ QQmlContext::QQmlContext(QQmlContextData *data)
{
Q_D(QQmlContext);
d->data = data;
+ // don't add a refcount here, as the data owns this context
}
/*!
@@ -212,7 +216,8 @@ QQmlContext::~QQmlContext()
{
Q_D(QQmlContext);
- if (!d->data->isInternal)
+ d->data->publicContext = 0;
+ if (!--d->data->refCount)
d->data->destroy();
}
@@ -521,12 +526,12 @@ QQmlContextData::QQmlContextData()
}
QQmlContextData::QQmlContextData(QQmlContext *ctxt)
-: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
- isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
- publicContext(ctxt), incubator(0), componentObjectIndex(-1),
- contextObject(0), childContexts(0), nextChild(0), prevChild(0),
- expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
- componentAttached(0)
+ : engine(0), isInternal(false), isJSContext(false),
+ isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
+ publicContext(ctxt), incubator(0), componentObjectIndex(-1),
+ contextObject(0), nextChild(0), prevChild(0),
+ expressions(0), contextObjects(0), idValues(0), idValueCount(0),
+ componentAttached(0)
{
}
@@ -563,11 +568,8 @@ void QQmlContextData::invalidate()
emitDestruction();
while (childContexts) {
- if (childContexts->ownedByParent) {
- childContexts->destroy();
- } else {
- childContexts->invalidate();
- }
+ Q_ASSERT(childContexts != this);
+ childContexts->invalidate();
}
if (prevChild) {
@@ -601,12 +603,17 @@ void QQmlContextData::clearContext()
void QQmlContextData::destroy()
{
- if (linkedContext)
- linkedContext->destroy();
+ Q_ASSERT(refCount == 0);
+ linkedContext = 0;
- if (engine) invalidate();
+ // avoid recursion
+ ++refCount;
+ if (engine)
+ invalidate();
+ Q_ASSERT(refCount == 1);
clearContext();
+ Q_ASSERT(refCount == 1);
while (contextObjects) {
QQmlData *co = contextObjects;
@@ -617,6 +624,7 @@ void QQmlContextData::destroy()
co->nextContextObject = 0;
co->prevContextObject = 0;
}
+ Q_ASSERT(refCount == 1);
QQmlGuardedContextData *contextGuard = contextGuards;
while (contextGuard) {
@@ -627,17 +635,29 @@ void QQmlContextData::destroy()
contextGuard = next;
}
contextGuards = 0;
+ Q_ASSERT(refCount == 1);
delete [] idValues;
+ idValues = 0;
- if (isInternal)
+ Q_ASSERT(refCount == 1);
+ if (publicContext) {
+ // the QQmlContext destructor will remove one ref again
+ ++refCount;
delete publicContext;
+ }
+
+ Q_ASSERT(refCount == 1);
+ --refCount;
+ Q_ASSERT(refCount == 0);
delete this;
}
-void QQmlContextData::setParent(QQmlContextData *p, bool parentTakesOwnership)
+void QQmlContextData::setParent(QQmlContextData *p)
{
+ if (p == parent)
+ return;
if (p) {
parent = p;
engine = p->engine;
@@ -645,7 +665,6 @@ void QQmlContextData::setParent(QQmlContextData *p, bool parentTakesOwnership)
if (nextChild) nextChild->prevChild = &nextChild;
prevChild = &p->childContexts;
p->childContexts = this;
- ownedByParent = parentTakesOwnership;
}
}
@@ -660,6 +679,10 @@ void QQmlContextData::refreshExpressionsRecursive(QQmlJavaScriptExpression *expr
expression->refresh();
}
+QQmlContextData::~QQmlContextData()
+{
+}
+
static inline bool expressions_to_run(QQmlContextData *ctxt, bool isGlobalRefresh)
{
return ctxt->expressions && (!isGlobalRefresh || ctxt->unresolvedNames);
@@ -795,7 +818,7 @@ QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, int subComponentIndex)
{
typeCompilationUnit = unit;
- componentObjectIndex = subComponentIndex == -1 ? typeCompilationUnit->data->indexOfRootObject : subComponentIndex;
+ componentObjectIndex = subComponentIndex == -1 ? /*root object*/0 : subComponentIndex;
Q_ASSERT(!idValues);
idValueCount = typeCompilationUnit->data->objectAt(componentObjectIndex)->nNamedObjectsInComponent;
idValues = new ContextGuard[idValueCount];
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index a259fd62d8..d01820a430 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -78,6 +78,7 @@ class QQmlExpression;
class QQmlExpressionPrivate;
class QQmlJavaScriptExpression;
class QQmlContextData;
+class QQmlGuardedContextData;
class QQmlIncubatorPrivate;
class QQmlContextPrivate : public QObjectPrivate
@@ -106,7 +107,7 @@ public:
};
class QQmlComponentAttached;
-class QQmlGuardedContextData;
+
class Q_QML_PRIVATE_EXPORT QQmlContextData
{
public:
@@ -114,7 +115,6 @@ public:
QQmlContextData(QQmlContext *);
void emitDestruction();
void clearContext();
- void destroy();
void invalidate();
inline bool isValid() const {
@@ -122,10 +122,10 @@ public:
}
// My parent context and engine
- QQmlContextData *parent;
+ QQmlContextData *parent = nullptr;
QQmlEngine *engine;
- void setParent(QQmlContextData *, bool parentTakesOwnership = false);
+ void setParent(QQmlContextData *);
void refreshExpressions();
void addObject(QObject *);
@@ -136,14 +136,14 @@ public:
// If internal is false publicContext owns this.
QQmlContext *asQQmlContext();
QQmlContextPrivate *asQQmlContextPrivate();
+ quint32 refCount = 0;
quint32 isInternal:1;
- quint32 ownedByParent:1; // unrelated to isInternal; parent context deletes children if true.
quint32 isJSContext:1;
quint32 isPragmaLibraryContext:1;
quint32 unresolvedNames:1; // True if expressions in this context failed to resolve a toplevel name
quint32 hasEmittedDestruction:1;
quint32 isRootObjectInCreation:1;
- quint32 dummy:25;
+ quint32 dummy:26;
QQmlContext *publicContext;
// The incubator that is constructing this context if any
@@ -178,7 +178,7 @@ public:
QQmlRefPointer<QQmlTypeNameCache> imports;
// My children
- QQmlContextData *childContexts;
+ QQmlContextData *childContexts = 0;
// My peers in parent's childContexts list
QQmlContextData *nextChild;
@@ -191,7 +191,7 @@ public:
QQmlData *contextObjects;
// Doubly-linked list of context guards (XXX merge with contextObjects)
- QQmlGuardedContextData *contextGuards;
+ QQmlGuardedContextData *contextGuards = 0;
// id guards
struct ContextGuard : public QQmlGuard<QObject>
@@ -210,7 +210,7 @@ public:
void setIdProperty(int, QObject *);
// Linked contexts. this owns linkedContext.
- QQmlContextData *linkedContext;
+ QQmlContextDataRef linkedContext;
// Linked list of uses of the Component attached property in this
// context
@@ -224,91 +224,137 @@ public:
}
private:
+ friend class QQmlContextDataRef;
+ friend class QQmlContext; // needs to do manual refcounting :/
void refreshExpressionsRecursive(bool isGlobal);
void refreshExpressionsRecursive(QQmlJavaScriptExpression *);
- ~QQmlContextData() {}
+ ~QQmlContextData();
+ void destroy();
};
+
class QQmlGuardedContextData
{
public:
- inline QQmlGuardedContextData();
- inline QQmlGuardedContextData(QQmlContextData *);
- inline ~QQmlGuardedContextData();
-
- inline QQmlContextData *contextData() const;
+ inline QQmlGuardedContextData() = default;
+ inline QQmlGuardedContextData(QQmlContextData *data)
+ { setContextData(data); }
+ inline ~QQmlGuardedContextData()
+ { clear(); }
+
+ inline QQmlContextData *contextData() const
+ { return m_contextData; }
inline void setContextData(QQmlContextData *);
inline bool isNull() const { return !m_contextData; }
inline operator QQmlContextData*() const { return m_contextData; }
inline QQmlContextData* operator->() const { return m_contextData; }
- inline QQmlGuardedContextData &operator=(QQmlContextData *d);
+ inline QQmlGuardedContextData &operator=(QQmlContextData *d) {
+ setContextData(d); return *this;
+ }
private:
- QQmlGuardedContextData &operator=(const QQmlGuardedContextData &);
- QQmlGuardedContextData(const QQmlGuardedContextData &);
+ QQmlGuardedContextData &operator=(const QQmlGuardedContextData &) = delete;
+ QQmlGuardedContextData(const QQmlGuardedContextData &) = delete;
friend class QQmlContextData;
inline void clear();
- QQmlContextData *m_contextData;
- QQmlGuardedContextData *m_next;
- QQmlGuardedContextData **m_prev;
+ QQmlContextData *m_contextData = 0;
+ QQmlGuardedContextData *m_next = 0;
+ QQmlGuardedContextData **m_prev = 0;
};
-QQmlGuardedContextData::QQmlGuardedContextData()
-: m_contextData(0), m_next(0), m_prev(0)
+
+void QQmlGuardedContextData::setContextData(QQmlContextData *contextData)
+ {
+ if (m_contextData == contextData)
+ return;
+ clear();
+
+ if (contextData) {
+ m_contextData = contextData;
+ m_next = contextData->contextGuards;
+ if (m_next) m_next->m_prev = &m_next;
+ m_prev = &contextData->contextGuards;
+ contextData->contextGuards = this;
+ }
+}
+
+void QQmlGuardedContextData::clear()
+{
+ if (m_prev) {
+ *m_prev = m_next;
+ if (m_next) m_next->m_prev = m_prev;
+ m_contextData = 0;
+ m_next = 0;
+ m_prev = 0;
+ }
+}
+
+QQmlContextDataRef::QQmlContextDataRef()
+ : m_contextData(0)
{
}
-QQmlGuardedContextData::QQmlGuardedContextData(QQmlContextData *data)
-: m_contextData(0), m_next(0), m_prev(0)
+QQmlContextDataRef::QQmlContextDataRef(const QQmlContextDataRef &other)
+ : m_contextData(other.m_contextData)
{
- setContextData(data);
+ if (m_contextData)
+ ++m_contextData->refCount;
}
-QQmlGuardedContextData::~QQmlGuardedContextData()
+QQmlContextDataRef::QQmlContextDataRef(QQmlContextData *data)
+ : m_contextData(data)
+{
+ if (m_contextData)
+ ++m_contextData->refCount;
+}
+
+QQmlContextDataRef::~QQmlContextDataRef()
{
clear();
}
-void QQmlGuardedContextData::setContextData(QQmlContextData *contextData)
+void QQmlContextDataRef::setContextData(QQmlContextData *contextData)
{
+ if (m_contextData == contextData)
+ return;
clear();
if (contextData) {
m_contextData = contextData;
- m_next = contextData->contextGuards;
- if (m_next) m_next->m_prev = &m_next;
- m_prev = &contextData->contextGuards;
- contextData->contextGuards = this;
+ ++m_contextData->refCount;
}
}
-QQmlContextData *QQmlGuardedContextData::contextData() const
+QQmlContextData *QQmlContextDataRef::contextData() const
{
return m_contextData;
}
-void QQmlGuardedContextData::clear()
+void QQmlContextDataRef::clear()
{
- if (m_prev) {
- *m_prev = m_next;
- if (m_next) m_next->m_prev = m_prev;
- m_contextData = 0;
- m_next = 0;
- m_prev = 0;
- }
+ if (m_contextData && !--m_contextData->refCount)
+ m_contextData->destroy();
+ m_contextData = 0;
}
-QQmlGuardedContextData &
-QQmlGuardedContextData::operator=(QQmlContextData *d)
+QQmlContextDataRef &
+QQmlContextDataRef::operator=(QQmlContextData *d)
{
setContextData(d);
return *this;
}
+QQmlContextDataRef &
+QQmlContextDataRef::operator=(const QQmlContextDataRef &other)
+{
+ setContextData(other.m_contextData);
+ return *this;
+}
+
QQmlContextData::ContextGuard::ContextGuard()
: context(0)
{
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 2083326cd5..75ea720358 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -78,6 +78,34 @@ struct CompilationUnit;
}
}
+// This is declared here because QQmlData below needs it and this file
+// in turn is included from qqmlcontext_p.h.
+class QQmlContextData;
+class Q_QML_PRIVATE_EXPORT QQmlContextDataRef
+{
+public:
+ inline QQmlContextDataRef();
+ inline QQmlContextDataRef(QQmlContextData *);
+ inline QQmlContextDataRef(const QQmlContextDataRef &);
+ inline ~QQmlContextDataRef();
+
+ inline QQmlContextData *contextData() const;
+ inline void setContextData(QQmlContextData *);
+
+ inline bool isNull() const { return !m_contextData; }
+
+ inline operator QQmlContextData*() const { return m_contextData; }
+ inline QQmlContextData* operator->() const { return m_contextData; }
+ inline QQmlContextDataRef &operator=(QQmlContextData *d);
+ inline QQmlContextDataRef &operator=(const QQmlContextDataRef &other);
+
+private:
+
+ inline void clear();
+
+ QQmlContextData *m_contextData;
+};
+
// This class is structured in such a way, that simply zero'ing it is the
// default state for elemental object allocations. This is crucial in the
// workings of the QQmlInstruction::CreateSimpleObject instruction.
@@ -114,7 +142,6 @@ public:
quint32 ownedByQml1:1; // This bit is shared with QML1's QDeclarativeData.
quint32 ownMemory:1;
- quint32 ownContext:1;
quint32 indestructible:1;
quint32 explicitIndestructibleSet:1;
quint32 hasTaintedV4Object:1;
@@ -127,7 +154,7 @@ public:
quint32 hasInterceptorMetaObject:1;
quint32 hasVMEMetaObject:1;
quint32 parentFrozen:1;
- quint32 dummy:21;
+ quint32 dummy:22;
// When bindingBitsSize < sizeof(ptr), we store the binding bit flags inside
// bindingBitsValue. When we need more than sizeof(ptr) bits, we allocated
@@ -161,9 +188,10 @@ public:
void disconnectNotifiers();
// The context that created the C++ object
- QQmlContextData *context;
+ QQmlContextData *context = 0;
// The outermost context in which this object lives
- QQmlContextData *outerContext;
+ QQmlContextData *outerContext = 0;
+ QQmlContextDataRef ownContext;
QQmlAbstractBinding *bindings;
QQmlBoundSignal *signalHandlers;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 194c58b805..5f4e291775 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -718,8 +718,13 @@ QQmlEnginePrivate::~QQmlEnginePrivate()
void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
{
if (QQmlData *d = QQmlData::get(o)) {
- if (d->ownContext && d->context) {
- d->context->destroy();
+ if (d->ownContext) {
+ for (QQmlContextData *lc = d->ownContext->linkedContext; lc; lc = lc->linkedContext)
+ lc->invalidate();
+ d->ownContext->invalidate();
+ if (d->ownContext->contextObject == o)
+ d->ownContext->contextObject = nullptr;
+ d->ownContext = 0;
d->context = 0;
}
@@ -735,10 +740,10 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
}
QQmlData::QQmlData()
- : ownedByQml1(false), ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false),
+ : ownedByQml1(false), ownMemory(true), indestructible(true), explicitIndestructibleSet(false),
hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false),
- bindingBitsSize(MaxInlineBits), bindingBitsValue(0), notifyList(0), context(0), outerContext(0),
+ bindingBitsSize(MaxInlineBits), bindingBitsValue(0), notifyList(0),
bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0),
lineNumber(0), columnNumber(0), jsEngineId(0), compilationUnit(0), deferredData(0),
propertyCache(0), guards(0), extendedData(0)
@@ -888,8 +893,12 @@ void QQmlData::setQueuedForDeletion(QObject *object)
{
if (object) {
if (QQmlData *ddata = QQmlData::get(object)) {
- if (ddata->ownContext && ddata->context)
+ if (ddata->ownContext) {
+ Q_ASSERT(ddata->ownContext == ddata->context);
ddata->context->emitDestruction();
+ ddata->ownContext = 0;
+ ddata->context = 0;
+ }
ddata->isQueuedForDeletion = true;
}
}
@@ -1786,8 +1795,7 @@ void QQmlData::destroyed(QObject *object)
if (propertyCache)
propertyCache->release();
- if (ownContext && context)
- context->destroy();
+ ownContext = 0;
while (guards) {
QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 66c0be41da..bc8be04f24 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -472,6 +472,17 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::
resultList.append(ref);
}
}
+
+ if (QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion)) {
+ module->walkCompositeSingletons([&resultList, &set](const QQmlType &singleton) {
+ QQmlImports::CompositeSingletonReference ref;
+ ref.typeName = singleton.elementName();
+ ref.prefix = set.prefix;
+ ref.majorVersion = singleton.majorVersion();
+ ref.minorVersion = singleton.minorVersion();
+ resultList.append(ref);
+ });
+ }
}
}
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index bddbda5832..8e6be538ef 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -1306,6 +1306,13 @@ void QQmlType::derefHandle(QQmlTypePrivate *priv)
delete priv;
}
+int QQmlType::refCount(QQmlTypePrivate *priv)
+{
+ if (priv)
+ return priv->refCount;
+ return -1;
+}
+
namespace {
template <typename QQmlTypeContainer>
void removeQQmlTypePrivate(QQmlTypeContainer &container, const QQmlTypePrivate *reference)
@@ -1377,7 +1384,7 @@ void QQmlTypeModulePrivate::add(QQmlTypePrivate *type)
void QQmlTypeModulePrivate::remove(const QQmlTypePrivate *type)
{
for (TypeHash::ConstIterator elementIt = typeHash.begin(); elementIt != typeHash.end();) {
- QList<QQmlTypePrivate *> &list = typeHash[elementIt.key()];
+ QList<QQmlTypePrivate *> &list = const_cast<QList<QQmlTypePrivate *> &>(elementIt.value());
removeQQmlTypePrivate(list, type);
@@ -1420,6 +1427,18 @@ QQmlType QQmlTypeModule::type(const QV4::String *name, int minor) const
return QQmlType();
}
+void QQmlTypeModule::walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const
+{
+ QMutexLocker lock(metaTypeDataLock());
+ for (auto typeCandidates = d->typeHash.begin(), end = d->typeHash.end();
+ typeCandidates != end; ++typeCandidates) {
+ for (auto type: typeCandidates.value()) {
+ if (type->regType == QQmlType::CompositeSingletonType)
+ callback(QQmlType(type));
+ }
+ }
+}
+
QQmlTypeModuleVersion::QQmlTypeModuleVersion()
: m_module(0), m_minor(0)
{
@@ -1484,6 +1503,7 @@ void qmlClearTypeRegistrations() // Declared in qqml.h
data->urlToNonFileImportType.clear();
data->metaObjectToType.clear();
data->uriToModule.clear();
+ data->undeletableTypes.clear();
QQmlEnginePrivate::baseModulesUninitialized = true; //So the engine re-registers its types
#if QT_CONFIG(library)
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 8eb91f321a..720c6d904a 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -253,6 +253,7 @@ public:
QQmlTypePrivate *priv() const { return d; }
static void refHandle(QQmlTypePrivate *priv);
static void derefHandle(QQmlTypePrivate *priv);
+ static int refCount(QQmlTypePrivate *priv);
enum RegistrationType {
CppType = 0,
@@ -307,6 +308,8 @@ public:
QQmlType type(const QHashedStringRef &, int) const;
QQmlType type(const QV4::String *, int) const;
+ void walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const;
+
QQmlTypeModulePrivate *priv() { return d; }
private:
//Used by register functions and creates the QQmlTypeModule for them
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 11d090a415..1c15022124 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -163,7 +163,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
int objectToCreate;
if (subComponentIndex == -1) {
- objectToCreate = qmlUnit->indexOfRootObject;
+ objectToCreate = /*root object*/0;
} else {
const QV4::CompiledData::Object *compObj = qmlUnit->objectAt(subComponentIndex);
objectToCreate = compObj->bindingTable()->value.objectIndex;
@@ -1122,7 +1122,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
}
ddata->setImplicitDestructible();
- if (static_cast<quint32>(index) == qmlUnit->indexOfRootObject || ddata->rootObjectInCreation) {
+ if (static_cast<quint32>(index) == /*root object*/0 || ddata->rootObjectInCreation) {
if (ddata->context) {
Q_ASSERT(ddata->context != context);
Q_ASSERT(ddata->outerContext);
@@ -1132,7 +1132,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
c->linkedContext = context;
} else
context->addObject(instance);
- ddata->ownContext = true;
+ ddata->ownContext = ddata->context;
} else if (!ddata->context)
context->addObject(instance);
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 7e298a1f2d..d5ed5792b3 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -700,8 +700,7 @@ void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
{
Q_ASSERT(m_waitingFor.contains(blob));
Q_ASSERT(blob->status() == Error || blob->status() == Complete);
- QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler,
- blob);
+ QQmlCompilingProfiler prof(typeLoader()->profiler(), blob);
m_inCallback = true;
@@ -963,6 +962,14 @@ void QQmlTypeLoader::invalidate()
#endif // qml_network
}
+#ifndef QT_NO_QML_DEBUGGER
+void QQmlTypeLoader::setProfiler(QQmlProfiler *profiler)
+{
+ Q_ASSERT(!m_profiler);
+ m_profiler.reset(profiler);
+}
+#endif
+
void QQmlTypeLoader::lock()
{
m_thread->lock();
@@ -1262,7 +1269,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName)
void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeData &d)
{
QML_MEMORY_SCOPE_URL(blob->url());
- QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob);
+ QQmlCompilingProfiler prof(profiler(), blob);
blob->m_inCallback = true;
@@ -1282,7 +1289,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::SourceCodeD
void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit)
{
QML_MEMORY_SCOPE_URL(blob->url());
- QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob);
+ QQmlCompilingProfiler prof(profiler(), blob);
blob->m_inCallback = true;
@@ -2814,7 +2821,7 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
effectiveCtxt = 0;
// Create the script context if required
- QQmlContextData *ctxt = new QQmlContextData;
+ QQmlContextDataRef ctxt(new QQmlContextData);
ctxt->isInternal = true;
ctxt->isJSContext = true;
if (shared)
@@ -2834,7 +2841,7 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
}
if (effectiveCtxt) {
- ctxt->setParent(effectiveCtxt, true);
+ ctxt->setParent(effectiveCtxt);
} else {
ctxt->engine = parentCtxt->engine; // Fix for QTBUG-21620
}
@@ -2856,12 +2863,10 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
if (!m_program) {
if (shared)
m_loaded = true;
- ctxt->destroy();
return QV4::Encode::undefined();
}
QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxt, 0));
- qmlContext->takeContextOwnership();
m_program->qmlContext.set(scope.engine, qmlContext);
m_program->run();
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 05923f77e8..c214f0cd43 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -84,6 +84,7 @@ class QQmlComponentPrivate;
class QQmlTypeData;
class QQmlTypeLoader;
class QQmlExtensionInterface;
+class QQmlProfiler;
struct QQmlCompileError;
namespace QmlIR {
@@ -248,7 +249,7 @@ private:
QString m_location;
};
-class Q_AUTOTEST_EXPORT QQmlTypeLoader
+class Q_QML_PRIVATE_EXPORT QQmlTypeLoader
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader)
public:
@@ -320,6 +321,15 @@ public:
void initializeEngine(QQmlExtensionInterface *, const char *);
void invalidate();
+#ifdef QT_NO_QML_DEBUGGER
+ QQmlProfiler *profiler() const { return nullptr; }
+ void setProfiler(QQmlProfiler *) {}
+#else
+ QQmlProfiler *profiler() const { return m_profiler.data(); }
+ void setProfiler(QQmlProfiler *profiler);
+#endif // QT_NO_QML_DEBUGGER
+
+
private:
friend class QQmlDataBlob;
friend class QQmlTypeLoaderThread;
@@ -368,6 +378,11 @@ private:
QQmlEngine *m_engine;
QQmlTypeLoaderThread *m_thread;
+
+#ifndef QT_NO_QML_DEBUGGER
+ QScopedPointer<QQmlProfiler> m_profiler;
+#endif
+
#if QT_CONFIG(qml_network)
NetworkReplies m_networkReplies;
#endif
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 113ef0c412..08f3d35e46 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1058,7 +1058,7 @@ private:
void readEncoding();
PersistentValue m_thisObject;
- QQmlGuardedContextData m_qmlContext;
+ QQmlContextDataRef m_qmlContext;
static void dispatchCallback(Object *thisObj, QQmlContextData *context);
void dispatchCallback();
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 64ab436363..1630efe081 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -1152,6 +1152,10 @@ void QtObject::method_createQmlObject(const BuiltinFunction *, Scope &scope, Cal
if (!component.isReady())
THROW_GENERIC_ERROR("Qt.createQmlObject(): Component is not ready");
+ if (!effectiveContext->isValid()) {
+ THROW_GENERIC_ERROR("Qt.createQmlObject(): Cannot create a component in an invalid context");
+ }
+
QObject *obj = component.beginCreate(effectiveContext);
if (obj) {
QQmlData::get(obj, true)->explicitIndestructibleSet = false;
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index d54bdeede6..4d2a9746c3 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -269,7 +269,8 @@ QQmlDelegateModel::~QQmlDelegateModel()
delete cacheItem->object;
cacheItem->object = 0;
- cacheItem->contextData->destroy();
+ cacheItem->contextData->invalidate();
+ Q_ASSERT(cacheItem->contextData->refCount == 1);
cacheItem->contextData = 0;
cacheItem->scriptRef -= 1;
}
@@ -840,7 +841,8 @@ void QQDMIncubationTask::statusChanged(Status status)
delete incubating->object;
incubating->object = 0;
if (incubating->contextData) {
- incubating->contextData->destroy();
+ incubating->contextData->invalidate();
+ Q_ASSERT(incubating->contextData->refCount == 1);
incubating->contextData = 0;
}
incubating->scriptRef = 0;
@@ -900,8 +902,10 @@ void QQmlDelegateModelPrivate::incubatorStatusChanged(QQDMIncubationTask *incuba
delete cacheItem->object;
cacheItem->object = 0;
cacheItem->scriptRef -= 1;
- if (cacheItem->contextData)
- cacheItem->contextData->destroy();
+ if (cacheItem->contextData) {
+ cacheItem->contextData->invalidate();
+ Q_ASSERT(cacheItem->contextData->refCount == 1);
+ }
cacheItem->contextData = 0;
if (!cacheItem->isReferenced()) {
@@ -983,7 +987,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, bo
if (QQmlAdaptorModelProxyInterface *proxy
= qobject_cast<QQmlAdaptorModelProxyInterface *>(cacheItem)) {
ctxt = new QQmlContextData;
- ctxt->setParent(cacheItem->contextData, true);
+ ctxt->setParent(cacheItem->contextData);
ctxt->contextObject = proxy->proxiedObject();
}
}
@@ -1264,6 +1268,13 @@ void QQmlDelegateModel::_q_itemsInserted(int index, int count)
d->emitChanges();
}
+//### This method should be split in two. It will remove delegates, and it will re-render the list.
+// When e.g. QQmlListModel::remove is called, the removal of the delegates should be done on
+// QAbstractItemModel::rowsAboutToBeRemoved, and the re-rendering on
+// QAbstractItemModel::rowsRemoved. Currently both are done on the latter signal. The problem is
+// that the destruction of an item will emit a changed signal that ends up at the delegate, which
+// in turn will try to load the data from the model (which should have already freed it), resulting
+// in a use-after-free. See QTBUG-59256.
void QQmlDelegateModelPrivate::itemsRemoved(
const QVector<Compositor::Remove> &removes,
QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedRemoves,
@@ -1944,8 +1955,11 @@ void QQmlDelegateModelItem::destroyObject()
QQmlData *data = QQmlData::get(object);
Q_ASSERT(data);
- if (data->ownContext && data->context)
- data->context->clearContext();
+ if (data->ownContext) {
+ data->ownContext->clearContext();
+ data->ownContext = 0;
+ data->context = 0;
+ }
object->deleteLater();
if (attached) {
@@ -1953,7 +1967,7 @@ void QQmlDelegateModelItem::destroyObject()
attached = 0;
}
- contextData->destroy();
+ contextData->invalidate();
contextData = 0;
object = 0;
}
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index 4ebfd9b938..3759fe8667 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -135,7 +135,7 @@ public:
QV4::ExecutionEngine *v4;
QQmlDelegateModelItemMetaType * const metaType;
- QQmlContextData *contextData;
+ QQmlContextDataRef contextData;
QPointer<QObject> object;
QPointer<QQmlDelegateModelAttached> attached;
QQDMIncubationTask *incubationTask;
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 20000557ee..d088a5da42 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -572,14 +572,20 @@ void ListModel::clear()
elements.clear();
}
-void ListModel::remove(int index, int count)
+QVector<std::function<void()>> ListModel::remove(int index, int count)
{
+ QVector<std::function<void()>> toDestroy;
+ auto layout = m_layout;
for (int i=0 ; i < count ; ++i) {
- elements[index+i]->destroy(m_layout);
- delete elements[index+i];
+ auto element = elements[index+i];
+ toDestroy.append([element, layout](){
+ element->destroy(layout);
+ delete element;
+ });
}
elements.remove(index, count);
updateCacheIndices(index);
+ return toDestroy;
}
void ListModel::insert(int elementIndex, QV4::Object *object)
@@ -1394,7 +1400,10 @@ void ModelObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name, u
p->value = v4->fromVariant(value);
return;
}
- QV4::QObjectWrapper::advanceIterator(m, it, name, index, p, attributes);
+ // Fall back to QV4::Object as opposed to QV4::QObjectWrapper otherwise it will add
+ // unnecessary entries that relate to the roles used. These just create extra work
+ // later on as they will just be ignored.
+ QV4::Object::advanceIterator(m, it, name, index, p, attributes);
}
DEFINE_OBJECT_VTABLE(ModelObject);
@@ -2059,15 +2068,22 @@ void QQmlListModel::remove(QQmlV4Function *args)
emitItemsAboutToBeRemoved(index, removeCount);
+ QVector<std::function<void()>> toDestroy;
if (m_dynamicRoles) {
- for (int i=0 ; i < removeCount ; ++i)
- delete m_modelObjects[index+i];
+ for (int i=0 ; i < removeCount ; ++i) {
+ auto modelObject = m_modelObjects[index+i];
+ toDestroy.append([modelObject](){
+ delete modelObject;
+ });
+ }
m_modelObjects.remove(index, removeCount);
} else {
- m_listModel->remove(index, removeCount);
+ toDestroy = m_listModel->remove(index, removeCount);
}
emitItemsRemoved(index, removeCount);
+ for (const auto &destroyer : toDestroy)
+ destroyer();
} else {
qmlWarning(this) << tr("remove: incorrect number of arguments");
}
diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h
index e2653c220d..77d2002afa 100644
--- a/src/qml/types/qqmllistmodel_p_p.h
+++ b/src/qml/types/qqmllistmodel_p_p.h
@@ -367,7 +367,7 @@ public:
void insert(int elementIndex, QV4::Object *object);
void clear();
- void remove(int index, int count);
+ Q_REQUIRED_RESULT QVector<std::function<void()>> remove(int index, int count);
int appendElement();
void insertElement(int index);
diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp
index a9bf02aeca..3cd1694dd0 100644
--- a/src/qmltest/quicktest.cpp
+++ b/src/qmltest/quicktest.cpp
@@ -271,7 +271,7 @@ private:
TestCaseEnumerationResult result;
if (!object) // Start at root of compilation unit if not enumerating a specific child
- object = compilationUnit->objectAt(compilationUnit->rootObjectIndex());
+ object = compilationUnit->objectAt(0);
if (CompilationUnit *superTypeUnit = compilationUnit->resolvedTypes.value(object->inheritedTypeNameIndex)->compilationUnit) {
// We have a non-C++ super type, which could indicate we're a subtype of a TestCase
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index df6dd9dba2..a8bf14ba9f 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -54,6 +54,9 @@
#include <QtGui/QGuiApplication>
QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcCanvas, "qt.quick.canvas")
+
#if QT_CONFIG(opengl)
#define QT_MINIMUM_FBO_SIZE 64
@@ -96,6 +99,7 @@ QQuickContext2DTexture::QQuickContext2DTexture()
#endif
, m_surface(0)
, m_item(0)
+ , m_canvasDevicePixelRatio(1)
, m_canvasWindowChanged(false)
, m_dirtyTexture(false)
, m_smooth(true)
@@ -161,12 +165,22 @@ void QQuickContext2DTexture::setItem(QQuickCanvasItem* item)
bool QQuickContext2DTexture::setCanvasWindow(const QRect& r)
{
+ qreal canvasDevicePixelRatio = (m_item && m_item->window()) ?
+ m_item->window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio();
+ if (!qFuzzyCompare(m_canvasDevicePixelRatio, canvasDevicePixelRatio)) {
+ qCDebug(lcCanvas, "%s device pixel ratio %.1lf -> %.1lf",
+ (m_item->objectName().isEmpty() ? "Canvas" : qPrintable(m_item->objectName())),
+ m_canvasDevicePixelRatio, canvasDevicePixelRatio);
+ m_canvasDevicePixelRatio = canvasDevicePixelRatio;
+ m_canvasWindowChanged = true;
+ }
+
if (m_canvasWindow != r) {
m_canvasWindow = r;
m_canvasWindowChanged = true;
- return true;
}
- return false;
+
+ return m_canvasWindowChanged;
}
bool QQuickContext2DTexture::setDirtyRect(const QRect &r)
@@ -549,9 +563,6 @@ QPaintDevice* QQuickContext2DFBOTexture::beginPainting()
{
QQuickContext2DTexture::beginPainting();
- const qreal devicePixelRatio = (m_item && m_item->window()) ?
- m_item->window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio();
-
if (m_canvasWindow.size().isEmpty()) {
delete m_fbo;
delete m_multisampledFbo;
@@ -566,7 +577,7 @@ QPaintDevice* QQuickContext2DFBOTexture::beginPainting()
delete m_paint_device;
m_paint_device = 0;
- m_fboSize = npotAdjustedSize(m_canvasWindow.size() * devicePixelRatio);
+ m_fboSize = npotAdjustedSize(m_canvasWindow.size() * m_canvasDevicePixelRatio);
m_canvasWindowChanged = false;
if (doMultisampling()) {
@@ -604,7 +615,10 @@ QPaintDevice* QQuickContext2DFBOTexture::beginPainting()
QOpenGLPaintDevice *gl_device = new QOpenGLPaintDevice(m_fbo->size());
gl_device->setPaintFlipped(true);
gl_device->setSize(m_fbo->size());
- gl_device->setDevicePixelRatio(devicePixelRatio);
+ gl_device->setDevicePixelRatio(m_canvasDevicePixelRatio);
+ qCDebug(lcCanvas, "%s size %.1lf x %.1lf painting with size %d x %d DPR %.1lf",
+ (m_item->objectName().isEmpty() ? "Canvas" : qPrintable(m_item->objectName())),
+ m_item->width(), m_item->height(), m_fbo->size().width(), m_fbo->size().height(), m_canvasDevicePixelRatio);
m_paint_device = gl_device;
}
@@ -710,14 +724,15 @@ QPaintDevice* QQuickContext2DImageTexture::beginPainting()
if (m_canvasWindow.size().isEmpty())
return 0;
- const qreal devicePixelRatio = (m_item && m_item->window()) ?
- m_item->window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio();
if (m_canvasWindowChanged) {
- m_image = QImage(m_canvasWindow.size() * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
- m_image.setDevicePixelRatio(devicePixelRatio);
+ m_image = QImage(m_canvasWindow.size() * m_canvasDevicePixelRatio, QImage::Format_ARGB32_Premultiplied);
+ m_image.setDevicePixelRatio(m_canvasDevicePixelRatio);
m_image.fill(0x00000000);
m_canvasWindowChanged = false;
+ qCDebug(lcCanvas, "%s size %.1lf x %.1lf painting with size %d x %d DPR %.1lf",
+ (m_item->objectName().isEmpty() ? "Canvas" : qPrintable(m_item->objectName())),
+ m_item->width(), m_item->height(), m_image.size().width(), m_image.size().height(), m_canvasDevicePixelRatio);
}
return &m_image;
diff --git a/src/quick/items/context2d/qquickcontext2dtexture_p.h b/src/quick/items/context2d/qquickcontext2dtexture_p.h
index 97135816a2..81896dcdc1 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtexture_p.h
@@ -168,6 +168,7 @@ protected:
QSize m_canvasSize;
QSize m_tileSize;
QRect m_canvasWindow;
+ qreal m_canvasDevicePixelRatio;
QMutex m_mutex;
QWaitCondition m_condition;
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp
index a30d71dd1e..5bc5b0faff 100644
--- a/src/quick/items/qquickanimatedimage.cpp
+++ b/src/quick/items/qquickanimatedimage.cpp
@@ -279,8 +279,7 @@ void QQuickAnimatedImage::setSource(const QUrl &url)
d->oldPlaying = isPlaying();
if (d->_movie) {
- delete d->_movie;
- d->_movie = 0;
+ d->setMovie(nullptr);
}
d->url = url;
@@ -320,7 +319,7 @@ void QQuickAnimatedImage::load()
QString lf = QQmlFile::urlToLocalFileOrQrc(loadUrl);
if (!lf.isEmpty()) {
- d->_movie = new QMovie(lf);
+ d->setMovie(new QMovie(lf));
movieRequestFinished();
} else {
#if QT_CONFIG(qml_network)
@@ -366,14 +365,13 @@ void QQuickAnimatedImage::movieRequestFinished()
}
d->redirectCount=0;
- d->_movie = new QMovie(d->reply);
+ d->setMovie(new QMovie(d->reply));
}
#endif
if (!d->_movie || !d->_movie->isValid()) {
qmlWarning(this) << "Error Reading Animated Image File " << d->url.toString();
- delete d->_movie;
- d->_movie = 0;
+ d->setMovie(nullptr);
d->setImage(QImage());
if (d->progress != 0) {
d->progress = 0;
@@ -490,6 +488,18 @@ void QQuickAnimatedImage::componentComplete()
load();
}
+void QQuickAnimatedImagePrivate::setMovie(QMovie *movie)
+{
+ Q_Q(QQuickAnimatedImage);
+ const int oldFrameCount = q->frameCount();
+
+ delete _movie;
+ _movie = movie;
+
+ if (oldFrameCount != q->frameCount())
+ emit q->frameCountChanged();
+}
+
QT_END_NAMESPACE
#include "moc_qquickanimatedimage_p.cpp"
diff --git a/src/quick/items/qquickanimatedimage_p.h b/src/quick/items/qquickanimatedimage_p.h
index 54da093259..94e44f27cd 100644
--- a/src/quick/items/qquickanimatedimage_p.h
+++ b/src/quick/items/qquickanimatedimage_p.h
@@ -69,7 +69,7 @@ class Q_AUTOTEST_EXPORT QQuickAnimatedImage : public QQuickImage
Q_PROPERTY(bool playing READ isPlaying WRITE setPlaying NOTIFY playingChanged)
Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged)
Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY frameChanged)
- Q_PROPERTY(int frameCount READ frameCount)
+ Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged)
// read-only for AnimatedImage
Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY sourceSizeChanged)
@@ -97,6 +97,7 @@ Q_SIGNALS:
void playingChanged();
void pausedChanged();
void frameChanged();
+ void frameCountChanged();
private Q_SLOTS:
void movieUpdate();
diff --git a/src/quick/items/qquickanimatedimage_p_p.h b/src/quick/items/qquickanimatedimage_p_p.h
index 9eff6a44e3..68c4f2d359 100644
--- a/src/quick/items/qquickanimatedimage_p_p.h
+++ b/src/quick/items/qquickanimatedimage_p_p.h
@@ -91,6 +91,7 @@ public:
#endif
QMap<int, QQuickPixmap *> frameMap;
QSize currentSourceSize;
+ void setMovie(QMovie *movie);
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index 41847e5f01..7c936ff21c 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -772,6 +772,7 @@ Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedAct
drag->setPixmap(QPixmap::fromImage(pixmapLoader.image()));
}
+ drag->setHotSpot(hotSpot.toPoint());
emit q->dragStarted();
Qt::DropAction dropAction = drag->exec(supportedActions);
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index ce584cd283..ee5f177855 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -56,6 +56,7 @@
#include <QtCore/qmath.h>
#include "qplatformdefs.h"
+#include <math.h>
#include <cmath>
QT_BEGIN_NAMESPACE
@@ -1771,6 +1772,7 @@ void QQuickFlickable::flick(qreal xVelocity, qreal yVelocity)
d->vData.reset();
d->hData.velocity = xVelocity;
d->vData.velocity = yVelocity;
+ d->hData.vTime = d->vData.vTime = d->timeline.time();
bool flickedX = d->flickX(xVelocity);
bool flickedY = d->flickY(yVelocity);
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index da11913bde..8f3a8998f5 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -2511,7 +2511,7 @@ void QQuickTextEdit::updateSize()
if (d->isImplicitResizeEnabled()) {
// ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
- if (!widthValid() && !d->requireImplicitWidth)
+ if (!widthValid())
setImplicitSize(newWidth + leftPadding() + rightPadding(), newHeight + topPadding() + bottomPadding());
else
setImplicitHeight(newHeight + topPadding() + bottomPadding());
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp
index 2954f591ad..bd5d8f72c0 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp
@@ -50,7 +50,7 @@ QSGSoftwareLayer::QSGSoftwareLayer(QSGRenderContext *renderContext)
, m_renderer(0)
, m_device_pixel_ratio(1)
, m_mirrorHorizontal(false)
- , m_mirrorVertical(false)
+ , m_mirrorVertical(true)
, m_live(true)
, m_grab(true)
, m_recursive(false)
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
index 8fbd402a2f..3ae79a933f 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -50,7 +50,9 @@
QT_BEGIN_NAMESPACE
+#if QT_CONFIG(opengl)
static const bool qsg_sanity_check = qEnvironmentVariableIntValue("QSG_SANITY_CHECK");
+#endif
static QElapsedTimer frameTimer;
static qint64 preprocessTime;
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index a3a2efd565..446f9b04a7 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -145,6 +145,7 @@ private slots:
void array_join_QTBUG_53672();
void regexpLastMatch();
+ void regexpLastIndex();
void indexedAccesses();
void prototypeChainGc();
@@ -3289,6 +3290,28 @@ void tst_QJSEngine::regexpLastMatch()
}
+void tst_QJSEngine::regexpLastIndex()
+{
+ QJSEngine eng;
+ QJSValue result;
+ result = eng.evaluate("function test(text, rx) {"
+ " var res;"
+ " while (res = rx.exec(text)) { "
+ " return true;"
+ " }"
+ " return false;"
+ " }"
+ "function tester(text) {"
+ " return test(text, /,\\s*/g);"
+ "}");
+ QVERIFY(!result.isError());
+
+ result = eng.evaluate("tester(\", \\n\");");
+ QVERIFY(result.toBool());
+ result = eng.evaluate("tester(\", \\n\");");
+ QVERIFY(result.toBool());
+}
+
void tst_QJSEngine::indexedAccesses()
{
QJSEngine engine;
diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
index 1f80ff46d0..7e81df93b9 100644
--- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
+++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
@@ -44,6 +44,7 @@ private slots:
void loadGeneratedFile();
void translationExpressionSupport();
void signalHandlerParameters();
+ void errorOnArgumentsInSignalHandler();
};
// A wrapper around QQmlComponent to ensure the temporary reference counts
@@ -68,15 +69,20 @@ public:
}
};
-static bool generateCache(const QString &qmlFileName)
+static bool generateCache(const QString &qmlFileName, QByteArray *capturedStderr = nullptr)
{
QProcess proc;
- proc.setProcessChannelMode(QProcess::ForwardedChannels);
+ if (capturedStderr == nullptr)
+ proc.setProcessChannelMode(QProcess::ForwardedChannels);
proc.setProgram(QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator() + QLatin1String("qmlcachegen"));
proc.setArguments(QStringList() << (QLatin1String("--target-architecture=") + QSysInfo::buildCpuArchitecture()) << (QLatin1String("--target-abi=") + QSysInfo::buildAbi()) << qmlFileName);
proc.start();
if (!proc.waitForFinished())
return false;
+
+ if (capturedStderr)
+ *capturedStderr = proc.readAllStandardError();
+
if (proc.exitStatus() != QProcess::NormalExit)
return false;
return proc.exitCode() == 0;
@@ -194,6 +200,31 @@ void tst_qmlcachegen::signalHandlerParameters()
QCOMPARE(obj->property("result").toInt(), 42);
}
+void tst_qmlcachegen::errorOnArgumentsInSignalHandler()
+{
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ const QString testFilePath = writeTempFile("test.qml", "import QtQml 2.2\n"
+ "QtObject {\n"
+ " signal mySignal(var arguments);\n"
+ " onMySignal: console.log(arguments);\n"
+ "}");
+
+
+ QByteArray errorOutput;
+ QVERIFY(!generateCache(testFilePath, &errorOutput));
+ QVERIFY2(errorOutput.contains("error: The use of the arguments object in signal handlers is"), errorOutput);
+}
+
QTEST_GUILESS_MAIN(tst_qmlcachegen)
#include "tst_qmlcachegen.moc"
diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
index 6ab84774f2..e75e51ed29 100644
--- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
+++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
@@ -59,6 +59,7 @@ private slots:
void cacheResources();
void stableOrderOfDependentCompositeTypes();
void singletonDependency();
+ void cppRegisteredSingletonDependency();
};
// A wrapper around QQmlComponent to ensure the temporary reference counts
@@ -790,6 +791,66 @@ void tst_qmldiskcache::singletonDependency()
}
}
+void tst_qmldiskcache::cppRegisteredSingletonDependency()
+{
+ qmlClearTypeRegistrations();
+ QScopedPointer<QQmlEngine> engine(new QQmlEngine);
+
+ QTemporaryDir tempDir;
+ QVERIFY(tempDir.isValid());
+
+ const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
+ QFile f(tempDir.path() + '/' + fileName);
+ const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ Q_ASSERT(ok);
+ f.write(contents);
+ return f.fileName();
+ };
+
+ writeTempFile("MySingleton.qml", "import QtQml 2.0\npragma Singleton\nQtObject { property int value: 42 }");
+
+ qmlRegisterSingletonType(QUrl::fromLocalFile(tempDir.path() + QLatin1String("/MySingleton.qml")), "CppRegisteredSingletonDependency", 1, 0, "Singly");
+
+ const QString testFilePath = writeTempFile("main.qml", "import QtQml 2.0\nimport CppRegisteredSingletonDependency 1.0\nQtObject {\n"
+ " function getValue() { return Singly.value; }\n"
+ "}");
+
+ {
+ CleanlyLoadingComponent component(engine.data(), QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QVariant value;
+ QVERIFY(QMetaObject::invokeMethod(obj.data(), "getValue", Q_RETURN_ARG(QVariant, value)));
+ QCOMPARE(value.toInt(), 42);
+ }
+
+ const QString testFileCachePath = testFilePath + QLatin1Char('c');
+ QVERIFY(QFile::exists(testFileCachePath));
+ QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
+
+ engine.reset(new QQmlEngine);
+ waitForFileSystem();
+
+ writeTempFile("MySingleton.qml", "import QtQml 2.0\npragma Singleton\nQtObject { property int value: 100 }");
+ waitForFileSystem();
+
+ {
+ CleanlyLoadingComponent component(engine.data(), QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ {
+ QVERIFY(QFile::exists(testFileCachePath));
+ QDateTime newCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
+ QVERIFY2(newCacheTimeStamp > initialCacheTimeStamp, qPrintable(newCacheTimeStamp.toString()));
+ }
+
+ QVariant value;
+ QVERIFY(QMetaObject::invokeMethod(obj.data(), "getValue", Q_RETURN_ARG(QVariant, value)));
+ QCOMPARE(value.toInt(), 100);
+ }
+}
+
QTEST_MAIN(tst_qmldiskcache)
#include "tst_qmldiskcache.moc"
diff --git a/tests/auto/qml/qqmlcontext/data/Singleton.qml b/tests/auto/qml/qqmlcontext/data/Singleton.qml
new file mode 100644
index 0000000000..68ef5850e3
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/Singleton.qml
@@ -0,0 +1,5 @@
+pragma Singleton
+import QtQml 2.0
+QtObject {
+ readonly property string song: "Highway to Hell"
+}
diff --git a/tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml b/tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml
new file mode 100644
index 0000000000..2e0e6f20e2
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml
@@ -0,0 +1,14 @@
+import QtQml 2.0
+
+import constants 1.0
+
+QtObject {
+ function createClosure() {
+ return function() { return Sing.song; }
+ }
+ function createComponentFactory() {
+ return function(parentObj) {
+ return Qt.createQmlObject('import QtQml 2.0; QtObject { property string test: "ok"; }', parentObj);
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
index f49fd391ac..5f57b9ebb0 100644
--- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
+++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
@@ -62,6 +62,7 @@ private slots:
void evalAfterInvalidate();
void qobjectDerived();
void qtbug_49232();
+ void contextViaClosureAfterDestruction();
private:
QQmlEngine engine;
@@ -723,6 +724,33 @@ void tst_qqmlcontext::qtbug_49232()
QCOMPARE(obj->property("valueTwo"), QVariant(97));
}
+void tst_qqmlcontext::contextViaClosureAfterDestruction()
+{
+ qmlRegisterSingletonType(testFileUrl("Singleton.qml"), "constants", 1, 0, "Sing");
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("contextViaClosureAfterDestruction.qml"));
+ QJSValue valueClosure;
+ QJSValue componentFactoryClosure;
+ {
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ // meta-calls don't support QJSValue return types, so do the call "by hand"
+ valueClosure = engine.newQObject(obj.data()).property(QStringLiteral("createClosure")).call();
+ QVERIFY(valueClosure.isCallable());
+ componentFactoryClosure = engine.newQObject(obj.data()).property(QStringLiteral("createComponentFactory")).call();
+ QVERIFY(componentFactoryClosure.isCallable());
+ }
+ QCOMPARE(valueClosure.call().toString(), QLatin1String("Highway to Hell"));
+
+ QScopedPointer<QObject> parent(new QObject);
+ QJSValue parentWrapper = engine.newQObject(parent.data());
+ QQmlEngine::setObjectOwnership(parent.data(), QQmlEngine::CppOwnership);
+
+ QJSValue subObject = componentFactoryClosure.callWithInstance(componentFactoryClosure, QJSValueList() << parentWrapper);
+ QVERIFY(subObject.isError());
+ QCOMPARE(subObject.toString(), QLatin1String("Error: Qt.createQmlObject(): Cannot create a component in an invalid context"));
+}
+
QTEST_MAIN(tst_qqmlcontext)
#include "tst_qqmlcontext.moc"
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp
index c4692fdf31..80da5d7e52 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.cpp
+++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp
@@ -245,9 +245,16 @@ public:
MyWorkerObject *o;
};
+MyWorkerObject::~MyWorkerObject()
+{
+ if (m_thread)
+ m_thread->wait();
+}
+
void MyWorkerObject::doIt()
{
- new MyWorkerObjectThread(this);
+ Q_ASSERT(!m_thread);
+ m_thread = new MyWorkerObjectThread(this);
}
class MyDateClass : public QObject
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h
index eedeb66647..e15a05a00c 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.h
+++ b/tests/auto/qml/qqmlecmascript/testtypes.h
@@ -1532,12 +1532,17 @@ private:
class MyWorkerObject : public QObject
{
Q_OBJECT
+public:
+ ~MyWorkerObject();
public Q_SLOTS:
void doIt();
Q_SIGNALS:
void done(const QString &result);
+
+private:
+ QThread *m_thread = 0;
};
class MyUnregisteredEnumTypeObject : public QObject
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 45f312e934..35f1534478 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -7444,21 +7444,17 @@ void tst_qqmlecmascript::signalEmitted()
void tst_qqmlecmascript::threadSignal()
{
{
- QQmlComponent c(&engine, testFileUrl("threadSignal.qml"));
- QObject *object = c.create();
- QVERIFY(object != 0);
- QTRY_VERIFY(object->property("passed").toBool());
- delete object;
+ QQmlComponent c(&engine, testFileUrl("threadSignal.qml"));
+ QScopedPointer<QObject> object(c.create());
+ QVERIFY(!object.isNull());
+ QTRY_VERIFY(object->property("passed").toBool());
}
{
- QQmlComponent c(&engine, testFileUrl("threadSignal.2.qml"));
- QObject *object = c.create();
- QVERIFY(object != 0);
- QSignalSpy doneSpy(object, SIGNAL(done(QString)));
- QMetaObject::invokeMethod(object, "doIt");
- QTRY_VERIFY(object->property("passed").toBool());
- QCOMPARE(doneSpy.count(), 1);
- delete object;
+ QQmlComponent c(&engine, testFileUrl("threadSignal.2.qml"));
+ QScopedPointer<QObject> object(c.create());
+ QVERIFY(!object.isNull());
+ QMetaObject::invokeMethod(object.data(), "doIt");
+ QTRY_VERIFY(object->property("passed").toBool());
}
}
diff --git a/tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro b/tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro
index 5bcec9f5b4..90508609a8 100644
--- a/tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro
+++ b/tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro
@@ -6,4 +6,4 @@ include (../../shared/util.pri)
SOURCES += tst_qqmlenginecleanup.cpp
-QT += testlib qml
+QT += testlib qml qml-private
diff --git a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp
index d0a8b6401f..7e9a1524b0 100644
--- a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp
+++ b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp
@@ -31,6 +31,8 @@
#include <QtQml/qqml.h>
#include <QtQml/QQmlEngine>
#include <QtQml/QQmlComponent>
+#include <private/qhashedstring_p.h>
+#include <private/qqmlmetatype_p.h>
//Separate test, because if engine cleanup attempts fail they can easily break unrelated tests
class tst_qqmlenginecleanup : public QQmlDataTest
@@ -44,41 +46,82 @@ private slots:
void test_valueTypeProviderModule(); // QTBUG-43004
};
+// A wrapper around QQmlComponent to ensure the temporary reference counts
+// on the type data as a result of the main thread <> loader thread communication
+// are dropped. Regular Synchronous loading will leave us with an event posted
+// to the gui thread and an extra refcount that will only be dropped after the
+// event delivery. A plain sendPostedEvents() however is insufficient because
+// we can't be sure that the event is posted after the constructor finished.
+class CleanlyLoadingComponent : public QQmlComponent
+{
+public:
+ CleanlyLoadingComponent(QQmlEngine *engine, const QUrl &url)
+ : QQmlComponent(engine, url, QQmlComponent::Asynchronous)
+ { waitForLoad(); }
+ CleanlyLoadingComponent(QQmlEngine *engine, const QString &fileName)
+ : QQmlComponent(engine, fileName, QQmlComponent::Asynchronous)
+ { waitForLoad(); }
+
+ void waitForLoad()
+ {
+ QTRY_VERIFY(status() == QQmlComponent::Ready || status() == QQmlComponent::Error);
+ }
+};
+
void tst_qqmlenginecleanup::test_qmlClearTypeRegistrations()
{
//Test for preventing memory leaks is in tests/manual/qmltypememory
QQmlEngine* engine;
- QQmlComponent* component;
+ CleanlyLoadingComponent* component;
QUrl testFile = testFileUrl("types.qml");
+ const auto qmlTypeForTestType = []() {
+ return QQmlMetaType::qmlType(QStringLiteral("TestTypeCpp"), QStringLiteral("Test"), 2, 0);
+ };
+
+ QVERIFY(!qmlTypeForTestType().isValid());
qmlRegisterType<QObject>("Test", 2, 0, "TestTypeCpp");
+ QVERIFY(qmlTypeForTestType().isValid());
+
engine = new QQmlEngine;
- component = new QQmlComponent(engine, testFile);
+ component = new CleanlyLoadingComponent(engine, testFile);
QVERIFY(component->isReady());
- delete engine;
delete component;
- qmlClearTypeRegistrations();
+ delete engine;
+
+ {
+ auto cppType = qmlTypeForTestType();
+
+ qmlClearTypeRegistrations();
+ QVERIFY(!qmlTypeForTestType().isValid());
+
+ // cppType should hold the last ref, qmlClearTypeRegistration should have wiped
+ // all internal references.
+ QCOMPARE(QQmlType::refCount(cppType.priv()), 1);
+ }
//2nd run verifies that types can reload after a qmlClearTypeRegistrations
qmlRegisterType<QObject>("Test", 2, 0, "TestTypeCpp");
+ QVERIFY(qmlTypeForTestType().isValid());
engine = new QQmlEngine;
- component = new QQmlComponent(engine, testFile);
+ component = new CleanlyLoadingComponent(engine, testFile);
QVERIFY(component->isReady());
- delete engine;
delete component;
+ delete engine;
qmlClearTypeRegistrations();
+ QVERIFY(!qmlTypeForTestType().isValid());
//3nd run verifies that TestTypeCpp is no longer registered
engine = new QQmlEngine;
- component = new QQmlComponent(engine, testFile);
+ component = new CleanlyLoadingComponent(engine, testFile);
QVERIFY(component->isError());
QCOMPARE(component->errorString(),
testFile.toString() +":33 module \"Test\" is not installed\n");
- delete engine;
delete component;
+ delete engine;
}
static void cleanState(QQmlEngine **e)
diff --git a/tests/auto/qml/qqmllanguage/data/MyLazyDeferredSubObject.qml b/tests/auto/qml/qqmllanguage/data/MyLazyDeferredSubObject.qml
new file mode 100644
index 0000000000..f311f6b602
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/MyLazyDeferredSubObject.qml
@@ -0,0 +1,6 @@
+import QtQml 2.0
+import Test 1.0
+LazyDeferredSubObject {
+ subObject: QtObject { objectName: 'default' }
+ objectName: subObject.objectName
+}
diff --git a/tests/auto/qml/qqmllanguage/data/lazyDeferredSubObject.qml b/tests/auto/qml/qqmllanguage/data/lazyDeferredSubObject.qml
new file mode 100644
index 0000000000..2465a18320
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lazyDeferredSubObject.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+import Test 1.0
+MyLazyDeferredSubObject {
+ subObject.objectName: 'custom'
+}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index bdcdaa8137..72e06d26aa 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -103,6 +103,8 @@ void registerTypes()
qmlRegisterSingletonType<MyTypeObjectSingleton>("Test", 1, 0, "MyTypeObjectSingleton", myTypeObjectSingleton);
qmlRegisterType<MyArrayBufferTestClass>("Test", 1, 0, "MyArrayBufferTestClass");
+
+ qmlRegisterType<LazyDeferredSubObject>("Test", 1, 0, "LazyDeferredSubObject");
}
QVariant myCustomVariantTypeConverter(const QString &data)
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index e4a76b4324..09c6992a51 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -1349,6 +1349,26 @@ private:
QObject *obj;
};
+class LazyDeferredSubObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *subObject READ subObject WRITE setSubObject NOTIFY subObjectChanged FINAL)
+ Q_CLASSINFO("DeferredPropertyNames", "subObject");
+public:
+ LazyDeferredSubObject()
+ : obj(0)
+ {}
+
+ QObject *subObject() const { if (!obj) qmlExecuteDeferred(const_cast<LazyDeferredSubObject *>(this)); return obj; }
+ void setSubObject(QObject *o) { if (obj == o) return; obj = o; emit subObjectChanged(); }
+
+signals:
+ void subObjectChanged();
+
+private:
+ QObject *obj;
+};
+
void registerTypes();
#endif // TESTTYPES_H
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index f09c130e38..e5366b5c48 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -250,6 +250,7 @@ private slots:
void propertyCacheInSync();
void rootObjectInCreationNotForSubObjects();
+ void lazyDeferredSubObject();
void noChildEvents();
@@ -2152,7 +2153,7 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode()
qmlUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
td->compilationUnit()->data = qmlUnit;
- const QV4::CompiledData::Object *rootObject = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
+ const QV4::CompiledData::Object *rootObject = qmlUnit->objectAt(/*root object*/0);
QCOMPARE(qmlUnit->stringAt(rootObject->inheritedTypeNameIndex), QString("MyTypeObject"));
quint32 i;
for (i = 0; i < rootObject->nBindings; ++i) {
@@ -4314,6 +4315,21 @@ void tst_qqmllanguage::rootObjectInCreationNotForSubObjects()
QVERIFY(!ddata->rootObjectInCreation);
}
+// QTBUG-63036
+void tst_qqmllanguage::lazyDeferredSubObject()
+{
+ QQmlComponent component(&engine, testFile("lazyDeferredSubObject.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QObject *subObject = qvariant_cast<QObject *>(object->property("subObject"));
+ QVERIFY(subObject);
+
+ QCOMPARE(object->objectName(), QStringLiteral("custom"));
+ QCOMPARE(subObject->objectName(), QStringLiteral("custom"));
+}
+
void tst_qqmllanguage::noChildEvents()
{
QQmlComponent component(&engine);
diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
index e442dd1421..4089673d68 100644
--- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
+++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
@@ -123,6 +123,7 @@ private slots:
void about_to_be_signals();
void modify_through_delegate();
void bindingsOnGetResult();
+ void stringifyModelEntry();
};
bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object)
@@ -1482,6 +1483,28 @@ void tst_qqmllistmodel::bindingsOnGetResult()
QVERIFY(obj->property("success").toBool());
}
+void tst_qqmllistmodel::stringifyModelEntry()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(
+ "import QtQuick 2.0\n"
+ "Item {\n"
+ " ListModel {\n"
+ " id: testModel\n"
+ " objectName: \"testModel\"\n"
+ " ListElement { name: \"Joe\"; age: 22 }\n"
+ " }\n"
+ "}\n", QUrl());
+ QScopedPointer<QObject> scene(component.create());
+ QQmlListModel *model = scene->findChild<QQmlListModel*>("testModel");
+ QQmlExpression expr(engine.rootContext(), model, "JSON.stringify(get(0));");
+ QVariant v = expr.evaluate();
+ QVERIFY2(!expr.hasError(), QTest::toString(expr.error().toString()));
+ const QString expectedString = QStringLiteral("{\"age\":22,\"name\":\"Joe\"}");
+ QCOMPARE(v.toString(), expectedString);
+}
+
QTEST_MAIN(tst_qqmllistmodel)
#include "tst_qqmllistmodel.moc"
diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
index 1c9523fc38..80c54bdf8e 100644
--- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
+++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
@@ -86,7 +86,7 @@ void tst_qqmltranslation::translation()
<< QStringLiteral("singular") << QStringLiteral("plural");
const QV4::CompiledData::Unit *unit = compilationUnit->data;
- const QV4::CompiledData::Object *rootObject = unit->objectAt(unit->indexOfRootObject);
+ const QV4::CompiledData::Object *rootObject = unit->objectAt(/*root object*/0);
const QV4::CompiledData::Binding *binding = rootObject->bindingTable();
for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) {
const QString propertyName = unit->stringAt(binding->propertyNameIndex);
@@ -141,7 +141,7 @@ void tst_qqmltranslation::idTranslation()
QVERIFY(compilationUnit);
const QV4::CompiledData::Unit *unit = compilationUnit->data;
- const QV4::CompiledData::Object *rootObject = unit->objectAt(unit->indexOfRootObject);
+ const QV4::CompiledData::Object *rootObject = unit->objectAt(/*root object*/0);
const QV4::CompiledData::Binding *binding = rootObject->bindingTable();
for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) {
const QString propertyName = unit->stringAt(binding->propertyNameIndex);
diff --git a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
index 34b9fb6b07..e303495944 100644
--- a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
+++ b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
@@ -132,6 +132,16 @@ void tst_qquickanimatedimage::frameCount()
QVERIFY(anim->isPlaying());
QCOMPARE(anim->frameCount(), 3);
+ QSignalSpy frameCountChangedSpy(anim, &QQuickAnimatedImage::frameCountChanged);
+
+ const QUrl origSource = anim->source();
+ anim->setSource(QUrl());
+ QCOMPARE(anim->frameCount(), 0);
+ QCOMPARE(frameCountChangedSpy.count(), 1);
+ anim->setSource(origSource);
+ QCOMPARE(anim->frameCount(), 3);
+ QCOMPARE(frameCountChangedSpy.count(), 2);
+
delete anim;
}
diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
index b2d6584701..2b14842658 100644
--- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
+++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
@@ -46,6 +46,8 @@
#include <QtGui/qguiapplication.h>
#include "qplatformdefs.h"
+#include <math.h>
+
Q_DECLARE_METATYPE(QQuickGridView::Flow)
Q_DECLARE_METATYPE(Qt::LayoutDirection)
Q_DECLARE_METATYPE(QQuickItemView::VerticalLayoutDirection)
diff --git a/tests/auto/quick/qquicklistview/data/programmaticFlickAtBounds3.qml b/tests/auto/quick/qquicklistview/data/programmaticFlickAtBounds3.qml
new file mode 100644
index 0000000000..bd913b2ce1
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/programmaticFlickAtBounds3.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.9
+
+ListView {
+ id: view
+ width: 200; height: 400
+
+ property real minOvershoot
+ onVerticalOvershootChanged: if (verticalOvershoot < minOvershoot) minOvershoot = verticalOvershoot
+
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ preferredHighlightBegin: 0
+ preferredHighlightEnd: 0
+
+ model: 10
+ delegate: Rectangle {
+ width: 200; height: 50
+ color: index % 2 ? "red" : "green"
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index 2eb87b9431..0d0f234d33 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -236,6 +236,7 @@ private slots:
void QTBUG_38209();
void programmaticFlickAtBounds();
void programmaticFlickAtBounds2();
+ void programmaticFlickAtBounds3();
void layoutChange();
@@ -8069,6 +8070,35 @@ void tst_QQuickListView::programmaticFlickAtBounds2()
QTRY_COMPARE(listview->contentY(), qreal(100.0));
}
+void tst_QQuickListView::programmaticFlickAtBounds3()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("programmaticFlickAtBounds3.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = qobject_cast<QQuickListView *>(window->rootObject());
+ QVERIFY(listview);
+
+ // flick down
+ listview->flick(0, 2000);
+
+ // verify scope of the movement
+ QTRY_VERIFY(listview->property("minOvershoot").toReal() < qreal(-50.0));
+
+ // reset, and test a second time
+ listview->cancelFlick();
+ listview->returnToBounds();
+ QTRY_COMPARE(listview->contentY(), qreal(0.0));
+ listview->setProperty("minOvershoot", qreal(0.0));
+
+ // flick down
+ listview->flick(0, 2000);
+
+ // verify scope of the movement is the same
+ QTRY_VERIFY(listview->property("minOvershoot").toReal() < qreal(-50.0));
+}
+
void tst_QQuickListView::layoutChange()
{
RandomSortModel *model = new RandomSortModel;
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml b/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml
index 039607e26c..027f90c7f4 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml
@@ -11,9 +11,21 @@ Rectangle {
maximumTouchPoints: 2
onGestureStarted: gesture.grab()
touchPoints: [
- TouchPoint { objectName: "point11" },
- TouchPoint { objectName: "point12" }
+ TouchPoint { id: point11; objectName: "point11" },
+ TouchPoint { id: point12; objectName: "point12" }
]
+ Rectangle {
+ color: "red"
+ width: 10; height: 10; radius: 5
+ x: point11.x - radius; y: point11.y - radius
+ visible: point11.pressed
+ }
+ Rectangle {
+ color: "tomato"
+ width: 10; height: 10; radius: 5
+ x: point12.x - radius; y: point12.y - radius
+ visible: point12.pressed
+ }
}
MultiPointTouchArea {
@@ -24,9 +36,27 @@ Rectangle {
maximumTouchPoints: 3
onGestureStarted: gesture.grab()
touchPoints: [
- TouchPoint { objectName: "point21" },
- TouchPoint { objectName: "point22" },
- TouchPoint { objectName: "point23" }
+ TouchPoint { id: point21; objectName: "point21" },
+ TouchPoint { id: point22; objectName: "point22" },
+ TouchPoint { id: point23; objectName: "point23" }
]
+ Rectangle {
+ color: "lightgreen"
+ width: 10; height: 10; radius: 5
+ x: point21.x - radius; y: point21.y - radius
+ visible: point21.pressed
+ }
+ Rectangle {
+ color: "green"
+ width: 10; height: 10; radius: 5
+ x: point22.x - radius; y: point22.y - radius
+ visible: point22.pressed
+ }
+ Rectangle {
+ color: "darkgreen"
+ width: 10; height: 10; radius: 5
+ x: point23.x - radius; y: point23.y - radius
+ visible: point23.pressed
+ }
}
}
diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
index b01d0c3cec..cbef0fcc8d 100644
--- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
+++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
@@ -48,6 +48,8 @@
#include "../shared/viewtestutil.h"
#include "../shared/visualtestutil.h"
+#include <math.h>
+
using namespace QQuickViewTestUtil;
using namespace QQuickVisualTestUtil;
diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
index ac57a05176..d58fc6c389 100644
--- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
+++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
@@ -158,6 +158,7 @@ private slots:
#endif
void implicitSize_data();
void implicitSize();
+ void implicitSize_QTBUG_63153();
void contentSize();
void boundingRect();
void clipRect();
@@ -3388,6 +3389,18 @@ void tst_qquicktextedit::implicitSize()
QCOMPARE(textObject->height(), textObject->implicitHeight());
}
+void tst_qquicktextedit::implicitSize_QTBUG_63153()
+{
+ QString componentStr = "import QtQuick 2.0\nTextEdit { }";
+ QQmlComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create());
+ textObject->setText("short");
+ qreal shortImplicitWidth = textObject->implicitWidth();
+ textObject->setText("in contrast to short this is long");
+ QVERIFY2(shortImplicitWidth < textObject->implicitWidth(), qPrintable(QString("%1 < %2").arg(textObject->implicitWidth()).arg(shortImplicitWidth)));
+}
+
void tst_qquicktextedit::contentSize()
{
QString componentStr = "import QtQuick 2.0\nTextEdit { width: 75; height: 16; font.pixelSize: 10 }";
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index b201176d5e..a62adc82f4 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -114,6 +114,37 @@ static void annotateListElements(QmlIR::Document *document)
}
}
+static bool checkArgumentsObjectUseInSignalHandlers(const QmlIR::Document &doc, Error *error)
+{
+ for (QmlIR::Object *object: qAsConst(doc.objects)) {
+ for (auto binding = object->bindingsBegin(); binding != object->bindingsEnd(); ++binding) {
+ if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ continue;
+ const QString propName = doc.stringAt(binding->propertyNameIndex);
+ if (!propName.startsWith(QLatin1String("on"))
+ || propName.length() < 3
+ || !propName.at(2).isUpper())
+ continue;
+ auto compiledFunction = doc.jsModule.functions.value(object->runtimeFunctionIndices.at(binding->value.compiledScriptIndex));
+ if (!compiledFunction)
+ continue;
+ if (compiledFunction->usesArgumentsObject) {
+ error->message = QLatin1Char(':') + QString::number(compiledFunction->line) + QLatin1Char(':');
+ if (compiledFunction->column > 0)
+ error->message += QString::number(compiledFunction->column) + QLatin1Char(':');
+
+ error->message += QLatin1String(" error: The use of the arguments object in signal handlers is\n"
+ "not supported when compiling qml files ahead of time, because it may be ambiguous if\n"
+ "any signal parameter is called \"arguments\". Unfortunately we cannot distinguish\n"
+ "between it being a parameter or the JavaScript arguments object at this point.\n"
+ "Consider renaming the parameter of the signal if applicable.");
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
static bool compileQmlFile(const QString &inputFileName, const QString &outputFileName, QV4::EvalISelFactory *iselFactory, const QString &targetABI, Error *error)
{
QmlIR::Document irDocument(/*debugMode*/false);
@@ -173,6 +204,11 @@ static bool compileQmlFile(const QString &inputFileName, const QString &outputFi
object->runtimeFunctionIndices.allocate(pool, runtimeFunctionIndices);
}
+ if (!checkArgumentsObjectUseInSignalHandlers(irDocument, error)) {
+ *error = error->augment(inputFileName);
+ return false;
+ }
+
QmlIR::QmlUnitGenerator generator;
{
diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp
index 9ab058d37b..d596613553 100644
--- a/tools/qmlimportscanner/main.cpp
+++ b/tools/qmlimportscanner/main.cpp
@@ -404,7 +404,7 @@ QVariantList findQmlImportsInDirectory(const QString &qmlDir)
if (qmlDir.isEmpty())
return ret;
- QDirIterator iterator(qmlDir, QDir::AllDirs | QDir::NoDot | QDir::NoDotDot, QDirIterator::Subdirectories);
+ QDirIterator iterator(qmlDir, QDir::AllDirs | QDir::NoDotDot, QDirIterator::Subdirectories);
QStringList blacklist;
while (iterator.hasNext()) {
diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp
index 79f9b2c49b..422e37fd89 100644
--- a/tools/qmlplugindump/main.cpp
+++ b/tools/qmlplugindump/main.cpp
@@ -788,7 +788,7 @@ static bool readDependenciesData(QString dependenciesFile, const QByteArray &fil
QString version = obj.value(QStringLiteral("version")).toString();
if (name.isEmpty() || urisToSkip.contains(name) || version.isEmpty())
continue;
- if (name.endsWith(QLatin1String("Private"), Qt::CaseInsensitive)) {
+ if (name.contains(QLatin1String("Private"), Qt::CaseInsensitive)) {
if (verbose)
std::cerr << "skipping private dependecy "
<< qPrintable( name ) << " " << qPrintable(version) << std::endl;