diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index 13017b01baffc5387fddb95328ba21667415152e..5f039321de4045922534ecd47174ed04cb034abe 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -40,6 +40,7 @@ #include <QtCore/QMap> #include <QtCore/QMetaObject> #include <QtCore/QMetaProperty> +#include <QtCore/QMetaEnum> #include <QtCore/QModelIndex> #include <QtCore/QObject> #include <QtCore/QPointer> @@ -1786,9 +1787,8 @@ static void qDumpQMapNode(QDumper &d) d.putItem("value", ""); d.putItem("numchild", 2); + InnerValueResult innerValueResult = InnerValueChildrenSpecified; if (d.dumpChildren) { - //unsigned keySize = d.extraInt[0]; - //unsigned valueSize = d.extraInt[1]; unsigned mapnodesize = d.extraInt[2]; unsigned valueOff = d.extraInt[3]; @@ -1803,11 +1803,11 @@ static void qDumpQMapNode(QDumper &d) d.endHash(); d.beginHash(); d.putItem("name", "value"); - qDumpInnerValue(d, valueType, addOffset(h, valueOffset)); + innerValueResult = qDumpInnerValue(d, valueType, addOffset(h, valueOffset)); d.endHash(); d.endChildren(); } - + dumpChildNumChildren(d, innerValueResult); d.disarm(); } @@ -2163,21 +2163,25 @@ static void qDumpQVariant(QDumper &d, const QVariant *v) 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"); + if (isInvalid || !numchild) { + d.putItem("numchild", "0"); + } else { + d.putItem("numchild", "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.putItem("type", v->typeName()); - d.putItem("numchild", numchild); - d.endHash(); - d.endChildren(); } d.disarm(); } @@ -2187,17 +2191,67 @@ static inline void qDumpQVariant(QDumper &d) qDumpQVariant(d, reinterpret_cast<const QVariant *>(d.data)); } +// Meta enumeration helpers +static inline void dumpMetaEnumType(QDumper &d, const QMetaEnum &me) +{ + QByteArray type = me.scope(); + if (!type.isEmpty()) + type += "::"; + type += me.name(); + d.putItem("type", type.constData()); +} + +static inline void dumpMetaEnumValue(QDumper &d, const QMetaProperty &mop, + int value) +{ + + const QMetaEnum me = mop.enumerator(); + dumpMetaEnumType(d, me); + if (const char *enumValue = me.valueToKey(value)) { + d.putItem("value", enumValue); + } else { + d.putItem("value", value); + } + d.putItem("numchild", 0); +} + +static inline void dumpMetaFlagValue(QDumper &d, const QMetaProperty &mop, + int value) +{ + const QMetaEnum me = mop.enumerator(); + dumpMetaEnumType(d, me); + const QByteArray flagsValue = me.valueToKeys(value); + if (flagsValue.isEmpty()) { + d.putItem("value", value); + } else { + d.putItem("value", flagsValue.constData()); + } + d.putItem("numchild", 0); +} + static void qDumpQObjectProperty(QDumper &d) { const QObject *ob = (const QObject *)d.data; + const QMetaObject *mob = ob->metaObject(); // 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); + const int index = mob->indexOfProperty(iname.toAscii()); + if (index == -1) + return; + const QMetaProperty mop = mob->property(index); + const QVariant value = mop.read(ob); + const bool isInteger = value.type() == QVariant::Int; + if (isInteger && mop.isEnumType()) { + dumpMetaEnumValue(d, mop, value.toInt()); + } else if (isInteger && mop.isFlagType()) { + dumpMetaFlagValue(d, mop, value.toInt()); + } else { + qDumpQVariant(d, &value); + } d.disarm(); } @@ -2229,8 +2283,14 @@ static void qDumpQObjectPropertyList(QDumper &d) d.putItem("numchild", "0"); break; case QVariant::Int: - d.putItem("value", prop.read(ob).toInt()); - d.putItem("numchild", "0"); + if (prop.isEnumType()) { + dumpMetaEnumValue(d, prop, prop.read(ob).toInt()); + } else if (prop.isFlagType()) { + dumpMetaFlagValue(d, prop, prop.read(ob).toInt()); + } else { + d.putItem("value", prop.read(ob).toInt()); + d.putItem("numchild", "0"); + } break; default: d.putItem("addr", d.data); @@ -2312,7 +2372,7 @@ static inline void qDumpQObjectConnectionPart(QDumper &d, d.put(number).put(namePostfix); d.endItem(); if (partner == owner) { - d.putItem("value", "<this>"); + d.putItem("value", QLatin1String("<this>")); d.putItem("valueencoded", "2"); d.putItem("type", owner->metaObject()->className()); d.putItem("numchild", 0); diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp index 12d78c0fc1c2bda8f004379244618371d580b543..098b30c86c580c6ce7baf7a6ee7066ec45bedd98 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -368,16 +368,42 @@ static inline bool isNullPointer(const WatchData &wd) return hexNullPattern.exactMatch(addr); } +// Fix a symbol group value. It is set to the class type for +// expandable classes (type="class std::foo<..>[*]", +// value="std::foo<...>[*]". This is not desired +// as it widens the value column for complex std::template types. +// Remove the inner template type. + +static inline QString removeInnerTemplateType(QString value) +{ + const int firstBracketPos = value.indexOf(QLatin1Char('<')); + const int lastBracketPos = firstBracketPos != -1 ? value.lastIndexOf(QLatin1Char('>')) : -1; + if (lastBracketPos != -1) + value.replace(firstBracketPos + 1, lastBracketPos - firstBracketPos -1, QLatin1String("...")); + return value; +} + +static inline QString fixValue(const QString &value) +{ + if (value.size() < 20 || value.endsWith(QLatin1Char('"'))) + return value; + return removeInnerTemplateType(value); +} + WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const { WatchData wd; wd.iname = symbolINameAt(index); wd.exp = wd.iname; const int lastDelimiterPos = wd.iname.lastIndexOf(m_nameDelimiter); - wd.name = lastDelimiterPos == -1 ? wd.iname : wd.iname.mid(lastDelimiterPos + 1); + // For class hierarchies, we get sometimes complicated std::template types here. + // Remove them for display + wd.name = removeInnerTemplateType(lastDelimiterPos == -1 ? wd.iname : wd.iname.mid(lastDelimiterPos + 1)); wd.addr = hexSymbolOffset(m_symbolGroup, index); - wd.setType(getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, index)); - wd.setValue(getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index).toUtf8()); + const QString type = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, index); + const QString value = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index); + wd.setType(type); + wd.setValue(fixValue(value)); wd.setChildrenNeeded(); // compensate side effects of above setters // Figure out children. The SubElement is only a guess unless the symbol, // is expanded, so, we leave this as a guess for later updates.