forked from qt-creator/qt-creator
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 <Friedemann.Kleint@nokia.com>
This commit is contained in:
@@ -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<std::string> 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()) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user