QV4DebugService: Reduce unnecessary recursion and redundancy
Large parts of the protocol are unnecessary. There is no reason to send a separate chunk of "handles" with almost every reply. The refs are given as part of the regular data and if the client wants to find out more, it can do further lookups. Also, it makes no sense to encode the function and script names as objects, as they are in fact not JavaScript objects. Unfortunately these cleanups require some cooperation from the client. Older clients will misbehave if we just drop the redundancy. Therefore, we introduce parameters which the client can explicitly set with the "connect" message. redundantRefs tells the service if redundant references are required, namesAsObjects tells it if script and function names have to be sent as objects/ Once we can require clients that support these options, we can drop the code that generates redundant data. Also, fix tst_qv4debugger::evaluateExpression() to actually check all the expressions evaluated, not only the first and second one. Task-number: QTBUG-42435 Change-Id: If93d2a2b9d0b8035f85dbef871bc1b03f199171d Reviewed-by: hjk <hjk@qt.io> Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
parent
9180241819
commit
ffe538a565
|
@ -118,14 +118,17 @@ int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine) : m_engine(engine)
|
QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine)
|
||||||
|
: m_engine(engine), m_namesAsObjects(true), m_redundantRefs(true)
|
||||||
{
|
{
|
||||||
m_values.set(engine, engine->newArrayObject());
|
m_values.set(engine, engine->newArrayObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Directly call addRef() once we don't need to support redundantRefs anymore
|
||||||
QV4DataCollector::Ref QV4DataCollector::collect(const QV4::ScopedValue &value)
|
QV4DataCollector::Ref QV4DataCollector::collect(const QV4::ScopedValue &value)
|
||||||
{
|
{
|
||||||
Ref ref = addRef(value);
|
Ref ref = addRef(value);
|
||||||
|
if (m_redundantRefs)
|
||||||
m_collectedRefs.append(ref);
|
m_collectedRefs.append(ref);
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
@ -190,24 +193,33 @@ const QV4::Object *collectProperty(const QV4::ScopedValue &value, QV4::Execution
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject QV4DataCollector::lookupRef(Ref ref)
|
QJsonObject QV4DataCollector::lookupRef(Ref ref, bool deep)
|
||||||
{
|
{
|
||||||
QJsonObject dict;
|
QJsonObject dict;
|
||||||
|
|
||||||
|
if (m_namesAsObjects) {
|
||||||
if (lookupSpecialRef(ref, &dict))
|
if (lookupSpecialRef(ref, &dict))
|
||||||
return dict;
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_redundantRefs)
|
||||||
|
deep = true;
|
||||||
|
|
||||||
dict.insert(QStringLiteral("handle"), qint64(ref));
|
dict.insert(QStringLiteral("handle"), qint64(ref));
|
||||||
QV4::Scope scope(engine());
|
QV4::Scope scope(engine());
|
||||||
QV4::ScopedValue value(scope, getValue(ref));
|
QV4::ScopedValue value(scope, getValue(ref));
|
||||||
|
|
||||||
if (const QV4::Object *o = collectProperty(value, engine(), dict))
|
const QV4::Object *object = collectProperty(value, engine(), dict);
|
||||||
dict.insert(QStringLiteral("properties"), collectProperties(o));
|
if (deep && object)
|
||||||
|
dict.insert(QStringLiteral("properties"), collectProperties(object));
|
||||||
|
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Drop this method once we don't need to support namesAsObjects anymore
|
||||||
QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionName)
|
QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionName)
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(m_namesAsObjects);
|
||||||
Ref ref = addRef(QV4::Primitive::emptyValue(), false);
|
Ref ref = addRef(QV4::Primitive::emptyValue(), false);
|
||||||
|
|
||||||
QJsonObject dict;
|
QJsonObject dict;
|
||||||
|
@ -220,8 +232,10 @@ QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionNa
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Drop this method once we don't need to support namesAsObjects anymore
|
||||||
QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName)
|
QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName)
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(m_namesAsObjects);
|
||||||
Ref ref = addRef(QV4::Primitive::emptyValue(), false);
|
Ref ref = addRef(QV4::Primitive::emptyValue(), false);
|
||||||
|
|
||||||
QJsonObject dict;
|
QJsonObject dict;
|
||||||
|
@ -250,6 +264,7 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr)
|
||||||
if (!ctxt)
|
if (!ctxt)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
Refs collectedRefs;
|
||||||
QV4::ScopedValue v(scope);
|
QV4::ScopedValue v(scope);
|
||||||
int nFormals = ctxt->formalCount();
|
int nFormals = ctxt->formalCount();
|
||||||
for (unsigned i = 0, ei = nFormals; i != ei; ++i) {
|
for (unsigned i = 0, ei = nFormals; i != ei; ++i) {
|
||||||
|
@ -258,7 +273,7 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr)
|
||||||
qName = name->string;
|
qName = name->string;
|
||||||
names.append(qName);
|
names.append(qName);
|
||||||
v = ctxt->argument(i);
|
v = ctxt->argument(i);
|
||||||
collect(v);
|
collectedRefs.append(collect(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0, ei = ctxt->variableCount(); i != ei; ++i) {
|
for (unsigned i = 0, ei = ctxt->variableCount(); i != ei; ++i) {
|
||||||
|
@ -267,19 +282,24 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr)
|
||||||
qName = name->string;
|
qName = name->string;
|
||||||
names.append(qName);
|
names.append(qName);
|
||||||
v = ctxt->d()->locals[i];
|
v = ctxt->d()->locals[i];
|
||||||
collect(v);
|
collectedRefs.append(collect(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
QV4::ScopedObject scopeObject(scope, engine()->newObject());
|
QV4::ScopedObject scopeObject(scope, engine()->newObject());
|
||||||
|
|
||||||
Q_ASSERT(names.size() == m_collectedRefs.size());
|
Q_ASSERT(names.size() == collectedRefs.size());
|
||||||
for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i)
|
for (int i = 0, ei = collectedRefs.size(); i != ei; ++i)
|
||||||
scopeObject->put(engine(), names.at(i),
|
scopeObject->put(engine(), names.at(i),
|
||||||
QV4::Value::fromReturnedValue(getValue(m_collectedRefs.at(i))));
|
QV4::Value::fromReturnedValue(getValue(collectedRefs.at(i))));
|
||||||
|
|
||||||
Ref scopeObjectRef = addRef(scopeObject);
|
Ref scopeObjectRef = addRef(scopeObject);
|
||||||
|
if (m_redundantRefs) {
|
||||||
dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef));
|
dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef));
|
||||||
m_collectedRefs.append(scopeObjectRef);
|
m_collectedRefs.append(scopeObjectRef);
|
||||||
|
} else {
|
||||||
|
*dict = lookupRef(scopeObjectRef, true);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,15 +311,16 @@ QJsonObject toRef(QV4DataCollector::Ref ref) {
|
||||||
|
|
||||||
QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int frameNr)
|
QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int frameNr)
|
||||||
{
|
{
|
||||||
QV4DataCollector::Ref ref;
|
|
||||||
|
|
||||||
QJsonObject frame;
|
QJsonObject frame;
|
||||||
frame[QLatin1String("index")] = frameNr;
|
frame[QLatin1String("index")] = frameNr;
|
||||||
frame[QLatin1String("debuggerFrame")] = false;
|
frame[QLatin1String("debuggerFrame")] = false;
|
||||||
ref = addFunctionRef(stackFrame.function);
|
if (m_namesAsObjects) {
|
||||||
frame[QLatin1String("func")] = toRef(ref);
|
frame[QLatin1String("func")] = toRef(addFunctionRef(stackFrame.function));
|
||||||
ref = addScriptRef(stackFrame.source);
|
frame[QLatin1String("script")] = toRef(addScriptRef(stackFrame.source));
|
||||||
frame[QLatin1String("script")] = toRef(ref);
|
} else {
|
||||||
|
frame[QLatin1String("func")] = stackFrame.function;
|
||||||
|
frame[QLatin1String("script")] = stackFrame.source;
|
||||||
|
}
|
||||||
frame[QLatin1String("line")] = stackFrame.line - 1;
|
frame[QLatin1String("line")] = stackFrame.line - 1;
|
||||||
if (stackFrame.column >= 0)
|
if (stackFrame.column >= 0)
|
||||||
frame[QLatin1String("column")] = stackFrame.column;
|
frame[QLatin1String("column")] = stackFrame.column;
|
||||||
|
@ -338,15 +359,17 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Drop this method once we don't need to support redundantRefs anymore
|
||||||
QJsonArray QV4DataCollector::flushCollectedRefs()
|
QJsonArray QV4DataCollector::flushCollectedRefs()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(m_redundantRefs);
|
||||||
QJsonArray refs;
|
QJsonArray refs;
|
||||||
std::sort(m_collectedRefs.begin(), m_collectedRefs.end());
|
std::sort(m_collectedRefs.begin(), m_collectedRefs.end());
|
||||||
for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i) {
|
for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i) {
|
||||||
QV4DataCollector::Ref ref = m_collectedRefs.at(i);
|
QV4DataCollector::Ref ref = m_collectedRefs.at(i);
|
||||||
if (i > 0 && ref == m_collectedRefs.at(i - 1))
|
if (i > 0 && ref == m_collectedRefs.at(i - 1))
|
||||||
continue;
|
continue;
|
||||||
refs.append(lookupRef(ref));
|
refs.append(lookupRef(ref, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_collectedRefs.clear();
|
m_collectedRefs.clear();
|
||||||
|
@ -358,6 +381,8 @@ void QV4DataCollector::clear()
|
||||||
m_values.set(engine(), engine()->newArrayObject());
|
m_values.set(engine(), engine()->newArrayObject());
|
||||||
m_collectedRefs.clear();
|
m_collectedRefs.clear();
|
||||||
m_specialRefs.clear();
|
m_specialRefs.clear();
|
||||||
|
m_namesAsObjects = true;
|
||||||
|
m_redundantRefs = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicate)
|
QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicate)
|
||||||
|
@ -401,8 +426,10 @@ QV4::ReturnedValue QV4DataCollector::getValue(Ref ref)
|
||||||
return array->getIndexed(ref, Q_NULLPTR);
|
return array->getIndexed(ref, Q_NULLPTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Drop this method once we don't need to support namesAsObjects anymore
|
||||||
bool QV4DataCollector::lookupSpecialRef(Ref ref, QJsonObject *dict)
|
bool QV4DataCollector::lookupSpecialRef(Ref ref, QJsonObject *dict)
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(m_namesAsObjects);
|
||||||
SpecialRefs::const_iterator it = m_specialRefs.constFind(ref);
|
SpecialRefs::const_iterator it = m_specialRefs.constFind(ref);
|
||||||
if (it == m_specialRefs.cend())
|
if (it == m_specialRefs.cend())
|
||||||
return false;
|
return false;
|
||||||
|
@ -440,6 +467,7 @@ QJsonObject QV4DataCollector::collectAsJson(const QString &name, const QV4::Scop
|
||||||
if (value->isManaged() && !value->isString()) {
|
if (value->isManaged() && !value->isString()) {
|
||||||
Ref ref = addRef(value);
|
Ref ref = addRef(value);
|
||||||
dict.insert(QStringLiteral("ref"), qint64(ref));
|
dict.insert(QStringLiteral("ref"), qint64(ref));
|
||||||
|
if (m_redundantRefs)
|
||||||
m_collectedRefs.append(ref);
|
m_collectedRefs.append(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,34 +66,42 @@ public:
|
||||||
|
|
||||||
QV4DataCollector(QV4::ExecutionEngine *engine);
|
QV4DataCollector(QV4::ExecutionEngine *engine);
|
||||||
|
|
||||||
Ref collect(const QV4::ScopedValue &value);
|
Ref collect(const QV4::ScopedValue &value); // only for redundantRefs
|
||||||
Ref addFunctionRef(const QString &functionName);
|
Ref addFunctionRef(const QString &functionName); // only for namesAsObjects
|
||||||
Ref addScriptRef(const QString &scriptName);
|
Ref addScriptRef(const QString &scriptName); // only for namesAsObjects
|
||||||
|
|
||||||
|
void setNamesAsObjects(bool namesAsObjects) { m_namesAsObjects = namesAsObjects; }
|
||||||
|
bool namesAsObjects() const { return m_namesAsObjects; }
|
||||||
|
|
||||||
|
void setRedundantRefs(bool redundantRefs) { m_redundantRefs = redundantRefs; }
|
||||||
|
bool redundantRefs() const { return m_redundantRefs; }
|
||||||
|
|
||||||
bool isValidRef(Ref ref) const;
|
bool isValidRef(Ref ref) const;
|
||||||
QJsonObject lookupRef(Ref ref);
|
QJsonObject lookupRef(Ref ref, bool deep);
|
||||||
|
|
||||||
bool collectScope(QJsonObject *dict, int frameNr, int scopeNr);
|
bool collectScope(QJsonObject *dict, int frameNr, int scopeNr);
|
||||||
QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr);
|
QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr);
|
||||||
|
|
||||||
QV4::ExecutionEngine *engine() const { return m_engine; }
|
QV4::ExecutionEngine *engine() const { return m_engine; }
|
||||||
QJsonArray flushCollectedRefs();
|
QJsonArray flushCollectedRefs(); // only for redundantRefs
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ref addRef(QV4::Value value, bool deduplicate = true);
|
Ref addRef(QV4::Value value, bool deduplicate = true);
|
||||||
QV4::ReturnedValue getValue(Ref ref);
|
QV4::ReturnedValue getValue(Ref ref);
|
||||||
bool lookupSpecialRef(Ref ref, QJsonObject *dict);
|
bool lookupSpecialRef(Ref ref, QJsonObject *dict); // only for namesAsObjects
|
||||||
|
|
||||||
QJsonArray collectProperties(const QV4::Object *object);
|
QJsonArray collectProperties(const QV4::Object *object);
|
||||||
QJsonObject collectAsJson(const QString &name, const QV4::ScopedValue &value);
|
QJsonObject collectAsJson(const QString &name, const QV4::ScopedValue &value);
|
||||||
void collectArgumentsInContext();
|
void collectArgumentsInContext();
|
||||||
|
|
||||||
QV4::ExecutionEngine *m_engine;
|
QV4::ExecutionEngine *m_engine;
|
||||||
Refs m_collectedRefs;
|
Refs m_collectedRefs; // only for redundantRefs
|
||||||
QV4::PersistentValue m_values;
|
QV4::PersistentValue m_values;
|
||||||
typedef QHash<Ref, QJsonObject> SpecialRefs;
|
typedef QHash<Ref, QJsonObject> SpecialRefs; // only for namesAsObjects
|
||||||
SpecialRefs m_specialRefs;
|
SpecialRefs m_specialRefs; // only for namesAsObjects
|
||||||
|
bool m_namesAsObjects;
|
||||||
|
bool m_redundantRefs;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
|
@ -148,7 +148,7 @@ void BacktraceJob::run()
|
||||||
result.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size());
|
result.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size());
|
||||||
result.insert(QStringLiteral("frames"), frameArray);
|
result.insert(QStringLiteral("frames"), frameArray);
|
||||||
}
|
}
|
||||||
collectedRefs = collector->flushCollectedRefs();
|
flushRedundantRefs();
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameJob::FrameJob(QV4DataCollector *collector, int frameNr) :
|
FrameJob::FrameJob(QV4DataCollector *collector, int frameNr) :
|
||||||
|
@ -163,7 +163,7 @@ void FrameJob::run()
|
||||||
success = false;
|
success = false;
|
||||||
} else {
|
} else {
|
||||||
result = collector->buildFrame(frames[frameNr], frameNr);
|
result = collector->buildFrame(frames[frameNr], frameNr);
|
||||||
collectedRefs = collector->flushCollectedRefs();
|
flushRedundantRefs();
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,7 +193,7 @@ void ScopeJob::run()
|
||||||
result[QLatin1String("index")] = scopeNr;
|
result[QLatin1String("index")] = scopeNr;
|
||||||
result[QLatin1String("frameIndex")] = frameNr;
|
result[QLatin1String("frameIndex")] = frameNr;
|
||||||
result[QLatin1String("object")] = object;
|
result[QLatin1String("object")] = object;
|
||||||
collectedRefs = collector->flushCollectedRefs();
|
flushRedundantRefs();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScopeJob::wasSuccessful() const
|
bool ScopeJob::wasSuccessful() const
|
||||||
|
@ -223,9 +223,9 @@ void ValueLookupJob::run()
|
||||||
exception = QString::fromLatin1("Invalid Ref: %1").arg(ref);
|
exception = QString::fromLatin1("Invalid Ref: %1").arg(ref);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
result[QString::number(ref)] = collector->lookupRef(ref);
|
result[QString::number(ref)] = collector->lookupRef(ref, true);
|
||||||
}
|
}
|
||||||
collectedRefs = collector->flushCollectedRefs();
|
flushRedundantRefs();
|
||||||
if (scopeObject)
|
if (scopeObject)
|
||||||
engine->popContext();
|
engine->popContext();
|
||||||
}
|
}
|
||||||
|
@ -246,7 +246,8 @@ void ExpressionEvalJob::handleResult(QV4::ScopedValue &value)
|
||||||
{
|
{
|
||||||
if (hasExeption())
|
if (hasExeption())
|
||||||
exception = value->toQStringNoThrow();
|
exception = value->toQStringNoThrow();
|
||||||
result = collector->lookupRef(collector->collect(value));
|
result = collector->lookupRef(collector->collect(value), true);
|
||||||
|
if (collector->redundantRefs())
|
||||||
collectedRefs = collector->flushCollectedRefs();
|
collectedRefs = collector->flushCollectedRefs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,8 +261,10 @@ const QJsonObject &ExpressionEvalJob::returnValue() const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Drop this method once we don't need to support redundantRefs anymore
|
||||||
const QJsonArray &ExpressionEvalJob::refs() const
|
const QJsonArray &ExpressionEvalJob::refs() const
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(collector->redundantRefs());
|
||||||
return collectedRefs;
|
return collectedRefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,11 +78,24 @@ class CollectJob : public QV4DebugJob
|
||||||
protected:
|
protected:
|
||||||
QV4DataCollector *collector;
|
QV4DataCollector *collector;
|
||||||
QJsonObject result;
|
QJsonObject result;
|
||||||
QJsonArray collectedRefs;
|
QJsonArray collectedRefs; // only for redundantRefs
|
||||||
|
|
||||||
|
void flushRedundantRefs()
|
||||||
|
{
|
||||||
|
if (collector->redundantRefs())
|
||||||
|
collectedRefs = collector->flushCollectedRefs();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CollectJob(QV4DataCollector *collector) : collector(collector) {}
|
CollectJob(QV4DataCollector *collector) : collector(collector) {}
|
||||||
const QJsonObject &returnValue() const { return result; }
|
const QJsonObject &returnValue() const { return result; }
|
||||||
const QJsonArray &refs() const { return collectedRefs; }
|
|
||||||
|
// TODO: Drop this method once we don't need to support redundantRefs anymore
|
||||||
|
const QJsonArray &refs() const
|
||||||
|
{
|
||||||
|
Q_ASSERT(collector->redundantRefs());
|
||||||
|
return collectedRefs;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class BacktraceJob: public CollectJob
|
class BacktraceJob: public CollectJob
|
||||||
|
@ -133,7 +146,7 @@ class ExpressionEvalJob: public JavaScriptJob
|
||||||
QV4DataCollector *collector;
|
QV4DataCollector *collector;
|
||||||
QString exception;
|
QString exception;
|
||||||
QJsonObject result;
|
QJsonObject result;
|
||||||
QJsonArray collectedRefs;
|
QJsonArray collectedRefs; // only for redundantRefs
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, int context,
|
ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, int context,
|
||||||
|
@ -141,7 +154,7 @@ public:
|
||||||
void handleResult(QV4::ScopedValue &value) override;
|
void handleResult(QV4::ScopedValue &value) override;
|
||||||
const QString &exceptionMessage() const;
|
const QString &exceptionMessage() const;
|
||||||
const QJsonObject &returnValue() const;
|
const QJsonObject &returnValue() const;
|
||||||
const QJsonArray &refs() const;
|
const QJsonArray &refs() const; // only for redundantRefs
|
||||||
};
|
};
|
||||||
|
|
||||||
class GatherSourcesJob: public QV4DebugJob
|
class GatherSourcesJob: public QV4DebugJob
|
||||||
|
|
|
@ -121,8 +121,18 @@ protected:
|
||||||
response.insert(QStringLiteral("running"), debugService->debuggerAgent.isRunning());
|
response.insert(QStringLiteral("running"), debugService->debuggerAgent.isRunning());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QV4DataCollector *saneCollector(QV4Debugger *debugger)
|
||||||
|
{
|
||||||
|
QV4DataCollector *collector = debugger->collector();
|
||||||
|
collector->setNamesAsObjects(debugService->clientRequiresNamesAsObjects());
|
||||||
|
collector->setRedundantRefs(debugService->clientRequiresRedundantRefs());
|
||||||
|
return collector;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: drop this method once we don't need to support redundantRefs anymore.
|
||||||
void addRefs(const QJsonArray &refs)
|
void addRefs(const QJsonArray &refs)
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(debugService->clientRequiresRedundantRefs());
|
||||||
response.insert(QStringLiteral("refs"), refs);
|
response.insert(QStringLiteral("refs"), refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +296,7 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BacktraceJob job(debugger->collector(), fromFrame, toFrame);
|
BacktraceJob job(saneCollector(debugger), fromFrame, toFrame);
|
||||||
debugger->runInEngine(&job);
|
debugger->runInEngine(&job);
|
||||||
|
|
||||||
// response:
|
// response:
|
||||||
|
@ -295,6 +305,7 @@ public:
|
||||||
addSuccess(true);
|
addSuccess(true);
|
||||||
addRunning();
|
addRunning();
|
||||||
addBody(job.returnValue());
|
addBody(job.returnValue());
|
||||||
|
if (debugService->clientRequiresRedundantRefs())
|
||||||
addRefs(job.refs());
|
addRefs(job.refs());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -322,7 +333,7 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameJob job(debugger->collector(), frameNr);
|
FrameJob job(saneCollector(debugger), frameNr);
|
||||||
debugger->runInEngine(&job);
|
debugger->runInEngine(&job);
|
||||||
if (!job.wasSuccessful()) {
|
if (!job.wasSuccessful()) {
|
||||||
createErrorResponse(QStringLiteral("frame retrieval failed"));
|
createErrorResponse(QStringLiteral("frame retrieval failed"));
|
||||||
|
@ -337,6 +348,7 @@ public:
|
||||||
addSuccess(true);
|
addSuccess(true);
|
||||||
addRunning();
|
addRunning();
|
||||||
addBody(job.returnValue());
|
addBody(job.returnValue());
|
||||||
|
if (debugService->clientRequiresRedundantRefs())
|
||||||
addRefs(job.refs());
|
addRefs(job.refs());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -369,7 +381,7 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeJob job(debugger->collector(), frameNr, scopeNr);
|
ScopeJob job(saneCollector(debugger), frameNr, scopeNr);
|
||||||
debugger->runInEngine(&job);
|
debugger->runInEngine(&job);
|
||||||
if (!job.wasSuccessful()) {
|
if (!job.wasSuccessful()) {
|
||||||
createErrorResponse(QStringLiteral("scope retrieval failed"));
|
createErrorResponse(QStringLiteral("scope retrieval failed"));
|
||||||
|
@ -382,6 +394,7 @@ public:
|
||||||
addSuccess(true);
|
addSuccess(true);
|
||||||
addRunning();
|
addRunning();
|
||||||
addBody(job.returnValue());
|
addBody(job.returnValue());
|
||||||
|
if (debugService->clientRequiresRedundantRefs())
|
||||||
addRefs(job.refs());
|
addRefs(job.refs());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -410,7 +423,7 @@ public:
|
||||||
debugger = debuggers.first();
|
debugger = debuggers.first();
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueLookupJob job(handles, debugger->collector());
|
ValueLookupJob job(handles, saneCollector(debugger));
|
||||||
debugger->runInEngine(&job);
|
debugger->runInEngine(&job);
|
||||||
if (!job.exceptionMessage().isEmpty()) {
|
if (!job.exceptionMessage().isEmpty()) {
|
||||||
createErrorResponse(job.exceptionMessage());
|
createErrorResponse(job.exceptionMessage());
|
||||||
|
@ -421,6 +434,7 @@ public:
|
||||||
addSuccess(true);
|
addSuccess(true);
|
||||||
addRunning();
|
addRunning();
|
||||||
addBody(job.returnValue());
|
addBody(job.returnValue());
|
||||||
|
if (debugService->clientRequiresRedundantRefs())
|
||||||
addRefs(job.refs());
|
addRefs(job.refs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -630,7 +644,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionEvalJob job(debugger->engine(), frame, context, expression,
|
ExpressionEvalJob job(debugger->engine(), frame, context, expression,
|
||||||
debugger->collector());
|
saneCollector(debugger));
|
||||||
debugger->runInEngine(&job);
|
debugger->runInEngine(&job);
|
||||||
if (job.hasExeption()) {
|
if (job.hasExeption()) {
|
||||||
createErrorResponse(job.exceptionMessage());
|
createErrorResponse(job.exceptionMessage());
|
||||||
|
@ -640,6 +654,7 @@ public:
|
||||||
addSuccess(true);
|
addSuccess(true);
|
||||||
addRunning();
|
addRunning();
|
||||||
addBody(job.returnValue());
|
addBody(job.returnValue());
|
||||||
|
if (debugService->clientRequiresRedundantRefs())
|
||||||
addRefs(job.refs());
|
addRefs(job.refs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -662,7 +677,7 @@ V8CommandHandler *QV4DebugServiceImpl::v8CommandHandler(const QString &command)
|
||||||
|
|
||||||
QV4DebugServiceImpl::QV4DebugServiceImpl(QObject *parent) :
|
QV4DebugServiceImpl::QV4DebugServiceImpl(QObject *parent) :
|
||||||
QQmlConfigurableDebugService<QV4DebugService>(1, parent),
|
QQmlConfigurableDebugService<QV4DebugService>(1, parent),
|
||||||
debuggerAgent(this), theSelectedFrame(0),
|
debuggerAgent(this), theSelectedFrame(0), redundantRefs(true), namesAsObjects(true),
|
||||||
unknownV8CommandHandler(new UnknownV8CommandHandler)
|
unknownV8CommandHandler(new UnknownV8CommandHandler)
|
||||||
{
|
{
|
||||||
addHandler(new V8VersionRequest);
|
addHandler(new V8VersionRequest);
|
||||||
|
@ -766,6 +781,14 @@ void QV4DebugServiceImpl::messageReceived(const QByteArray &message)
|
||||||
TRACE_PROTOCOL(qDebug() << "... type:" << type);
|
TRACE_PROTOCOL(qDebug() << "... type:" << type);
|
||||||
|
|
||||||
if (type == V4_CONNECT) {
|
if (type == V4_CONNECT) {
|
||||||
|
QJsonObject parameters = QJsonDocument::fromJson(payload).object();
|
||||||
|
namesAsObjects = true;
|
||||||
|
redundantRefs = true;
|
||||||
|
if (parameters.contains("namesAsObjects"))
|
||||||
|
namesAsObjects = parameters.value("namesAsObjects").toBool();
|
||||||
|
if (parameters.contains("redundantRefs"))
|
||||||
|
namesAsObjects = parameters.value("redundantRefs").toBool();
|
||||||
|
|
||||||
emit messageToClient(name(), packMessage(type));
|
emit messageToClient(name(), packMessage(type));
|
||||||
stopWaiting();
|
stopWaiting();
|
||||||
} else if (type == V4_PAUSE) {
|
} else if (type == V4_PAUSE) {
|
||||||
|
|
|
@ -86,6 +86,9 @@ public:
|
||||||
int selectedFrame() const;
|
int selectedFrame() const;
|
||||||
void selectFrame(int frameNr);
|
void selectFrame(int frameNr);
|
||||||
|
|
||||||
|
bool clientRequiresRedundantRefs() const { return redundantRefs; }
|
||||||
|
bool clientRequiresNamesAsObjects() const { return namesAsObjects; }
|
||||||
|
|
||||||
QV4DebuggerAgent debuggerAgent;
|
QV4DebuggerAgent debuggerAgent;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -105,6 +108,9 @@ private:
|
||||||
static int sequence;
|
static int sequence;
|
||||||
int theSelectedFrame;
|
int theSelectedFrame;
|
||||||
|
|
||||||
|
bool redundantRefs;
|
||||||
|
bool namesAsObjects;
|
||||||
|
|
||||||
void addHandler(V8CommandHandler* handler);
|
void addHandler(V8CommandHandler* handler);
|
||||||
QHash<QString, V8CommandHandler*> handlers;
|
QHash<QString, V8CommandHandler*> handlers;
|
||||||
QScopedPointer<UnknownV8CommandHandler> unknownV8CommandHandler;
|
QScopedPointer<UnknownV8CommandHandler> unknownV8CommandHandler;
|
||||||
|
|
|
@ -257,7 +257,7 @@ public:
|
||||||
stringify = jsEngine.evaluate(QLatin1String("JSON.stringify"));
|
stringify = jsEngine.evaluate(QLatin1String("JSON.stringify"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void connect();
|
void connect(bool redundantRefs = false, bool namesAsObjects = false);
|
||||||
void interrupt();
|
void interrupt();
|
||||||
|
|
||||||
void continueDebugging(StepAction stepAction);
|
void continueDebugging(StepAction stepAction);
|
||||||
|
@ -304,9 +304,13 @@ public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void QJSDebugClient::connect()
|
void QJSDebugClient::connect(bool redundantRefs, bool namesAsObjects)
|
||||||
{
|
{
|
||||||
sendMessage(packMessage(CONNECT));
|
QJSValue jsonVal = parser.call(QJSValueList() << QLatin1String("{}"));
|
||||||
|
jsonVal.setProperty("redundantRefs", QJSValue(redundantRefs));
|
||||||
|
jsonVal.setProperty("namesAsObjects", QJSValue(namesAsObjects));
|
||||||
|
sendMessage(packMessage(CONNECT,
|
||||||
|
stringify.call(QJSValueList() << jsonVal).toString().toUtf8()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QJSDebugClient::interrupt()
|
void QJSDebugClient::interrupt()
|
||||||
|
@ -870,8 +874,10 @@ void tst_QQmlDebugJS::interrupt()
|
||||||
//void connect()
|
//void connect()
|
||||||
|
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
init(qmlscene);
|
init(qmlscene);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
|
|
||||||
client->interrupt();
|
client->interrupt();
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(interruptRequested())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(interruptRequested())));
|
||||||
|
@ -882,8 +888,10 @@ void tst_QQmlDebugJS::getVersion()
|
||||||
//void version()
|
//void version()
|
||||||
|
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
init(qmlscene);
|
init(qmlscene);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(connected())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(connected())));
|
||||||
|
|
||||||
client->version();
|
client->version();
|
||||||
|
@ -894,9 +902,11 @@ void tst_QQmlDebugJS::getVersionWhenAttaching()
|
||||||
{
|
{
|
||||||
//void version()
|
//void version()
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
init(qmlscene, QLatin1String(TIMER_QMLFILE), false);
|
init(qmlscene, QLatin1String(TIMER_QMLFILE), false);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
|
|
||||||
client->version();
|
client->version();
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
|
||||||
|
@ -907,8 +917,10 @@ void tst_QQmlDebugJS::disconnect()
|
||||||
//void disconnect()
|
//void disconnect()
|
||||||
|
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
init(qmlscene);
|
init(qmlscene);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
|
|
||||||
client->disconnect();
|
client->disconnect();
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
|
||||||
|
@ -918,12 +930,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnCompleted()
|
||||||
{
|
{
|
||||||
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
|
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine = 34;
|
int sourceLine = 34;
|
||||||
init(qmlscene, ONCOMPLETED_QMLFILE);
|
init(qmlscene, ONCOMPLETED_QMLFILE);
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
QString jsonString(client->response);
|
QString jsonString(client->response);
|
||||||
|
@ -939,12 +953,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnComponentCreated()
|
||||||
{
|
{
|
||||||
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
|
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine = 34;
|
int sourceLine = 34;
|
||||||
init(qmlscene, CREATECOMPONENT_QMLFILE);
|
init(qmlscene, CREATECOMPONENT_QMLFILE);
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
QString jsonString(client->response);
|
QString jsonString(client->response);
|
||||||
|
@ -959,10 +975,12 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnComponentCreated()
|
||||||
void tst_QQmlDebugJS::setBreakpointInScriptOnTimerCallback()
|
void tst_QQmlDebugJS::setBreakpointInScriptOnTimerCallback()
|
||||||
{
|
{
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
int sourceLine = 35;
|
int sourceLine = 35;
|
||||||
init(qmlscene, TIMER_QMLFILE);
|
init(qmlscene, TIMER_QMLFILE);
|
||||||
|
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
//We can set the breakpoint after connect() here because the timer is repeating and if we miss
|
//We can set the breakpoint after connect() here because the timer is repeating and if we miss
|
||||||
//its first iteration we can still catch the second one.
|
//its first iteration we can still catch the second one.
|
||||||
client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine, -1, true);
|
||||||
|
@ -981,12 +999,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptInDifferentFile()
|
||||||
{
|
{
|
||||||
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
|
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine = 31;
|
int sourceLine = 31;
|
||||||
init(qmlscene, LOADJSFILE_QMLFILE);
|
init(qmlscene, LOADJSFILE_QMLFILE);
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(TEST_JSFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(TEST_JSFILE), sourceLine, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
QString jsonString(client->response);
|
QString jsonString(client->response);
|
||||||
|
@ -1002,13 +1022,15 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnComment()
|
||||||
{
|
{
|
||||||
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
|
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine = 34;
|
int sourceLine = 34;
|
||||||
int actualLine = 36;
|
int actualLine = 36;
|
||||||
init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
|
init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
|
QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()), 1));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()), 1));
|
||||||
|
|
||||||
|
@ -1025,13 +1047,15 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnEmptyLine()
|
||||||
{
|
{
|
||||||
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
|
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine = 35;
|
int sourceLine = 35;
|
||||||
int actualLine = 36;
|
int actualLine = 36;
|
||||||
init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
|
init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
|
QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()), 1));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()), 1));
|
||||||
|
|
||||||
|
@ -1048,12 +1072,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnOptimizedBinding()
|
||||||
{
|
{
|
||||||
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
|
//void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine = 39;
|
int sourceLine = 39;
|
||||||
init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
|
init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
QString jsonString(client->response);
|
QString jsonString(client->response);
|
||||||
|
@ -1068,11 +1094,13 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnOptimizedBinding()
|
||||||
void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
|
void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
|
||||||
{
|
{
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
int out = 10;
|
int out = 10;
|
||||||
int sourceLine = 37;
|
int sourceLine = 37;
|
||||||
init(qmlscene, CONDITION_QMLFILE);
|
init(qmlscene, CONDITION_QMLFILE);
|
||||||
|
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
//The breakpoint is in a timer loop so we can set it after connect().
|
//The breakpoint is in a timer loop so we can set it after connect().
|
||||||
client->setBreakpoint(QLatin1String(CONDITION_QMLFILE), sourceLine, 1, true, QLatin1String("a > 10"));
|
client->setBreakpoint(QLatin1String(CONDITION_QMLFILE), sourceLine, 1, true, QLatin1String("a > 10"));
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
@ -1105,12 +1133,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
|
||||||
void tst_QQmlDebugJS::setBreakpointInScriptThatQuits()
|
void tst_QQmlDebugJS::setBreakpointInScriptThatQuits()
|
||||||
{
|
{
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
init(qmlscene, QUIT_QMLFILE);
|
init(qmlscene, QUIT_QMLFILE);
|
||||||
|
|
||||||
int sourceLine = 36;
|
int sourceLine = 36;
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(QUIT_QMLFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(QUIT_QMLFILE), sourceLine, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
QString jsonString(client->response);
|
QString jsonString(client->response);
|
||||||
|
@ -1147,12 +1177,14 @@ void tst_QQmlDebugJS::clearBreakpoint()
|
||||||
{
|
{
|
||||||
//void clearBreakpoint(int breakpoint);
|
//void clearBreakpoint(int breakpoint);
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine1 = 37;
|
int sourceLine1 = 37;
|
||||||
int sourceLine2 = 38;
|
int sourceLine2 = 38;
|
||||||
init(qmlscene, CHANGEBREAKPOINT_QMLFILE);
|
init(qmlscene, CHANGEBREAKPOINT_QMLFILE);
|
||||||
|
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
//The breakpoints are in a timer loop so we can set them after connect().
|
//The breakpoints are in a timer loop so we can set them after connect().
|
||||||
//Furthermore the breakpoints should be hit in the right order because setting of breakpoints
|
//Furthermore the breakpoints should be hit in the right order because setting of breakpoints
|
||||||
//can only occur in the QML event loop. (see QCOMPARE for sourceLine2 below)
|
//can only occur in the QML event loop. (see QCOMPARE for sourceLine2 below)
|
||||||
|
@ -1195,10 +1227,12 @@ void tst_QQmlDebugJS::setExceptionBreak()
|
||||||
{
|
{
|
||||||
//void setExceptionBreak(QString type, bool enabled = false);
|
//void setExceptionBreak(QString type, bool enabled = false);
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
init(qmlscene, EXCEPTION_QMLFILE);
|
init(qmlscene, EXCEPTION_QMLFILE);
|
||||||
client->setExceptionBreak(QJSDebugClient::All,true);
|
client->setExceptionBreak(QJSDebugClient::All,true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1206,12 +1240,14 @@ void tst_QQmlDebugJS::stepNext()
|
||||||
{
|
{
|
||||||
//void continueDebugging(StepAction stepAction, int stepCount = 1);
|
//void continueDebugging(StepAction stepAction, int stepCount = 1);
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine = 37;
|
int sourceLine = 37;
|
||||||
init(qmlscene, STEPACTION_QMLFILE);
|
init(qmlscene, STEPACTION_QMLFILE);
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
client->continueDebugging(QJSDebugClient::Next);
|
client->continueDebugging(QJSDebugClient::Next);
|
||||||
|
@ -1230,13 +1266,15 @@ void tst_QQmlDebugJS::stepIn()
|
||||||
{
|
{
|
||||||
//void continueDebugging(StepAction stepAction, int stepCount = 1);
|
//void continueDebugging(StepAction stepAction, int stepCount = 1);
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine = 41;
|
int sourceLine = 41;
|
||||||
int actualLine = 37;
|
int actualLine = 37;
|
||||||
init(qmlscene, STEPACTION_QMLFILE);
|
init(qmlscene, STEPACTION_QMLFILE);
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, 1, true);
|
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, 1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
client->continueDebugging(QJSDebugClient::In);
|
client->continueDebugging(QJSDebugClient::In);
|
||||||
|
@ -1255,13 +1293,15 @@ void tst_QQmlDebugJS::stepOut()
|
||||||
{
|
{
|
||||||
//void continueDebugging(StepAction stepAction, int stepCount = 1);
|
//void continueDebugging(StepAction stepAction, int stepCount = 1);
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine = 37;
|
int sourceLine = 37;
|
||||||
int actualLine = 41;
|
int actualLine = 41;
|
||||||
init(qmlscene, STEPACTION_QMLFILE);
|
init(qmlscene, STEPACTION_QMLFILE);
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
client->continueDebugging(QJSDebugClient::Out);
|
client->continueDebugging(QJSDebugClient::Out);
|
||||||
|
@ -1280,6 +1320,8 @@ void tst_QQmlDebugJS::continueDebugging()
|
||||||
{
|
{
|
||||||
//void continueDebugging(StepAction stepAction, int stepCount = 1);
|
//void continueDebugging(StepAction stepAction, int stepCount = 1);
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine1 = 41;
|
int sourceLine1 = 41;
|
||||||
int sourceLine2 = 38;
|
int sourceLine2 = 38;
|
||||||
|
@ -1287,7 +1329,7 @@ void tst_QQmlDebugJS::continueDebugging()
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine1, -1, true);
|
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine1, -1, true);
|
||||||
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine2, -1, true);
|
client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine2, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
client->continueDebugging(QJSDebugClient::Continue);
|
client->continueDebugging(QJSDebugClient::Continue);
|
||||||
|
@ -1306,12 +1348,14 @@ void tst_QQmlDebugJS::backtrace()
|
||||||
{
|
{
|
||||||
//void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false);
|
//void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false);
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine = 34;
|
int sourceLine = 34;
|
||||||
init(qmlscene, ONCOMPLETED_QMLFILE);
|
init(qmlscene, ONCOMPLETED_QMLFILE);
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
client->backtrace();
|
client->backtrace();
|
||||||
|
@ -1322,12 +1366,14 @@ void tst_QQmlDebugJS::getFrameDetails()
|
||||||
{
|
{
|
||||||
//void frame(int number = -1);
|
//void frame(int number = -1);
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine = 34;
|
int sourceLine = 34;
|
||||||
init(qmlscene, ONCOMPLETED_QMLFILE);
|
init(qmlscene, ONCOMPLETED_QMLFILE);
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
client->frame();
|
client->frame();
|
||||||
|
@ -1338,12 +1384,14 @@ void tst_QQmlDebugJS::getScopeDetails()
|
||||||
{
|
{
|
||||||
//void scope(int number = -1, int frameNumber = -1);
|
//void scope(int number = -1, int frameNumber = -1);
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
|
|
||||||
int sourceLine = 34;
|
int sourceLine = 34;
|
||||||
init(qmlscene, ONCOMPLETED_QMLFILE);
|
init(qmlscene, ONCOMPLETED_QMLFILE);
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
client->scope();
|
client->scope();
|
||||||
|
@ -1374,11 +1422,13 @@ void tst_QQmlDebugJS::evaluateInLocalScope()
|
||||||
//void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap());
|
//void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap());
|
||||||
|
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
int sourceLine = 34;
|
int sourceLine = 34;
|
||||||
init(qmlscene, ONCOMPLETED_QMLFILE);
|
init(qmlscene, ONCOMPLETED_QMLFILE);
|
||||||
|
|
||||||
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
|
client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
client->frame();
|
client->frame();
|
||||||
|
@ -1461,10 +1511,12 @@ void tst_QQmlDebugJS::getScripts()
|
||||||
//void scripts(int types = -1, QList<int> ids = QList<int>(), bool includeSource = false, QVariant filter = QVariant());
|
//void scripts(int types = -1, QList<int> ids = QList<int>(), bool includeSource = false, QVariant filter = QVariant());
|
||||||
|
|
||||||
QFETCH(bool, qmlscene);
|
QFETCH(bool, qmlscene);
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
QFETCH(bool, namesAsObjects);
|
||||||
init(qmlscene);
|
init(qmlscene);
|
||||||
|
|
||||||
client->setBreakpoint(QString(TEST_QMLFILE), 35, -1, true);
|
client->setBreakpoint(QString(TEST_QMLFILE), 35, -1, true);
|
||||||
client->connect();
|
client->connect(redundantRefs, namesAsObjects);
|
||||||
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
|
||||||
|
|
||||||
client->scripts();
|
client->scripts();
|
||||||
|
@ -1482,8 +1534,16 @@ void tst_QQmlDebugJS::getScripts()
|
||||||
void tst_QQmlDebugJS::targetData()
|
void tst_QQmlDebugJS::targetData()
|
||||||
{
|
{
|
||||||
QTest::addColumn<bool>("qmlscene");
|
QTest::addColumn<bool>("qmlscene");
|
||||||
QTest::newRow("custom") << false;
|
QTest::addColumn<bool>("redundantRefs");
|
||||||
QTest::newRow("qmlscene") << true;
|
QTest::addColumn<bool>("namesAsObjects");
|
||||||
|
QTest::newRow("custom / redundant / objects") << false << true << true;
|
||||||
|
QTest::newRow("qmlscene / redundant / objects") << true << true << true;
|
||||||
|
QTest::newRow("custom / redundant / strings") << false << true << false;
|
||||||
|
QTest::newRow("qmlscene / redundant / strings") << true << true << false;
|
||||||
|
QTest::newRow("custom / sparse / objects") << false << false << true;
|
||||||
|
QTest::newRow("qmlscene / sparse / objects") << true << false << true;
|
||||||
|
QTest::newRow("custom / sparse / strings") << false << false << false;
|
||||||
|
QTest::newRow("qmlscene / sparse / strings") << true << false << false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QQmlDebugJS)
|
QTEST_MAIN(tst_QQmlDebugJS)
|
||||||
|
|
|
@ -120,7 +120,6 @@ public:
|
||||||
typedef QV4DataCollector::Refs Refs;
|
typedef QV4DataCollector::Refs Refs;
|
||||||
typedef QV4DataCollector::Ref Ref;
|
typedef QV4DataCollector::Ref Ref;
|
||||||
struct NamedRefs {
|
struct NamedRefs {
|
||||||
QJsonArray refs;
|
|
||||||
QJsonObject scope;
|
QJsonObject scope;
|
||||||
|
|
||||||
int size() const {
|
int size() const {
|
||||||
|
@ -131,15 +130,6 @@ public:
|
||||||
return scope.contains(name);
|
return scope.contains(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject resolveRef(int ref) const {
|
|
||||||
foreach (const QJsonValue &val, refs) {
|
|
||||||
QJsonObject obj = val.toObject();
|
|
||||||
if (obj.value(QLatin1String("handle")).toInt() == ref)
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
return QJsonObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DUMP_JSON(x) {\
|
#define DUMP_JSON(x) {\
|
||||||
QJsonDocument doc(x);\
|
QJsonDocument doc(x);\
|
||||||
qDebug() << #x << "=" << doc.toJson(QJsonDocument::Indented);\
|
qDebug() << #x << "=" << doc.toJson(QJsonDocument::Indented);\
|
||||||
|
@ -209,7 +199,6 @@ public slots:
|
||||||
request.expression, &collector);
|
request.expression, &collector);
|
||||||
debugger->runInEngine(&job);
|
debugger->runInEngine(&job);
|
||||||
m_expressionResults << job.returnValue();
|
m_expressionResults << job.returnValue();
|
||||||
m_expressionRefs << job.refs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_captureContextInfo)
|
if (m_captureContextInfo)
|
||||||
|
@ -235,24 +224,17 @@ public:
|
||||||
ScopeJob job(&collector, i, 0);
|
ScopeJob job(&collector, i, 0);
|
||||||
debugger->runInEngine(&job);
|
debugger->runInEngine(&job);
|
||||||
NamedRefs &refs = m_capturedScope.last();
|
NamedRefs &refs = m_capturedScope.last();
|
||||||
refs.refs = job.refs();
|
|
||||||
QJsonObject object = job.returnValue();
|
QJsonObject object = job.returnValue();
|
||||||
object = object.value(QLatin1String("object")).toObject();
|
object = object.value(QLatin1String("object")).toObject();
|
||||||
int ref = object.value(QLatin1String("ref")).toInt();
|
if (object.contains("ref") && !object.contains("properties")) {
|
||||||
object = refs.resolveRef(ref);
|
QVERIFY(collector.redundantRefs());
|
||||||
|
object = collector.lookupRef(object.value("ref").toInt(), true);
|
||||||
|
QVERIFY(object.contains("properties"));
|
||||||
|
}
|
||||||
foreach (const QJsonValue &value, object.value(QLatin1String("properties")).toArray()) {
|
foreach (const QJsonValue &value, object.value(QLatin1String("properties")).toArray()) {
|
||||||
QJsonObject property = value.toObject();
|
QJsonObject property = value.toObject();
|
||||||
QString name = property.value(QLatin1String("name")).toString();
|
QString name = property.value(QLatin1String("name")).toString();
|
||||||
property.remove(QLatin1String("name"));
|
property.remove(QLatin1String("name"));
|
||||||
if (property.contains(QLatin1String("ref"))) {
|
|
||||||
int childRef = property.value(QLatin1String("ref")).toInt();
|
|
||||||
if (childRef >= 0 && refs.refs.size() > childRef) {
|
|
||||||
property.remove(QLatin1String("ref"));
|
|
||||||
property.insert(QLatin1String("properties"),
|
|
||||||
refs.resolveRef(childRef).value(
|
|
||||||
QLatin1String("properties")).toArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
refs.scope.insert(name, property);
|
refs.scope.insert(name, property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,7 +265,6 @@ public:
|
||||||
QVector<ExpressionRequest> m_expressionRequests;
|
QVector<ExpressionRequest> m_expressionRequests;
|
||||||
QV4Debugger::Speed m_resumeSpeed;
|
QV4Debugger::Speed m_resumeSpeed;
|
||||||
QList<QJsonObject> m_expressionResults;
|
QList<QJsonObject> m_expressionResults;
|
||||||
QList<QJsonArray> m_expressionRefs;
|
|
||||||
QV4Debugger *m_debugger;
|
QV4Debugger *m_debugger;
|
||||||
|
|
||||||
// Utility methods:
|
// Utility methods:
|
||||||
|
@ -315,9 +296,13 @@ private slots:
|
||||||
void conditionalBreakPointInQml();
|
void conditionalBreakPointInQml();
|
||||||
|
|
||||||
// context access:
|
// context access:
|
||||||
|
void readArguments_data() { redundancy_data(); }
|
||||||
void readArguments();
|
void readArguments();
|
||||||
|
void readLocals_data() { redundancy_data(); }
|
||||||
void readLocals();
|
void readLocals();
|
||||||
|
void readObject_data() { redundancy_data(); }
|
||||||
void readObject();
|
void readObject();
|
||||||
|
void readContextInAllFrames_data() { redundancy_data(); }
|
||||||
void readContextInAllFrames();
|
void readContextInAllFrames();
|
||||||
|
|
||||||
// exceptions:
|
// exceptions:
|
||||||
|
@ -325,7 +310,9 @@ private slots:
|
||||||
void breakInCatch();
|
void breakInCatch();
|
||||||
void breakInWith();
|
void breakInWith();
|
||||||
|
|
||||||
|
void evaluateExpression_data() { redundancy_data(); }
|
||||||
void evaluateExpression();
|
void evaluateExpression();
|
||||||
|
void stepToEndOfScript_data() { redundancy_data(); }
|
||||||
void stepToEndOfScript();
|
void stepToEndOfScript();
|
||||||
|
|
||||||
void lastLineOfLoop_data();
|
void lastLineOfLoop_data();
|
||||||
|
@ -343,6 +330,8 @@ private:
|
||||||
waitForSignal(m_engine, SIGNAL(evaluateFinished()), /*timeout*/0);
|
waitForSignal(m_engine, SIGNAL(evaluateFinished()), /*timeout*/0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void redundancy_data();
|
||||||
|
|
||||||
TestEngine *m_engine;
|
TestEngine *m_engine;
|
||||||
QV4::ExecutionEngine *m_v4;
|
QV4::ExecutionEngine *m_v4;
|
||||||
TestAgent *m_debuggerAgent;
|
TestAgent *m_debuggerAgent;
|
||||||
|
@ -537,6 +526,9 @@ void tst_qv4debugger::conditionalBreakPointInQml()
|
||||||
|
|
||||||
void tst_qv4debugger::readArguments()
|
void tst_qv4debugger::readArguments()
|
||||||
{
|
{
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
|
||||||
|
|
||||||
m_debuggerAgent->m_captureContextInfo = true;
|
m_debuggerAgent->m_captureContextInfo = true;
|
||||||
QString script =
|
QString script =
|
||||||
"function f(a, b, c, d) {\n"
|
"function f(a, b, c, d) {\n"
|
||||||
|
@ -560,6 +552,9 @@ void tst_qv4debugger::readArguments()
|
||||||
|
|
||||||
void tst_qv4debugger::readLocals()
|
void tst_qv4debugger::readLocals()
|
||||||
{
|
{
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
|
||||||
|
|
||||||
m_debuggerAgent->m_captureContextInfo = true;
|
m_debuggerAgent->m_captureContextInfo = true;
|
||||||
QString script =
|
QString script =
|
||||||
"function f(a, b) {\n"
|
"function f(a, b) {\n"
|
||||||
|
@ -583,6 +578,9 @@ void tst_qv4debugger::readLocals()
|
||||||
|
|
||||||
void tst_qv4debugger::readObject()
|
void tst_qv4debugger::readObject()
|
||||||
{
|
{
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
|
||||||
|
|
||||||
m_debuggerAgent->m_captureContextInfo = true;
|
m_debuggerAgent->m_captureContextInfo = true;
|
||||||
QString script =
|
QString script =
|
||||||
"function f(a) {\n"
|
"function f(a) {\n"
|
||||||
|
@ -599,6 +597,12 @@ void tst_qv4debugger::readObject()
|
||||||
QVERIFY(frame0.contains("b"));
|
QVERIFY(frame0.contains("b"));
|
||||||
QCOMPARE(frame0.type("b"), QStringLiteral("object"));
|
QCOMPARE(frame0.type("b"), QStringLiteral("object"));
|
||||||
QJsonObject b = frame0.rawValue("b");
|
QJsonObject b = frame0.rawValue("b");
|
||||||
|
QVERIFY(b.contains(QStringLiteral("ref")));
|
||||||
|
QVERIFY(b.contains(QStringLiteral("value")));
|
||||||
|
QVERIFY(!b.contains(QStringLiteral("properties")));
|
||||||
|
QVERIFY(b.value("value").isDouble());
|
||||||
|
QCOMPARE(b.value("value").toInt(), 2);
|
||||||
|
b = m_debuggerAgent->collector.lookupRef(b.value("ref").toInt(), true);
|
||||||
QVERIFY(b.contains(QStringLiteral("properties")));
|
QVERIFY(b.contains(QStringLiteral("properties")));
|
||||||
QVERIFY(b.value("properties").isArray());
|
QVERIFY(b.value("properties").isArray());
|
||||||
QJsonArray b_props = b.value("properties").toArray();
|
QJsonArray b_props = b.value("properties").toArray();
|
||||||
|
@ -614,7 +618,8 @@ void tst_qv4debugger::readObject()
|
||||||
QCOMPARE(b_tail.value("name").toString(), QStringLiteral("tail"));
|
QCOMPARE(b_tail.value("name").toString(), QStringLiteral("tail"));
|
||||||
QVERIFY(b_tail.contains("ref"));
|
QVERIFY(b_tail.contains("ref"));
|
||||||
|
|
||||||
QJsonObject b_tail_value = m_debuggerAgent->collector.lookupRef(b_tail.value("ref").toInt());
|
QJsonObject b_tail_value = m_debuggerAgent->collector.lookupRef(b_tail.value("ref").toInt(),
|
||||||
|
true);
|
||||||
QCOMPARE(b_tail_value.value("type").toString(), QStringLiteral("object"));
|
QCOMPARE(b_tail_value.value("type").toString(), QStringLiteral("object"));
|
||||||
QVERIFY(b_tail_value.contains("properties"));
|
QVERIFY(b_tail_value.contains("properties"));
|
||||||
QJsonArray b_tail_props = b_tail_value.value("properties").toArray();
|
QJsonArray b_tail_props = b_tail_value.value("properties").toArray();
|
||||||
|
@ -631,6 +636,9 @@ void tst_qv4debugger::readObject()
|
||||||
|
|
||||||
void tst_qv4debugger::readContextInAllFrames()
|
void tst_qv4debugger::readContextInAllFrames()
|
||||||
{
|
{
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
|
||||||
|
|
||||||
m_debuggerAgent->m_captureContextInfo = true;
|
m_debuggerAgent->m_captureContextInfo = true;
|
||||||
QString script =
|
QString script =
|
||||||
"function fact(n) {\n"
|
"function fact(n) {\n"
|
||||||
|
@ -678,7 +686,8 @@ void tst_qv4debugger::pauseOnThrow()
|
||||||
QCOMPARE(m_debuggerAgent->m_pauseReason, QV4Debugger::Throwing);
|
QCOMPARE(m_debuggerAgent->m_pauseReason, QV4Debugger::Throwing);
|
||||||
QCOMPARE(m_debuggerAgent->m_stackTrace.size(), 2);
|
QCOMPARE(m_debuggerAgent->m_stackTrace.size(), 2);
|
||||||
QVERIFY(m_debuggerAgent->m_thrownValue >= qint64(0));
|
QVERIFY(m_debuggerAgent->m_thrownValue >= qint64(0));
|
||||||
QJsonObject exception = m_debuggerAgent->collector.lookupRef(m_debuggerAgent->m_thrownValue);
|
QJsonObject exception = m_debuggerAgent->collector.lookupRef(m_debuggerAgent->m_thrownValue,
|
||||||
|
true);
|
||||||
// DUMP_JSON(exception);
|
// DUMP_JSON(exception);
|
||||||
QCOMPARE(exception.value("type").toString(), QStringLiteral("string"));
|
QCOMPARE(exception.value("type").toString(), QStringLiteral("string"));
|
||||||
QCOMPARE(exception.value("value").toString(), QStringLiteral("hard"));
|
QCOMPARE(exception.value("value").toString(), QStringLiteral("hard"));
|
||||||
|
@ -722,6 +731,9 @@ void tst_qv4debugger::breakInWith()
|
||||||
|
|
||||||
void tst_qv4debugger::evaluateExpression()
|
void tst_qv4debugger::evaluateExpression()
|
||||||
{
|
{
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
|
||||||
|
|
||||||
QString script =
|
QString script =
|
||||||
"function testFunction() {\n"
|
"function testFunction() {\n"
|
||||||
" var x = 10\n"
|
" var x = 10\n"
|
||||||
|
@ -750,14 +762,12 @@ void tst_qv4debugger::evaluateExpression()
|
||||||
|
|
||||||
evaluateJavaScript(script, "evaluateExpression");
|
evaluateJavaScript(script, "evaluateExpression");
|
||||||
|
|
||||||
QCOMPARE(m_debuggerAgent->m_expressionRefs.count(), 4);
|
QCOMPARE(m_debuggerAgent->m_expressionResults.count(), 4);
|
||||||
QCOMPARE(m_debuggerAgent->m_expressionRefs[0].size(), 1);
|
QJsonObject result0 = m_debuggerAgent->m_expressionResults[0];
|
||||||
QJsonObject result0 = m_debuggerAgent->m_expressionRefs[0].first().toObject();
|
|
||||||
QCOMPARE(result0.value("type").toString(), QStringLiteral("number"));
|
QCOMPARE(result0.value("type").toString(), QStringLiteral("number"));
|
||||||
QCOMPARE(result0.value("value").toInt(), 10);
|
QCOMPARE(result0.value("value").toInt(), 10);
|
||||||
for (int i = 1; i < 4; ++i) {
|
for (int i = 1; i < 4; ++i) {
|
||||||
QCOMPARE(m_debuggerAgent->m_expressionRefs[i].size(), 1);
|
QJsonObject result1 = m_debuggerAgent->m_expressionResults[i];
|
||||||
QJsonObject result1 = m_debuggerAgent->m_expressionRefs[1].first().toObject();
|
|
||||||
QCOMPARE(result1.value("type").toString(), QStringLiteral("number"));
|
QCOMPARE(result1.value("type").toString(), QStringLiteral("number"));
|
||||||
QCOMPARE(result1.value("value").toInt(), 20);
|
QCOMPARE(result1.value("value").toInt(), 20);
|
||||||
}
|
}
|
||||||
|
@ -765,6 +775,9 @@ void tst_qv4debugger::evaluateExpression()
|
||||||
|
|
||||||
void tst_qv4debugger::stepToEndOfScript()
|
void tst_qv4debugger::stepToEndOfScript()
|
||||||
{
|
{
|
||||||
|
QFETCH(bool, redundantRefs);
|
||||||
|
m_debuggerAgent->collector.setRedundantRefs(redundantRefs);
|
||||||
|
|
||||||
QString script =
|
QString script =
|
||||||
"var ret = 0;\n"
|
"var ret = 0;\n"
|
||||||
"ret += 4;\n"
|
"ret += 4;\n"
|
||||||
|
@ -827,6 +840,13 @@ void tst_qv4debugger::lastLineOfLoop()
|
||||||
QCOMPARE(secondState.lineNumber, 7);
|
QCOMPARE(secondState.lineNumber, 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_qv4debugger::redundancy_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<bool>("redundantRefs");
|
||||||
|
QTest::addRow("redundant") << true;
|
||||||
|
QTest::addRow("sparse") << false;
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_qv4debugger)
|
QTEST_MAIN(tst_qv4debugger)
|
||||||
|
|
||||||
#include "tst_qv4debugger.moc"
|
#include "tst_qv4debugger.moc"
|
||||||
|
|
Loading…
Reference in New Issue