aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/ftw/qflagpointer_p.h8
-rw-r--r--src/qml/qml/qqmlbinding.cpp7
-rw-r--r--src/qml/qml/qqmlbinding_p.h1
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp8
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h15
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp5
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding_p.h2
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp12
-rw-r--r--src/quick/util/qquickstate.cpp2
-rw-r--r--src/quick/util/qquickstate_p_p.h4
-rw-r--r--tests/auto/qml/qqmlecmascript/data/removeBindingsWithNoDependencies.qml9
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp34
-rw-r--r--tests/auto/quick/qquickdesignersupport/data/TestComponent.qml4
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
}