diff options
author | hjk <qtc-committer@nokia.com> | 2009-08-31 09:14:04 +0200 |
---|---|---|
committer | hjk <qtc-committer@nokia.com> | 2009-08-31 16:05:55 +0200 |
commit | 452f108ac744c69b42bc2565f608338bdb8fffbc (patch) | |
tree | 674e3289c0a677f2cc893d61cde866718c12381b | |
parent | 7503d1bcf6c7186572b23dfb1ac98218de066080 (diff) | |
download | qt-creator-452f108ac744c69b42bc2565f608338bdb8fffbc.tar.gz |
debugger: fixes and improvements related to the Locals display
Split the concepts 'enabled' and 'editable' in the dumper output
Disable "<not in scope>" entries, also fix their type.
Fix glitch in type beautification for display
Find reason for failing bulk updates.
-rw-r--r-- | share/qtcreator/gdbmacros/gdbmacros.cpp | 130 | ||||
-rw-r--r-- | src/plugins/debugger/debuggermanager.cpp | 10 | ||||
-rw-r--r-- | src/plugins/debugger/gdb/gdbengine.cpp | 52 | ||||
-rw-r--r-- | src/plugins/debugger/gdb/gdbengine.h | 2 | ||||
-rw-r--r-- | src/plugins/debugger/idebuggerengine.h | 1 | ||||
-rw-r--r-- | src/plugins/debugger/shared/backtrace.cpp | 87 | ||||
-rw-r--r-- | src/plugins/debugger/shared/backtrace.h | 43 | ||||
-rw-r--r-- | src/plugins/debugger/shared/shared.pri | 4 | ||||
-rw-r--r-- | src/plugins/debugger/watchhandler.cpp | 181 | ||||
-rw-r--r-- | src/plugins/debugger/watchhandler.h | 13 | ||||
-rw-r--r-- | src/plugins/debugger/watchutils.cpp | 34 | ||||
-rw-r--r-- | src/plugins/debugger/watchutils.h | 4 | ||||
-rw-r--r-- | src/plugins/debugger/watchwindow.cpp | 11 | ||||
-rw-r--r-- | src/plugins/debugger/watchwindow.h | 1 | ||||
-rw-r--r-- | tests/manual/gdbdebugger/simple/app.cpp | 14 |
15 files changed, 428 insertions, 159 deletions
diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index b9a658ea42..92c8f707a3 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -500,10 +500,10 @@ struct QDumper // the dumper arguments int protocolVersion; // dumper protocol version int token; // some token to show on success - const char *outertype; // object type + const char *outerType; // object type const char *iname; // object name used for display const char *exp; // object expression - const char *innertype; // 'inner type' for class templates + const char *innerType; // 'inner type' for class templates const void *data; // pointer to raw data bool dumpChildren; // do we want to see children? @@ -543,7 +543,7 @@ QDumper::~QDumper() void QDumper::setupTemplateParameters() { - char *s = const_cast<char *>(innertype); + char *s = const_cast<char *>(innerType); int templateParametersCount = 1; templateParameters[0] = s; @@ -734,7 +734,7 @@ void QDumper::endHash() void QDumper::putEllipsis() { putCommaIfNeeded(); - put("{name=\"<incomplete>\",value=\"\",type=\"").put(innertype).put("\"}"); + put("{name=\"<incomplete>\",value=\"\",type=\"").put(innerType).put("\"}"); } void QDumper::putItemCount(const char *name, int count) @@ -875,13 +875,11 @@ void QDumper::putHash(const char *name, QChar value) #define DUMPUNKNOWN_MESSAGE "<not in scope>" static void qDumpUnknown(QDumper &d, const char *why = 0) { - //d.putItem("iname", d.iname); - //d.putItem("addr", d.data); if (!why) why = DUMPUNKNOWN_MESSAGE; d.putItem("value", why); - d.putItem("type", d.outertype); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); + d.putItem("valueenabled", "false"); d.putItem("numchild", "0", d.currentChildNumChild); d.disarm(); } @@ -983,7 +981,7 @@ void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr, if (startsWith(type, "QList<")) { const QListData *ldata = reinterpret_cast<const QListData*>(addr); d.putItemCount("value", ldata->size()); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", ldata->size()); } break; @@ -1638,12 +1636,12 @@ static void qDumpQList(QDumper &d) int n = nn; d.putItemCount("value", n); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", n); if (d.dumpChildren) { unsigned innerSize = d.extraInt[0]; - bool innerTypeIsPointer = isPointerType(d.innertype); - QByteArray strippedInnerType = stripPointerType(d.innertype); + bool innerTypeIsPointer = isPointerType(d.innerType); + QByteArray strippedInnerType = stripPointerType(d.innerType); // The exact condition here is: // QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic @@ -1651,11 +1649,11 @@ static void qDumpQList(QDumper &d) // in the frontend. // So as first approximation only do the 'isLarge' check: bool isInternal = innerSize <= int(sizeof(void*)) - && isMovableType(d.innertype); + && isMovableType(d.innerType); d.putItem("internal", (int)isInternal); if (n > 1000) n = 1000; - d.beginChildren(n ? d.innertype : 0); + d.beginChildren(n ? d.innerType : 0); for (int i = 0; i != n; ++i) { d.beginHash(); if (innerTypeIsPointer) { @@ -1671,13 +1669,13 @@ static void qDumpQList(QDumper &d) } else { void *p = ldata.d->array + i + pdata->begin; if (isInternal) { - //qDumpInnerValue(d, d.innertype, p); + //qDumpInnerValue(d, d.innerType, p); d.putItem("addr", p); - qDumpInnerValueHelper(d, d.innertype, p); + qDumpInnerValueHelper(d, d.innerType, p); } else { - //qDumpInnerValue(d, d.innertype, deref(p)); + //qDumpInnerValue(d, d.innerType, deref(p)); d.putItem("addr", deref(p)); - qDumpInnerValueHelper(d, d.innertype, deref(p)); + qDumpInnerValueHelper(d, d.innerType, deref(p)); } } d.endHash(); @@ -1702,23 +1700,23 @@ static void qDumpQLinkedList(QDumper &d) int n = nn; d.putItemCount("value", n); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", n); if (d.dumpChildren) { //unsigned innerSize = d.extraInt[0]; - //bool innerTypeIsPointer = isPointerType(d.innertype); - QByteArray strippedInnerType = stripPointerType(d.innertype); + //bool innerTypeIsPointer = isPointerType(d.innerType); + QByteArray strippedInnerType = stripPointerType(d.innerType); const char *stripped = - isPointerType(d.innertype) ? strippedInnerType.data() : 0; + isPointerType(d.innerType) ? strippedInnerType.data() : 0; if (n > 1000) n = 1000; - d.beginChildren(d.innertype); + d.beginChildren(d.innerType); const void *p = deref(ldata); for (int i = 0; i != n; ++i) { d.beginHash(); const void *addr = addOffset(p, 2 * sizeof(void*)); - qDumpInnerValueOrPointer(d, d.innertype, stripped, addr); + qDumpInnerValueOrPointer(d, d.innerType, stripped, addr); p = deref(p); d.endHash(); } @@ -2750,7 +2748,7 @@ static void qDumpQSet(QDumper &d) } d.putItemCount("value", n); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", 2 * n); if (d.dumpChildren) { if (n > 100) @@ -2760,9 +2758,9 @@ static void qDumpQSet(QDumper &d) for (int bucket = 0; bucket != hd->numBuckets && i <= 10000; ++bucket) { for (node = hd->buckets[bucket]; node->next; node = node->next) { d.beginHash(); - d.putItem("type", d.innertype); + d.putItem("type", d.innerType); d.beginItem("exp"); - d.put("(('"NS"QHashNode<").put(d.innertype + d.put("(('"NS"QHashNode<").put(d.innerType ).put(","NS"QHashDummyValue>'*)" ).put(static_cast<const void*>(node)).put(")->key"); d.endItem(); @@ -2788,23 +2786,23 @@ static void qDumpQSharedPointer(QDumper &d) if (ptr.isNull()) { d.putItem("value", "<null>"); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", 0); d.disarm(); return; } - if (isSimpleType(d.innertype)) - qDumpInnerValueHelper(d, d.innertype, ptr.data()); + if (isSimpleType(d.innerType)) + qDumpInnerValueHelper(d, d.innerType, ptr.data()); else d.putItem("value", ""); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", 1); if (d.dumpChildren) { d.beginChildren(); d.beginHash(); d.putItem("name", "data"); - qDumpInnerValue(d, d.innertype, ptr.data()); + qDumpInnerValue(d, d.innerType, ptr.data()); d.endHash(); const int v = sizeof(void *); d.beginHash(); @@ -2868,7 +2866,7 @@ static void qDumpQStringList(QDumper &d) } d.putItemCount("value", n); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", n); if (d.dumpChildren) { if (n > 1000) @@ -2926,18 +2924,18 @@ static void qDumpQVector(QDumper &d) int n = nn; d.putItemCount("value", n); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", n); if (d.dumpChildren) { - QByteArray strippedInnerType = stripPointerType(d.innertype); + QByteArray strippedInnerType = stripPointerType(d.innerType); const char *stripped = - isPointerType(d.innertype) ? strippedInnerType.data() : 0; + isPointerType(d.innerType) ? strippedInnerType.data() : 0; if (n > 1000) n = 1000; - d.beginChildren(d.innertype); + d.beginChildren(d.innerType); for (int i = 0; i != n; ++i) { d.beginHash(); - qDumpInnerValueOrPointer(d, d.innertype, stripped, + qDumpInnerValueOrPointer(d, d.innerType, stripped, addOffset(v, i * innersize + typeddatasize)); d.endHash(); } @@ -2958,23 +2956,23 @@ static void qDumpQWeakPointer(QDumper &d) if (value == 0 || data == 0) { d.putItem("value", "<null>"); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", 0); d.disarm(); return; } - if (isSimpleType(d.innertype)) - qDumpInnerValueHelper(d, d.innertype, value); + if (isSimpleType(d.innerType)) + qDumpInnerValueHelper(d, d.innerType, value); else d.putItem("value", ""); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", 1); if (d.dumpChildren) { d.beginChildren(); d.beginHash(); d.putItem("name", "data"); - qDumpInnerValue(d, d.innertype, value); + qDumpInnerValue(d, d.innerType, value); d.endHash(); d.beginHash(); const void *weak = addOffset(deref(d.data), v); @@ -3034,16 +3032,16 @@ static void qDumpStdList(QDumper &d) d.putItemCount("value", nn); d.putItem("numchild", nn); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); if (d.dumpChildren) { - QByteArray strippedInnerType = stripPointerType(d.innertype); + QByteArray strippedInnerType = stripPointerType(d.innerType); const char *stripped = - isPointerType(d.innertype) ? strippedInnerType.data() : 0; - d.beginChildren(d.innertype); + isPointerType(d.innerType) ? strippedInnerType.data() : 0; + d.beginChildren(d.innerType); it = list.begin(); for (int i = 0; i < 1000 && it != cend; ++i, ++it) { d.beginHash(); - qDumpInnerValueOrPointer(d, d.innertype, stripped, it.operator->()); + qDumpInnerValueOrPointer(d, d.innerType, stripped, it.operator->()); d.endHash(); } if (it != list.end()) @@ -3078,10 +3076,10 @@ static void qDumpStdMapHelper(QDumper &d) for (int i = 0; i < nn && i < 10 && it != cend; ++i, ++it) qCheckAccess(it.operator->()); - const QByteArray strippedInnerType = stripPointerType(d.innertype); + const QByteArray strippedInnerType = stripPointerType(d.innerType); d.putItem("numchild", nn); d.putItemCount("value", nn); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("valueoffset", d.extraInt[2]); // HACK: we need a properly const qualified version of the @@ -3105,7 +3103,7 @@ static void qDumpStdMapHelper(QDumper &d) d.put(" valueOffset: ").put(valueOffset); d.endItem(); - d.beginChildren(d.innertype); + d.beginChildren(d.innerType); it = map.begin(); for (int i = 0; i < 1000 && it != cend; ++i, ++it) { d.beginHash(); @@ -3185,26 +3183,26 @@ static void qDumpStdSetHelper(QDumper &d) qCheckAccess(it.operator->()); d.putItemCount("value", nn); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", nn); d.putItem("valueoffset", d.extraInt[0]); if (d.dumpChildren) { int valueOffset = 0; // d.extraInt[0]; - QByteArray strippedInnerType = stripPointerType(d.innertype); + QByteArray strippedInnerType = stripPointerType(d.innerType); const char *stripped = - isPointerType(d.innertype) ? strippedInnerType.data() : 0; + isPointerType(d.innerType) ? strippedInnerType.data() : 0; d.beginItem("extra"); d.put("valueOffset: ").put(valueOffset); d.endItem(); - d.beginChildren(d.innertype); + d.beginChildren(d.innerType); it = set.begin(); for (int i = 0; i < 1000 && it != cend; ++i, ++it) { const void *node = it.operator->(); d.beginHash(); - qDumpInnerValueOrPointer(d, d.innertype, stripped, node); + qDumpInnerValueOrPointer(d, d.innerType, stripped, node); d.endHash(); } if (it != set.end()) @@ -3295,19 +3293,19 @@ static void qDumpStdVector(QDumper &d) int n = nn; d.putItemCount("value", n); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", n); if (d.dumpChildren) { unsigned innersize = d.extraInt[0]; - QByteArray strippedInnerType = stripPointerType(d.innertype); + QByteArray strippedInnerType = stripPointerType(d.innerType); const char *stripped = - isPointerType(d.innertype) ? strippedInnerType.data() : 0; + isPointerType(d.innerType) ? strippedInnerType.data() : 0; if (n > 1000) n = 1000; - d.beginChildren(n ? d.innertype : 0); + d.beginChildren(n ? d.innerType : 0); for (int i = 0; i != n; ++i) { d.beginHash(); - qDumpInnerValueOrPointer(d, d.innertype, stripped, + qDumpInnerValueOrPointer(d, d.innerType, stripped, addOffset(v->start, i * innersize)); d.endHash(); } @@ -3326,7 +3324,7 @@ static void qDumpStdVectorBool(QDumper &d) static void handleProtocolVersion2and3(QDumper &d) { - if (!d.outertype[0]) { + if (!d.outerType[0]) { qDumpUnknown(d); return; } @@ -3341,7 +3339,7 @@ static void handleProtocolVersion2and3(QDumper &d) #ifdef QT_NO_QDATASTREAM if (d.protocolVersion == 3) { - QVariant::Type type = QVariant::nameToType(d.outertype); + QVariant::Type type = QVariant::nameToType(d.outerType); if (type != QVariant::Invalid) { QVariant v(type, d.data); QByteArray ba; @@ -3352,7 +3350,7 @@ static void handleProtocolVersion2and3(QDumper &d) } #endif - const char *type = stripNamespace(d.outertype); + const char *type = stripNamespace(d.outerType); // type[0] is usally 'Q', so don't use it switch (type[1]) { case 'a': @@ -3774,10 +3772,10 @@ void *qDumpObjectData440( d.extraInt[3] = extraInt3; const char *inbuffer = inBuffer; - d.outertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; + d.outerType = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.exp = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; - d.innertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; + d.innerType = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; handleProtocolVersion2and3(d); diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index f1dbc7b71d..844ba750b4 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -319,9 +319,7 @@ void DebuggerManager::init() //qRegisterMetaType<WatchData>("Debugger::Internal::WatchData"); qRegisterMetaType<WatchData>("WatchData"); connect(m_watchHandler, SIGNAL(watchDataUpdateNeeded(WatchData)), - this, SLOT(updateWatchDataAnnounce())); - connect(m_watchHandler, SIGNAL(watchDataUpdateNeeded(WatchData)), - this, SLOT(updateWatchData(WatchData)), Qt::QueuedConnection); + this, SLOT(updateWatchData(WatchData))); m_continueAction = new QAction(this); m_continueAction->setText(tr("Continue")); @@ -695,12 +693,6 @@ void DebuggerManager::updateWatchData(const WatchData &data) m_engine->updateWatchData(data); } -void DebuggerManager::updateWatchDataAnnounce() -{ - if (m_engine) - m_engine->updateWatchDataAnnounce(); -} - static inline QString msgEngineNotAvailable(const char *engine) { return DebuggerManager::tr("The application requires the debugger engine '%1', which is disabled.").arg(QLatin1String(engine)); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index c12a4a1b1c..89669c9df5 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -57,6 +57,7 @@ #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFileInfo> +#include <QtCore/QMetaObject> #include <QtCore/QTime> #include <QtCore/QTimer> #include <QtCore/QTextStream> @@ -2814,12 +2815,20 @@ static void setWatchDataChildCount(WatchData &data, const GdbMi &mi) data.setHasChildren(mi.data().toInt() > 0); } -static void setWatchDataValueDisabled(WatchData &data, const GdbMi &mi) +static void setWatchDataValueEnabled(WatchData &data, const GdbMi &mi) { if (mi.data() == "true") - data.valuedisabled = true; + data.valueEnabled = true; else if (mi.data() == "false") - data.valuedisabled = false; + data.valueEnabled = false; +} + +static void setWatchDataValueEditable(WatchData &data, const GdbMi &mi) +{ + if (mi.data() == "true") + data.valueEditable = true; + else if (mi.data() == "false") + data.valueEditable = false; } static void setWatchDataExpression(WatchData &data, const GdbMi &mi) @@ -3127,20 +3136,26 @@ void GdbEngine::updateSubItem(const WatchData &data0) QTC_ASSERT(false, return); } -void GdbEngine::updateWatchDataAnnounce() +void GdbEngine::updateWatchData(const WatchData &data) { // Bump requests to avoid model rebuilding during the nested // updateWatchModel runs. ++m_pendingRequests; +#if 1 + QMetaObject::invokeMethod(this, "updateWatchDataHelper", + Qt::QueuedConnection, Q_ARG(WatchData, data)); +#else + updateWatchDataHelper(data); +#endif } -void GdbEngine::updateWatchData(const WatchData &data) +void GdbEngine::updateWatchDataHelper(const WatchData &data) { //m_pendingRequests = 0; PENDING_DEBUG("UPDATE WATCH DATA"); #if DEBUG_PENDING //qDebug() << "##############################################"; - //qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:"; + qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:"; //qDebug() << data.toString(); #endif @@ -3153,9 +3168,11 @@ void GdbEngine::updateWatchData(const WatchData &data) void GdbEngine::rebuildModel() { + static int count = 0; + ++count; m_processedNames.clear(); - PENDING_DEBUG("REBUILDING MODEL"); - emit gdbInputAvailable(LogStatus, _("<Rebuild Watchmodel>")); + PENDING_DEBUG("REBUILDING MODEL" << count); + emit gdbInputAvailable(LogStatus, _("<Rebuild Watchmodel %1>").arg(count)); q->showStatusMessage(tr("Finished retrieving data."), 400); qq->watchHandler()->endCycle(); showToolTip(); @@ -3330,7 +3347,8 @@ void GdbEngine::handleVarCreate(const GdbResultRecord &record, data.type = _(" "); data.setAllUnneeded(); data.setHasChildren(false); - data.valuedisabled = true; + data.valueEnabled = false; + data.valueEditable = false; insertData(data); } } @@ -3445,7 +3463,8 @@ void GdbEngine::handleChildren(const WatchData &data0, const GdbMi &item, setWatchDataSAddress(data, item.findChild("saddr")); setWatchDataValueToolTip(data, item.findChild("valuetooltip"), item.findChild("valuetooltipencoded").data().toInt()); - setWatchDataValueDisabled(data, item.findChild("valuedisabled")); + setWatchDataValueEnabled(data, item.findChild("valueenabled")); + setWatchDataValueEditable(data, item.findChild("valueeditable")); //qDebug() << "HANDLE CHILDREN: " << data.toString(); list->append(data); @@ -3495,7 +3514,7 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResultRecord &record, // << " STREAM:" << out; if (list.isEmpty()) { //: Value for variable - data.setValue(strNotInScope); + data.setError(strNotInScope); data.setAllUnneeded(); insertData(data); } else if (data.type == __("QString") @@ -3540,13 +3559,13 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResultRecord &record, } } else { //: Value for variable - data.setValue(strNotInScope); + data.setError(strNotInScope); data.setAllUnneeded(); insertData(data); } } else if (record.resultClass == GdbResultError) { WatchData data = cookie.value<WatchData>(); - data.setValue(strNotInScope); + data.setError(strNotInScope); data.setAllUnneeded(); insertData(data); } @@ -3628,6 +3647,7 @@ void GdbEngine::setLocals(const QList<GdbMi> &locals) //qDebug() << m_varToType; QMap<QByteArray, int> seen; + QList<WatchData> list; foreach (const GdbMi &item, locals) { // Local variables of inlined code are reported as // 26^done,locals={varobj={exp="this",value="",name="var4",exp="this", @@ -3657,7 +3677,7 @@ void GdbEngine::setLocals(const QList<GdbMi> &locals) //variable of the same name in a nested block data.setType(tr("<shadowed>")); data.setHasChildren(false); - insertData(data); + list.append(data); } else { seen[name] = 1; WatchData data; @@ -3679,9 +3699,10 @@ void GdbEngine::setLocals(const QList<GdbMi> &locals) qDebug() << "RE-USING" << m_varToType.value(data.framekey); data.setType(m_varToType.value(data.framekey)); } - insertData(data); + list.append(data); } } + qq->watchHandler()->insertBulkData(list); } void GdbEngine::insertData(const WatchData &data0) @@ -3698,7 +3719,6 @@ void GdbEngine::insertData(const WatchData &data0) void GdbEngine::handleVarListChildrenHelper(const GdbMi &item, const WatchData &parent) { - //qDebug() << "VAR_LIST_CHILDREN: PARENT 2" << parent.toString(); //qDebug() << "VAR_LIST_CHILDREN: APPENDEE" << data.toString(); QByteArray exp = item.findChild("exp").data(); QByteArray name = item.findChild("name").data(); diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index fdf67f15b8..2694ec01fb 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -332,7 +332,7 @@ private: void updateSubItem(const WatchData &data); void updateWatchData(const WatchData &data); - void updateWatchDataAnnounce(); + Q_SLOT void updateWatchDataHelper(const WatchData &data); void rebuildModel(); void insertData(const WatchData &data); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index 327b1866c0..89ff302931 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -63,7 +63,6 @@ public: virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters) = 0; virtual void exitDebugger() = 0; virtual void detachDebugger() {} - virtual void updateWatchDataAnnounce() {} virtual void updateWatchData(const WatchData &data) = 0; virtual void stepExec() = 0; diff --git a/src/plugins/debugger/shared/backtrace.cpp b/src/plugins/debugger/shared/backtrace.cpp new file mode 100644 index 0000000000..6b81e9339e --- /dev/null +++ b/src/plugins/debugger/shared/backtrace.cpp @@ -0,0 +1,87 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include <QtCore/QCoreApplication> +#include <QtCore/QDebug> +#include <QtCore/QProcess> + +#if defined(Q_OS_LINUX) +#include <stdio.h> +#include <signal.h> +#include <execinfo.h> +#endif + +namespace Debugger { +namespace Internal { + +void dumpBacktrace(int maxdepth) +{ + if (maxdepth == -1) + maxdepth = 200; +#if defined(Q_OS_LINUX) + void *bt[200] = {0}; + qDebug() << "BACKTRACE:"; + int size = backtrace(bt, sizeof(bt) / sizeof(bt[0])); + for (int i = 0; i < qMin(size, maxdepth); i++) + qDebug() << "0x" + QByteArray::number(quintptr(bt[i]), 16); + QProcess proc; + QStringList args; + args.append("-e"); + args.append(QCoreApplication::arguments().at(0)); + proc.start("addr2line", args); + proc.waitForStarted(); + for (int i = 0; i < qMin(size, maxdepth); i++) + proc.write("0x" + QByteArray::number(quintptr(bt[i]), 16) + "\n"); + proc.closeWriteChannel(); + QByteArray out = proc.readAllStandardOutput(); + qDebug() << QCoreApplication::arguments().at(0); + qDebug() << out; + proc.waitForFinished(); + out = proc.readAllStandardOutput(); + qDebug() << out; +#endif +} + +/* +void installSignalHandlers() +{ +#if defined(Q_OS_LINUX) + struct sigaction SignalAction; + + SignalAction.sa_sigaction = handler; + sigemptyset(&SignalAction.sa_mask); + SignalAction.sa_flags = SA_SIGINFO; + sigaction(SIGSEGV, &SignalAction, NULL); + sigaction(SIGABRT, &SignalAction, NULL); +#endif +} +*/ + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/shared/backtrace.h b/src/plugins/debugger/shared/backtrace.h new file mode 100644 index 0000000000..771ec2a3d1 --- /dev/null +++ b/src/plugins/debugger/shared/backtrace.h @@ -0,0 +1,43 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef DEBUGGER_BACKTRACE_H +#define DEBUGGER_BACKTRACE_H + +#include <QtCore/qglobal.h> + +namespace Debugger { +namespace Internal { + +void dumpBacktrace(int maxdepth = -1); + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_BACKTRACE_H diff --git a/src/plugins/debugger/shared/shared.pri b/src/plugins/debugger/shared/shared.pri index a3dc29a6b3..bd69e956ce 100644 --- a/src/plugins/debugger/shared/shared.pri +++ b/src/plugins/debugger/shared/shared.pri @@ -1,4 +1,8 @@ + +SOURCES += $$PWD/backtrace.cpp +HEADERS += $$PWD/backtrace.h + win32 { INCLUDEPATH+=$$PWD diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 13bf8698b3..d8e6cca600 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -102,19 +102,40 @@ public: WatchData::WatchData() : hasChildren(false), generation(-1), - valuedisabled(false), + valueEnabled(true), + valueEditable(true), source(0), state(InitialState), changed(false) { } +bool WatchData::isEqual(const WatchData &other) const +{ + return iname == other.iname + && exp == other.exp + && name == other.name + && value == other.value + && editvalue == other.editvalue + && valuetooltip == other.valuetooltip + && type == other.type + && displayedType == other.displayedType + && variable == other.variable + && addr == other.addr + && saddr == other.saddr + && framekey == other.framekey + && hasChildren == other.hasChildren + && valueEnabled == other.valueEnabled + && valueEditable == other.valueEditable; +} + void WatchData::setError(const QString &msg) { setAllUnneeded(); value = msg; setHasChildren(false); - valuedisabled = true; + valueEnabled = false; + valueEditable = false; } void WatchData::setValue(const QString &value0) @@ -276,6 +297,8 @@ QString WatchData::toToolTip() const formatToolTipRow(str, WatchHandler::tr("Object Address"), addr); formatToolTipRow(str, WatchHandler::tr("Stored Address"), saddr); formatToolTipRow(str, WatchHandler::tr("Internal ID"), iname); + formatToolTipRow(str, WatchHandler::tr("Generation"), + QString::number(generation)); str << "</table></body></html>"; return res; } @@ -330,6 +353,33 @@ void WatchModel::reinitialize() endRemoveRows(); } +void WatchModel::beginCycle() +{ + emit enableUpdates(false); +} + +void WatchModel::endCycle() +{ + removeOutdated(); + emit enableUpdates(true); +} + +void WatchModel::dump() +{ + qDebug() << "\n"; + foreach (WatchItem *child, m_root->children) + dumpHelper(child); +} + +void WatchModel::dumpHelper(WatchItem *item) +{ + qDebug() << "ITEM: " << item->iname + << (item->parent ? item->parent->iname : "<none>") + << item->generation; + foreach (WatchItem *child, item->children) + dumpHelper(child); +} + void WatchModel::removeOutdated() { foreach (WatchItem *child, m_root->children) @@ -343,9 +393,9 @@ void WatchModel::removeOutdated() void WatchModel::removeOutdatedHelper(WatchItem *item) { - if (item->generation < generationCounter) + if (item->generation < generationCounter) { removeItem(item); - else { + } else { foreach (WatchItem *child, item->children) removeOutdatedHelper(child); item->fetchTriggered = false; @@ -407,9 +457,9 @@ QString niceType(const QString typeIn) { static QMap<QString, QString> cache; const QMap<QString, QString>::const_iterator it = cache.constFind(typeIn); - if (it != cache.constEnd()) { + if (it != cache.constEnd()) return it.value(); - } + QString type = typeIn; type.replace(QLatin1Char('*'), QLatin1Char('@')); @@ -434,23 +484,23 @@ QString niceType(const QString typeIn) QString inner = alloc.mid(15, alloc.size() - 16).trimmed(); if (inner == QLatin1String("char")) { // std::string - static const QRegExp stringRegexp = stdStringRegExp(inner); + const QRegExp stringRegexp = stdStringRegExp(inner); type.replace(stringRegexp, QLatin1String("string")); } else if (inner == QLatin1String("wchar_t")) { // std::wstring - static const QRegExp wchartStringRegexp = stdStringRegExp(inner); + 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); + const QRegExp usStringRegexp = stdStringRegExp(inner); type.replace(usStringRegexp, QLatin1String("wstring")); } // std::vector, std::deque, std::list - static const QRegExp re1(QString::fromLatin1("(vector|list|deque)<%1,[ ]?%2\\s*>").arg(inner, alloc)); + 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::fromLatin1("%1<%2>").arg(re1.cap(1), inner)); // std::stack - static QRegExp re6(QString::fromLatin1("stack<%1,[ ]?std::deque<%2> >").arg(inner, inner)); + QRegExp re6(QString::fromLatin1("stack<%1, ?std::deque<%2> >").arg(inner, inner)); if (!re6.isMinimal()) re6.setMinimal(true); Q_ASSERT(re6.isValid()); @@ -458,7 +508,7 @@ QString niceType(const QString typeIn) type.replace(re6.cap(0), QString::fromLatin1("stack<%1>").arg(inner)); // std::set - static QRegExp re4(QString::fromLatin1("set<%1,[ ]?std::less<%2>,[ ]?%3\\s*>").arg(inner, inner, alloc)); + 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()); @@ -481,17 +531,16 @@ QString niceType(const QString typeIn) } QString ckey = inner.mid(10, pos - 10); QString key = chopConst(ckey); - QString value = inner.mid(pos + 2, inner.size() - 3 - pos); - - static QRegExp re5(QString("map<%1,[ ]?%2,[ ]?std::less<%3>,[ ]?%4\\s*>") + QString value = inner.mid(pos + 2, inner.size() - 3 - pos).trimmed(); + QRegExp re5(QString("map<%1, ?%2, ?std::less<%3 ?>, ?%4\\s*>") .arg(key, value, key, alloc)); if (!re5.isMinimal()) re5.setMinimal(true); Q_ASSERT(re5.isValid()); - if (re5.indexIn(type) != -1) + if (re5.indexIn(type) != -1) { type.replace(re5.cap(0), QString("map<%1, %2>").arg(key, value)); - else { - static QRegExp re7(QString("map<const %1,[ ]?%2,[ ]?std::less<const %3>,[ ]?%4\\s*>") + } else { + QRegExp re7(QString("map<const %1, ?%2, ?std::less<const %3>, ?%4\\s*>") .arg(key, value, key, alloc)); if (!re7.isMinimal()) re7.setMinimal(true); @@ -657,7 +706,7 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const static const QVariant red(QColor(200, 0, 0)); static const QVariant gray(QColor(140, 140, 140)); switch (idx.column()) { - case 1: return data.valuedisabled ? gray : data.changed ? red : QVariant(); + case 1: return !data.valueEnabled ? gray : data.changed ? red : QVariant(); } break; } @@ -751,9 +800,9 @@ Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const return editable; // watcher names are editable if (data.isWatcher() && idx.column() == 2) return editable; // watcher types are - if (idx.column() == 1) - return editable; // locals and watcher values are editable - return notEditable; + if (idx.column() == 1 && data.valueEditable) + return editable; // locals and watcher values are sometimes editable + return notEditable; } QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -775,7 +824,7 @@ struct IName : public QString IName(const QString &iname) : QString(iname) {} }; -bool operator<(const IName &iname1, const IName &iname2) +bool iNameLess(const QString &iname1, const QString &iname2) { QString name1 = iname1.section('.', -1); QString name2 = iname2.section('.', -1); @@ -790,10 +839,14 @@ bool operator<(const IName &iname1, const IName &iname2) return name1 < name2; } +bool operator<(const IName &iname1, const IName &iname2) +{ + return iNameLess(iname1, iname2); +} static bool iNameSorter(const WatchItem *item1, const WatchItem *item2) { - return IName(item1->iname) < IName(item2->iname); + return iNameLess(item1->iname, item2->iname); } static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *item) @@ -806,7 +859,7 @@ static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *i void WatchModel::insertData(const WatchData &data) { // qDebug() << "WMI:" << data.toString(); - static int bulk = 0; + //static int bulk = 0; //qDebug() << "SINGLE: " << ++bulk << data.toString(); QTC_ASSERT(!data.iname.isEmpty(), return); WatchItem *parent = findItem(parentName(data.iname), m_root); @@ -845,8 +898,16 @@ void WatchModel::insertData(const WatchData &data) void WatchModel::insertBulkData(const QList<WatchData> &list) { +#if 1 + for (int i = 0; i != list.size(); ++i) + insertData(list.at(i)); + return; +#endif + // This method does not properly insert items in proper "iname sort + // order", leading to random removal of items in removeOutDated(); + //qDebug() << "WMI:" << list.toString(); - static int bulk = 0; + //static int bulk = 0; //foreach (const WatchItem &data, list) // qDebug() << "BULK: " << ++bulk << data.toString(); QTC_ASSERT(!list.isEmpty(), return); @@ -885,22 +946,39 @@ void WatchModel::insertBulkData(const QList<WatchData> &list) foreach (WatchItem *oldItem, parent->children) { Iterator it = newList.find(oldItem->iname); if (it == newList.end()) { - newList[oldItem->iname] = *oldItem; + WatchData data = *oldItem; + data.generation = generationCounter; + newList[oldItem->iname] = data; } else { bool changed = !it->value.isEmpty() && it->value != oldItem->value && it->value != strNotInScope; it->changed = changed; - it->generation = generationCounter; + if (it->generation == -1) + it->generation = generationCounter; } } + for (Iterator it = newList.begin(); it != newList.end(); ++it) { + qDebug() << " NEW: " << it->iname; + } + // overwrite existing items Iterator it = newList.begin(); - const int oldCount = parent->children.size(); - for (int i = 0; i < oldCount; ++i, ++it) - parent->children[i]->setData(*it); QModelIndex idx = watchIndex(parent); + const int oldCount = parent->children.size(); + for (int i = 0; i < oldCount; ++i, ++it) { + if (!parent->children[i]->isEqual(*it)) { + qDebug() << "REPLACING" << parent->children.at(i)->iname + << " WITH " << it->iname << it->generation; + parent->children[i]->setData(*it); + if (parent->children[i]->generation == -1) + parent->children[i]->generation = generationCounter; + //emit dataChanged(idx.sibling(i, 0), idx.sibling(i, 2)); + } else { + //qDebug() << "SKIPPING REPLACEMENT" << parent->children.at(i)->iname; + } + } emit dataChanged(idx.sibling(0, 0), idx.sibling(oldCount - 1, 2)); // add new items @@ -909,13 +987,17 @@ void WatchModel::insertBulkData(const QList<WatchData> &list) //MODEL_DEBUG("INSERT : " << data.iname << data.value); for (int i = oldCount; i < newList.size(); ++i, ++it) { WatchItem *item = new WatchItem(*it); + qDebug() << "ADDING" << it->iname; item->parent = parent; - item->generation = generationCounter; + if (item->generation == -1) + item->generation = generationCounter; item->changed = true; parent->children.append(item); } endInsertRows(); } + //qDebug() << "ITEMS: " << parent->children.size(); + dump(); } WatchItem *WatchModel::findItem(const QString &iname, WatchItem *root) const @@ -965,11 +1047,20 @@ WatchHandler::WatchHandler() SIGNAL(triggered()), this, SLOT(removeWatchExpression())); } +void WatchHandler::beginCycle() +{ + ++generationCounter; + m_locals->beginCycle(); + m_watchers->beginCycle(); + m_tooltips->beginCycle(); +} + void WatchHandler::endCycle() { - m_locals->removeOutdated(); - m_watchers->removeOutdated(); - m_tooltips->removeOutdated(); + //qDebug() << "END CYCLE"; + m_locals->endCycle(); + m_watchers->endCycle(); + m_tooltips->endCycle(); } void WatchHandler::cleanup() @@ -1004,7 +1095,7 @@ void WatchHandler::insertData(const WatchData &data) // bulk-insertion void WatchHandler::insertBulkData(const QList<WatchData> &list) { -#if 1 +#if 0 foreach (const WatchItem &data, list) insertData(data); return; @@ -1015,16 +1106,20 @@ void WatchHandler::insertBulkData(const QList<WatchData> &list) QMap<QString, QList<WatchData> > hash; foreach (const WatchData &data, list) { - if (data.isSomethingNeeded()) - emit watchDataUpdateNeeded(data); - else - hash[parentName(data.iname)].append(data); + // we insert everything, including incomplete stuff + // to reduce the number of row add operations in the model. + hash[parentName(data.iname)].append(data); } foreach (const QString &parentIName, hash.keys()) { WatchModel *model = modelForIName(parentIName); QTC_ASSERT(model, return); model->insertBulkData(hash[parentIName]); } + + foreach (const WatchData &data, list) { + if (data.isSomethingNeeded()) + emit watchDataUpdateNeeded(data); + } } void WatchHandler::removeData(const QString &iname) @@ -1157,12 +1252,6 @@ void WatchHandler::removeWatchExpression(const QString &exp) } } -void WatchHandler::beginCycle() -{ - ++generationCounter; - //m_locals->beginCycle(); -} - void WatchHandler::updateWatchers() { //qDebug() << "UPDATE WATCHERS"; diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index 4c2d2d36fe..8f6590484b 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -111,6 +111,8 @@ public: bool isLocal() const { return iname.startsWith(QLatin1String("local.")); } bool isWatcher() const { return iname.startsWith(QLatin1String("watch.")); } bool isValid() const { return !iname.isEmpty(); } + + bool isEqual(const WatchData &other) const; public: QString iname; // internal name sth like 'local.baz.public.a' @@ -128,7 +130,8 @@ public: QScriptValue scriptValue; // if needed... bool hasChildren; int generation; // when updated? - bool valuedisabled; // value will be greyed out + bool valueEnabled; // value will be greyed out or not + bool valueEditable; // value will be editable private: @@ -204,8 +207,16 @@ private: void emitDataChanged(int column, const QModelIndex &parentIndex = QModelIndex()); + void beginCycle(); // called at begin of updateLocals() cycle + void endCycle(); // called after all results have been received friend QDebug operator<<(QDebug d, const WatchModel &m); + + void dump(); + void dumpHelper(WatchItem *item); +signals: + void enableUpdates(bool); + private: WatchHandler *m_handler; WatchType m_type; diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 6b6a358455..1663f94266 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -491,7 +491,7 @@ QtDumperResult::Child::Child() : keyEncoded(0), valueEncoded(0), childCount(-1), - valuedisabled(false), + valueEnabled(true), valueEncountered(false) { } @@ -499,7 +499,7 @@ QtDumperResult::Child::Child() : QtDumperResult::QtDumperResult() : valueEncountered(false), valueEncoded(0), - valuedisabled(false), + valueEnabled(true), childCount(-1), internal(false), childChildCount(-1) @@ -516,7 +516,8 @@ void QtDumperResult::clear() extra.clear(); displayedType.clear(); valueEncoded = 0; - valueEncountered = valuedisabled = false; + valueEncountered = false; + valueEnabled = false; childCount = -1; internal = false; childType.clear(); @@ -535,7 +536,7 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const root.exp = root.name = lastDotIndex == -1 ? iname : iname.mid(lastDotIndex + 1); if (valueEncountered) { root.setValue(decodeData(value, valueEncoded)); - root.valuedisabled = valuedisabled; + root.valueEnabled = valueEnabled; } root.setType(type); if (!displayedType.isEmpty()) @@ -575,7 +576,7 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const wchild.iname += iname; wchild.exp = dchild.exp; if (dchild.valueEncountered) { - wchild.valuedisabled = dchild.valuedisabled; + wchild.valueEnabled = dchild.valueEnabled; wchild.setValue(decodeData(dchild.value, dchild.valueEncoded)); } wchild.setAddress(dchild.address); @@ -611,14 +612,15 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const QDebug operator<<(QDebug in, const QtDumperResult &d) { QDebug nospace = in.nospace(); - nospace << " iname=" << d.iname << " type=" << d.type << " displayed=" << d.displayedType + nospace << " iname=" << d.iname << " type=" << d.type + << " displayed=" << d.displayedType << " address=" << d.address; if (!d.addressInfo.isEmpty()) nospace << " addressInfo=" << d.addressInfo; if (d.valueEncountered) { nospace << " encoded=" << d.valueEncoded << " value=" << d.value - << " disabled=" << d.valuedisabled; + << " enabled=" << d.valueEnabled; } else { nospace << " <no value>"; } @@ -633,7 +635,7 @@ QDebug operator<<(QDebug in, const QtDumperResult &d) for (int i = 0; i < realChildCount; i++) { const QtDumperResult::Child &c = d.children.at(i); nospace << " #" << i << " addr=" << c.address - << " disabled=" << c.valuedisabled + << " enabled=" << c.valueEnabled << " type=" << c.type << " exp=" << c.exp << " name=" << c.name; if (!c.key.isEmpty()) @@ -1518,7 +1520,7 @@ protected: private: enum Mode { None, ExpectingIName, ExpectingAddress, ExpectingValue, ExpectingType, ExpectingDisplayedType, ExpectingInternal, - ExpectingValueDisabled, ExpectingValueEncoded, + ExpectingValueEnabled, ExpectingValueEncoded, ExpectingCommonChildType, ExpectingChildCount, ExpectingChildChildOverrideCount, ExpectingExtra, @@ -1529,7 +1531,7 @@ private: ExpectingChildDisplayedType, ExpectingChildKey, ExpectingChildKeyEncoded, ExpectingChildValue, ExpectingChildValueEncoded, - ExpectingChildValueDisabled, ExpectingChildChildCount, + ExpectingChildValueEnabled, ExpectingChildChildCount, IgnoreNextChildMode }; @@ -1593,8 +1595,8 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword return in > ChildModeStart ? ExpectingChildValueEncoded : ExpectingValueEncoded; break; case 13: - if (!qstrncmp(keyword, "valuedisabled", size)) - return in > ChildModeStart ? ExpectingChildValueDisabled : ExpectingValueDisabled; + if (!qstrncmp(keyword, "valueenabled", size)) + return in > ChildModeStart ? ExpectingChildValueEnabled : ExpectingValueEnabled; if (!qstrncmp(keyword, "displayedtype", size)) return in > ChildModeStart ? ExpectingChildDisplayedType : ExpectingDisplayedType; if (!qstrncmp(keyword, "childnumchild", size)) @@ -1642,8 +1644,8 @@ bool ValueDumperParser::handleValue(const char *k, int size) m_result.valueEncountered = true; m_result.value = valueBA; break; - case ExpectingValueDisabled: - m_result.valuedisabled = valueBA == "true"; + case ExpectingValueEnabled: + m_result.valueEnabled = valueBA == "true"; break; case ExpectingValueEncoded: m_result.valueEncoded = QString::fromLatin1(valueBA).toInt(); @@ -1695,8 +1697,8 @@ bool ValueDumperParser::handleValue(const char *k, int size) case ExpectingChildValueEncoded: m_result.children.back().valueEncoded = QString::fromLatin1(valueBA).toInt(); break; - case ExpectingChildValueDisabled: - m_result.children.back().valuedisabled = valueBA == "true"; + case ExpectingChildValueEnabled: + m_result.children.back().valueEnabled = valueBA == "true"; break; case ExpectingChildType: m_result.children.back().type = QString::fromLatin1(valueBA); diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h index 7c85400981..f085179d41 100644 --- a/src/plugins/debugger/watchutils.h +++ b/src/plugins/debugger/watchutils.h @@ -97,7 +97,7 @@ struct QtDumperResult int keyEncoded; int valueEncoded; int childCount; - bool valuedisabled; + bool valueEnabled; QString name; QString address; QString exp; @@ -121,7 +121,7 @@ struct QtDumperResult bool valueEncountered; QByteArray value; int valueEncoded; - bool valuedisabled; + bool valueEnabled; int childCount; bool internal; QString childType; diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index b8a687c82d..edb3c9bbaf 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -353,7 +353,16 @@ void WatchWindow::setModel(QAbstractItemModel *model) if (m_type != LocalsType) header()->hide(); - connect(model, SIGNAL(layoutChanged()), this, SLOT(resetHelper())); + connect(model, SIGNAL(layoutChanged()), + this, SLOT(resetHelper())); + connect(model, SIGNAL(enableUpdates(bool)), + this, SLOT(setUpdatesEnabled(bool))); +} + +void WatchWindow::setUpdatesEnabled(bool enable) +{ + //qDebug() << "ENABLING UPDATES: " << enable; + QTreeView::setUpdatesEnabled(enable); } void WatchWindow::resetHelper() diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h index b2b27a9f06..582ffdcd6f 100644 --- a/src/plugins/debugger/watchwindow.h +++ b/src/plugins/debugger/watchwindow.h @@ -64,6 +64,7 @@ private: Q_SLOT void resetHelper(); Q_SLOT void expandNode(const QModelIndex &idx); Q_SLOT void collapseNode(const QModelIndex &idx); + Q_SLOT void setUpdatesEnabled(bool enable); void keyPressEvent(QKeyEvent *ev); void contextMenuEvent(QContextMenuEvent *ev); diff --git a/tests/manual/gdbdebugger/simple/app.cpp b/tests/manual/gdbdebugger/simple/app.cpp index 3a63d348b8..0259c0a2e2 100644 --- a/tests/manual/gdbdebugger/simple/app.cpp +++ b/tests/manual/gdbdebugger/simple/app.cpp @@ -90,6 +90,20 @@ public: int t = 2; b = 2 + s + t; a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; } ~Foo() |