summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2010-07-08 03:09:07 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2010-07-08 03:09:07 (GMT)
commit76a1804b0fff9ffd092a551defe448d3e9d4346e (patch)
tree8907d76f7f3e0d1263dea252914c660e4cf37200
parent4ec4ba7bde9ac321640c3e0c7b186f0b044423b7 (diff)
downloadQt-76a1804b0fff9ffd092a551defe448d3e9d4346e.zip
Qt-76a1804b0fff9ffd092a551defe448d3e9d4346e.tar.gz
Qt-76a1804b0fff9ffd092a551defe448d3e9d4346e.tar.bz2
Allow the debugger to modify method bodies
QTBUG-11933
-rw-r--r--src/declarative/debugger/qdeclarativedebug.cpp36
-rw-r--r--src/declarative/debugger/qdeclarativedebug_p.h19
-rw-r--r--src/declarative/qml/qdeclarativeenginedebug.cpp55
-rw-r--r--src/declarative/qml/qdeclarativeenginedebug_p.h1
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject.cpp30
-rw-r--r--src/declarative/qml/qdeclarativevmemetaobject_p.h2
-rw-r--r--tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp56
7 files changed, 160 insertions, 39 deletions
diff --git a/src/declarative/debugger/qdeclarativedebug.cpp b/src/declarative/debugger/qdeclarativedebug.cpp
index e4a991b..0c0cf2e 100644
--- a/src/declarative/debugger/qdeclarativedebug.cpp
+++ b/src/declarative/debugger/qdeclarativedebug.cpp
@@ -562,31 +562,37 @@ QDeclarativeDebugExpressionQuery *QDeclarativeEngineDebug::queryExpressionResult
return query;
}
-QDeclarativeDebugExpressionQuery *QDeclarativeEngineDebug::setBindingForObject(int objectDebugId,
- const QString &propertyName,
- const QVariant &bindingExpression,
- bool isLiteralValue,
- QObject *parent)
+bool QDeclarativeEngineDebug::setBindingForObject(int objectDebugId, const QString &propertyName,
+ const QVariant &bindingExpression,
+ bool isLiteralValue)
{
Q_D(QDeclarativeEngineDebug);
- QDeclarativeDebugExpressionQuery *query = new QDeclarativeDebugExpressionQuery(parent);
if (d->client->isConnected() && objectDebugId != -1) {
- query->m_client = this;
- query->m_expr = bindingExpression;
- int queryId = d->getId();
- query->m_queryId = queryId;
- d->expressionQuery.insert(queryId, query);
-
QByteArray message;
QDataStream ds(&message, QIODevice::WriteOnly);
- ds << QByteArray("SET_BINDING") << queryId << objectDebugId << propertyName << bindingExpression << isLiteralValue;
+ ds << QByteArray("SET_BINDING") << objectDebugId << propertyName << bindingExpression << isLiteralValue;
d->client->sendMessage(message);
+ return true;
} else {
- query->m_state = QDeclarativeDebugQuery::Error;
+ return false;
}
+}
- return query;
+bool QDeclarativeEngineDebug::setMethodBody(int objectDebugId, const QString &methodName,
+ const QString &methodBody)
+{
+ Q_D(QDeclarativeEngineDebug);
+
+ if (d->client->isConnected() && objectDebugId != -1) {
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << QByteArray("SET_METHOD_BODY") << objectDebugId << methodName << methodBody;
+ d->client->sendMessage(message);
+ return true;
+ } else {
+ return false;
+ }
}
QDeclarativeDebugWatch::QDeclarativeDebugWatch(QObject *parent)
diff --git a/src/declarative/debugger/qdeclarativedebug_p.h b/src/declarative/debugger/qdeclarativedebug_p.h
index 007cbd7..9c38184 100644
--- a/src/declarative/debugger/qdeclarativedebug_p.h
+++ b/src/declarative/debugger/qdeclarativedebug_p.h
@@ -94,11 +94,10 @@ public:
QDeclarativeDebugExpressionQuery *queryExpressionResult(int objectDebugId,
const QString &expr,
QObject *parent = 0);
- QDeclarativeDebugExpressionQuery *setBindingForObject(int objectDebugId,
- const QString &propertyName,
- const QVariant &bindingExpression,
- bool isLiteralValue,
- QObject *parent = 0);
+ bool setBindingForObject(int objectDebugId, const QString &propertyName,
+ const QVariant &bindingExpression, bool isLiteralValue);
+ bool setMethodBody(int objectDebugId, const QString &methodName, const QString &methodBody);
+
private:
Q_DECLARE_PRIVATE(QDeclarativeEngineDebug)
};
@@ -202,11 +201,6 @@ public:
private:
friend class QDeclarativeEngineDebugPrivate;
- QDeclarativeDebugExpressionQuery *setBindingForObject(int objectDebugId,
- const QString &propertyName,
- const QVariant &bindingExpression,
- bool isLiteralValue,
- QObject *parent);
QUrl m_url;
int m_lineNumber;
int m_columnNumber;
@@ -224,11 +218,6 @@ public:
QString name() const;
private:
- QDeclarativeDebugExpressionQuery *setBindingForObject(int objectDebugId,
- const QString &propertyName,
- const QVariant &bindingExpression,
- bool isLiteralValue,
- QObject *parent);
friend class QDeclarativeEngineDebugPrivate;
int m_debugId;
QString m_name;
diff --git a/src/declarative/qml/qdeclarativeenginedebug.cpp b/src/declarative/qml/qdeclarativeenginedebug.cpp
index d765649..acd7ab6 100644
--- a/src/declarative/qml/qdeclarativeenginedebug.cpp
+++ b/src/declarative/qml/qdeclarativeenginedebug.cpp
@@ -50,6 +50,8 @@
#include "private/qdeclarativecontext_p.h"
#include "private/qdeclarativewatcher_p.h"
#include "private/qdeclarativevaluetype_p.h"
+#include "private/qdeclarativevmemetaobject_p.h"
+#include "private/qdeclarativeexpression_p.h"
#include <QtCore/qdebug.h>
#include <QtCore/qmetaobject.h>
@@ -453,20 +455,25 @@ void QDeclarativeEngineDebugServer::messageReceived(const QByteArray &message)
sendMessage(reply);
} else if (type == "SET_BINDING") {
- int queryId;
int objectId;
QString propertyName;
QVariant expr;
bool isLiteralValue;
- ds >> queryId >> objectId >> propertyName >> expr >> isLiteralValue;
+ ds >> objectId >> propertyName >> expr >> isLiteralValue;
setBinding(objectId, propertyName, expr, isLiteralValue);
+ } else if (type == "SET_METHOD_BODY") {
+ int objectId;
+ QString methodName;
+ QString methodBody;
+ ds >> objectId >> methodName >> methodBody;
+ setMethodBody(objectId, methodName, methodBody);
}
}
void QDeclarativeEngineDebugServer::setBinding(int objectId,
- const QString &propertyName,
- const QVariant &expression,
- bool isLiteralValue)
+ const QString &propertyName,
+ const QVariant &expression,
+ bool isLiteralValue)
{
QObject *object = objectForId(objectId);
QDeclarativeContext *context = qmlContext(object);
@@ -493,7 +500,45 @@ void QDeclarativeEngineDebugServer::setBinding(int objectId,
}
}
}
+}
+
+void QDeclarativeEngineDebugServer::setMethodBody(int objectId, const QString &method, const QString &body)
+{
+ QObject *object = objectForId(objectId);
+ QDeclarativeContext *context = qmlContext(object);
+ if (!object || !context || !context->engine())
+ return;
+ QDeclarativeContextData *contextData = QDeclarativeContextData::get(context);
+ if (!contextData)
+ return;
+
+ QDeclarativePropertyCache::Data dummy;
+ QDeclarativePropertyCache::Data *prop =
+ QDeclarativePropertyCache::property(context->engine(), object, method, dummy);
+
+ if (!prop || !(prop->flags & QDeclarativePropertyCache::Data::IsVMEFunction))
+ return;
+
+ QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex);
+ QList<QByteArray> paramNames = metaMethod.parameterNames();
+
+ QString paramStr;
+ for (int ii = 0; ii < paramNames.count(); ++ii) {
+ if (ii != 0) paramStr.append(QLatin1String(","));
+ paramStr.append(QString::fromUtf8(paramNames.at(ii)));
+ }
+
+ QString jsfunction = QLatin1String("(function ") + method + QLatin1String("(") + paramStr +
+ QLatin1String(") {");
+ jsfunction += body;
+ jsfunction += QLatin1String("\n})");
+
+ QDeclarativeVMEMetaObject *vmeMetaObject =
+ static_cast<QDeclarativeVMEMetaObject*>(QObjectPrivate::get(object)->metaObject);
+ Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
+ int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex);
+ vmeMetaObject->setVmeMethod(prop->coreIndex, QDeclarativeExpressionPrivate::evalInObjectScope(contextData, object, jsfunction, contextData->url.toString(), lineNumber, 0));
}
void QDeclarativeEngineDebugServer::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value)
diff --git a/src/declarative/qml/qdeclarativeenginedebug_p.h b/src/declarative/qml/qdeclarativeenginedebug_p.h
index b3c23bd..ce6df0d 100644
--- a/src/declarative/qml/qdeclarativeenginedebug_p.h
+++ b/src/declarative/qml/qdeclarativeenginedebug_p.h
@@ -108,6 +108,7 @@ private:
QDeclarativeObjectProperty propertyData(QObject *, int);
QVariant valueContents(const QVariant &defaultValue) const;
void setBinding(int objectId, const QString &propertyName, const QVariant &expression, bool isLiteralValue);
+ void setMethodBody(int objectId, const QString &method, const QString &body);
static QList<QDeclarativeEngine *> m_engines;
QDeclarativeWatcher *m_watch;
diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp
index 7aea7cb..689ed92 100644
--- a/src/declarative/qml/qdeclarativevmemetaobject.cpp
+++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp
@@ -751,6 +751,22 @@ void QDeclarativeVMEMetaObject::registerInterceptor(int index, int valueIndex, Q
interceptors.insert(index, qMakePair(valueIndex, interceptor));
}
+int QDeclarativeVMEMetaObject::vmeMethodLineNumber(int index)
+{
+ if (index < methodOffset) {
+ Q_ASSERT(parent);
+ return static_cast<QDeclarativeVMEMetaObject *>(parent)->vmeMethodLineNumber(index);
+ }
+
+ int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
+ Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+
+ int rawIndex = index - methodOffset - plainSignals;
+
+ QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + rawIndex;
+ return data->lineNumber;
+}
+
QScriptValue QDeclarativeVMEMetaObject::vmeMethod(int index)
{
if (index < methodOffset) {
@@ -762,6 +778,20 @@ QScriptValue QDeclarativeVMEMetaObject::vmeMethod(int index)
return method(index - methodOffset - plainSignals);
}
+void QDeclarativeVMEMetaObject::setVmeMethod(int index, const QScriptValue &value)
+{
+ if (index < methodOffset) {
+ Q_ASSERT(parent);
+ return static_cast<QDeclarativeVMEMetaObject *>(parent)->setVmeMethod(index, value);
+ }
+ int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
+ Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+
+ if (!methods)
+ methods = new QScriptValue[metaData->methodCount];
+ methods[index - methodOffset - plainSignals] = value;
+}
+
QScriptValue QDeclarativeVMEMetaObject::vmeProperty(int index)
{
if (index < propOffset) {
diff --git a/src/declarative/qml/qdeclarativevmemetaobject_p.h b/src/declarative/qml/qdeclarativevmemetaobject_p.h
index 4fc3269..20ca80b 100644
--- a/src/declarative/qml/qdeclarativevmemetaobject_p.h
+++ b/src/declarative/qml/qdeclarativevmemetaobject_p.h
@@ -121,6 +121,8 @@ public:
void registerInterceptor(int index, int valueIndex, QDeclarativePropertyValueInterceptor *interceptor);
QScriptValue vmeMethod(int index);
+ int vmeMethodLineNumber(int index);
+ void setVmeMethod(int index, const QScriptValue &);
QScriptValue vmeProperty(int index);
void setVMEProperty(int index, const QScriptValue &);
diff --git a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp
index dcd1a85..4a945f3 100644
--- a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp
+++ b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp
@@ -71,7 +71,7 @@ class tst_QDeclarativeDebug : public QObject
Q_OBJECT
private:
- QDeclarativeDebugObjectReference findRootObject();
+ QDeclarativeDebugObjectReference findRootObject(int context = 0);
QDeclarativeDebugPropertyReference findProperty(const QList<QDeclarativeDebugPropertyReference> &props, const QString &name) const;
void waitForQuery(QDeclarativeDebugQuery *query);
@@ -111,9 +111,11 @@ private slots:
void tst_QDeclarativeDebugObjectReference();
void tst_QDeclarativeDebugContextReference();
void tst_QDeclarativeDebugPropertyReference();
+
+ void setMethodBody();
};
-QDeclarativeDebugObjectReference tst_QDeclarativeDebug::findRootObject()
+QDeclarativeDebugObjectReference tst_QDeclarativeDebug::findRootObject(int context)
{
QDeclarativeDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this);
waitForQuery(q_engines);
@@ -125,7 +127,7 @@ QDeclarativeDebugObjectReference tst_QDeclarativeDebug::findRootObject()
if (q_context->rootContext().objects().count() == 0)
return QDeclarativeDebugObjectReference();
- QDeclarativeDebugObjectQuery *q_obj = m_dbg->queryObject(q_context->rootContext().objects()[0], this);
+ QDeclarativeDebugObjectQuery *q_obj = m_dbg->queryObject(q_context->rootContext().objects()[context], this);
waitForQuery(q_obj);
QDeclarativeDebugObjectReference result = q_obj->object();
@@ -290,10 +292,19 @@ void tst_QDeclarativeDebug::initTestCase()
"onEntered: { console.log('hello') }"
"}"
"}";
+
// add second component to test multiple root contexts
qml << "import Qt 4.7\n"
"Item {}";
+ // and a third to test methods
+ qml << "import Qt 4.7\n"
+ "Item {"
+ "function myMethodNoArgs() { return 3; }\n"
+ "function myMethod(a) { return a + 9; }\n"
+ "function myMethodIndirect() { myMethod(3); }\n"
+ "}";
+
for (int i=0; i<qml.count(); i++) {
QDeclarativeComponent component(m_engine);
component.setData(qml[i], QUrl::fromLocalFile(""));
@@ -322,6 +333,43 @@ void tst_QDeclarativeDebug::cleanupTestCase()
qDeleteAll(m_components);
}
+void tst_QDeclarativeDebug::setMethodBody()
+{
+ QDeclarativeDebugObjectReference obj = findRootObject(2);
+
+ QObject *root = m_components.at(2);
+ // Without args
+ {
+ QVariant rv;
+ QVERIFY(QMetaObject::invokeMethod(root, "myMethodNoArgs", Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, rv)));
+ QVERIFY(rv == QVariant(qreal(3)));
+
+
+ QVERIFY(m_dbg->setMethodBody(obj.debugId(), "myMethodNoArgs", "return 7"));
+ QTest::qWait(100);
+
+ QVERIFY(QMetaObject::invokeMethod(root, "myMethodNoArgs", Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, rv)));
+ QVERIFY(rv == QVariant(qreal(7)));
+ }
+
+ // With args
+ {
+ QVariant rv;
+ QVERIFY(QMetaObject::invokeMethod(root, "myMethod", Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, rv), Q_ARG(QVariant, QVariant(19))));
+ QVERIFY(rv == QVariant(qreal(28)));
+
+ QVERIFY(m_dbg->setMethodBody(obj.debugId(), "myMethod", "return a + 7"));
+ QTest::qWait(100);
+
+ QVERIFY(QMetaObject::invokeMethod(root, "myMethod", Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, rv), Q_ARG(QVariant, QVariant(19))));
+ QVERIFY(rv == QVariant(qreal(26)));
+ }
+}
+
void tst_QDeclarativeDebug::watch_property()
{
QDeclarativeDebugObjectReference obj = findRootObject();
@@ -581,7 +629,7 @@ void tst_QDeclarativeDebug::queryRootContexts()
QCOMPARE(context.debugId(), QDeclarativeDebugService::idForObject(actualContext));
QCOMPARE(context.name(), actualContext->objectName());
- QCOMPARE(context.objects().count(), 2); // 2 qml component objects created for context in main()
+ QCOMPARE(context.objects().count(), 3); // 3 qml component objects created for context in main()
// root context query sends only root object data - it doesn't fill in
// the children or property info