aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <[email protected]>2009-07-06 17:36:50 +0200
committerFriedemann Kleint <[email protected]>2009-07-06 17:36:50 +0200
commit5bd1d2a0284d90bda180a18f45d48018999fff9b (patch)
treed7cc5705c937374879610838bd9952129101d904
parent45448ce5d51c9b33d2e02c24d9bd3b52526caf16 (diff)
Fix up Debugger helpers to be able to dump QObject's with CDB.
- Make container dumper routines set "childnumchild" when known in order to avoid roundtrips; avoid repeated invocations of container.end(). - Completed dumper information in some places to avoid roundtrips. - Extended QVariant helpers by dumpers for common GUI types (rectangles, points, sizes, fonts, size policies). - Introduced artificial QObjectChildList/QObjectProperty types to be able to dump QObject children and properties without using gdb expressions. - Fixed dumping of Signal/Slot list to pass on correct types. Avoid recursions if signal is connected to self. - Replaced expressions by addresses in the dumpers to it make work for CDB. - Reworked dumper test program to have -a, making it usable for tests, add further types. - Gdb: Clear output buffer before calling dumpers, avoiding mixups in case evaluation of expression fails. - Fix the dumper parser used by CDB, do not be fooled by "<synthetic>" addresses, etc. - Pass on a "dumperVersion" in initial query.
-rw-r--r--share/qtcreator/gdbmacros/gdbmacros.cpp646
-rw-r--r--share/qtcreator/gdbmacros/test/dumpertest.pro2
-rw-r--r--share/qtcreator/gdbmacros/test/main.cpp173
-rw-r--r--src/plugins/debugger/cdb/cdbdumperhelper.cpp4
-rw-r--r--src/plugins/debugger/cdb/cdbstackframecontext.cpp50
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp24
-rw-r--r--src/plugins/debugger/watchhandler.cpp3
-rw-r--r--src/plugins/debugger/watchutils.cpp192
-rw-r--r--src/plugins/debugger/watchutils.h5
9 files changed, 741 insertions, 358 deletions
diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp
index 156bfc5e3f2..13017b01baf 100644
--- a/share/qtcreator/gdbmacros/gdbmacros.cpp
+++ b/share/qtcreator/gdbmacros/gdbmacros.cpp
@@ -46,6 +46,13 @@
#include <QtCore/QString>
#include <QtCore/QTextCodec>
#include <QtCore/QVector>
+#include <QtCore/QTextStream>
+#include <QtCore/QPoint>
+#include <QtCore/QSize>
+#include <QtCore/QRect>
+#include <QtCore/QPointF>
+#include <QtCore/QSizeF>
+#include <QtCore/QRectF>
#if QT_VERSION >= 0x040500
#include <QtCore/QSharedPointer>
@@ -67,6 +74,10 @@ int qtGhVersion = QT_VERSION;
# include <QtGui/QImage>
# include <QtGui/QPixmap>
# include <QtGui/QWidget>
+# include <QtGui/QFont>
+# include <QtGui/QColor>
+# include <QtGui/QKeySequence>
+# include <QtGui/QSizePolicy>
#endif
#ifdef Q_OS_WIN
@@ -445,7 +456,7 @@ struct QDumper
explicit QDumper();
~QDumper();
- // direct write to the output
+ // direct write to the output
QDumper &put(long c);
QDumper &put(int i);
QDumper &put(double d);
@@ -454,6 +465,7 @@ struct QDumper
QDumper &put(unsigned int i);
QDumper &put(const void *p);
QDumper &put(qulonglong c);
+ QDumper &put(long long c);
QDumper &put(const char *str);
QDumper &put(const QByteArray &ba);
QDumper &put(const QString &str);
@@ -578,6 +590,13 @@ QDumper &QDumper::put(unsigned long long c)
return *this;
}
+QDumper &QDumper::put(long long c)
+{
+ checkFill();
+ pos += sprintf(outBuffer + pos, "%lld", c);
+ return *this;
+}
+
QDumper &QDumper::put(unsigned long c)
{
checkFill();
@@ -864,7 +883,28 @@ static inline void dumpStdWStringValue(QDumper &d, const std::wstring &str)
d.putItem("numchild", "0");
}
-static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr,
+// Tell the calling routine whether a global "childnumchild" attribute makes sense
+enum InnerValueResult { InnerValueNotHandled,
+ InnerValueChildrenSpecified,
+ InnerValueNoFurtherChildren,
+ InnerValueFurtherChildren };
+
+static inline void dumpChildNumChildren(QDumper &d, InnerValueResult innerValueResult)
+{
+ switch (innerValueResult) {
+ case InnerValueChildrenSpecified:
+ case InnerValueNotHandled:
+ break;
+ case InnerValueNoFurtherChildren:
+ d.putItem("childnumchild", "0");
+ break;
+ case InnerValueFurtherChildren:
+ d.putItem("childnumchild", "1");
+ break;
+ }
+}
+
+static InnerValueResult qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr,
const char *field = "value")
{
char buf[30];
@@ -872,41 +912,60 @@ static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr
switch (type[1]) {
case 'l':
if (isEqual(type, "float"))
- d.putItem(field, *(float*)addr);
- return;
+ { d.putItem(field, *(float*)addr); return InnerValueNoFurtherChildren; }
+ return InnerValueNotHandled;
case 'n':
- if (isEqual(type, "int"))
+ if (isEqual(type, "int")) {
d.putItem(field, *(int*)addr);
- else if (isEqual(type, "unsigned"))
+ return InnerValueNoFurtherChildren;
+ }
+ if (isEqual(type, "unsigned")) {
d.putItem(field, *(unsigned int*)addr);
- else if (isEqual(type, "unsigned int"))
+ return InnerValueNoFurtherChildren;
+ }
+ if (isEqual(type, "unsigned int")) {
d.putItem(field, *(unsigned int*)addr);
- else if (isEqual(type, "unsigned long"))
+ return InnerValueNoFurtherChildren;
+ }
+ if (isEqual(type, "unsigned long")) {
d.putItem(field, *(unsigned long*)addr);
- else if (isEqual(type, "unsigned long long"))
+ return InnerValueNoFurtherChildren;
+ }
+ if (isEqual(type, "unsigned long long")) {
d.putItem(field, *(qulonglong*)addr);
- return;
+ return InnerValueNoFurtherChildren;
+ }
+ return InnerValueNotHandled;
case 'o':
- if (isEqual(type, "bool"))
+ if (isEqual(type, "bool")) {
switch (*(bool*)addr) {
- case 0: d.putItem(field, "false"); break;
- case 1: d.putItem(field, "true"); break;
- default: d.putItem(field, *(bool*)addr); break;
+ case 0: d.putItem(field, "false"); break;
+ case 1: d.putItem(field, "true"); break;
+ default: d.putItem(field, *(bool*)addr); break;
}
- else if (isEqual(type, "double"))
+ return InnerValueNoFurtherChildren;
+ }
+ if (isEqual(type, "double")) {
d.putItem(field, *(double*)addr);
- else if (isEqual(type, "long"))
+ return InnerValueNoFurtherChildren;
+ }
+ if (isEqual(type, "long")) {
d.putItem(field, *(long*)addr);
- else if (isEqual(type, "long long"))
+ return InnerValueNoFurtherChildren;
+ }
+ else if (isEqual(type, "long long")) {
d.putItem(field, *(qulonglong*)addr);
- return;
+ return InnerValueNoFurtherChildren;
+ }
+ return InnerValueNotHandled;
case 'B':
if (isEqual(type, "QByteArray")) {
d.putCommaIfNeeded();
d.put(field).put("encoded=\"1\",");
d.putItem(field, *(QByteArray*)addr);
+ return InnerValueFurtherChildren;
}
- return;
+ return InnerValueNotHandled;
case 'C':
if (isEqual(type, "QChar")) {
d.putCommaIfNeeded();
@@ -916,16 +975,18 @@ static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr
buf[1] = char(c.unicode());
d.putItem(field, buf);
d.putItem("numchild", 0);
+ return InnerValueNoFurtherChildren;
}
- return;
+ return InnerValueNotHandled;
case 'L':
if (startsWith(type, "QList<")) {
const QListData *ldata = reinterpret_cast<const QListData*>(addr);
d.putItemCount("value", ldata->size());
d.putItem("valuedisabled", "true");
d.putItem("numchild", ldata->size());
+ return InnerValueChildrenSpecified;
}
- return;
+ return InnerValueNotHandled;
case 'O':
if (isEqual(type, "QObject *")) {
if (addr) {
@@ -935,46 +996,55 @@ static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr
d.putItem("valueencoded", "2");
d.putItem("type", NS"QObject");
d.putItem("displayedtype", ob->metaObject()->className());
+ d.putItem("numchild", 1);
+ return InnerValueChildrenSpecified;
} else {
d.putItem("value", "0x0");
d.putItem("type", NS"QObject *");
+ d.putItem("numchild", 0);
+ return InnerValueNoFurtherChildren;
}
}
- return;
+ return InnerValueNotHandled;
case 'S':
if (isEqual(type, "QString")) {
d.putCommaIfNeeded();
d.put(field).put("encoded=\"2\"");
d.putItem(field, *(QString*)addr);
+ return InnerValueNoFurtherChildren;
}
- return;
+ return InnerValueNotHandled;
case 't':
if (isEqual(type, "std::string")
|| isEqual(type, "std::basic_string<char,std::char_traits<char>,std::allocator<char> >")) {
d.putCommaIfNeeded();
dumpStdStringValue(d, *reinterpret_cast<const std::string*>(addr));
- } else if (isEqual(type, "std::wstring")
- || isEqual(type, "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >")) {
+ return InnerValueNoFurtherChildren;
+ }
+ if (isEqual(type, "std::wstring")
+ || isEqual(type, "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >")) {
dumpStdWStringValue(d, *reinterpret_cast<const std::wstring*>(addr));
+ return InnerValueNoFurtherChildren;
}
- return;
+ return InnerValueNotHandled;
default:
- return;
+ break;
}
+ return InnerValueNotHandled;
}
-static void qDumpInnerValue(QDumper &d, const char *type, const void *addr)
+static InnerValueResult qDumpInnerValue(QDumper &d, const char *type, const void *addr)
{
d.putItem("addr", addr);
d.putItem("type", type);
if (!type[0])
- return;
+ return InnerValueNotHandled;
- qDumpInnerValueHelper(d, type, addr);
+ return qDumpInnerValueHelper(d, type, addr);
}
-static void qDumpInnerValueOrPointer(QDumper &d,
+static InnerValueResult qDumpInnerValueOrPointer(QDumper &d,
const char *type, const char *strippedtype, const void *addr)
{
if (strippedtype) {
@@ -982,18 +1052,17 @@ static void qDumpInnerValueOrPointer(QDumper &d,
d.putItem("addr", deref(addr));
d.putItem("saddr", deref(addr));
d.putItem("type", strippedtype);
- qDumpInnerValueHelper(d, strippedtype, deref(addr));
- } else {
- d.putItem("addr", addr);
- d.putItem("type", strippedtype);
- d.putItem("value", "<null>");
- d.putItem("numchild", "0");
+ return qDumpInnerValueHelper(d, strippedtype, deref(addr));
}
- } else {
d.putItem("addr", addr);
- d.putItem("type", type);
- qDumpInnerValueHelper(d, type, addr);
+ d.putItem("type", strippedtype);
+ d.putItem("value", "<null>");
+ d.putItem("numchild", "0");
+ return InnerValueChildrenSpecified;
}
+ d.putItem("addr", addr);
+ d.putItem("type", type);
+ return qDumpInnerValueHelper(d, type, addr);
}
//////////////////////////////////////////////////////////////////////////////
@@ -1404,14 +1473,15 @@ static void qDumpQHash(QDumper &d)
d.putItemCount("value", n);
d.putItem("numchild", n);
+
if (d.dumpChildren) {
if (n > 1000)
n = 1000;
- bool isSimpleKey = isSimpleType(keyType);
- bool isSimpleValue = isSimpleType(valueType);
- bool opt = isOptimizedIntKey(keyType);
- int keyOffset = hashOffset(opt, true, keySize, valueSize);
- int valueOffset = hashOffset(opt, false, keySize, valueSize);
+ const bool isSimpleKey = isSimpleType(keyType);
+ const bool isSimpleValue = isSimpleType(valueType);
+ const bool opt = isOptimizedIntKey(keyType);
+ const int keyOffset = hashOffset(opt, true, keySize, valueSize);
+ const int valueOffset = hashOffset(opt, false, keySize, valueSize);
d.beginItem("extra");
d.put("isSimpleKey: ").put(isSimpleKey);
@@ -1436,10 +1506,7 @@ static void qDumpQHash(QDumper &d)
d.putItem("type", valueType);
d.putItem("addr", addOffset(node, valueOffset));
} else {
- d.beginItem("exp");
- d.put("*('"NS"QHashNode<").put(keyType).put(","
- ).put(valueType).put(" >'*)").put(node);
- d.endItem();
+ d.putItem("addr", node);
d.beginItem("type");
d.put("'"NS"QHashNode<").put(keyType).put(",")
.put(valueType).put(MAP_NODE_TYPE_END"'");
@@ -1557,6 +1624,7 @@ static void qDumpQList(QDumper &d)
d.putItem("valuedisabled", "true");
d.putItem("numchild", n);
d.putItem("childtype", d.innertype);
+ InnerValueResult innerValueResult = InnerValueChildrenSpecified;
if (d.dumpChildren) {
unsigned innerSize = d.extraInt[0];
bool innerTypeIsPointer = isPointerType(d.innertype);
@@ -1583,7 +1651,7 @@ static void qDumpQList(QDumper &d)
d.putItem("saddr", p);
if (*(void**)p) {
//d.putItem("value","@").put(p);
- qDumpInnerValue(d, strippedInnerType.data(), deref(p));
+ innerValueResult = qDumpInnerValue(d, strippedInnerType.data(), deref(p));
} else {
d.putItem("value", "<null>");
d.putItem("numchild", "0");
@@ -1593,11 +1661,11 @@ static void qDumpQList(QDumper &d)
if (isInternal) {
//qDumpInnerValue(d, d.innertype, p);
d.putItem("addr", p);
- qDumpInnerValueHelper(d, d.innertype, p);
+ innerValueResult = qDumpInnerValueHelper(d, d.innertype, p);
} else {
//qDumpInnerValue(d, d.innertype, deref(p));
d.putItem("addr", deref(p));
- qDumpInnerValueHelper(d, d.innertype, deref(p));
+ innerValueResult = qDumpInnerValueHelper(d, d.innertype, deref(p));
}
}
d.endHash();
@@ -1606,6 +1674,7 @@ static void qDumpQList(QDumper &d)
d.putEllipsis();
d.endChildren();
}
+ dumpChildNumChildren(d, innerValueResult);
d.disarm();
}
@@ -1624,6 +1693,7 @@ static void qDumpQLinkedList(QDumper &d)
d.putItem("valuedisabled", "true");
d.putItem("numchild", n);
d.putItem("childtype", d.innertype);
+ InnerValueResult innerValueResult = InnerValueChildrenSpecified;
if (d.dumpChildren) {
//unsigned innerSize = d.extraInt[0];
//bool innerTypeIsPointer = isPointerType(d.innertype);
@@ -1640,7 +1710,7 @@ static void qDumpQLinkedList(QDumper &d)
d.beginHash();
d.putItem("name", i);
const void *addr = addOffset(p, 2 * sizeof(void*));
- qDumpInnerValueOrPointer(d, d.innertype, stripped, addr);
+ innerValueResult = qDumpInnerValueOrPointer(d, d.innertype, stripped, addr);
p = deref(p);
d.endHash();
}
@@ -1648,6 +1718,7 @@ static void qDumpQLinkedList(QDumper &d)
d.putEllipsis();
d.endChildren();
}
+ dumpChildNumChildren(d, innerValueResult);
d.disarm();
}
@@ -1795,19 +1866,12 @@ static void qDumpQMap(QDumper &d)
d.putItem("addr", addOffset(node, valueOffset));
} else {
#if QT_VERSION >= 0x040500
+ d.putItem("addr", node);
// actually, any type (even 'char') will do...
d.beginItem("type");
d.put(NS"QMapNode<").put(keyType).put(",");
d.put(valueType).put(MAP_NODE_TYPE_END);
d.endItem();
- d.beginItem("exp");
- d.put("*('"NS"QMapNode<").put(keyType).put(",");
- d.put(valueType).put(" >'*)").put(node);
- d.endItem();
-
- //d.putItem("exp", "*('"NS"QMapData'*)").put((void*)node);
- //d.putItem("exp", "*(char*)").put((void*)node);
- // d.putItem("addr", node); does not work as gdb fails to parse
#else
d.beginItem("type");
d.put(NS"QMapData::Node<").put(keyType).put(",");
@@ -1889,14 +1953,12 @@ static void qDumpQObject(QDumper &d)
{
const QObject *ob = reinterpret_cast<const QObject *>(d.data);
const QMetaObject *mo = ob->metaObject();
- unsigned childrenOffset = d.extraInt[0];
d.putItem("value", ob->objectName());
d.putItem("valueencoded", "2");
d.putItem("type", NS"QObject");
d.putItem("displayedtype", mo->className());
d.putItem("numchild", 4);
if (d.dumpChildren) {
- const QObjectList &children = ob->children();
int slotCount = 0;
int signalCount = 0;
for (int i = mo->methodCount(); --i >= 0; ) {
@@ -1907,61 +1969,33 @@ static void qDumpQObject(QDumper &d)
d.beginChildren();
d.beginHash();
d.putItem("name", "properties");
- // FIXME: Note that when simply using '(QObject*)'
- // in the cast below, Gdb/MI _sometimes_ misparses
- // expressions further down in the tree.
- d.beginItem("exp");
- d.put("*(class '"NS"QObject'*)").put(d.data);
- d.endItem();
+ d.putItem("addr", d.data);
d.putItem("type", NS"QObjectPropertyList");
d.putItemCount("value", mo->propertyCount());
d.putItem("numchild", mo->propertyCount());
d.endHash();
-#if 0
- d.beginHash();
- d.putItem("name", "methods");
- d.putItem("exp", "*(class '"NS"QObject'*)").put(d.data);
- d.putItemCount("value", mo->methodCount());
- d.putItem("numchild", mo->methodCount());
- d.endHash();
-#endif
-#if 0
- d.beginHash();
- d.putItem("name", "senders");
- d.putItem("exp", "(*(class '"NS"ObjectPrivate'*)").put(dfunc(ob)).put(")->senders");
- d.putItem("type", NS"QList<"NS"QObjectPrivateSender>");
- d.endHash();
-#endif
d.beginHash();
d.putItem("name", "signals");
- d.beginItem("exp");
- d.put("*(class '"NS"QObject'*)").put(d.data);
- d.endItem();
+ d.putItem("addr", d.data);
d.putItem("type", NS"QObjectSignalList");
d.putItemCount("value", signalCount);
d.putItem("numchild", signalCount);
d.endHash();
d.beginHash();
d.putItem("name", "slots");
- d.beginItem("exp");
- d.put("*(class '"NS"QObject'*)").put(d.data);
- d.endItem();
+ d.putItem("addr", d.data);
d.putItem("type", NS"QObjectSlotList");
d.putItemCount("value", slotCount);
d.putItem("numchild", slotCount);
d.endHash();
- if (childrenOffset) {
+ const QObjectList objectChildren = ob->children();
+ if (!objectChildren.empty()) {
d.beginHash();
d.putItem("name", "children");
- // works always, but causes additional traffic on the list
- //d.putItem("exp", "((class '"NS"QObject'*)").put(d.data).put(")->children()");
- //
- //d.putItem("addr", addOffset(dfunc(ob), childrenOffset));
- //d.putItem("type", NS"QList<QObject *>");
- //d.putItemCount("value", children.size());
- qDumpInnerValue(d, NS"QList<"NS"QObject *>",
- addOffset(dfunc(ob), childrenOffset));
- d.putItem("numchild", children.size());
+ d.putItem("addr", d.data);
+ d.putItem("type", NS"QObjectChildList");
+ d.putItemCount("value", objectChildren.size());
+ d.putItem("numchild", objectChildren.size());
d.endHash();
}
d.beginHash();
@@ -1981,37 +2015,229 @@ static void qDumpQObject(QDumper &d)
d.disarm();
}
+#if USE_QT_GUI
+static const char *sizePolicyEnumValue(QSizePolicy::Policy p)
+{
+ switch (p) {
+ case QSizePolicy::Fixed:
+ return "Fixed";
+ case QSizePolicy::Minimum:
+ return "Minimum";
+ case QSizePolicy::Maximum:
+ return "Maximum";
+ case QSizePolicy::Preferred:
+ return "Preferred";
+ case QSizePolicy::Expanding:
+ return "Expanding";
+ case QSizePolicy::MinimumExpanding:
+ return "MinimumExpanding";
+ case QSizePolicy::Ignored:
+ break;
+ }
+ return "Ignored";
+}
+
+static QString sizePolicyValue(const QSizePolicy &sp)
+{
+ QString rc;
+ QTextStream str(&rc);
+ // Display as in Designer
+ str << '[' << sizePolicyEnumValue(sp.horizontalPolicy())
+ << ", " << sizePolicyEnumValue(sp.verticalPolicy())
+ << ", " << sp.horizontalStretch() << ", " << sp.verticalStretch() << ']';
+ return rc;
+}
+#endif
+
+static void qDumpQVariantHelper(const QVariant *v, QString *value,
+ QString *exp, int *numchild)
+{
+ switch (v->type()) {
+ case QVariant::Invalid:
+ *value = QLatin1String("<invalid>");
+ *numchild = 0;
+ break;
+ case QVariant::String:
+ *value = QLatin1Char('"') + v->toString() + QLatin1Char('"');
+ *numchild = 0;
+ break;
+ #if QT_VERSION >= 0x040500
+ case QVariant::StringList:
+ *exp = QString(QLatin1String("(*('"NS"QStringList'*)%1)"))
+ .arg((quintptr)v);
+ *numchild = v->toStringList().size();
+ break;
+ #endif
+ case QVariant::Int:
+ *value = QString::number(v->toInt());
+ *numchild= 0;
+ break;
+ case QVariant::Double:
+ *value = QString::number(v->toDouble());
+ *numchild = 0;
+ break;
+ case QVariant::Point: {
+ const QPoint p = v->toPoint();
+ *value = QString::fromLatin1("%1, %2").arg(p.x()).arg(p.y());
+ }
+ *numchild = 0;
+ break;
+ case QVariant::Size: {
+ const QSize size = v->toSize();
+ *value = QString::fromLatin1("%1x%2").arg(size.width()).arg(size.height());
+ }
+ *numchild = 0;
+ break;
+ case QVariant::Rect: {
+ const QRect rect = v->toRect();
+ *value = QString::fromLatin1("%1x%2+%3+%4").arg(rect.width()).arg(rect.height()).arg(rect.x()).arg(rect.y());
+ }
+ *numchild = 0;
+ break;
+ case QVariant::PointF: {
+ const QPointF p = v->toPointF();
+ *value = QString::fromLatin1("%1, %2").arg(p.x()).arg(p.y());
+ }
+ *numchild = 0;
+ break;
+
+ case QVariant::SizeF: {
+ const QSizeF size = v->toSizeF();
+ *value = QString::fromLatin1("%1x%2").arg(size.width()).arg(size.height());
+ }
+ *numchild = 0;
+ break;
+ case QVariant::RectF: {
+ const QRectF rect = v->toRectF();
+ *value = QString::fromLatin1("%1x%2+%3+%4").arg(rect.width()).arg(rect.height()).arg(rect.x()).arg(rect.y());
+ }
+ *numchild = 0;
+ break;
+#if USE_QT_GUI
+ case QVariant::Font:
+ *value = qvariant_cast<QFont>(*v).toString();
+ break;
+ case QVariant::Color:
+ *value = qvariant_cast<QColor>(*v).name();
+ break;
+ case QVariant::KeySequence:
+ *value = qvariant_cast<QKeySequence>(*v).toString();
+ break;
+ case QVariant::SizePolicy:
+ *value = sizePolicyValue(qvariant_cast<QSizePolicy>(*v));
+ break;
+#endif
+ default: {
+ char buf[1000];
+ const char *format = (v->typeName()[0] == 'Q')
+ ? "'"NS"%s "NS"qVariantValue<"NS"%s >'(*('"NS"QVariant'*)%p)"
+ : "'%s "NS"qVariantValue<%s >'(*('"NS"QVariant'*)%p)";
+ qsnprintf(buf, sizeof(buf) - 1, format, v->typeName(), v->typeName(), v);
+ *exp = QLatin1String(buf);
+ *numchild = 1;
+ break;
+ }
+ }
+}
+
+static void qDumpQVariant(QDumper &d, const QVariant *v)
+{
+ QString value;
+ QString exp;
+ int numchild = 0;
+ qDumpQVariantHelper(v, &value, &exp, &numchild);
+ bool isInvalid = (v->typeName() == 0);
+ if (isInvalid) {
+ d.putItem("value", "(invalid)");
+ } else if (value.isEmpty()) {
+ d.beginItem("value");
+ d.put("(").put(v->typeName()).put(") ");
+ d.endItem();
+ } else {
+ QByteArray ba;
+ ba += '(';
+ ba += v->typeName();
+ ba += ") ";
+ ba += qPrintable(value);
+ d.putItem("value", ba);
+ d.putItem("valueencoded", "5");
+ }
+ d.putItem("type", NS"QVariant");
+ d.putItem("numchild", (isInvalid ? "0" : "1"));
+ if (d.dumpChildren) {
+ d.beginChildren();
+ d.beginHash();
+ d.putItem("name", "value");
+ if (!exp.isEmpty())
+ d.putItem("exp", qPrintable(exp));
+ if (!value.isEmpty()) {
+ d.putItem("value", value);
+ d.putItem("valueencoded", "4");
+ }
+ d.putItem("type", v->typeName());
+ d.putItem("numchild", numchild);
+ d.endHash();
+ d.endChildren();
+ }
+ d.disarm();
+}
+
+static inline void qDumpQVariant(QDumper &d)
+{
+ qDumpQVariant(d, reinterpret_cast<const QVariant *>(d.data));
+}
+
+static void qDumpQObjectProperty(QDumper &d)
+{
+ const QObject *ob = (const QObject *)d.data;
+ // extract "local.Object.property"
+ QString iname = d.iname;
+ const int dotPos = iname.lastIndexOf(QLatin1Char('.'));
+ if (dotPos == -1)
+ return;
+ iname.remove(0, dotPos + 1);
+ const QVariant v = ob->property(iname.toAscii().constData());
+ qDumpQVariant(d, &v);
+ d.disarm();
+}
+
static void qDumpQObjectPropertyList(QDumper &d)
{
const QObject *ob = (const QObject *)d.data;
const QMetaObject *mo = ob->metaObject();
+ const int propertyCount = mo->propertyCount();
d.putItem("addr", "<synthetic>");
d.putItem("type", NS"QObjectPropertyList");
- d.putItem("numchild", mo->propertyCount());
+ d.putItem("numchild", propertyCount);
+ d.putItemCount("value", propertyCount);
if (d.dumpChildren) {
d.beginChildren();
- for (int i = mo->propertyCount(); --i >= 0; ) {
+ for (int i = propertyCount; --i >= 0; ) {
const QMetaProperty & prop = mo->property(i);
d.beginHash();
d.putItem("name", prop.name());
- d.beginItem("exp");
- d.put("((").put(mo->className()).put("*)");
- d.put(ob).put(")->").put(prop.name()).put("()");
- d.endItem();
- if (isEqual(prop.typeName(), "QString")) {
+ switch (prop.type()) {
+ case QVariant::String:
+ d.putItem("type", prop.typeName());
d.putItem("value", prop.read(ob).toString());
d.putItem("valueencoded", "2");
- d.putItem("type", NS"QString");
d.putItem("numchild", "0");
- } else if (isEqual(prop.typeName(), "bool")) {
+ break;
+ case QVariant::Bool:
+ d.putItem("type", prop.typeName());
d.putItem("value", (prop.read(ob).toBool() ? "true" : "false"));
d.putItem("numchild", "0");
- } else if (isEqual(prop.typeName(), "int")) {
+ break;
+ case QVariant::Int:
d.putItem("value", prop.read(ob).toInt());
d.putItem("numchild", "0");
+ break;
+ default:
+ d.putItem("addr", d.data);
+ d.putItem("type", NS"QObjectProperty");
+ d.putItem("numchild", "1");
+ break;
}
- d.putItem("type", prop.typeName());
- d.putItem("numchild", "1");
d.endHash();
}
d.endChildren();
@@ -2074,6 +2300,29 @@ static const ConnectionList &qConnectionList(const QObject *ob, int signalNumber
}
#endif
+// Write party involved in a slot/signal element,
+// avoid to recursion to self.
+static inline void qDumpQObjectConnectionPart(QDumper &d,
+ const QObject *owner,
+ const QObject *partner,
+ int number, const char *namePostfix)
+{
+ d.beginHash();
+ d.beginItem("name");
+ d.put(number).put(namePostfix);
+ d.endItem();
+ if (partner == owner) {
+ d.putItem("value", "<this>");
+ d.putItem("valueencoded", "2");
+ d.putItem("type", owner->metaObject()->className());
+ d.putItem("numchild", 0);
+ d.putItem("addr", owner);
+ } else {
+ qDumpInnerValueHelper(d, NS"QObject *", partner);
+ }
+ d.endHash();
+}
+
static void qDumpQObjectSignal(QDumper &d)
{
unsigned signalNumber = d.extraInt[0];
@@ -2089,12 +2338,7 @@ static void qDumpQObjectSignal(QDumper &d)
const ConnectionList &connList = qConnectionList(ob, signalNumber);
for (int i = 0; i != connList.size(); ++i) {
const Connection &conn = connectionAt(connList, i);
- d.beginHash();
- d.beginItem("name");
- d.put(i).put(" receiver");
- d.endItem();
- qDumpInnerValueHelper(d, NS"QObject *", conn.receiver);
- d.endHash();
+ qDumpQObjectConnectionPart(d, ob, conn.receiver, i, " receiver");
d.beginHash();
d.beginItem("name");
d.put(i).put(" slot");
@@ -2129,14 +2373,17 @@ static void qDumpQObjectSignalList(QDumper &d)
const QObject *ob = reinterpret_cast<const QObject *>(d.data);
const QMetaObject *mo = ob->metaObject();
int count = 0;
- for (int i = mo->methodCount(); --i >= 0; )
+ const int methodCount = mo->methodCount();
+ for (int i = methodCount; --i >= 0; )
count += (mo->method(i).methodType() == QMetaMethod::Signal);
+ d.putItem("type", "QObjectSignalList");
+ d.putItemCount("value", count);
d.putItem("addr", d.data);
d.putItem("numchild", count);
#if QT_VERSION >= 0x040400
if (d.dumpChildren) {
d.beginChildren();
- for (int i = 0; i != mo->methodCount(); ++i) {
+ for (int i = 0; i != methodCount; ++i) {
const QMetaMethod & method = mo->method(i);
if (method.methodType() == QMetaMethod::Signal) {
int k = mo->indexOfSignal(method.signature());
@@ -2145,10 +2392,7 @@ static void qDumpQObjectSignalList(QDumper &d)
d.putItem("name", k);
d.putItem("value", method.signature());
d.putItem("numchild", connList.size());
- //d.putItem("numchild", "1");
- d.beginItem("exp");
- d.put("*(class '"NS"QObject'*)").put(d.data);
- d.endItem();
+ d.putItem("addr", d.data);
d.putItem("type", NS"QObjectSignal");
d.endHash();
}
@@ -2182,12 +2426,7 @@ static void qDumpQObjectSlot(QDumper &d)
if (conn.receiver == ob && conn.method == slotNumber) {
++numchild;
const QMetaMethod &method = sender->metaObject()->method(signal);
- d.beginHash();
- d.beginItem("name");
- d.put(s).put(" sender");
- d.endItem();
- qDumpInnerValueHelper(d, NS"QObject *", sender);
- d.endHash();
+ qDumpQObjectConnectionPart(d, ob, sender, s, " sender");
d.beginHash();
d.beginItem("name");
d.put(s).put(" signal");
@@ -2226,14 +2465,17 @@ static void qDumpQObjectSlotList(QDumper &d)
const QMetaObject *mo = ob->metaObject();
int count = 0;
- for (int i = mo->methodCount(); --i >= 0; )
+ const int methodCount = mo->methodCount();
+ for (int i = methodCount; --i >= 0; )
count += (mo->method(i).methodType() == QMetaMethod::Slot);
d.putItem("numchild", count);
+ d.putItemCount("value", count);
+ d.putItem("type", NS"QObjectSlotList");
if (d.dumpChildren) {
d.beginChildren();
#if QT_VERSION >= 0x040400
- for (int i = 0; i != mo->methodCount(); ++i) {
+ for (int i = 0; i != methodCount; ++i) {
const QMetaMethod & method = mo->method(i);
if (method.methodType() == QMetaMethod::Slot) {
d.beginHash();
@@ -2254,9 +2496,7 @@ static void qDumpQObjectSlotList(QDumper &d)
}
}
d.putItem("numchild", numchild);
- d.beginItem("exp");
- d.put("*(class '"NS"QObject'*)").put(d.data);
- d.endItem();
+ d.putItem("addr", d.data);
d.putItem("type", NS"QObjectSlot");
d.endHash();
}
@@ -2267,6 +2507,27 @@ static void qDumpQObjectSlotList(QDumper &d)
d.disarm();
}
+static void qDumpQObjectChildList(QDumper &d)
+{
+ const QObject *ob = reinterpret_cast<const QObject *>(d.data);
+ const QObjectList children = ob->children();
+ const int size = children.size();
+
+ d.putItem("numchild", size);
+ d.putItemCount("value", size);
+ d.putItem("type", NS"QObjectChildList");
+ if (d.dumpChildren) {
+ d.beginChildren();
+ for (int i = 0; i != size; ++i) {
+ d.beginHash();
+ d.putItem("name", i);
+ qDumpInnerValueHelper(d, NS"QObject *", children.at(i));
+ d.endHash();
+ }
+ d.endChildren();
+ }
+ d.disarm();
+}
#if USE_QT_GUI
static void qDumpQPixmap(QDumper &d)
@@ -2442,89 +2703,6 @@ static void qDumpQTextCodec(QDumper &d)
d.disarm();
}
-static void qDumpQVariantHelper(const void *data, QString *value,
- QString *exp, int *numchild)
-{
- const QVariant &v = *reinterpret_cast<const QVariant *>(data);
- switch (v.type()) {
- case QVariant::Invalid:
- *value = QLatin1String("<invalid>");
- *numchild = 0;
- break;
- case QVariant::String:
- *value = QLatin1Char('"') + v.toString() + QLatin1Char('"');
- *numchild = 0;
- break;
- #if QT_VERSION >= 0x040500
- case QVariant::StringList:
- *exp = QString(QLatin1String("(*('"NS"QStringList'*)%1)"))
- .arg((quintptr)data);
- *numchild = v.toStringList().size();
- break;
- #endif
- case QVariant::Int:
- *value = QString::number(v.toInt());
- *numchild= 0;
- break;
- case QVariant::Double:
- *value = QString::number(v.toDouble());
- *numchild = 0;
- break;
- default: {
- char buf[1000];
- const char *format = (v.typeName()[0] == 'Q')
- ? "'"NS"%s "NS"qVariantValue<"NS"%s >'(*('"NS"QVariant'*)%p)"
- : "'%s "NS"qVariantValue<%s >'(*('"NS"QVariant'*)%p)";
- qsnprintf(buf, sizeof(buf) - 1, format, v.typeName(), v.typeName(), data);
- *exp = QLatin1String(buf);
- *numchild = 1;
- break;
- }
- }
-}
-
-static void qDumpQVariant(QDumper &d)
-{
- const QVariant &v = *reinterpret_cast<const QVariant *>(d.data);
- QString value;
- QString exp;
- int numchild = 0;
- qDumpQVariantHelper(d.data, &value, &exp, &numchild);
- bool isInvalid = (v.typeName() == 0);
- if (isInvalid) {
- d.putItem("value", "(invalid)");
- } else if (value.isEmpty()) {
- d.beginItem("value");
- d.put("(").put(v.typeName()).put(") ");
- d.endItem();
- } else {
- QByteArray ba;
- ba += '(';
- ba += v.typeName();
- ba += ") ";
- ba += qPrintable(value);
- d.putItem("value", ba);
- d.putItem("valueencoded", "5");
- }
- d.putItem("type", NS"QVariant");
- d.putItem("numchild", (isInvalid ? "0" : "1"));
- if (d.dumpChildren) {
- d.beginChildren();
- d.beginHash();
- d.putItem("name", "value");
- if (!exp.isEmpty())
- d.putItem("exp", qPrintable(exp));
- if (!value.isEmpty()) {
- d.putItem("value", value);
- d.putItem("valueencoded", "4");
- }
- d.putItem("type", v.typeName());
- d.putItem("numchild", numchild);
- d.endHash();
- d.endChildren();
- }
- d.disarm();
-}
static void qDumpQVector(QDumper &d)
{
@@ -2547,6 +2725,7 @@ static void qDumpQVector(QDumper &d)
d.putItemCount("value", n);
d.putItem("valuedisabled", "true");
d.putItem("numchild", n);
+ InnerValueResult innerValueResult = InnerValueChildrenSpecified;
if (d.dumpChildren) {
QByteArray strippedInnerType = stripPointerType(d.innertype);
const char *stripped =
@@ -2557,7 +2736,7 @@ static void qDumpQVector(QDumper &d)
for (int i = 0; i != n; ++i) {
d.beginHash();
d.putItem("name", i);
- qDumpInnerValueOrPointer(d, d.innertype, stripped,
+ innerValueResult = qDumpInnerValueOrPointer(d, d.innertype, stripped,
addOffset(v, i * innersize + typeddatasize));
d.endHash();
}
@@ -2565,6 +2744,7 @@ static void qDumpQVector(QDumper &d)
d.putEllipsis();
d.endChildren();
}
+ dumpChildNumChildren(d, innerValueResult);
d.disarm();
}
@@ -2633,7 +2813,8 @@ static void qDumpStdList(QDumper &d)
#endif
int nn = 0;
std::list<int>::const_iterator it = list.begin();
- for (; nn < 101 && it != list.end(); ++nn, ++it)
+ const std::list<int>::const_iterator cend = list.end();
+ for (; nn < 101 && it != cend; ++nn, ++it)
qCheckAccess(it.operator->());
if (nn > 100)
@@ -2643,22 +2824,24 @@ static void qDumpStdList(QDumper &d)
d.putItem("numchild", nn);
d.putItem("valuedisabled", "true");
+ InnerValueResult innerValueResult = InnerValueChildrenSpecified;
if (d.dumpChildren) {
QByteArray strippedInnerType = stripPointerType(d.innertype);
const char *stripped =
isPointerType(d.innertype) ? strippedInnerType.data() : 0;
d.beginChildren();
it = list.begin();
- for (int i = 0; i < 1000 && it != list.end(); ++i, ++it) {
+ for (int i = 0; i < 1000 && it != cend; ++i, ++it) {
d.beginHash();
d.putItem("name", i);
- qDumpInnerValueOrPointer(d, d.innertype, stripped, it.operator->());
+ innerValueResult = qDumpInnerValueOrPointer(d, d.innertype, stripped, it.operator->());
d.endHash();
}
if (it != list.end())
d.putEllipsis();
d.endChildren();
}
+ dumpChildNumChildren(d, innerValueResult);
d.disarm();
}
@@ -2744,7 +2927,8 @@ static void qDumpStdSet(QDumper &d)
if (nn < 0)
return;
DummyType::const_iterator it = set.begin();
- for (int i = 0; i < nn && i < 10 && it != set.end(); ++i, ++it)
+ const DummyType::const_iterator cend = set.end();
+ for (int i = 0; i < nn && i < 10 && it != cend; ++i, ++it)
qCheckAccess(it.operator->());
d.putItemCount("value", nn);
@@ -2752,6 +2936,7 @@ static void qDumpStdSet(QDumper &d)
d.putItem("numchild", nn);
d.putItem("valueoffset", d.extraInt[0]);
+ InnerValueResult innerValueResult = InnerValueChildrenSpecified;
if (d.dumpChildren) {
int valueOffset = 0; // d.extraInt[0];
QByteArray strippedInnerType = stripPointerType(d.innertype);
@@ -2764,17 +2949,18 @@ static void qDumpStdSet(QDumper &d)
d.beginChildren();
it = set.begin();
- for (int i = 0; i < 1000 && it != set.end(); ++i, ++it) {
+ for (int i = 0; i < 1000 && it != cend; ++i, ++it) {
const void *node = it.operator->();
d.beginHash();
d.putItem("name", i);
- qDumpInnerValueOrPointer(d, d.innertype, stripped, node);
+ innerValueResult = qDumpInnerValueOrPointer(d, d.innertype, stripped, node);
d.endHash();
}
if (it != set.end())
d.putEllipsis();
d.endChildren();
}
+ dumpChildNumChildren(d, innerValueResult);
d.disarm();
}
@@ -2838,6 +3024,7 @@ static void qDumpStdVector(QDumper &d)
d.putItemCount("value", n);
d.putItem("valuedisabled", "true");
d.putItem("numchild", n);
+ InnerValueResult innerValueResult = InnerValueChildrenSpecified;
if (d.dumpChildren) {
unsigned innersize = d.extraInt[0];
QByteArray strippedInnerType = stripPointerType(d.innertype);
@@ -2857,6 +3044,7 @@ static void qDumpStdVector(QDumper &d)
d.putEllipsis();
d.endChildren();
}
+ dumpChildNumChildren(d, innerValueResult);
d.disarm();
}
@@ -2974,6 +3162,8 @@ static void handleProtocolVersion2and3(QDumper & d)
qDumpQObject(d);
else if (isEqual(type, "QObjectPropertyList"))
qDumpQObjectPropertyList(d);
+ else if (isEqual(type, "QObjectProperty"))
+ qDumpQObjectProperty(d);
else if (isEqual(type, "QObjectMethodList"))
qDumpQObjectMethodList(d);
else if (isEqual(type, "QObjectSignal"))
@@ -2984,6 +3174,8 @@ static void handleProtocolVersion2and3(QDumper & d)
qDumpQObjectSlot(d);
else if (isEqual(type, "QObjectSlotList"))
qDumpQObjectSlotList(d);
+ else if (isEqual(type, "QObjectChildList"))
+ qDumpQObjectChildList(d);
break;
case 'P':
#if USE_QT_GUI
@@ -3125,11 +3317,13 @@ void *qDumpObjectData440(
"\""NS"QModelIndex\","
"\""NS"QObject\","
"\""NS"QObjectMethodList\"," // hack to get nested properties display
+ "\""NS"QObjectProperty\","
"\""NS"QObjectPropertyList\","
"\""NS"QObjectSignal\","
"\""NS"QObjectSignalList\","
"\""NS"QObjectSlot\","
"\""NS"QObjectSlotList\","
+ "\""NS"QObjectChildList\","
//"\""NS"QRegion\","
"\""NS"QSet\","
"\""NS"QString\","
@@ -3166,7 +3360,7 @@ void *qDumpObjectData440(
"\"").put(((QT_VERSION >> 16) & 255)).put("\","
"\"").put(((QT_VERSION >> 8) & 255)).put("\","
"\"").put(((QT_VERSION) & 255)).put("\"]");
- d.put(",namespace=\""NS"\",");
+ d.put(",dumperversion=\"1.3\",");
// Dump out size information
d.put("sizes={");
d.put("int=\"").put(sizeof(int)).put("\",")
diff --git a/share/qtcreator/gdbmacros/test/dumpertest.pro b/share/qtcreator/gdbmacros/test/dumpertest.pro
index 7b5fd3e582a..ddac946a12a 100644
--- a/share/qtcreator/gdbmacros/test/dumpertest.pro
+++ b/share/qtcreator/gdbmacros/test/dumpertest.pro
@@ -4,8 +4,6 @@
#
#-------------------------------------------------
-QT -= gui
-
TARGET = dumpertest
CONFIG += console
CONFIG -= app_bundle
diff --git a/share/qtcreator/gdbmacros/test/main.cpp b/share/qtcreator/gdbmacros/test/main.cpp
index eca00156df3..0ec31578b0e 100644
--- a/share/qtcreator/gdbmacros/test/main.cpp
+++ b/share/qtcreator/gdbmacros/test/main.cpp
@@ -32,6 +32,8 @@
#include <QtCore/QSharedPointer>
#include <QtCore/QTimer>
#include <QtCore/QMap>
+#include <QtCore/QVariant>
+#include <QtGui/QAction>
#include <string>
#include <list>
@@ -174,6 +176,20 @@ static int dumpQMapIntString()
return 0;
}
+static int dumpQVariant()
+{
+ QVariant test(QLatin1String("item"));
+ prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", "");
+ qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0);
+ fputs(qDumpOutBuffer, stdout);
+ fputs("\n\n", stdout);
+ test = QVariant(QStringList(QLatin1String("item1")));
+ prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", "");
+ qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0);
+ fputs(qDumpOutBuffer, stdout);
+ return 0;
+}
+
// --------------- std types
static int dumpStdString()
@@ -309,76 +325,127 @@ static int dumpStdMapIntString()
static int dumpQObject()
{
// Requires the childOffset to be know, but that is not critical
- QTimer t;
+ QAction action(0);
+ QObject x;
+ QAction *a2= new QAction(&action);
+ a2->setObjectName(QLatin1String("a2"));
+ action.setObjectName(QLatin1String("action"));
+ QObject::connect(&action, SIGNAL(triggered()), &x, SLOT(deleteLater()));
prepareInBuffer("QObject", "local.qobject", "local.qobject", "");
- qDumpObjectData440(2, 42, testAddress(&t), 1, 0, 0, 0, 0);
+ qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
+ fputs(qDumpOutBuffer, stdout);
+ fputs("\n\n", stdout);
+ // Property list
+ prepareInBuffer("QObjectPropertyList", "local.qobjectpropertylist", "local.qobjectpropertylist", "");
+ qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
+ fputs(qDumpOutBuffer, stdout);
+ fputs("\n\n", stdout);
+ // Signal list
+ prepareInBuffer("QObjectSignalList", "local.qobjectsignallist", "local.qobjectsignallist", "");
+ qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
+ fputs(qDumpOutBuffer, stdout);
+ // Slot list
+ prepareInBuffer("QObjectSlotList", "local.qobjectslotlist", "local.qobjectslotlist", "");
+ qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
+ fputs(qDumpOutBuffer, stdout);
+ fputs("\n\n", stdout);
+ // Signal list
+ prepareInBuffer("QObjectChildList", "local.qobjectchildlist", "local.qobjectchildlist", "");
+ qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
+ fputs(qDumpOutBuffer, stdout);
+ return 0;
+}
+
+static int dumpQObjectList()
+{
+ // Requires the childOffset to be know, but that is not critical
+ QObject *root = new QObject;
+ root ->setObjectName("root");
+ QTimer *t1 = new QTimer;
+ t1 ->setObjectName("t1");
+ QTimer *t2 = new QTimer;
+ t2 ->setObjectName("t2");
+ QObjectList test;
+ test << root << t1 << t2;
+ prepareInBuffer("QList", "local.qobjectlist", "local.qobjectlist", "QObject *");
+ qDumpObjectData440(2, 42, testAddress(&test), sizeof(QObject*), 0, 0, 0, 0);
fputs(qDumpOutBuffer, stdout);
fputc('\n', stdout);
+ delete root;
return 0;
}
-static bool dumpType(const char *arg)
+typedef int (*DumpFunction)();
+typedef QMap<QString, DumpFunction> TypeDumpFunctionMap;
+
+static TypeDumpFunctionMap registerTypes()
{
- if (!qstrcmp(arg, "QString"))
- { dumpQString(); return true; }
- if (!qstrcmp(arg, "QSharedPointer<QString>"))
- { dumpQSharedPointerQString(); return true; }
- if (!qstrcmp(arg, "QStringList"))
- { dumpQStringList(); return true; }
- if (!qstrcmp(arg, "QList<int>"))
- { dumpQIntList(); return true; }
- if (!qstrcmp(arg, "QList<std::string>"))
- { dumpStdStringQList(); return true; }
- if (!qstrcmp(arg, "QVector<int>"))
- { dumpQIntVector(); return true; }
- if (!qstrcmp(arg, "QMap<int,QString>"))
- { dumpQMapIntString(); return true; }
- if (!qstrcmp(arg, "QMap<int,int>"))
- { dumpQMapIntInt(); return true; }
- if (!qstrcmp(arg, "string"))
- { dumpStdString(); return true; }
- if (!qstrcmp(arg, "wstring"))
- { dumpStdWString(); return true; }
- if (!qstrcmp(arg, "list<int>"))
- { dumpStdIntList(); return true; }
- if (!qstrcmp(arg, "list<string>"))
- { dumpStdStringList(); return true; }
- if (!qstrcmp(arg, "vector<int>"))
- { dumpStdIntVector(); return true; }
- if (!qstrcmp(arg, "vector<string>"))
- { dumpStdStringVector(); return true; }
- if (!qstrcmp(arg, "vector<wstring>"))
- { dumpStdWStringVector(); return true; }
- if (!qstrcmp(arg, "set<int>"))
- { dumpStdIntSet(); return true; }
- if (!qstrcmp(arg, "set<string>"))
- { dumpStdStringSet(); return true; }
- if (!qstrcmp(arg, "map<int,string>"))
- { dumpStdMapIntString(); return true; }
- if (!qstrcmp(arg, "QObject"))
- { dumpQObject(); return true; }
- return false;
+ TypeDumpFunctionMap rc;
+ rc.insert("QString", dumpQString);
+ rc.insert("QSharedPointer<QString>", dumpQSharedPointerQString);
+ rc.insert("QStringList", dumpQStringList);
+ rc.insert("QList<int>", dumpQIntList);
+ rc.insert("QList<std::string>", dumpStdStringQList);
+ rc.insert("QVector<int>", dumpQIntVector);
+ rc.insert("QMap<int,QString>", dumpQMapIntString);
+ rc.insert("QMap<int,int>", dumpQMapIntInt);
+ rc.insert("string", dumpStdString);
+ rc.insert("wstring", dumpStdWString);
+ rc.insert("list<int>", dumpStdIntList);
+ rc.insert("list<string>", dumpStdStringList);
+ rc.insert("vector<int>", dumpStdIntVector);
+ rc.insert("vector<string>", dumpStdStringVector);
+ rc.insert("vector<wstring>", dumpStdWStringVector);
+ rc.insert("set<int>", dumpStdIntSet);
+ rc.insert("set<string>", dumpStdStringSet);
+ rc.insert("map<int,string>", dumpStdMapIntString);
+ rc.insert("QObject", dumpQObject);
+ rc.insert("QObjectList", dumpQObjectList);
+ rc.insert("QVariant", dumpQVariant);
+ return rc;
}
int main(int argc, char *argv[])
{
+ printf("\nQt Creator Debugging Helper testing tool\n\n");
printf("Running query protocol\n");
qDumpObjectData440(1, 42, 0, 1, 0, 0, 0, 0);
fputs(qDumpOutBuffer, stdout);
fputc('\n', stdout);
fputc('\n', stdout);
- if (argc < 2)
+
+ const TypeDumpFunctionMap tdm = registerTypes();
+ const TypeDumpFunctionMap::const_iterator cend = tdm.constEnd();
+
+ if (argc < 2) {
+ printf("Usage: %s [-a]|<type1> <type2..>\n", argv[0]);
+ printf("Supported types: ");
+ for (TypeDumpFunctionMap::const_iterator it = tdm.constBegin(); it != cend; ++it) {
+ fputs(qPrintable(it.key()), stdout);
+ fputc(' ', stdout);
+ }
+ fputc('\n', stdout);
return 0;
- for (int i = 1; i < argc; i++) {
- const char *arg = argv[i];
- if (!strcmp(arg, "-u")) {
- optTestUninitialized = true;
- printf("\nTesting uninitialized...\n");
- continue;
+ }
+
+ int rc = 0;
+ if (argc == 2 && !qstrcmp(argv[1], "-a")) {
+ for (TypeDumpFunctionMap::const_iterator it = tdm.constBegin(); it != cend; ++it) {
+ printf("\nTesting: %s\n", qPrintable(it.key()));
+ rc += (*it.value())();
+ }
+ } else {
+ for (int i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+ printf("\nTesting: %s\n", arg);
+ const TypeDumpFunctionMap::const_iterator it = tdm.constFind(QLatin1String(arg));
+ if (it == cend) {
+ rc = -1;
+ fprintf(stderr, "\nUnhandled type: %s\n", argv[i]);
+ } else {
+ rc = (*it.value())();
+ }
}
- printf("\nTesting %s\n", arg);
- if (!dumpType(arg))
- printf("\nUnhandled type: %s\n", arg);
}
- return 0;
+ return rc;
}
diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp
index bedf02dd41e..b4cd0bff6c7 100644
--- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp
+++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp
@@ -561,6 +561,10 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool
*errorMessage = msgNotHandled(wd.type);
return DumpNotHandled;
}
+ if (wd.addr.isEmpty()) {
+ *errorMessage = QString::fromLatin1("Adress is missing for '%1' (%2).").arg(wd.exp, wd.type);
+ return DumpNotHandled;
+ }
// Ensure types are parsed and known.
if (!ensureInitialized(errorMessage)) {
diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
index 870ba8f262f..f68beb0db3c 100644
--- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
@@ -35,6 +35,7 @@
#include "watchhandler.h"
#include <QtCore/QDebug>
+#include <QtCore/QCoreApplication>
namespace Debugger {
namespace Internal {
@@ -164,6 +165,46 @@ bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QSt
return handled;
}
+// When querying an item, the queried item is sometimes returned in incomplete form.
+// Take over values from source.
+static inline void fixDumperResult(const WatchData &source,
+ QList<WatchData> *result,
+ bool suppressGrandChildren)
+{
+ const int size = result->size();
+ if (!size)
+ return;
+ WatchData &returned = result->front();
+ if (returned.iname != source.iname)
+ return;
+ if (returned.type.isEmpty())
+ returned.setType(source.type);
+ if (returned.isValueNeeded()) {
+ if (source.isValueKnown()) {
+ returned.setValue(source.value);
+ } else {
+ // Should not happen
+ returned.setValue(QCoreApplication::translate("CdbStackFrameContext", "<Unknown>"));
+ }
+ }
+ if (size == 1)
+ return;
+ // Fix the children: If the address is missing, we cannot query any further.
+ const QList<WatchData>::iterator wend = result->end();
+ QList<WatchData>::iterator it = result->begin();
+ for (++it; it != wend; ++it) {
+ WatchData &wd = *it;
+ if (wd.addr.isEmpty() && wd.isSomethingNeeded()) {
+ wd.setAllUnneeded();
+ } else {
+ // Hack: Suppress endless recursion of the model. To be fixed,
+ // the model should not query non-visible items.
+ if (suppressGrandChildren && (wd.isChildrenNeeded() || wd.isHasChildrenNeeded()))
+ wd.setHasChildren(false);
+ }
+ }
+}
+
WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd)
{
if (debugCDBWatchHandling)
@@ -180,9 +221,7 @@ WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd)
if (debugCDBWatchHandling)
qDebug() << "dumper triggered";
// Dumpers omit types for complicated templates
- if (!m_dumperResult.isEmpty() && m_dumperResult.front().type.isEmpty()
- && m_dumperResult.front().iname == wd.iname)
- m_dumperResult.front().setType(wd.type);
+ fixDumperResult(wd, &m_dumperResult, false);
// Discard the original item and insert the dumper results
foreach(const WatchData &dwd, m_dumperResult)
m_wh->insertData(dwd);
@@ -254,12 +293,17 @@ bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal,
QList<WatchData> dumperResult;
const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(incompleteLocal, true, OwnerDumper, &dumperResult, errorMessage);
if (dr == CdbDumperHelper::DumpOk) {
+ // Hack to stop endless model recursion
+ const bool suppressGrandChildren = !wh->isExpandedIName(incompleteLocal.iname);
+ fixDumperResult(incompleteLocal, &dumperResult, suppressGrandChildren);
foreach(const WatchData &dwd, dumperResult)
wh->insertData(dwd);
} else {
const QString msg = QString::fromLatin1("Unable to further expand dumper watch data: '%1' (%2): %3/%4").arg(incompleteLocal.name, incompleteLocal.type).arg(int(dr)).arg(*errorMessage);
qWarning("%s", qPrintable(msg));
WatchData wd = incompleteLocal;
+ if (wd.isValueNeeded())
+ wd.setValue(QCoreApplication::translate("CdbStackFrameContext", "<Unknown>"));
wd.setAllUnneeded();
wh->insertData(wd);
}
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index b564a5468a7..597b12ebd19 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -3192,24 +3192,36 @@ void GdbEngine::handleQueryDebuggingHelper(const GdbResultRecord &record, const
//qDebug() << m_availableSimpleDebuggingHelpers << "DATA DUMPERS AVAILABLE";
}
-void GdbEngine::sendWatchParameters(const QByteArray &params0)
+static inline QString arrayFillCommand(const char *array, const QByteArray &params)
{
- QByteArray params = params0;
- params.append('\0');
char buf[50];
- sprintf(buf, "set {char[%d]} &qDumpInBuffer = {", params.size());
+ sprintf(buf, "set {char[%d]} &%s = {", params.size(), array);
QByteArray encoded;
encoded.append(buf);
- for (int i = 0; i != params.size(); ++i) {
+ const int size = params.size();
+ for (int i = 0; i != size; ++i) {
sprintf(buf, "%d,", int(params[i]));
encoded.append(buf);
}
encoded[encoded.size() - 1] = '}';
+ return _(encoded);
+}
+
+void GdbEngine::sendWatchParameters(const QByteArray &params0)
+{
+ QByteArray params = params0;
+ params.append('\0');
+ const QString inBufferCmd = arrayFillCommand("qDumpInBuffer", params);
params.replace('\0','!');
emit gdbInputAvailable(LogMisc, QString::fromUtf8(params));
- postCommand(_(encoded));
+ params.clear();
+ params.append('\0');
+ const QString outBufferCmd = arrayFillCommand("qDumpOutBuffer", params);
+
+ postCommand(inBufferCmd);
+ postCommand(outBufferCmd);
}
void GdbEngine::handleVarAssign(const GdbResultRecord &, const QVariant &)
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index 30eb77478b0..a5e188ed3c9 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -209,6 +209,8 @@ QString WatchData::toString() const
QTextStream str(&res);
if (!iname.isEmpty())
str << "iname=\"" << iname << doubleQuoteComma;
+ if (!addr.isEmpty())
+ str << "addr=\"" << addr << doubleQuoteComma;
if (!exp.isEmpty())
str << "exp=\"" << exp << doubleQuoteComma;
@@ -780,6 +782,7 @@ static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *i
void WatchModel::insertData(const WatchData &data)
{
+ // qDebug() << "WMI:" << data.toString();
QTC_ASSERT(!data.iname.isEmpty(), return);
WatchItem *parent = findItem(parentName(data.iname), m_root);
if (!parent) {
diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp
index 5ef9523ed45..555b6ac6cd4 100644
--- a/src/plugins/debugger/watchutils.cpp
+++ b/src/plugins/debugger/watchutils.cpp
@@ -470,16 +470,19 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos,
QtDumperResult::Child::Child() :
keyEncoded(0),
valueEncoded(0),
- childCount(0),
- valuedisabled(false)
+ childCount(-1),
+ valuedisabled(false),
+ valueEncountered(false)
{
}
QtDumperResult::QtDumperResult() :
+ valueEncountered(false),
valueEncoded(0),
valuedisabled(false),
- childCount(0),
- internal(false)
+ childCount(-1),
+ internal(false),
+ childChildCount(-1)
{
}
@@ -488,15 +491,17 @@ void QtDumperResult::clear()
iname.clear();
value.clear();
address.clear();
+ addressInfo.clear();
type.clear();
extra.clear();
displayedType.clear();
valueEncoded = 0;
- valuedisabled = false;
- childCount = 0;
+ valueEncountered = valuedisabled = false;
+ childCount = -1;
internal = false;
childType.clear();
children.clear();
+ childChildCount = -1;
}
QList<WatchData> QtDumperResult::toWatchData(int source) const
@@ -508,45 +513,70 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
const QChar dot = QLatin1Char('.');
const int lastDotIndex = root.iname.lastIndexOf(dot);
root.exp = root.name = lastDotIndex == -1 ? iname : iname.mid(lastDotIndex + 1);
- root.setValue(decodeData(value, valueEncoded));
+ if (valueEncountered) {
+ root.setValue(decodeData(value, valueEncoded));
+ root.valuedisabled = valuedisabled;
+ }
root.setType(displayedType.isEmpty() ? type : displayedType);
- root.valuedisabled = valuedisabled;
root.setAddress(address);
root.source = source;
- root.setHasChildren(childCount > 0);
- // Children
- if (childCount > 0) {
- if (children.size() == childCount) {
- for (int c = 0; c < childCount; c++) {
- const Child &dchild = children.at(c);
- rc.push_back(WatchData());
- WatchData &wchild = rc.back();
- wchild.source = source;
- wchild.iname = iname;
- wchild.iname += dot;
- wchild.iname += dchild.name;
- // Use key entry as name (which is used for map nodes)
- if (dchild.key.isEmpty()) {
- wchild.name = dchild.name;
- } else {
- wchild.name = decodeData(dchild.key, dchild.keyEncoded);
- if (wchild.name.size() > 13) {
- wchild.name.truncate(12);
- wchild.name += QLatin1String("...");
- }
+ if (childCount >= 0)
+ root.setHasChildren(childCount > 0);
+ // Children. Sanity check after parsing sets childcount to list size
+ // if list is not empty
+ if (children.empty()) {
+ if (childCount > 0)
+ root.setChildrenNeeded();
+ } else {
+ root.setChildrenUnneeded();
+ for (int c = 0; c < childCount; c++) {
+ const Child &dchild = children.at(c);
+ rc.push_back(WatchData());
+ WatchData &wchild = rc.back();
+ wchild.source = source;
+ wchild.iname = iname;
+ wchild.iname += dot;
+ wchild.iname += dchild.name;
+ // Use key entry as name (which is used for map nodes)
+ if (dchild.key.isEmpty()) {
+ wchild.name = dchild.name;
+ } else {
+ wchild.name = decodeData(dchild.key, dchild.keyEncoded);
+ if (wchild.name.size() > 13) {
+ wchild.name.truncate(12);
+ wchild.name += QLatin1String("...");
}
- wchild.exp = dchild.exp;
+ }
+ wchild.exp = dchild.exp;
+ if (dchild.valueEncountered) {
wchild.valuedisabled = dchild.valuedisabled;
- wchild.setType(dchild.type.isEmpty() ? childType : dchild.type);
- wchild.setAddress(dchild.address);
wchild.setValue(decodeData(dchild.value, dchild.valueEncoded));
+ }
+ wchild.setType(dchild.type.isEmpty() ? childType : dchild.type);
+ wchild.setAddress(dchild.address);
+ // Child overrides.
+ const int effectiveChildChildCount = dchild.childCount == -1 ? childChildCount : dchild.childCount;
+ switch (effectiveChildChildCount) {
+ case -1:
+ wchild.setChildrenNeeded();
+ wchild.setHasChildrenNeeded();
+ break;
+ case 0:
wchild.setHasChildren(false);
+ break;
+ default:
+ wchild.setHasChildren(true);
+ break;
}
- root.setChildrenUnneeded();
- } else {
- root.setChildrenNeeded();
}
}
+ if (debug) {
+ QDebug nospace = qDebug().nospace();
+ nospace << "QtDumperResult::toWatchData" << *this << '\n';
+ foreach(const WatchData &wd, rc)
+ nospace << " " << wd.toString() << '\n';
+ }
+
return rc;
}
@@ -554,11 +584,20 @@ QDebug operator<<(QDebug in, const QtDumperResult &d)
{
QDebug nospace = in.nospace();
nospace << " iname=" << d.iname << " type=" << d.type << " displayed=" << d.displayedType
- << " address=" << d.address
- << " value=" << d.value
- << " disabled=" << d.valuedisabled
- << " encoded=" << d.valueEncoded << " internal=" << d.internal
+ << " address=" << d.address;
+ if (!d.addressInfo.isEmpty())
+ nospace << " addressInfo=" << d.addressInfo;
+ if (d.valueEncountered) {
+ nospace << " encoded=" << d.valueEncoded
+ << " value=" << d.value
+ << " disabled=" << d.valuedisabled;
+ } else {
+ nospace << " <no value>";
+ }
+ nospace << " childnumchild=" << d.childChildCount
+ << " internal=" << d.internal
<< " extra='" << d.extra << "'\n";
+
const int realChildCount = d.children.size();
if (d.childCount || realChildCount) {
nospace << "childCount=" << d.childCount << '/' << realChildCount
@@ -571,8 +610,12 @@ QDebug operator<<(QDebug in, const QtDumperResult &d)
<< " name=" << c.name;
if (!c.key.isEmpty())
nospace << " keyencoded=" << c.keyEncoded << " key=" << c.key;
- nospace << " valueencoded=" << c.valueEncoded << " value=" << c.value
- << "childcount=" << c.childCount << '\n';
+ if (c.valueEncountered) {
+ nospace << " valueencoded=" << c.valueEncoded << " value=" << c.value;
+ } else {
+ nospace << " <no value>";
+ }
+ nospace << "childcount=" << c.childCount << '\n';
}
}
return in;
@@ -608,6 +651,7 @@ void QtDumperHelper::clear()
m_sizeCache.clear();
qFill(m_specialSizes, m_specialSizes + SpecialSizeCount, 0);
m_expressionCache.clear();
+ m_dumperVersion.clear();
}
static inline void formatQtVersion(int v, QTextStream &str)
@@ -622,7 +666,7 @@ QString QtDumperHelper::toString(bool debug) const
QTextStream str(&rc);
str << "version=";
formatQtVersion(m_qtVersion, str);
- str << " namespace='" << m_qtNamespace << "'," << m_nameTypeMap.size() << " known types <type enum>: ";
+ str << "dumperversion='" << m_dumperVersion << "' namespace='" << m_qtNamespace << "'," << m_nameTypeMap.size() << " known types <type enum>: ";
const NameTypeMap::const_iterator cend = m_nameTypeMap.constEnd();
for (NameTypeMap::const_iterator it = m_nameTypeMap.constBegin(); it != cend; ++it) {
str <<",[" << it.key() << ',' << it.value() << ']';
@@ -639,9 +683,9 @@ QString QtDumperHelper::toString(bool debug) const
}
const QString nameSpace = m_qtNamespace.isEmpty() ? QCoreApplication::translate("QtDumperHelper", "<none>") : m_qtNamespace;
return QCoreApplication::translate("QtDumperHelper",
- "%n known types, Qt version: %1, Qt namespace: %2",
+ "%n known types, Qt version: %1, Qt namespace: %2 Dumper version: %3",
0, QCoreApplication::CodecForTr,
- m_nameTypeMap.size()).arg(qtVersionString(), nameSpace);
+ m_nameTypeMap.size()).arg(qtVersionString(), nameSpace, m_dumperVersion);
}
QtDumperHelper::Type QtDumperHelper::simpleType(const QString &simpleType) const
@@ -726,10 +770,9 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s)
QtDumperHelper::ExpressionRequirement QtDumperHelper::expressionRequirements(Type t)
{
+
switch (t) {
case QAbstractItemType:
- case QObjectSlotType:
- case QObjectSignalType:
case QVectorType:
case StdMapType:
return NeedsComplexExpression;
@@ -738,6 +781,7 @@ QtDumperHelper::ExpressionRequirement QtDumperHelper::expressionRequirements(Typ
case QMapNodeType:
return NeedsCachedExpression;
default:
+ // QObjectSlotType, QObjectSignalType need the signal number, which is numeric
break;
}
return NeedsNoExpression;
@@ -968,9 +1012,9 @@ public:
explicit QueryDumperParser(const char *s);
struct Data {
- Data() : qtVersion(0) {}
QString qtNameSpace;
QString qtVersion;
+ QString dumperVersion;
QStringList types;
QList<SizeEntry> sizes;
QMap<QString, QString> expressionCache;
@@ -986,7 +1030,7 @@ protected:
virtual bool handleValue(const char *k, int size);
private:
- enum Mode { None, ExpectingDumpers, ExpectingVersion,
+ enum Mode { None, ExpectingDumpers, ExpectingQtVersion, ExpectingDumperVersion,
ExpectingNameSpace, ExpectingSizes, ExpectingExpressionCache };
Mode m_mode;
Data m_data;
@@ -1017,7 +1061,11 @@ bool QueryDumperParser::handleKeyword(const char *k, int size)
return true;
}
if (!qstrncmp(k, "qtversion", size)) {
- m_mode = ExpectingVersion;
+ m_mode = ExpectingQtVersion;
+ return true;
+ }
+ if (!qstrncmp(k, "dumperversion", size)) {
+ m_mode = ExpectingDumperVersion;
return true;
}
if (!qstrncmp(k, "namespace", size)) {
@@ -1038,7 +1086,7 @@ bool QueryDumperParser::handleKeyword(const char *k, int size)
bool QueryDumperParser::handleListStart()
{
- return m_mode == ExpectingDumpers || m_mode == ExpectingVersion;
+ return m_mode == ExpectingDumpers || m_mode == ExpectingQtVersion;
}
bool QueryDumperParser::handleListEnd()
@@ -1064,7 +1112,10 @@ bool QueryDumperParser::handleValue(const char *k, int size)
case ExpectingNameSpace:
m_data.qtNameSpace = QString::fromLatin1(k, size);
break;
- case ExpectingVersion: // ["4","1","5"]
+ case ExpectingDumperVersion:
+ m_data.dumperVersion = QString::fromLatin1(k, size);
+ break;
+ case ExpectingQtVersion: // ["4","1","5"]
if (!m_data.qtVersion.isEmpty())
m_data.qtVersion += QLatin1Char('.');
m_data.qtVersion += QString::fromLatin1(k, size);
@@ -1092,6 +1143,7 @@ bool QtDumperHelper::parseQuery(const char *data, Debugger debugger)
foreach (const QueryDumperParser::SizeEntry &se, parser.data().sizes)
addSize(se.first, se.second);
m_expressionCache = parser.data().expressionCache;
+ m_dumperVersion = parser.data().dumperVersion;
return true;
}
@@ -1248,17 +1300,6 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
case QAbstractItemType:
inner = data.addr.mid(1);
break;
- case QObjectType:
- case QWidgetType:
- if (debugger == GdbDebugger) {
- extraArgs[0] = QLatin1String("(char*)&((('");
- extraArgs[0] += m_qtNamespace;
- extraArgs[0] += QLatin1String("QObjectPrivate'*)&");
- extraArgs[0] += data.exp;
- extraArgs[0] += QLatin1String(")->children)-(char*)&");
- extraArgs[0] += data.exp;
- }
- break;
case QVectorType:
extraArgs[1] = QLatin1String("(char*)&((");
extraArgs[1] += data.exp;
@@ -1355,6 +1396,8 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
qWarning("Unknown type encountered in %s.\n", Q_FUNC_INFO);
break;
case SupportedType:
+ case QObjectType:
+ case QWidgetType:
break;
}
@@ -1412,6 +1455,7 @@ private:
ExpectingType, ExpectingDisplayedType, ExpectingInternal,
ExpectingValueDisabled, ExpectingValueEncoded,
ExpectingCommonChildType, ExpectingChildCount,
+ ExpectingChildChildOverrideCount,
ExpectingExtra,
IgnoreNext,
ChildModeStart,
@@ -1488,7 +1532,7 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword
if (!qstrncmp(keyword, "displayedtype", size))
return ExpectingDisplayedType;
if (!qstrncmp(keyword, "childnumchild", size))
- return IgnoreNextChildMode;
+ return ExpectingChildChildOverrideCount;
break;
}
return in > ChildModeStart ? IgnoreNextChildMode : IgnoreNext;
@@ -1519,10 +1563,17 @@ bool ValueDumperParser::handleValue(const char *k, int size)
case ExpectingIName:
m_result.iname = QString::fromLatin1(valueBA);
break;
- case ExpectingAddress:
- m_result.address = QString::fromLatin1(valueBA);
- break;
+ case ExpectingAddress: {
+ const QString address = QString::fromLatin1(valueBA);
+ if (address.startsWith(QLatin1String("0x"))) {
+ m_result.address = address;
+ } else {
+ m_result.addressInfo = address;
+ }
+ }
+ break;
case ExpectingValue:
+ m_result.valueEncountered = true;
m_result.value = valueBA;
break;
case ExpectingValueDisabled:
@@ -1549,6 +1600,9 @@ bool ValueDumperParser::handleValue(const char *k, int size)
case ExpectingChildCount:
m_result.childCount = QString::fromLatin1(valueBA).toInt();
break;
+ case ExpectingChildChildOverrideCount:
+ m_result.childChildCount = QString::fromLatin1(valueBA).toInt();
+ break;
case ExpectingChildren:
case IgnoreNextChildMode:
case IgnoreNext:
@@ -1566,6 +1620,7 @@ bool ValueDumperParser::handleValue(const char *k, int size)
m_result.children.back().key = valueBA;
break;
case ExpectingChildValue:
+ m_result.children.back().valueEncountered = true;
m_result.children.back().value = valueBA;
break;
case ExpectingChildExpression:
@@ -1590,12 +1645,13 @@ bool ValueDumperParser::handleValue(const char *k, int size)
bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r)
{
ValueDumperParser parser(data);
+
if (!parser.run())
return false;
*r = parser.result();
// Sanity
- if (r->childCount < r->children.size())
- r->childCount = r->children.size();
+ if (!r->children.empty() && r->childCount != r->children.size())
+ r->childCount = r->children.size();
if (debug)
qDebug() << '\n' << data << '\n' << *r;
return true;
diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h
index 9d39372aa0e..d1d9b05215f 100644
--- a/src/plugins/debugger/watchutils.h
+++ b/src/plugins/debugger/watchutils.h
@@ -99,6 +99,7 @@ struct QtDumperResult
QString exp;
QString type;
QByteArray key;
+ bool valueEncountered;
QByteArray value;
};
@@ -108,15 +109,18 @@ struct QtDumperResult
QString iname;
QString address;
+ QString addressInfo; // "<synthetic>" or such, in the 2nd adress field.
QString type;
QString extra;
QString displayedType;
+ bool valueEncountered;
QByteArray value;
int valueEncoded;
bool valuedisabled;
int childCount;
bool internal;
QString childType;
+ int childChildCount;
QList <Child> children;
};
@@ -242,6 +246,7 @@ private:
QMap<QString, QString> m_expressionCache;
int m_qtVersion;
+ QString m_dumperVersion;
QString m_qtNamespace;
};