From ee7b327f4c2dd709e67369fd6251c9af7ca8ac08 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 1 Aug 2011 08:36:00 +0200 Subject: [PATCH] Debugger[CDB]: Fix bug in updating pointer-type watch items. Collapse pointer-type items in watch symbol group when updating. Task-number: QTCREATORBUG-5652 Change-Id: I077120c7352da5bc330bb000786a50432bb47738 Reviewed-on: http://codereview.qt.nokia.com/2424 Reviewed-by: Friedemann Kleint --- src/libs/qtcreatorcdbext/symbolgroup.cpp | 43 +++++++++++++++++++- src/libs/qtcreatorcdbext/symbolgroup.h | 2 + src/libs/qtcreatorcdbext/symbolgroupnode.cpp | 33 +++++++++++++++ src/libs/qtcreatorcdbext/symbolgroupnode.h | 3 +- 4 files changed, 78 insertions(+), 3 deletions(-) diff --git a/src/libs/qtcreatorcdbext/symbolgroup.cpp b/src/libs/qtcreatorcdbext/symbolgroup.cpp index 6d2a0a6bf6c..39ef5ffeb06 100644 --- a/src/libs/qtcreatorcdbext/symbolgroup.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroup.cpp @@ -384,6 +384,14 @@ bool SymbolGroup::expand(const std::string &nodeName, std::string *errorMessage) return false; } +bool SymbolGroup::collapse(const std::string &nodeName, std::string *errorMessage) +{ + SymbolGroupNode *node = findNodeForExpansion(this, nodeName, errorMessage); + if (!node) + return false; + return node->collapse(errorMessage); +} + bool SymbolGroup::expandRunComplexDumpers(const std::string &nodeName, const SymbolGroupValueContext &ctx, std::string *errorMessage) { if (SymbolGroupNode *node = findNodeForExpansion(this, nodeName, errorMessage)) @@ -797,8 +805,37 @@ WatchesSymbolGroup::InameExpressionMap return rc; } +/*! + \brief Collapse all expanded pointer items. + + If we have an item '*(Foo*)(address_of_Foo_D_Ptr)' and the + D-Ptr changes due to detaching, the expanded items (whose address + change) do not adapt their value. Force a re-evaluation by collapsing + them. +*/ + +bool WatchesSymbolGroup::collapsePointerItems(std::string *errorMessage) +{ + typedef AbstractSymbolGroupNodePtrVector::const_iterator CIT; + + const AbstractSymbolGroupNodePtrVector existingWatches = root()->children(); + if (existingWatches.empty()) + return true; + + const CIT cend = existingWatches.end(); + for (CIT it = existingWatches.begin(); it != cend; ++it) { + if (SymbolGroupNode *n = (*it)->asSymbolGroupNode()) + if (n->isExpanded() && SymbolGroupValue::isPointerType(n->type())) + if (!n->collapse(errorMessage)) + return false; + } + return true; +} + // Synchronize watches passing on a map of '0' -> '*(int *)(0xA0)' -bool WatchesSymbolGroup::synchronize(CIDebugSymbols *s, const InameExpressionMap &newInameExpMap, std::string *errorMessage) +bool WatchesSymbolGroup::synchronize(CIDebugSymbols *s, + const InameExpressionMap &newInameExpMap, + std::string *errorMessage) { typedef std::set StringSet; typedef InameExpressionMap::const_iterator InameExpressionMapConstIt; @@ -808,7 +845,7 @@ bool WatchesSymbolGroup::synchronize(CIDebugSymbols *s, const InameExpressionMap DebugPrint() << "WatchesSymbolGroup::synchronize oldsize=" << oldInameExpMap.size() << " newsize=" << newInameExpMap.size() << " items, changed=" << changed; if (!changed) // Quick check: All ok - return true; + return collapsePointerItems(errorMessage); // Check both maps against each other and determine elements to be deleted/added. StringSet deletionSet; InameExpressionMap addMap; @@ -840,6 +877,8 @@ bool WatchesSymbolGroup::synchronize(CIDebugSymbols *s, const InameExpressionMap return false; } } + if (!collapsePointerItems(errorMessage)) + return false; // Insertion: We cannot possible fail here since this will trigger an // endless loop of the watch model. Insert a dummy item. if (!addMap.empty()) { diff --git a/src/libs/qtcreatorcdbext/symbolgroup.h b/src/libs/qtcreatorcdbext/symbolgroup.h index b2b9fc1c742..993eb69e2d9 100644 --- a/src/libs/qtcreatorcdbext/symbolgroup.h +++ b/src/libs/qtcreatorcdbext/symbolgroup.h @@ -74,6 +74,7 @@ public: // Expand a single node "locals.A.B" requiring that "locals.A.B" is already visible // (think mkdir without -p). bool expand(const std::string &node, std::string *errorMessage); + bool collapse(const std::string &node, std::string *errorMessage); bool expandRunComplexDumpers(const std::string &node, const SymbolGroupValueContext &ctx, std::string *errorMessage); // Expand a node list "locals.i1,locals.i2", expanding all nested child nodes // (think mkdir -p). @@ -173,6 +174,7 @@ private: InameExpressionMap currentInameExpressionMap() const; inline SymbolGroupNode *rootChildByIname(const std::string &iname) const; static inline std::string fixWatchExpressionI(CIDebugSymbols *s, const std::string &ex); + bool collapsePointerItems(std::string *errorMessage); }; #endif // SYMBOLGROUP_H diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp index 631c53e2b78..63086c246e3 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp @@ -1093,6 +1093,39 @@ static std::string msgExpandFailed(const std::string &name, const std::string &i return str.str(); } +static std::string msgCollapseFailed(const std::string &name, const std::string &iname, + ULONG index, const std::string &why) +{ + std::ostringstream str; + str << "Collapsing of '" << name << "'/'" << iname << " (index: " << index + << ") failed: " << why; + return str.str(); +} + +bool SymbolGroupNode::collapse(std::string *errorMessage) +{ + if (!isExpanded()) + return true; + SymbolGroupNode *sParent = symbolGroupNodeParent(); + if (!sParent) { + *errorMessage = msgCollapseFailed(name(), absoluteFullIName(), m_index, "Cannot collapse root."); + ExtensionContext::instance().report('X', 0, 0, "Error", "%s", errorMessage->c_str()); + return false; + } + // Get current number of children + const ULONG next = nextSymbolIndex(); + HRESULT hr = m_symbolGroup->debugSymbolGroup()->ExpandSymbol(m_index, FALSE); + if (FAILED(hr)) { + *errorMessage = msgCollapseFailed(name(), absoluteFullIName(), m_index, msgDebugEngineComFailed("ExpandSymbol(FALSE)", hr)); + ExtensionContext::instance().report('X', 0, 0, "Error", "%s", errorMessage->c_str()); + return false; + } + removeChildren(); + if (next) + sParent->notifyIndexesMoved(m_index + 1, false, next - m_index - 1); + return true; +} + // Expand! bool SymbolGroupNode::expand(std::string *errorMessage) { diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.h b/src/libs/qtcreatorcdbext/symbolgroupnode.h index a10b3aa6c94..999c42df8c5 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupnode.h +++ b/src/libs/qtcreatorcdbext/symbolgroupnode.h @@ -158,7 +158,7 @@ protected: void reserveChildren(AbstractSymbolGroupNodePtrVector::size_type s) { m_children.reserve(s); } -private: +protected: AbstractSymbolGroupNodePtrVector m_children; void removeChildren(); }; @@ -244,6 +244,7 @@ public: bool expandRunComplexDumpers(const SymbolGroupValueContext &ctx, std::string *errorMessage); bool isExpanded() const { return !children().empty(); } bool canExpand() const { return m_parameters.SubElements > 0; } + bool collapse(std::string *errorMessage); void runComplexDumpers(const SymbolGroupValueContext &ctx); // Cast to a different type. Works only on unexpanded nodes bool typeCast(const std::string &desiredType, std::string *errorMessage);