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;
|
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)
|
bool SymbolGroup::expandRunComplexDumpers(const std::string &nodeName, const SymbolGroupValueContext &ctx, std::string *errorMessage)
|
||||||
{
|
{
|
||||||
if (SymbolGroupNode *node = findNodeForExpansion(this, nodeName, errorMessage))
|
if (SymbolGroupNode *node = findNodeForExpansion(this, nodeName, errorMessage))
|
||||||
@@ -797,8 +805,37 @@ WatchesSymbolGroup::InameExpressionMap
|
|||||||
return rc;
|
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)'
|
// 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 std::set<std::string> StringSet;
|
||||||
typedef InameExpressionMap::const_iterator InameExpressionMapConstIt;
|
typedef InameExpressionMap::const_iterator InameExpressionMapConstIt;
|
||||||
@@ -808,7 +845,7 @@ bool WatchesSymbolGroup::synchronize(CIDebugSymbols *s, const InameExpressionMap
|
|||||||
DebugPrint() << "WatchesSymbolGroup::synchronize oldsize=" << oldInameExpMap.size()
|
DebugPrint() << "WatchesSymbolGroup::synchronize oldsize=" << oldInameExpMap.size()
|
||||||
<< " newsize=" << newInameExpMap.size() << " items, changed=" << changed;
|
<< " newsize=" << newInameExpMap.size() << " items, changed=" << changed;
|
||||||
if (!changed) // Quick check: All ok
|
if (!changed) // Quick check: All ok
|
||||||
return true;
|
return collapsePointerItems(errorMessage);
|
||||||
// Check both maps against each other and determine elements to be deleted/added.
|
// Check both maps against each other and determine elements to be deleted/added.
|
||||||
StringSet deletionSet;
|
StringSet deletionSet;
|
||||||
InameExpressionMap addMap;
|
InameExpressionMap addMap;
|
||||||
@@ -840,6 +877,8 @@ bool WatchesSymbolGroup::synchronize(CIDebugSymbols *s, const InameExpressionMap
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!collapsePointerItems(errorMessage))
|
||||||
|
return false;
|
||||||
// Insertion: We cannot possible fail here since this will trigger an
|
// Insertion: We cannot possible fail here since this will trigger an
|
||||||
// endless loop of the watch model. Insert a dummy item.
|
// endless loop of the watch model. Insert a dummy item.
|
||||||
if (!addMap.empty()) {
|
if (!addMap.empty()) {
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ public:
|
|||||||
// Expand a single node "locals.A.B" requiring that "locals.A.B" is already visible
|
// Expand a single node "locals.A.B" requiring that "locals.A.B" is already visible
|
||||||
// (think mkdir without -p).
|
// (think mkdir without -p).
|
||||||
bool expand(const std::string &node, std::string *errorMessage);
|
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);
|
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
|
// Expand a node list "locals.i1,locals.i2", expanding all nested child nodes
|
||||||
// (think mkdir -p).
|
// (think mkdir -p).
|
||||||
@@ -173,6 +174,7 @@ private:
|
|||||||
InameExpressionMap currentInameExpressionMap() const;
|
InameExpressionMap currentInameExpressionMap() const;
|
||||||
inline SymbolGroupNode *rootChildByIname(const std::string &iname) const;
|
inline SymbolGroupNode *rootChildByIname(const std::string &iname) const;
|
||||||
static inline std::string fixWatchExpressionI(CIDebugSymbols *s, const std::string &ex);
|
static inline std::string fixWatchExpressionI(CIDebugSymbols *s, const std::string &ex);
|
||||||
|
bool collapsePointerItems(std::string *errorMessage);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SYMBOLGROUP_H
|
#endif // SYMBOLGROUP_H
|
||||||
|
|||||||
@@ -1093,6 +1093,39 @@ static std::string msgExpandFailed(const std::string &name, const std::string &i
|
|||||||
return str.str();
|
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!
|
// Expand!
|
||||||
bool SymbolGroupNode::expand(std::string *errorMessage)
|
bool SymbolGroupNode::expand(std::string *errorMessage)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ protected:
|
|||||||
|
|
||||||
void reserveChildren(AbstractSymbolGroupNodePtrVector::size_type s) { m_children.reserve(s); }
|
void reserveChildren(AbstractSymbolGroupNodePtrVector::size_type s) { m_children.reserve(s); }
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
AbstractSymbolGroupNodePtrVector m_children;
|
AbstractSymbolGroupNodePtrVector m_children;
|
||||||
void removeChildren();
|
void removeChildren();
|
||||||
};
|
};
|
||||||
@@ -244,6 +244,7 @@ public:
|
|||||||
bool expandRunComplexDumpers(const SymbolGroupValueContext &ctx, std::string *errorMessage);
|
bool expandRunComplexDumpers(const SymbolGroupValueContext &ctx, std::string *errorMessage);
|
||||||
bool isExpanded() const { return !children().empty(); }
|
bool isExpanded() const { return !children().empty(); }
|
||||||
bool canExpand() const { return m_parameters.SubElements > 0; }
|
bool canExpand() const { return m_parameters.SubElements > 0; }
|
||||||
|
bool collapse(std::string *errorMessage);
|
||||||
void runComplexDumpers(const SymbolGroupValueContext &ctx);
|
void runComplexDumpers(const SymbolGroupValueContext &ctx);
|
||||||
// Cast to a different type. Works only on unexpanded nodes
|
// Cast to a different type. Works only on unexpanded nodes
|
||||||
bool typeCast(const std::string &desiredType, std::string *errorMessage);
|
bool typeCast(const std::string &desiredType, std::string *errorMessage);
|
||||||
|
|||||||
Reference in New Issue
Block a user