diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 54c901b6aef..223acde6d43 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4939,27 +4939,7 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response) } WatchHandler *handler = watchHandler(); - QList list; - if (!partial) { - list.append(*handler->findData("local")); - list.append(*handler->findData("watch")); - list.append(*handler->findData("return")); - } - - foreach (const GdbMi &child, data.children()) { - WatchData dummy; - dummy.iname = child["iname"].data(); - GdbMi wname = child["wname"]; - if (wname.isValid()) { - // Happens (only) for watched expressions. - dummy.name = QString::fromUtf8(QByteArray::fromHex(wname.data())); - dummy.exp = dummy.name.toUtf8(); - } else { - dummy.name = _(child["name"].data()); - } - parseWatchData(handler->expandedINames(), dummy, child, &list); - } const GdbMi typeInfo = all["typeinfo"]; if (typeInfo.type() == GdbMi::List) { foreach (const GdbMi &s, typeInfo.children()) { @@ -4970,13 +4950,38 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response) TypeInfo(size.data().toUInt())); } } - for (int i = 0; i != list.size(); ++i) { - const TypeInfo ti = m_typeInfoCache.value(list.at(i).type); - if (ti.size) - list[i].size = ti.size; + + QSet toDelete; + if (!partial) { + foreach (WatchItem *item, handler->model()->treeLevelItems(2)) + toDelete.insert(item->d.iname); } - handler->insertData(list); + foreach (const GdbMi &child, data.children()) { + QByteArray iname = child["iname"].data(); + QString name; + + GdbMi wname = child["wname"]; + if (wname.isValid()) // Happens (only) for watched expressions. + name = QString::fromUtf8(QByteArray::fromHex(wname.data())); + else + name = _(child["name"].data()); + + WatchItem *item = new WatchItem(iname, name); + item->parseWatchData(handler->expandedINames(), child); + + const TypeInfo ti = m_typeInfoCache.value(item->d.type); + if (ti.size) + item->d.size = ti.size; + + if (wname.isValid()) + item->d.exp = name.toUtf8(); + + handler->insertItem(item); + toDelete.remove(item->d.iname); + } + + handler->purgeOutdatedItems(toDelete); //PENDING_DEBUG("AFTER handleStackFrame()"); // FIXME: This should only be used when updateLocals() was diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index d41b500c1db..9288bb341a0 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -535,7 +535,7 @@ QString decodeItemHelper(const double &t) } template -void decodeArrayHelper(QList *list, const WatchData &tmplate, +void decodeArrayHelper(std::function itemHandler, const WatchData &tmplate, const QByteArray &rawData) { const QByteArray ba = QByteArray::fromHex(rawData); @@ -551,43 +551,43 @@ void decodeArrayHelper(QList *list, const WatchData &tmplate, data.address += i * sizeof(T); data.exp = exp + QByteArray::number(data.address, 16); data.setAllUnneeded(); - list->append(data); + itemHandler(data); } } -static void decodeArray(QList *list, const WatchData &tmplate, +void decodeArrayData(std::function itemHandler, const WatchData &tmplate, const QByteArray &rawData, int encoding) { switch (encoding) { case Hex2EncodedInt1: - decodeArrayHelper(list, tmplate, rawData); + decodeArrayHelper(itemHandler, tmplate, rawData); break; case Hex2EncodedInt2: - decodeArrayHelper(list, tmplate, rawData); + decodeArrayHelper(itemHandler, tmplate, rawData); break; case Hex2EncodedInt4: - decodeArrayHelper(list, tmplate, rawData); + decodeArrayHelper(itemHandler, tmplate, rawData); break; case Hex2EncodedInt8: - decodeArrayHelper(list, tmplate, rawData); + decodeArrayHelper(itemHandler, tmplate, rawData); break; case Hex2EncodedUInt1: - decodeArrayHelper(list, tmplate, rawData); + decodeArrayHelper(itemHandler, tmplate, rawData); break; case Hex2EncodedUInt2: - decodeArrayHelper(list, tmplate, rawData); + decodeArrayHelper(itemHandler, tmplate, rawData); break; case Hex2EncodedUInt4: - decodeArrayHelper(list, tmplate, rawData); + decodeArrayHelper(itemHandler, tmplate, rawData); break; case Hex2EncodedUInt8: - decodeArrayHelper(list, tmplate, rawData); + decodeArrayHelper(itemHandler, tmplate, rawData); break; case Hex2EncodedFloat4: - decodeArrayHelper(list, tmplate, rawData); + decodeArrayHelper(itemHandler, tmplate, rawData); break; case Hex2EncodedFloat8: - decodeArrayHelper(list, tmplate, rawData); + decodeArrayHelper(itemHandler, tmplate, rawData); break; default: qDebug() << "ENCODING ERROR: " << encoding; @@ -714,9 +714,9 @@ void parseWatchData(const QSet &expandedINames, const WatchData &innerData, const GdbMi &innerInput) { parseWatchData(expandedINames, innerData, innerInput, list); }; - auto arrayDecoder = [list](const WatchData &childTemplate, + auto arrayDecoder = [itemHandler](const WatchData &childTemplate, const QByteArray &encodedData, int encoding) { - decodeArray(list, childTemplate, encodedData, encoding); + decodeArrayData(itemHandler, childTemplate, encodedData, encoding); }; parseChildrenData(expandedINames, data0, input, itemHandler, childHandler, arrayDecoder); diff --git a/src/plugins/debugger/watchdata.h b/src/plugins/debugger/watchdata.h index 42094764194..53169bc9725 100644 --- a/src/plugins/debugger/watchdata.h +++ b/src/plugins/debugger/watchdata.h @@ -154,6 +154,11 @@ public: qint32 source; // Originated from dumper or symbol evaluation? (CDB only) }; +void decodeArrayData(std::function itemHandler, + const WatchData &tmplate, + const QByteArray &rawData, + int encoding); + void parseChildrenData(const QSet &expandedINames, const WatchData &parent, const GdbMi &child, std::function itemHandler, diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index ffa02150d9b..a4f5363d6a2 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -261,6 +261,8 @@ public: void checkTree(WatchItem *item, QSet *inames); #endif void checkIndex(const QModelIndex &index) const; + void insertItem(WatchItem *item); + void reexpandItems(); }; WatchModel::WatchModel(WatchHandler *handler) @@ -642,6 +644,8 @@ bool WatchItem::canFetchMore() const { if (!d.hasChildren) return false; + if (!watchModel()) + return false; if (!watchModel()->contentIsValid() && !d.isInspect()) return false; return !fetchTriggered; @@ -834,6 +838,7 @@ QVariant WatchItem::data(int column, int role) const static const QVariant red(QColor(200, 0, 0)); static const QVariant gray(QColor(140, 140, 140)); if (column == 1) { + QTC_ASSERT(model(), break); if (!d.valueEnabled) return gray; if (!watchModel()->contentIsValid() && !d.isInspect()) @@ -961,6 +966,7 @@ bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role Qt::ItemFlags WatchItem::flags(int column) const { + QTC_ASSERT(model(), return Qt::ItemFlags()); if (!watchModel()->contentIsValid() && !d.isInspect()) return Qt::ItemFlags(); @@ -1313,6 +1319,31 @@ void WatchHandler::insertIncompleteData(const WatchData &data) } } +void WatchHandler::insertItem(WatchItem *item) +{ + m_model->insertItem(item); +} + +void WatchModel::insertItem(WatchItem *item) +{ + WatchItem *existing = findItem(item->d.iname); + if (existing) + removeItem(existing); + + WatchItem *parent = findItem(parentName(item->d.iname)); + QTC_ASSERT(parent, return); + const int row = findInsertPosition(parent->children(), item); + parent->insertChild(row, item); +} + +void WatchModel::reexpandItems() +{ + foreach (const QByteArray &iname, m_expandedINames) { + WatchItem *item = findItem(iname); + emit itemIsExpanded(indexFromItem(item)); + } +} + void WatchHandler::insertData(const WatchData &data) { QList list; @@ -1344,6 +1375,18 @@ void WatchHandler::resetValueCache() }); } +void WatchHandler::purgeOutdatedItems(const QSet &inames) +{ + foreach (const QByteArray &iname, inames) { + WatchItem *item = findItem(iname); + m_model->removeItem(item); + } + + m_model->layoutChanged(); + m_model->reexpandItems(); + m_contentsValid = true; +} + void WatchHandler::removeData(const QByteArray &iname) { WatchItem *item = m_model->findItem(iname); @@ -1638,6 +1681,11 @@ const WatchData *WatchHandler::findData(const QByteArray &iname) const return item ? &item->d : 0; } +WatchItem *WatchHandler::findItem(const QByteArray &iname) const +{ + return m_model->findItem(iname); +} + const WatchData *WatchHandler::findCppLocalVariable(const QString &name) const { // Can this be found as a local variable? @@ -1880,6 +1928,30 @@ WatchModel *WatchItem::watchModel() return static_cast(model()); } +void WatchItem::parseWatchData(const QSet &expandedINames, const GdbMi &input) +{ + auto itemHandler = [this](const WatchData &data) { + d = data; + }; + auto childHandler = [this](const QSet &expandedINames, + const WatchData &innerData, const GdbMi &innerInput) { + WatchItem *item = new WatchItem(innerData); + item->parseWatchData(expandedINames, innerInput); + appendChild(item); + }; + + auto itemAdder = [this](const WatchData &data) { + appendChild(new WatchItem(data)); + }; + + auto arrayDecoder = [itemAdder](const WatchData &childTemplate, + const QByteArray &encodedData, int encoding) { + decodeArrayData(itemAdder, childTemplate, encodedData, encoding); + }; + + parseChildrenData(expandedINames, d, input, itemHandler, childHandler, arrayDecoder); +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index c3f03b76483..4a1ba185b23 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -75,6 +75,7 @@ public: void formatRequests(QByteArray *out) const; void showInEditorHelper(QString *contents, int depth) const; WatchItem *findItem(const QByteArray &iname); + void parseWatchData(const QSet &expandedINames, const GdbMi &input); public: WatchData d; @@ -196,6 +197,7 @@ public: const WatchData *watchData(const QModelIndex &) const; void fetchMore(const QByteArray &iname) const; const WatchData *findData(const QByteArray &iname) const; + WatchItem *findItem(const QByteArray &iname) const; const WatchData *findCppLocalVariable(const QString &name) const; bool hasItem(const QByteArray &iname) const; @@ -234,10 +236,12 @@ public: void insertData(const WatchData &data); // Convenience. void insertData(const QList &list); void insertIncompleteData(const WatchData &data); + void insertItem(WatchItem *item); void removeData(const QByteArray &iname); void removeChildren(const QByteArray &iname); void removeAllData(bool includeInspectData = false); void resetValueCache(); + void purgeOutdatedItems(const QSet &inames); private: friend class WatchModel;