diff --git a/share/qtcreator/gdbmacros/test/main.cpp b/share/qtcreator/gdbmacros/test/main.cpp index 22f68e1a3c6..482bc8313a2 100644 --- a/share/qtcreator/gdbmacros/test/main.cpp +++ b/share/qtcreator/gdbmacros/test/main.cpp @@ -187,6 +187,10 @@ static int dumpQVariant() prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", ""); qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0); fputs(qDumpOutBuffer, stdout); + test = QVariant(QRect(1,2, 3, 4)); + prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", ""); + qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0); + fputs(qDumpOutBuffer, stdout); return 0; } diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index 910a915b713..787926468b5 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -853,6 +853,8 @@ void CdbDebugEngine::updateWatchData(const WatchData &incomplete) } while (false); if (!success) warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage)); + if (debugCDBWatchHandling > 1) + qDebug() << *m_d->m_debuggerManagerAccess->watchHandler()->model(LocalsWatch); } void CdbDebugEngine::stepExec() diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp index 8c14d45fff9..2128fc8ceab 100644 --- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp @@ -51,6 +51,16 @@ inline bool falsePredicate(const WatchData & /* whatever */) { return false; } inline bool isDumperPredicate(const WatchData &wd) { return wd.source == OwnerDumper; } +static inline void debugWatchDataList(const QList &l, const char *why = 0) +{ + QDebug nospace = qDebug().nospace(); + if (why) + nospace << why << '\n'; + foreach(const WatchData &wd, l) + nospace << wd.toString() << '\n'; + nospace << '\n'; +} + // Match an item that is expanded in the watchhandler. class WatchHandlerExpandedPredicate { public: @@ -174,6 +184,7 @@ static inline void fixDumperResult(const WatchData &source, const int size = result->size(); if (!size) return; + // debugWatchDataList(*result, suppressGrandChildren ? ">fixDumperResult suppressGrandChildren" : ">fixDumperResult"); WatchData &returned = result->front(); if (returned.iname != source.iname) return; @@ -195,6 +206,7 @@ static inline void fixDumperResult(const WatchData &source, for (++it; it != wend; ++it) { WatchData &wd = *it; if (wd.addr.isEmpty() && wd.isSomethingNeeded()) { + wd.setHasChildren(false); wd.setAllUnneeded(); } else { // Hack: Suppress endless recursion of the model. To be fixed, @@ -203,6 +215,7 @@ static inline void fixDumperResult(const WatchData &source, wd.setHasChildren(false); } } + // debugWatchDataList(*result, "")); + wd.setHasChildren(false); wd.setAllUnneeded(); wh->insertData(wd); } diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 9e2d10c4d7a..23a1ae83cda 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -847,6 +847,7 @@ void DebuggerManager::startNewDebugger(DebuggerRunControl *runControl, emit debugModeRequested(); showDebuggerOutput(LogStatus, tr("Starting debugger for tool chain '%1'...").arg(toolChainName)); + showDebuggerOutput(LogDebug, DebuggerSettings::instance()->dump()); QString errorMessage; QString settingsIdHint; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index e5d279fade2..7881c026595 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -1444,7 +1444,6 @@ bool GdbEngine::startDebugger(const QSharedPointer &sp) QTC_ASSERT(m_debuggingHelperState == DebuggingHelperUninitialized, initializeVariables()); - debugMessage(DebuggerSettings::instance()->dump()); QStringList gdbArgs; if (m_gdbProc.state() != QProcess::NotRunning) { @@ -3288,16 +3287,21 @@ void GdbEngine::handleVarAssign(const GdbResultRecord &, const QVariant &) updateLocals(); } -void GdbEngine::setWatchDataType(WatchData &data, const GdbMi &mi) +// Find the "type" and "displayedtype" children of root and set up type. +void GdbEngine::setWatchDataType(WatchData &data, const GdbMi &root) { - if (mi.isValid()) { - QString miData = _(mi.data()); + const GdbMi &typeItem = root.findChild("type"); + if (typeItem.isValid()) { + const QString miData = _(typeItem.data()); if (!data.framekey.isEmpty()) m_varToType[data.framekey] = miData; data.setType(miData); } else if (data.type.isEmpty()) { data.setTypeNeeded(); } + const GdbMi &displayedTypeItem = root.findChild("displayedtype"); + if (displayedTypeItem.isValid()) + data.displayedType = _(displayedTypeItem.data()); } void GdbEngine::handleVarCreate(const GdbResultRecord &record, @@ -3310,7 +3314,7 @@ void GdbEngine::handleVarCreate(const GdbResultRecord &record, //qDebug() << "HANDLE VARIABLE CREATION:" << data.toString(); if (record.resultClass == GdbResultDone) { data.variable = data.iname; - setWatchDataType(data, record.data.findChild("type")); + setWatchDataType(data, record.data); if (hasDebuggingHelperForType(data.type)) { // we do not trust gdb if we have a custom dumper if (record.data.findChild("children").isValid()) @@ -3412,7 +3416,7 @@ void GdbEngine::handleDebuggingHelperValue2(const GdbResultRecord &record, return; } - setWatchDataType(data, contents.findChild("type")); + setWatchDataType(data, contents); setWatchDataValue(data, contents.findChild("value"), contents.findChild("valueencoded").data().toInt()); setWatchDataAddress(data, contents.findChild("addr")); @@ -3438,7 +3442,7 @@ void GdbEngine::handleDebuggingHelperValue2(const GdbResultRecord &record, // try not to repeat data too often WatchData childtemplate; - setWatchDataType(childtemplate, contents.findChild("childtype")); + setWatchDataType(childtemplate, contents); setWatchDataChildCount(childtemplate, contents.findChild("childnumchild")); //qDebug() << "DATA:" << data.toString(); @@ -3466,7 +3470,7 @@ void GdbEngine::handleDebuggingHelperValue2(const GdbResultRecord &record, //data1.name += " (" + skey + ")"; data1.name = skey; } - setWatchDataType(data1, item.findChild("type")); + setWatchDataType(data1, item); setWatchDataExpression(data1, item.findChild("exp")); setWatchDataChildCount(data1, item.findChild("numchild")); setWatchDataValue(data1, item.findChild("value"), @@ -3668,7 +3672,7 @@ void GdbEngine::setLocals(const QList &locals) data.name = nam; data.exp = nam; data.framekey = m_currentFrame + data.name; - setWatchDataType(data, item.findChild("type")); + setWatchDataType(data, item); // set value only directly if it is simple enough, otherwise // pass through the insertData() machinery if (isIntOrFloatType(data.type) || isPointerType(data.type)) @@ -3725,7 +3729,7 @@ void GdbEngine::handleVarListChildrenHelper(const GdbMi &item, data.name = _(exp); data.iname = parent.iname + _c('.') + data.name; data.variable = _(name); - setWatchDataType(data, item.findChild("type")); + setWatchDataType(data, item); setWatchDataValue(data, item.findChild("value")); setWatchDataAddress(data, item.findChild("addr")); setWatchDataSAddress(data, item.findChild("saddr")); @@ -3747,7 +3751,7 @@ void GdbEngine::handleVarListChildrenHelper(const GdbMi &item, WatchData data; data.iname = parent.iname + _c('.') + __(exp); data.variable = _(name); - setWatchDataType(data, item.findChild("type")); + setWatchDataType(data, item); setWatchDataValue(data, item.findChild("value")); setWatchDataAddress(data, item.findChild("addr")); setWatchDataSAddress(data, item.findChild("saddr")); diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index b4e7ad020d9..fad2dfa77f4 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -246,6 +246,17 @@ static void formatToolTipRow(QTextStream &str, const QString &category, const QS << Qt::escape(value) << ""; } +static inline QString typeToolTip(const WatchData &wd) +{ + if (wd.displayedType.isEmpty()) + return wd.type; + QString rc = wd.displayedType; + rc += QLatin1String(" ("); + rc += wd.type; + rc += QLatin1Char(')'); + return rc; +} + QString WatchData::toToolTip() const { if (!valuetooltip.isEmpty()) @@ -254,7 +265,7 @@ QString WatchData::toToolTip() const QTextStream str(&res); str << ""; formatToolTipRow(str, WatchHandler::tr("Expression"), exp); - formatToolTipRow(str, WatchHandler::tr("Type"), type); + formatToolTipRow(str, WatchHandler::tr("Type"), typeToolTip(*this)); QString val = value; if (value.size() > 1000) { val.truncate(1000); @@ -629,7 +640,10 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const case 1: return formattedValue(data, m_handler->m_individualFormats[data.iname], m_handler->m_typeFormats[data.type]); - case 2: return niceType(data.type); + case 2: + if (!data.displayedType.isEmpty()) + return data.displayedType; + return niceType(data.type); default: break; } break; @@ -886,6 +900,21 @@ WatchItem *WatchModel::findItem(const QString &iname, WatchItem *root) const return 0; } +static void debugRecursion(QDebug &d, const WatchItem *item, int depth) +{ + d << QString(2 * depth, QLatin1Char(' ')) << item->toString() << '\n'; + foreach(const WatchItem *i, item->children) + debugRecursion(d, i, depth + 1); +} + +QDebug operator<<(QDebug d, const WatchModel &m) +{ + QDebug nospace = d.nospace(); + if (m.m_root) + debugRecursion(nospace, m.m_root, 0); + return d; +} + /////////////////////////////////////////////////////////////////////// // diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index 661e9a0c728..0778ec25451 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -39,6 +39,10 @@ #include #include +QT_BEGIN_NAMESPACE +class QDebug; +QT_END_NAMESPACE + namespace Debugger { namespace Internal { @@ -115,7 +119,8 @@ public: QString value; // displayed value QByteArray editvalue; // displayed value QString valuetooltip; // tooltip in value column - QString type; // displayed type + QString type; // type for further processing + QString displayedType; // displayed type (optional) QString variable; // name of internal Gdb variable if created QString addr; // displayed adress QString saddr; // stored address (pointer in container) @@ -199,6 +204,7 @@ private: void emitDataChanged(int column, const QModelIndex &parentIndex = QModelIndex()); + friend QDebug operator<<(QDebug d, const WatchModel &m); private: WatchHandler *m_handler; WatchType m_type; diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 49b4cc02c56..c902998c280 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -56,7 +56,6 @@ #include enum { debug = 0 }; - namespace Debugger { namespace Internal { @@ -528,7 +527,9 @@ QList QtDumperResult::toWatchData(int source) const root.setValue(decodeData(value, valueEncoded)); root.valuedisabled = valuedisabled; } - root.setType(displayedType.isEmpty() ? type : displayedType); + root.setType(type); + if (!displayedType.isEmpty()) + root.displayedType = displayedType; root.setAddress(address); root.source = source; if (childCount >= 0) @@ -570,21 +571,20 @@ QList QtDumperResult::toWatchData(int source) const wchild.setAddress(dchild.address); // The type setter sets hasChildren for known types. wchild.setType(dchild.type.isEmpty() ? childType : dchild.type); - if (wchild.isHasChildrenNeeded()) { - // 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; - } + if (!dchild.displayedType.isEmpty()) + wchild.displayedType = dchild.displayedType; + // Child overrides. + const int effectiveChildChildCount = dchild.childCount == -1 ? childChildCount : dchild.childCount; + switch (effectiveChildChildCount) { + case -1: // In this case, trust WatchData::setType(). + break; + case 0: + wchild.setHasChildren(false); + break; + default: + wchild.setHasChildren(true); + wchild.setChildrenNeeded(); + break; } } } @@ -904,7 +904,7 @@ bool DumperParser::run() { const char *ptr = m_s; const bool rc = parseHash(0, ptr); - if (debug) + if (debug > 1) qDebug() << Q_FUNC_INFO << '\n' << m_s << rc; return rc; } @@ -988,35 +988,35 @@ bool DumperParser::parseValue(int level, const char *&pos) bool DumperParser::handleKeyword(const char *k, int size) { - if (debug) + if (debug > 1) qDebug() << Q_FUNC_INFO << '\n' << QByteArray(k, size); return true; } bool DumperParser::handleListStart() { - if (debug) + if (debug > 1) qDebug() << Q_FUNC_INFO; return true; } bool DumperParser::handleListEnd() { - if (debug) + if (debug > 1) qDebug() << Q_FUNC_INFO; return true; } bool DumperParser::handleHashStart() { - if (debug) + if (debug > 1) qDebug() << Q_FUNC_INFO; return true; } bool DumperParser::handleHashEnd() { - if (debug) + if (debug > 1) qDebug() << Q_FUNC_INFO; return true; @@ -1024,7 +1024,7 @@ bool DumperParser::handleHashEnd() bool DumperParser::handleValue(const char *k, int size) { - if (debug) + if (debug > 1) qDebug() << Q_FUNC_INFO << '\n' << QByteArray(k, size); return true; } @@ -1513,6 +1513,7 @@ private: ChildModeStart, ExpectingChildren,ExpectingChildName, ExpectingChildAddress, ExpectingChildExpression, ExpectingChildType, + ExpectingChildDisplayedType, ExpectingChildKey, ExpectingChildKeyEncoded, ExpectingChildValue, ExpectingChildValueEncoded, ExpectingChildValueDisabled, ExpectingChildChildCount, @@ -1582,7 +1583,7 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword if (!qstrncmp(keyword, "valuedisabled", size)) return in > ChildModeStart ? ExpectingChildValueDisabled : ExpectingValueDisabled; if (!qstrncmp(keyword, "displayedtype", size)) - return ExpectingDisplayedType; + return in > ChildModeStart ? ExpectingChildDisplayedType : ExpectingDisplayedType; if (!qstrncmp(keyword, "childnumchild", size)) return ExpectingChildChildOverrideCount; break; @@ -1687,6 +1688,9 @@ bool ValueDumperParser::handleValue(const char *k, int size) case ExpectingChildType: m_result.children.back().type = QString::fromLatin1(valueBA); break; + case ExpectingChildDisplayedType: + m_result.children.back().displayedType = QString::fromLatin1(valueBA); + break; case ExpectingChildChildCount: m_result.children.back().childCount = QString::fromLatin1(valueBA).toInt(); break; @@ -1704,7 +1708,7 @@ bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r) // Sanity if (!r->children.empty() && r->childCount != r->children.size()) r->childCount = r->children.size(); - if (debug) + if (debug > 1) qDebug() << '\n' << data << '\n' << *r; return true; } diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h index 4d828bbc156..27598f219a8 100644 --- a/src/plugins/debugger/watchutils.h +++ b/src/plugins/debugger/watchutils.h @@ -102,6 +102,7 @@ struct QtDumperResult QString address; QString exp; QString type; + QString displayedType; QByteArray key; bool valueEncountered; QByteArray value;