diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index 29b6feed765cbde9a846aeae741dd9bbf4135704..156bfc5e3f2ed03ad217c2ad2814f5987f689ca8 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -844,6 +844,26 @@ static void qDumpUnknown(QDumper &d, const char *why = 0) d.disarm(); } +static inline void dumpStdStringValue(QDumper &d, const std::string &str) +{ + d.beginItem("value"); + d.putBase64Encoded(str.c_str(), str.size()); + d.endItem(); + d.putItem("valueencoded", "1"); + d.putItem("type", "std::string"); + d.putItem("numchild", "0"); +} + +static inline void dumpStdWStringValue(QDumper &d, const std::wstring &str) +{ + d.beginItem("value"); + d.putBase64Encoded((const char *)str.c_str(), str.size() * sizeof(wchar_t)); + d.endItem(); + d.putItem("valueencoded", (sizeof(wchar_t) == 2 ? "2" : "3")); + d.putItem("type", "std::wstring"); + d.putItem("numchild", "0"); +} + static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr, const char *field = "value") { @@ -928,6 +948,16 @@ static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr d.putItem(field, *(QString*)addr); } return; + 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> >")) { + dumpStdWStringValue(d, *reinterpret_cast<const std::wstring*>(addr)); + } + return; default: return; } @@ -944,7 +974,6 @@ static void qDumpInnerValue(QDumper &d, const char *type, const void *addr) qDumpInnerValueHelper(d, type, addr); } - static void qDumpInnerValueOrPointer(QDumper &d, const char *type, const char *strippedtype, const void *addr) { @@ -2753,37 +2782,28 @@ static void qDumpStdString(QDumper &d) { const std::string &str = *reinterpret_cast<const std::string *>(d.data); - if (!str.empty()) { + const std::string::size_type size = str.size(); + if (int(size) < 0) + return; + if (size) { qCheckAccess(str.c_str()); - qCheckAccess(str.c_str() + str.size() - 1); + qCheckAccess(str.c_str() + size - 1); } - - d.beginItem("value"); - d.putBase64Encoded(str.c_str(), str.size()); - d.endItem(); - d.putItem("valueencoded", "1"); - d.putItem("type", "std::string"); - d.putItem("numchild", "0"); - + dumpStdStringValue(d, str); d.disarm(); } static void qDumpStdWString(QDumper &d) { const std::wstring &str = *reinterpret_cast<const std::wstring *>(d.data); - - if (!str.empty()) { + const std::wstring::size_type size = str.size(); + if (int(size) < 0) + return; + if (size) { qCheckAccess(str.c_str()); - qCheckAccess(str.c_str() + str.size() - 1); + qCheckAccess(str.c_str() + size - 1); } - - d.beginItem("value"); - d.putBase64Encoded((const char *)str.c_str(), str.size() * sizeof(wchar_t)); - d.endItem(); - d.putItem("valueencoded", (sizeof(wchar_t) == 2 ? "2" : "3")); - d.putItem("type", "std::wstring"); - d.putItem("numchild", "0"); - + dumpStdWStringValue(d, str); d.disarm(); } @@ -3164,6 +3184,8 @@ void *qDumpObjectData440( .put("std::string=\"").put(sizeof(std::string)).put("\",") .put("std::wstring=\"").put(sizeof(std::wstring)).put("\",") .put("std::allocator=\"").put(sizeof(std::allocator<int>)).put("\",") + .put("std::char_traits<char>=\"").put(sizeof(std::char_traits<char>)).put("\",") + .put("std::char_traits<unsigned short>=\"").put(sizeof(std::char_traits<unsigned short>)).put("\",") #if QT_VERSION >= 0x040500 .put(NS"QSharedPointer=\"").put(sizeof(QSharedPointer<int>)).put("\",") .put(NS"QSharedDataPointer=\"").put(sizeof(QSharedDataPointer<QSharedData>)).put("\",") diff --git a/share/qtcreator/gdbmacros/test/main.cpp b/share/qtcreator/gdbmacros/test/main.cpp index fe6c2c6723eebd142c3b812f49bcccaac5cbd72e..eca00156df3ecf9f10b1e1e5c170d9a32389cef6 100644 --- a/share/qtcreator/gdbmacros/test/main.cpp +++ b/share/qtcreator/gdbmacros/test/main.cpp @@ -256,6 +256,18 @@ static int dumpStdStringVector() return 0; } +static int dumpStdWStringVector() +{ + std::vector<std::wstring> test; + test.push_back(L"item1"); + test.push_back(L"item2"); + prepareInBuffer("std::vector", "local.wstringvector", "local.wstringvector", "std::wstring"); + qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(std::wstring), sizeof(std::list<int>::allocator_type), 0, 0); + fputs(qDumpOutBuffer, stdout); + fputc('\n', stdout); + return 0; +} + static int dumpStdIntSet() { std::set<int> test; @@ -335,6 +347,8 @@ static bool dumpType(const char *arg) { 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>")) diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp index 0209a08e2b479df8a9df9f5ee66befe7f5a787e4..bedf02dd41e0368f1e40c032471c391097883c8c 100644 --- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp +++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp @@ -544,12 +544,23 @@ static inline QString msgDumpFailed(const WatchData &wd, const QString *why) return QString::fromLatin1("Unable to dump '%1' (%2): %3").arg(wd.name, wd.type, *why); } +static inline QString msgNotHandled(const QString &type) +{ + return QString::fromLatin1("The type '%1' is not handled.").arg(type); +} + CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool dumpChildren, int source, QList<WatchData> *result, QString *errorMessage) { // Check failure cache and supported types - if (m_state == Disabled || m_failedTypes.contains(wd.type)) + if (m_state == Disabled) { + *errorMessage = QLatin1String("Dumpers are disabled"); return DumpNotHandled; + } + if (m_failedTypes.contains(wd.type)) { + *errorMessage = msgNotHandled(wd.type); + return DumpNotHandled; + } // Ensure types are parsed and known. if (!ensureInitialized(errorMessage)) { @@ -562,8 +573,10 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool const QtDumperHelper::TypeData td = m_helper.typeData(wd.type); if (loadDebug) qDebug() << "dumpType" << wd.type << td; - if (td.type == QtDumperHelper::UnknownType) + if (td.type == QtDumperHelper::UnknownType) { + *errorMessage = msgNotHandled(wd.type); return DumpNotHandled; + } // Now evaluate const QString message = QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp index 9cd7589636e031473725e619439aae54ae12eddb..870ba8f262f2fc4b42ba897e568f7fbc2ecb4cb0 100644 --- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp @@ -257,7 +257,7 @@ bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal, 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); + 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; wd.setAllUnneeded(); diff --git a/src/plugins/debugger/debuggertooltip.cpp b/src/plugins/debugger/debuggertooltip.cpp index 18fa2f7d6f1695d6e903052b34e3bd5fa7bb9a4d..622a8948e872f436d318902503bbfcd1bff757ec 100644 --- a/src/plugins/debugger/debuggertooltip.cpp +++ b/src/plugins/debugger/debuggertooltip.cpp @@ -144,7 +144,7 @@ void ToolTipWidget::done() } void ToolTipWidget::run(const QPoint &point, QAbstractItemModel *model, - const QModelIndex &index, const QString &msg) + const QModelIndex &index, const QString & /* msg */) { move(point); setModel(model); diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index c37938af49278b4a974fe445457153bd43a98443..30eb77478b0ea7cec227020968d26fe9d698d2ed 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -390,9 +390,29 @@ static QString chopConst(QString type) return type; } -QString niceType(QString type) -{ - type.replace('*', '@'); +static inline QRegExp stdStringRegExp(const QString &charType) +{ + QString rc = QLatin1String("basic_string<"); + rc += charType; + rc += QLatin1String(",[ ]?std::char_traits<"); + rc += charType; + rc += QLatin1String(">,[ ]?std::allocator<"); + rc += charType; + rc += QLatin1String("> >"); + const QRegExp re(rc); + Q_ASSERT(re.isValid()); + return re; +} + +QString niceType(const QString typeIn) +{ + static QMap<QString, QString> cache; + const QMap<QString, QString>::const_iterator it = cache.constFind(typeIn); + if (it != cache.constEnd()) { + return it.value(); + } + QString type = typeIn; + type.replace(QLatin1Char('*'), QLatin1Char('@')); for (int i = 0; i < 10; ++i) { int start = type.indexOf("std::allocator<"); @@ -414,33 +434,37 @@ QString niceType(QString type) QString alloc = type.mid(start, pos + 1 - start).trimmed(); QString inner = alloc.mid(15, alloc.size() - 16).trimmed(); - if (inner == QLatin1String("char")) - // std::string - type.replace(QLatin1String("basic_string<char, std::char_traits<char>, " - "std::allocator<char> >"), QLatin1String("string")); - else if (inner == QLatin1String("wchar_t")) - // std::wstring - type.replace(QLatin1String("basic_string<wchar_t, std::char_traits<wchar_t>, " - "std::allocator<wchar_t> >"), QLatin1String("wstring")); - + if (inner == QLatin1String("char")) { // std::string + static const QRegExp stringRegexp = stdStringRegExp(inner); + type.replace(stringRegexp, QLatin1String("string")); + } else if (inner == QLatin1String("wchar_t")) { // std::wstring + static const QRegExp wchartStringRegexp = stdStringRegExp(inner); + type.replace(wchartStringRegexp, QLatin1String("wstring")); + } else if (inner == QLatin1String("unsigned short")) { // std::wstring/MSVC + static const QRegExp usStringRegexp = stdStringRegExp(inner); + type.replace(usStringRegexp, QLatin1String("wstring")); + } // std::vector, std::deque, std::list - QRegExp re1(QString("(vector|list|deque)<%1, %2\\s*>").arg(inner, alloc)); + static const QRegExp re1(QString::fromLatin1("(vector|list|deque)<%1,[ ]?%2\\s*>").arg(inner, alloc)); + Q_ASSERT(re1.isValid()); if (re1.indexIn(type) != -1) - type.replace(re1.cap(0), QString("%1<%2>").arg(re1.cap(1), inner)); - + type.replace(re1.cap(0), QString::fromLatin1("%1<%2>").arg(re1.cap(1), inner)); // std::stack - QRegExp re6(QString("stack<%1, std::deque<%2> >").arg(inner, inner)); - re6.setMinimal(true); + static QRegExp re6(QString::fromLatin1("stack<%1,[ ]?std::deque<%2> >").arg(inner, inner)); + if (!re6.isMinimal()) + re6.setMinimal(true); + Q_ASSERT(re6.isValid()); if (re6.indexIn(type) != -1) - type.replace(re6.cap(0), QString("stack<%1>").arg(inner)); + type.replace(re6.cap(0), QString::fromLatin1("stack<%1>").arg(inner)); // std::set - QRegExp re4(QString("set<%1, std::less<%2>, %3\\s*>").arg(inner, inner, alloc)); - re4.setMinimal(true); + static QRegExp re4(QString::fromLatin1("set<%1,[ ]?std::less<%2>,[ ]?%3\\s*>").arg(inner, inner, alloc)); + if (!re4.isMinimal()) + re4.setMinimal(true); + Q_ASSERT(re4.isValid()); if (re4.indexIn(type) != -1) - type.replace(re4.cap(0), QString("set<%1>").arg(inner)); - + type.replace(re4.cap(0), QString::fromLatin1("set<%1>").arg(inner)); // std::map if (inner.startsWith("std::pair<")) { @@ -460,22 +484,26 @@ QString niceType(QString type) QString key = chopConst(ckey); QString value = inner.mid(pos + 2, inner.size() - 3 - pos); - QRegExp re5(QString("map<%1, %2, std::less<%3>, %4\\s*>") + static QRegExp re5(QString("map<%1,[ ]?%2,[ ]?std::less<%3>,[ ]?%4\\s*>") .arg(key, value, key, alloc)); - re5.setMinimal(true); + if (!re5.isMinimal()) + re5.setMinimal(true); + Q_ASSERT(re5.isValid()); if (re5.indexIn(type) != -1) type.replace(re5.cap(0), QString("map<%1, %2>").arg(key, value)); else { - QRegExp re7(QString("map<const %1, %2, std::less<const %3>, %4\\s*>") + static QRegExp re7(QString("map<const %1,[ ]?%2,[ ]?std::less<const %3>,[ ]?%4\\s*>") .arg(key, value, key, alloc)); - re7.setMinimal(true); + if (!re7.isMinimal()) + re7.setMinimal(true); if (re7.indexIn(type) != -1) type.replace(re7.cap(0), QString("map<const %1, %2>").arg(key, value)); } } } - type.replace('@', '*'); + type.replace(QLatin1Char('@'), QLatin1Char('*')); type.replace(QLatin1String(" >"), QString(QLatin1Char('>'))); + cache.insert(typeIn, type); // For simplicity, also cache unmodified types return type; } diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 0263ca51a832693949678c0cc1d6b54a68b3741f..5ef9523ed4535fba43d55b7af9f1db97270542f6 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -266,30 +266,43 @@ bool extractTemplate(const QString &type, QString *tmplate, QString *inner) // Input "Template<Inner1,Inner2,...>::Foo" will return "Template::Foo" in // 'tmplate' and "Inner1@Inner2@..." etc in 'inner'. Result indicates // whether parsing was successful + // Gdb inserts a blank after each comma which we would like to avoid + tmplate->clear(); + inner->clear(); + if (!type.contains(QLatin1Char('<'))) + return false; int level = 0; bool skipSpace = false; + const int size = type.size(); - for (int i = 0; i != type.size(); ++i) { + for (int i = 0; i != size; ++i) { const QChar c = type.at(i); - if (c == QLatin1Char(' ') && skipSpace) { - skipSpace = false; - } else if (c == QLatin1Char('<')) { + const char asciiChar = c.toAscii(); + switch (asciiChar) { + case '<': *(level == 0 ? tmplate : inner) += c; ++level; - } else if (c == QLatin1Char('>')) { + break; + case '>': --level; *(level == 0 ? tmplate : inner) += c; - } else if (c == QLatin1Char(',')) { + break; + case ',': *inner += (level == 1) ? QLatin1Char('@') : QLatin1Char(','); skipSpace = true; - } else { - *(level == 0 ? tmplate : inner) += c; + break; + default: + if (!skipSpace || asciiChar != ' ') { + *(level == 0 ? tmplate : inner) += c; + skipSpace = false; + } + break; } } *tmplate = tmplate->trimmed(); *tmplate = tmplate->remove(QLatin1String("<>")); *inner = inner->trimmed(); - //qDebug() << "EXTRACT TEMPLATE: " << *tmplate << *inner << " FROM " << type; + // qDebug() << "EXTRACT TEMPLATE: " << *tmplate << *inner << " FROM " << type; return !inner->isEmpty(); } @@ -408,7 +421,7 @@ bool isCppEditor(Core::IEditor *editor) // Find the function the cursor is in to use a scope. - + // Return the Cpp expression, and, if desired, the function @@ -442,7 +455,7 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos, const QTextCursor tc = plaintext->textCursor(); *column = tc.columnNumber(); *line = tc.blockNumber(); - } + } if (function && !expr.isEmpty()) if (const Core::IFile *file = editor->file()) @@ -455,6 +468,7 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos, // --------------- QtDumperResult QtDumperResult::Child::Child() : + keyEncoded(0), valueEncoded(0), childCount(0), valuedisabled(false) @@ -475,6 +489,7 @@ void QtDumperResult::clear() value.clear(); address.clear(); type.clear(); + extra.clear(); displayedType.clear(); valueEncoded = 0; valuedisabled = false; @@ -509,8 +524,17 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const wchild.source = source; wchild.iname = iname; wchild.iname += dot; - wchild.iname += dchild.name; - wchild.name = dchild.name; + 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.valuedisabled = dchild.valuedisabled; wchild.setType(dchild.type.isEmpty() ? childType : dchild.type); @@ -533,18 +557,21 @@ QDebug operator<<(QDebug in, const QtDumperResult &d) << " address=" << d.address << " value=" << d.value << " disabled=" << d.valuedisabled - << " encoded=" << d.valueEncoded << " internal=" << d.internal; + << " encoded=" << d.valueEncoded << " internal=" << d.internal + << " extra='" << d.extra << "'\n"; const int realChildCount = d.children.size(); if (d.childCount || realChildCount) { - nospace << " childCount=" << d.childCount << '/' << realChildCount + nospace << "childCount=" << d.childCount << '/' << realChildCount << " childType=" << d.childType << '\n'; for (int i = 0; i < realChildCount; i++) { const QtDumperResult::Child &c = d.children.at(i); nospace << " #" << i << " addr=" << c.address << " disabled=" << c.valuedisabled << " type=" << c.type << " exp=" << c.exp - << " name=" << c.name << " encoded=" << c.valueEncoded - << " value=" << c.value + << " 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'; } } @@ -770,6 +797,7 @@ class DumperParser public: explicit DumperParser(const char *s) : m_s(s) {} bool run(); + virtual ~DumperParser() {} protected: // handle 'key="value"' @@ -833,9 +861,9 @@ bool DumperParser::parseHash(int level, const char *&pos) return false; pos = equalsPtr + 1; if (!*pos) - return false; + return false; if (!parseValue(level + 1, pos)) - return false; + return false; if (*pos == ',') pos++; } @@ -871,7 +899,7 @@ bool DumperParser::parseValue(int level, const char *&pos) if (*pos == ',') pos++; } - } + } return false; // A hash '{a="b",b="c"}' case '{': { @@ -879,7 +907,7 @@ bool DumperParser::parseValue(int level, const char *&pos) return false; pos++; if (!parseHash(level + 1, pos)) - return false; + return false; return handleHashEnd(); } return false; @@ -952,7 +980,7 @@ public: protected: virtual bool handleKeyword(const char *k, int size); - virtual bool handleListStart(); + virtual bool handleListStart(); virtual bool handleListEnd(); virtual bool handleHashEnd(); virtual bool handleValue(const char *k, int size); @@ -972,7 +1000,7 @@ QueryDumperParser::QueryDumperParser(const char *s) : { } -bool QueryDumperParser::handleKeyword(const char *k, int size) +bool QueryDumperParser::handleKeyword(const char *k, int size) { switch (m_mode) { case ExpectingSizes: @@ -1064,7 +1092,6 @@ 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; - qDebug() << m_expressionCache; return true; } @@ -1081,13 +1108,15 @@ void QtDumperHelper::addSize(const QString &name, int size) return; } do { + // CDB helpers if (name == QLatin1String("std::string")) { - m_sizeCache.insert(QLatin1String("std::basic_string<char,std::char_traits<char>,std::allocator<char>>"), size); + m_sizeCache.insert(QLatin1String("std::basic_string<char,std::char_traits<char>,std::allocator<char> >"), size); + m_sizeCache.insert(QLatin1String("basic_string<char,char_traits<char>,allocator<char> >"), size); break; } if (name == QLatin1String("std::wstring")) { - // FIXME: check space between > > below? - m_sizeCache.insert(QLatin1String("std::basic_string<unsigned short,std::char_traits<unsignedshort>,std::allocator<unsignedshort> >"), size); + m_sizeCache.insert(QLatin1String("basic_string<unsigned short,char_traits<unsignedshort>,allocator<unsignedshort> >"), size); + m_sizeCache.insert(QLatin1String("std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >"), size); break; } } while (false); @@ -1297,10 +1326,16 @@ void QtDumperHelper::evaluationParameters(const WatchData &data, // But we need the offset of the second item in the value pair. // We read the type of the pair from the allocator argument because // that gets the constness "right" (in the sense that gdb can - // read it back; + // read it back: "std::allocator<std::pair<Key,Value> >" + // -> "std::pair<Key,Value>". Different debuggers have varying + // amounts of terminating blanks... QString pairType = inners.at(3); - // remove 'std::allocator<...>': - pairType = pairType.mid(15, pairType.size() - 15 - 2); + int bracketPos = pairType.indexOf(QLatin1Char('<')); + if (bracketPos != -1) + pairType.remove(0, bracketPos + 1); + bracketPos = pairType.indexOf(QLatin1Char('>')); + if (bracketPos != -1) + pairType.truncate(bracketPos + 1); extraArgs[2] = QLatin1String("(size_t)&(('"); extraArgs[2] += pairType; extraArgs[2] += QLatin1String("'*)0)->second"); @@ -1377,12 +1412,15 @@ private: ExpectingType, ExpectingDisplayedType, ExpectingInternal, ExpectingValueDisabled, ExpectingValueEncoded, ExpectingCommonChildType, ExpectingChildCount, + ExpectingExtra, IgnoreNext, ChildModeStart, ExpectingChildren,ExpectingChildName, ExpectingChildAddress, ExpectingChildExpression, ExpectingChildType, + ExpectingChildKey, ExpectingChildKeyEncoded, ExpectingChildValue, ExpectingChildValueEncoded, - ExpectingChildValueDisabled, ExpectingChildChildCount + ExpectingChildValueDisabled, ExpectingChildChildCount, + IgnoreNextChildMode }; static inline Mode nextMode(Mode in, const char *keyword, int size); @@ -1405,6 +1443,8 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword case 3: if (!qstrncmp(keyword, "exp", size)) return ExpectingChildExpression; + if (!qstrncmp(keyword, "key", size)) + return ExpectingChildKey; break; case 4: if (!qstrncmp(keyword, "addr", size)) @@ -1419,6 +1459,8 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword return ExpectingIName; if (!qstrncmp(keyword, "value", size)) return in > ChildModeStart ? ExpectingChildValue : ExpectingValue; + if (!qstrncmp(keyword, "extra", size)) + return ExpectingExtra; break; case 8: if (!qstrncmp(keyword, "children", size)) @@ -1431,7 +1473,11 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword case 9: if (!qstrncmp(keyword, "childtype", size)) return ExpectingCommonChildType; - break; + break; + case 10: + if (!qstrncmp(keyword, "keyencoded", size)) + return ExpectingChildKeyEncoded; + break; case 12: if (!qstrncmp(keyword, "valueencoded", size)) return in > ChildModeStart ? ExpectingChildValueEncoded : ExpectingValueEncoded; @@ -1442,10 +1488,10 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword if (!qstrncmp(keyword, "displayedtype", size)) return ExpectingDisplayedType; if (!qstrncmp(keyword, "childnumchild", size)) - return IgnoreNext; + return IgnoreNextChildMode; break; } - return IgnoreNext; + return in > ChildModeStart ? IgnoreNextChildMode : IgnoreNext; } bool ValueDumperParser::handleKeyword(const char *k, int size) @@ -1491,6 +1537,9 @@ bool ValueDumperParser::handleValue(const char *k, int size) case ExpectingDisplayedType: m_result.displayedType = QString::fromLatin1(valueBA); break; + case ExpectingExtra: + m_result.extra = valueBA; + break; case ExpectingInternal: m_result.internal = valueBA == "true"; break; @@ -1501,6 +1550,7 @@ bool ValueDumperParser::handleValue(const char *k, int size) m_result.childCount = QString::fromLatin1(valueBA).toInt(); break; case ExpectingChildren: + case IgnoreNextChildMode: case IgnoreNext: break; case ExpectingChildName: @@ -1509,6 +1559,12 @@ bool ValueDumperParser::handleValue(const char *k, int size) case ExpectingChildAddress: m_result.children.back().address = QString::fromLatin1(valueBA); break; + case ExpectingChildKeyEncoded: + m_result.children.back().keyEncoded = QString::fromLatin1(valueBA).toInt(); + break; + case ExpectingChildKey: + m_result.children.back().key = valueBA; + break; case ExpectingChildValue: m_result.children.back().value = valueBA; break; @@ -1532,7 +1588,7 @@ bool ValueDumperParser::handleValue(const char *k, int size) } bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r) -{ +{ ValueDumperParser parser(data); if (!parser.run()) return false; @@ -1541,7 +1597,7 @@ bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r) if (r->childCount < r->children.size()) r->childCount = r->children.size(); if (debug) - qDebug() << '\n' << data << *r; + qDebug() << '\n' << data << '\n' << *r; return true; } diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h index 94948499e7bc2e7083b83e9523a1952663d6988e..9d39372aa0e8588fd3c56ccf50024c0e94a99269 100644 --- a/src/plugins/debugger/watchutils.h +++ b/src/plugins/debugger/watchutils.h @@ -90,13 +90,15 @@ struct QtDumperResult struct Child { Child(); - int valueEncoded; + int keyEncoded; + int valueEncoded; int childCount; bool valuedisabled; QString name; QString address; QString exp; QString type; + QByteArray key; QByteArray value; }; @@ -107,6 +109,7 @@ struct QtDumperResult QString iname; QString address; QString type; + QString extra; QString displayedType; QByteArray value; int valueEncoded;