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:
Friedemann Kleint
2011-08-01 08:36:00 +02:00
parent 65c0eb5165
commit ee7b327f4c
4 changed files with 78 additions and 3 deletions

View File

@@ -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()) {

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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);