From edeccf73077bd799c8636c0e04d468e6f5467be5 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@nokia.com> Date: Fri, 8 Oct 2010 14:55:57 +0200 Subject: [PATCH] Debugger: Fix dumpers in case alphabetical sorting is off. No longer change iname to obtain sorting. Reviewed-by: hjk --- .../debugger/cdb/cdbsymbolgroupcontext.cpp | 16 ++-- .../debugger/cdb/cdbsymbolgroupcontext_tpl.h | 2 + src/plugins/debugger/gdb/classicgdbengine.cpp | 5 +- src/plugins/debugger/gdb/pythongdbengine.cpp | 4 +- src/plugins/debugger/pdb/pdbengine.cpp | 3 +- src/plugins/debugger/watchdata.cpp | 4 +- src/plugins/debugger/watchdata.h | 1 + src/plugins/debugger/watchhandler.cpp | 80 ++++++++++++------- src/plugins/debugger/watchutils.cpp | 11 +-- src/plugins/debugger/watchutils.h | 2 +- 10 files changed, 73 insertions(+), 55 deletions(-) diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp index fae1a564244..9cd8f6903cf 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -187,15 +187,15 @@ static inline void fixDumperResult(const WatchData &source, // If the model queries the expanding item by pretending childrenNeeded=1, // refuse the request as the children are already known returned.source |= CdbSymbolGroupContext::ChildrenKnownBit; - // Fix the children: If the address is missing, we cannot query any further. - const QList<WatchData>::iterator wend = result->end(); - QList<WatchData>::iterator it = result->begin(); - for (++it; it != wend; ++it) { - WatchData &wd = *it; + // Fix the children: Assign sort id , if the address is missing, we cannot query any further. + const int resultSize = result->size(); + for (int i = 1; i < resultSize; i++) { + WatchData &wd = (*result)[i]; + wd.sortId = i; // Indicate owner and known children - it->source = OwnerDumper; - if (it->isChildrenKnown() && it->isHasChildrenKnown() && it->hasChildren) - it->source |= CdbSymbolGroupContext::ChildrenKnownBit; + wd.source = OwnerDumper; + if (wd.isChildrenKnown() && wd.isHasChildrenKnown() && wd.hasChildren) + wd.source |= CdbSymbolGroupContext::ChildrenKnownBit; // Cannot dump items with missing addresses or missing types const bool typeFixed = fixDumperType(&wd); // Order of evaluation! if ((wd.address == 0 && wd.isSomethingNeeded()) || typeFixed) { diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h index 9cc79b3eecf..fcaf098bb76 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h @@ -52,6 +52,7 @@ bool CdbSymbolGroupContext::getDumpChildSymbols(const QString &prefix, // children, so, re-evaluate size in end condition. // Note the that the internal dumpers might expand children, // so the size might change. + int sortId = 0; for (int s = start; s < size(); ++s) { const DEBUG_SYMBOL_PARAMETERS &p = symbolParameterAt(s); if (p.ParentSymbol == parentId && isSymbolDisplayable(p)) { @@ -59,6 +60,7 @@ bool CdbSymbolGroupContext::getDumpChildSymbols(const QString &prefix, const unsigned rc = watchDataAt(s, &wd); if (rc & InternalDumperMask) wd.source = dumpedOwner; + wd.sortId = sortId++; *it = wd; ++it; } diff --git a/src/plugins/debugger/gdb/classicgdbengine.cpp b/src/plugins/debugger/gdb/classicgdbengine.cpp index 6918f23c20f..090c4cbd953 100644 --- a/src/plugins/debugger/gdb/classicgdbengine.cpp +++ b/src/plugins/debugger/gdb/classicgdbengine.cpp @@ -425,10 +425,7 @@ void GdbEngine::handleDebuggingHelperValue2Classic(const GdbResponse &response) setWatchDataType(data, response.data.findChild("type")); setWatchDataDisplayedType(data, response.data.findChild("displaytype")); QList<WatchData> list; - parseWatchData(watchHandler()->expandedINames(), - data, contents, - theDebuggerBoolSetting(SortStructMembers), - &list); + parseWatchData(watchHandler()->expandedINames(), data, contents, &list); //for (int i = 0; i != list.size(); ++i) // qDebug() << "READ: " << list.at(i).toString(); watchHandler()->insertBulkData(list); diff --git a/src/plugins/debugger/gdb/pythongdbengine.cpp b/src/plugins/debugger/gdb/pythongdbengine.cpp index 20e06886985..b55c5e5d25a 100644 --- a/src/plugins/debugger/gdb/pythongdbengine.cpp +++ b/src/plugins/debugger/gdb/pythongdbengine.cpp @@ -133,14 +133,12 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response) GdbMi data = all.findChild("data"); QList<WatchData> list; - const bool sortMembers = theDebuggerBoolSetting(SortStructMembers); foreach (const GdbMi &child, data.children()) { WatchData dummy; dummy.iname = child.findChild("iname").data(); dummy.name = _(child.findChild("name").data()); //qDebug() << "CHILD: " << child.toString(); - parseWatchData(watchHandler()->expandedINames(), dummy, child, - sortMembers, &list); + parseWatchData(watchHandler()->expandedINames(), dummy, child, &list); } watchHandler()->insertBulkData(list); //for (int i = 0; i != list.size(); ++i) diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index dd55400e008..3c857fbf461 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -826,13 +826,12 @@ void PdbEngine::handleListLocals(const PdbResponse &response) //GdbMi data = all.findChild("data"); QList<WatchData> list; WatchHandler *handler = watchHandler(); - bool sortMembers = theDebuggerBoolSetting(SortStructMembers); foreach (const GdbMi &child, all.children()) { WatchData dummy; dummy.iname = child.findChild("iname").data(); dummy.name = _(child.findChild("name").data()); //qDebug() << "CHILD: " << child.toString(); - parseWatchData(handler->expandedINames(), dummy, child, sortMembers, &list); + parseWatchData(handler->expandedINames(), dummy, child, &list); } handler->insertBulkData(list); } diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index 74171d0d0b8..b21d1609f6a 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -28,7 +28,8 @@ WatchData::WatchData() : source(0), objectId(0), state(InitialState), - changed(false) + changed(false), + sortId(0) { } @@ -172,6 +173,7 @@ QString WatchData::toString() const str << QLatin1Char('{'); if (!iname.isEmpty()) str << "iname=\"" << iname << doubleQuoteComma; + str << "sortId=\"" << sortId << doubleQuoteComma; if (!name.isEmpty() && name != iname) str << "name=\"" << name << doubleQuoteComma; if (error) diff --git a/src/plugins/debugger/watchdata.h b/src/plugins/debugger/watchdata.h index c64473767ae..f36fce1fe65 100644 --- a/src/plugins/debugger/watchdata.h +++ b/src/plugins/debugger/watchdata.h @@ -136,6 +136,7 @@ public: quint64 objectId; // Object id used for the QMLEngine int state; bool changed; + int sortId; }; } // namespace Internal diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index fd428f211ef..1c5b6cdad97 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -960,40 +960,62 @@ QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int ro return QVariant(); } -struct IName : public QByteArray -{ - IName(const QByteArray &iname) : QByteArray(iname) {} -}; +// Determine sort order of watch items by sort order or alphabetical inames +// according to setting 'SortStructMembers'. We need a map key for bulkInsert +// and a predicate for finding the insertion position of a single item. + +// Set this before using any of the below according to action +static bool sortWatchDataAlphabetically = true; -bool iNameLess(const QString &iname1, const QString &iname2) +static bool watchDataLessThan(const QByteArray &iname1, int sortId1, const QByteArray &iname2, int sortId2) { - QString name1 = iname1.section('.', -1); - QString name2 = iname2.section('.', -1); - if (!name1.isEmpty() && !name2.isEmpty()) { - if (name1.at(0).isDigit() && name2.at(0).isDigit()) { - bool ok1 = false, ok2 = false; - int i1 = name1.toInt(&ok1), i2 = name2.toInt(&ok2); - if (ok1 && ok2) - return i1 < i2; - } + if (!sortWatchDataAlphabetically) + return sortId1 < sortId2; + // Get positions of last part of iname 'local.this.i1" -> "i1" + int cmpPos1 = iname1.lastIndexOf('.'); + if (cmpPos1 == -1) { + cmpPos1 = 0; + } else { + cmpPos1++; } - return name1 < name2; -} + int cmpPos2 = iname2.lastIndexOf('.'); + if (cmpPos2 == -1) { + cmpPos2 = 0; + } else { + cmpPos2++; + } + // Are we looking at an array with numerical inames 'local.this.i1.0" -> + // Go by sort id. + if (cmpPos1 < iname1.size() && cmpPos2 < iname2.size() + && isdigit(iname1.at(cmpPos1)) && isdigit(iname2.at(cmpPos2))) + return sortId1 < sortId2; + // Alphabetically + return qstrcmp(iname1.constData() + cmpPos1, iname2.constData() + cmpPos2) < 0; +} + +// Sort key for watch data consisting of iname and numerical sort id. +struct WatchDataSortKey { + explicit WatchDataSortKey(const WatchData &wd) : + iname(wd.iname), sortId(wd.sortId) {} + QByteArray iname; + int sortId; +}; -bool operator<(const IName &iname1, const IName &iname2) +inline bool operator<(const WatchDataSortKey &k1, const WatchDataSortKey &k2) { - return iNameLess(iname1, iname2); + return watchDataLessThan(k1.iname, k1.sortId, k2.iname, k2.sortId); } -static bool iNameSorter(const WatchItem *item1, const WatchItem *item2) +bool watchItemSorter(const WatchItem *item1, const WatchItem *item2) { - return iNameLess(item1->iname, item2->iname); + return watchDataLessThan(item1->iname, item1->sortId, item2->iname, item2->sortId); } static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *item) { - QList<WatchItem *>::const_iterator it = - qLowerBound(list.begin(), list.end(), item, iNameSorter); + sortWatchDataAlphabetically = theDebuggerBoolSetting(SortStructMembers); + const QList<WatchItem *>::const_iterator it = + qLowerBound(list.begin(), list.end(), item, watchItemSorter); return it - list.begin(); } @@ -1045,7 +1067,7 @@ void WatchModel::insertData(const WatchData &data) item->parent = parent; item->generation = generationCounter; item->changed = true; - int n = findInsertPosition(parent->children, item); + const int n = findInsertPosition(parent->children, item); beginInsertRows(index, n, n); parent->children.insert(n, item); endInsertRows(); @@ -1078,10 +1100,11 @@ void WatchModel::insertBulkData(const QList<WatchData> &list) } QModelIndex index = watchIndex(parent); - QMap<IName, WatchData> newList; - typedef QMap<IName, WatchData>::iterator Iterator; + sortWatchDataAlphabetically = theDebuggerBoolSetting(SortStructMembers); + QMap<WatchDataSortKey, WatchData> newList; + typedef QMap<WatchDataSortKey, WatchData>::iterator Iterator; foreach (const WatchItem &data, list) - newList[data.iname] = data; + newList.insert(WatchDataSortKey(data), data); if (newList.size() != list.size()) { qDebug() << "LIST: "; foreach (const WatchItem &data, list) @@ -1100,11 +1123,12 @@ void WatchModel::insertBulkData(const QList<WatchData> &list) QTC_ASSERT(newList.size() == list.size(), return); foreach (WatchItem *oldItem, parent->children) { - Iterator it = newList.find(oldItem->iname); + const WatchDataSortKey oldSortKey(*oldItem); + Iterator it = newList.find(oldSortKey); if (it == newList.end()) { WatchData data = *oldItem; data.generation = generationCounter; - newList[oldItem->iname] = data; + newList.insert(oldSortKey, data); } else { bool changed = !it->value.isEmpty() && it->value != oldItem->value diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 73016f69610..2c198204143 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -1666,7 +1666,7 @@ void setWatchDataDisplayedType(WatchData &data, const GdbMi &item) void parseWatchData(const QSet<QByteArray> &expandedINames, const WatchData &data0, const GdbMi &item, - bool sortMembers, QList<WatchData> *list) + QList<WatchData> *list) { //qDebug() << "HANDLE CHILDREN: " << data0.toString() << item.toString(); WatchData data = data0; @@ -1711,6 +1711,7 @@ void parseWatchData(const QSet<QByteArray> &expandedINames, int i = 0; foreach (const GdbMi &child, children.children()) { WatchData data1 = childtemplate; + data1.sortId = i++; GdbMi name = child.findChild("name"); if (name.isValid()) data1.name = _(name.data()); @@ -1722,11 +1723,6 @@ void parseWatchData(const QSet<QByteArray> &expandedINames, } else { data1.iname = data.iname; data1.iname += '.'; - if (!sortMembers) { - char buf[10]; - qsnprintf(buf, sizeof(buf) - 1, "%04d", i); - data1.iname += buf; - } data1.iname += data1.name.toLatin1(); } if (!data1.name.isEmpty() && data1.name.at(0).isDigit()) @@ -1747,8 +1743,7 @@ void parseWatchData(const QSet<QByteArray> &expandedINames, //data1.name += " (" + skey + ")"; data1.name = skey; } - parseWatchData(expandedINames, data1, child, sortMembers, list); - ++i; + parseWatchData(expandedINames, data1, child, list); } } diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h index 61d3aa4c7fc..e1da61a37ab 100644 --- a/src/plugins/debugger/watchutils.h +++ b/src/plugins/debugger/watchutils.h @@ -257,7 +257,7 @@ void setWatchDataType(WatchData &data, const GdbMi &mi); void setWatchDataDisplayedType(WatchData &data, const GdbMi &mi); void parseWatchData(const QSet<QByteArray> &expandedINames, - const WatchData &parent, const GdbMi &child, bool sortMembers, + const WatchData &parent, const GdbMi &child, QList<WatchData> *insertions); } // namespace Internal -- GitLab