diff options
-rw-r--r-- | src/qml/qml/ftw/qflagpointer_p.h | 8 | ||||
-rw-r--r-- | src/qml/qml/qqmlbinding.cpp | 7 | ||||
-rw-r--r-- | src/qml/qml/qqmlbinding_p.h | 1 | ||||
-rw-r--r-- | src/qml/qml/qqmljavascriptexpression.cpp | 8 | ||||
-rw-r--r-- | src/qml/qml/qqmljavascriptexpression_p.h | 15 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmlvaluetypeproxybinding_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 12 | ||||
-rw-r--r-- | src/quick/util/qquickstate.cpp | 2 | ||||
-rw-r--r-- | src/quick/util/qquickstate_p_p.h | 4 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/data/removeBindingsWithNoDependencies.qml | 9 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 34 | ||||
-rw-r--r-- | tests/auto/quick/qquickdesignersupport/data/TestComponent.qml | 4 |
13 files changed, 97 insertions, 14 deletions
diff --git a/src/qml/qml/ftw/qflagpointer_p.h b/src/qml/qml/ftw/qflagpointer_p.h index 91ce74bec9..71b41cd30b 100644 --- a/src/qml/qml/ftw/qflagpointer_p.h +++ b/src/qml/qml/ftw/qflagpointer_p.h @@ -82,6 +82,8 @@ public: inline T *data() const; + inline explicit operator bool() const; + private: quintptr ptr_value = 0; @@ -230,6 +232,12 @@ T *QFlagPointer<T>::data() const return (T *)(ptr_value & ~FlagsMask); } +template<typename T> +QFlagPointer<T>::operator bool() const +{ + return data() != nullptr; +} + template<typename T, typename T2> QBiPointer<T, T2>::QBiPointer() { diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 5fcd38aa54..a4b3f1f4e4 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -374,6 +374,8 @@ public: } } + bool hasDependencies() const override final { return true; } + private: const QV4::CompiledData::Binding *m_binding; }; @@ -663,6 +665,11 @@ QVector<QQmlProperty> QQmlBinding::dependencies() const return dependencies; } +bool QQmlBinding::hasDependencies() const +{ + return !permanentGuards.isEmpty() || !activeGuards.isEmpty() || translationsCaptured(); +} + class QObjectPointerBinding: public QQmlNonbindingBinding { QQmlMetaObject targetMetaObject; diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 6cd64c7ca0..f192de4342 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -118,6 +118,7 @@ public: * Call this method from the UI thread. */ QVector<QQmlProperty> dependencies() const; + virtual bool hasDependencies() const; protected: virtual void doUpdate(const DeleteWatcher &watcher, diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index f0a5f18a15..9f2a96d5d9 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -93,8 +93,7 @@ void QQmlDelayedError::catchJavaScriptException(QV4::ExecutionEngine *engine) QQmlJavaScriptExpression::QQmlJavaScriptExpression() - : m_error(nullptr), - m_context(nullptr), + : m_context(nullptr), m_prevExpression(nullptr), m_nextExpression(nullptr), m_v4Function(nullptr) @@ -247,6 +246,9 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b while (QQmlJavaScriptExpressionGuard *g = capture.guards.takeFirst()) g->Delete(); + if (!watcher.wasDeleted()) + setTranslationsCaptured(capture.translationCaptured); + ep->propertyCapture = lastPropertyCapture; return result->asReturnedValue(); @@ -392,7 +394,7 @@ QQmlDelayedError *QQmlJavaScriptExpression::delayedError() { if (!m_error) m_error = new QQmlDelayedError; - return m_error; + return m_error.data(); } QV4::ReturnedValue diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 9562476940..de3fba0774 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -171,13 +171,17 @@ protected: QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards; QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> permanentGuards; + void setTranslationsCaptured(bool captured) { m_error.setFlagValue(captured); } + bool translationsCaptured() const { return m_error.flag(); } + private: friend class QQmlContextData; friend class QQmlPropertyCapture; friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **); friend class QQmlTranslationBinding; - QQmlDelayedError *m_error; + // m_error:flag1 translationsCapturedDuringEvaluation + QFlagPointer<QQmlDelayedError> m_error; QQmlContextData *m_context; QQmlJavaScriptExpression **m_prevExpression; @@ -208,12 +212,14 @@ public: static void registerQmlDependencies(QV4::Heap::QmlContext *context, const QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction); void captureProperty(QQmlNotifier *, Duration duration = OnlyOnce); void captureProperty(QObject *, int, int, Duration duration = OnlyOnce, bool doNotify = true); + void captureTranslation() { translationCaptured = true; } QQmlEngine *engine; QQmlJavaScriptExpression *expression; QQmlJavaScriptExpression::DeleteWatcher *watcher; QFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> guards; QStringList *errorString; + bool translationCaptured = false; }; QQmlJavaScriptExpression::DeleteWatcher::DeleteWatcher(QQmlJavaScriptExpression *e) @@ -260,18 +266,17 @@ void QQmlJavaScriptExpression::setScopeObject(QObject *v) bool QQmlJavaScriptExpression::hasError() const { - return m_error && m_error->isValid(); + return !m_error.isNull() && m_error->isValid(); } bool QQmlJavaScriptExpression::hasDelayedError() const { - return m_error; + return !m_error.isNull(); } inline void QQmlJavaScriptExpression::clearError() { - if (m_error) - delete m_error; + delete m_error.data(); m_error = nullptr; } diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 60617630d2..bec9c9840f 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -1344,6 +1344,11 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru data->clearPendingBindingBit(b->targetPropertyIndex().coreIndex()); b->setEnabled(true, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); + if (!b->isValueTypeProxy()) { + QQmlBinding *binding = static_cast<QQmlBinding*>(b.data()); + if (!binding->hasError() && !binding->hasDependencies()) + b->removeFromObject(); + } if (watcher.hasRecursed() || interrupt.shouldInterrupt()) return nullptr; diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h index ba0d305bd9..35b54c339b 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h +++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE -class QQmlValueTypeProxyBinding : public QQmlAbstractBinding +class Q_AUTOTEST_EXPORT QQmlValueTypeProxyBinding : public QQmlAbstractBinding { public: QQmlValueTypeProxyBinding(QObject *o, QQmlPropertyIndex coreIndex); diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 571f0af9d4..4ae78645ea 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1853,6 +1853,10 @@ ReturnedValue GlobalExtensions::method_qsTranslate(const FunctionObject *b, cons if (argc > i) n = argv[i].toInt32(); + if (QQmlEnginePrivate *ep = (scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : nullptr)) + if (ep->propertyCapture) + ep->propertyCapture->captureTranslation(); + QString result = QCoreApplication::translate(context.toUtf8().constData(), text.toUtf8().constData(), comment.toUtf8().constData(), @@ -1956,6 +1960,10 @@ ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value if (argc > 2) n = argv[2].toInt32(); + if (QQmlEnginePrivate *ep = (scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : nullptr)) + if (ep->propertyCapture) + ep->propertyCapture->captureTranslation(); + QString result = QCoreApplication::translate(context.toUtf8().constData(), text.toUtf8().constData(), comment.toUtf8().constData(), n); @@ -2036,6 +2044,10 @@ ReturnedValue GlobalExtensions::method_qsTrId(const FunctionObject *b, const Val if (argc > 1) n = argv[1].toInt32(); + if (QQmlEnginePrivate *ep = (scope.engine->qmlEngine() ? QQmlEnginePrivate::get(scope.engine->qmlEngine()) : nullptr)) + if (ep->propertyCapture) + ep->propertyCapture->captureTranslation(); + return Encode(scope.engine->newString(qtTrId(argv[0].toQStringNoThrow().toUtf8().constData(), n))); } diff --git a/src/quick/util/qquickstate.cpp b/src/quick/util/qquickstate.cpp index be8300f531..02c1efb62f 100644 --- a/src/quick/util/qquickstate.cpp +++ b/src/quick/util/qquickstate.cpp @@ -222,7 +222,7 @@ bool QQuickState::isWhenKnown() const QQmlBinding *QQuickState::when() const { Q_D(const QQuickState); - return d->when; + return d->when.data(); } void QQuickState::setWhen(QQmlBinding *when) diff --git a/src/quick/util/qquickstate_p_p.h b/src/quick/util/qquickstate_p_p.h index f1bc24c558..61472b4d06 100644 --- a/src/quick/util/qquickstate_p_p.h +++ b/src/quick/util/qquickstate_p_p.h @@ -203,12 +203,12 @@ class QQuickStatePrivate : public QObjectPrivate public: QQuickStatePrivate() - : when(nullptr), named(false), inState(false), group(nullptr) {} + : named(false), inState(false), group(nullptr) {} typedef QList<QQuickSimpleAction> SimpleActionList; QString name; - QQmlBinding *when; + QQmlBinding::Ptr when; bool named; struct OperationGuard : public QQmlGuard<QQuickStateOperation> diff --git a/tests/auto/qml/qqmlecmascript/data/removeBindingsWithNoDependencies.qml b/tests/auto/qml/qqmlecmascript/data/removeBindingsWithNoDependencies.qml new file mode 100644 index 0000000000..aacf16474d --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/removeBindingsWithNoDependencies.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 +Item { + property rect placement: Qt.rect(0, 0, 100, 100) + + function someFunction() { return 42; } + + property rect partialPlacement + partialPlacement.x: someFunction() +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index d9c1b2aed1..0fa4c03dcb 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -49,6 +49,8 @@ #include <private/qv4object_p.h> #include <private/qqmlcomponentattached_p.h> #include <private/qv4objectiterator_p.h> +#include <private/qqmlabstractbinding_p.h> +#include <private/qqmlvaluetypeproxybinding_p.h> #ifdef Q_CC_MSVC #define NO_INLINE __declspec(noinline) @@ -353,6 +355,7 @@ private slots: void anotherNaN(); void callPropertyOnUndefined(); void jumpStrictNotEqualUndefined(); + void removeBindingsWithNoDependencies(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -5974,7 +5977,7 @@ void tst_qqmlecmascript::nullObjectInitializer() { const int propertyIndex = obj->metaObject()->indexOfProperty("testProperty"); QVERIFY(propertyIndex > 0); - QVERIFY(ddata->hasBindingBit(propertyIndex)); + QVERIFY(!ddata->hasBindingBit(propertyIndex)); } QVERIFY(obj->property("success").toBool()); @@ -8758,6 +8761,35 @@ void tst_qqmlecmascript::jumpStrictNotEqualUndefined() QCOMPARE(v.toInt(), 2); } +void tst_qqmlecmascript::removeBindingsWithNoDependencies() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("removeBindingsWithNoDependencies.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + QVariant rect = object->property("placement"); + QCOMPARE(rect.toRectF(), QRectF(0, 0, 100, 100)); + const QMetaObject *metaObject = object->metaObject(); + + { + const QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("placement")); + QVERIFY(prop.isValid()); + QVERIFY(!QQmlPropertyPrivate::binding(object.data(), QQmlPropertyIndex(prop.propertyIndex()))); + } + + { + const QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("partialPlacement")); + QVERIFY(prop.isValid()); + QQmlAbstractBinding *vtProxyBinding = QQmlPropertyPrivate::binding(object.data(), QQmlPropertyIndex(prop.propertyIndex())); + QVERIFY(vtProxyBinding); + QVERIFY(vtProxyBinding->isValueTypeProxy()); + + QQmlValueTypeProxyBinding *proxy = static_cast<QQmlValueTypeProxyBinding*>(vtProxyBinding); + QVERIFY(!proxy->subBindings()); + } + +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/quick/qquickdesignersupport/data/TestComponent.qml b/tests/auto/quick/qquickdesignersupport/data/TestComponent.qml index 68f456af99..63d65b435c 100644 --- a/tests/auto/quick/qquickdesignersupport/data/TestComponent.qml +++ b/tests/auto/quick/qquickdesignersupport/data/TestComponent.qml @@ -4,6 +4,8 @@ Item { width: 100 height: 62 - x: Math.max(0, 200) + // Add a dummy dependency to parent.x to ensure that the + // binding stays for the test. + x: parent.x + Math.max(0, 200) - parent.x } |