summaryrefslogtreecommitdiff
path: root/src/libs/qtcreatorcdbext
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>2010-12-10 17:17:55 +0100
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>2010-12-10 17:17:55 +0100
commitd3619e806d6ee61a9457057b924d607876b87abb (patch)
tree8f6b2c15a70e6ce5826d566ce830165fecf269ad /src/libs/qtcreatorcdbext
parentddf360d4a9718ae5a80f4a266515a76348198d3c (diff)
downloadqt-creator-d3619e806d6ee61a9457057b924d607876b87abb.tar.gz
Debugger[New CDB]: First stab at containers.
Set up infrastructure for having 'fake' children in a symbolgroup that merely reference others. Print inames correctly, do index bookkeeping accordingly, adapt visitor. Prototypically implement complex dumpers for array-type containers. adding children as additional symbols.
Diffstat (limited to 'src/libs/qtcreatorcdbext')
-rw-r--r--src/libs/qtcreatorcdbext/containers.cpp135
-rw-r--r--src/libs/qtcreatorcdbext/containers.h46
-rw-r--r--src/libs/qtcreatorcdbext/qtcreatorcdbext_build.pro6
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroup.cpp141
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroup.h49
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroupvalue.cpp113
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroupvalue.h10
7 files changed, 430 insertions, 70 deletions
diff --git a/src/libs/qtcreatorcdbext/containers.cpp b/src/libs/qtcreatorcdbext/containers.cpp
new file mode 100644
index 0000000000..3df9514d2c
--- /dev/null
+++ b/src/libs/qtcreatorcdbext/containers.cpp
@@ -0,0 +1,135 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "containers.h"
+#include "symbolgroupvalue.h"
+#include "symbolgroup.h"
+#include "stringutils.h"
+
+typedef SymbolGroupNode::SymbolGroupNodePtrVector SymbolGroupNodePtrVector;
+
+/* Helper for array-type containers:
+ * Add a series of "*(innertype *)0x (address + n * size)" fake child symbols. */
+static SymbolGroupNodePtrVector arrayChildList(SymbolGroup *sg, ULONG64 address,
+ int count, const std::string &innerType)
+{
+ SymbolGroupNodePtrVector rc;
+ const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str());
+ if (!innerTypeSize)
+ return rc;
+
+ std::string errorMessage;
+ rc.reserve(count);
+ for (int i = 0; i < count; i++, address += innerTypeSize) {
+ std::ostringstream str;
+ str << "*(" << innerType << " *)" << std::showbase << std::hex << address;
+ if (SymbolGroupNode *child = sg->addSymbol(str.str(), toString(i), &errorMessage)) {
+ rc.push_back(child);
+ } else {
+ break;
+ }
+ }
+ return rc;
+}
+
+// std::vector<T>
+static inline SymbolGroupNodePtrVector
+ stdVectorChildList(SymbolGroupNode *n, int count, const SymbolGroupValueContext &ctx)
+{
+ if (count) {
+ // std::vector<T>: _Myfirst is a pointer of T*. Get address
+ // element to obtain address.
+ const SymbolGroupValue vec(n, ctx);
+ SymbolGroupValue myFirst = vec[unsigned(0)]["_Myfirst"]; // MSVC2010
+ if (!myFirst)
+ myFirst = vec["_Myfirst"]; // MSVC2008
+ if (myFirst)
+ if (const ULONG64 address = myFirst.pointerValue())
+ return arrayChildList(n->symbolGroup(), address, count,
+ SymbolGroupValue::stripPointerType(myFirst.type()));
+ }
+ return SymbolGroupNodePtrVector();
+}
+
+// QVector<T>
+static inline SymbolGroupNodePtrVector
+ qVectorChildList(SymbolGroupNode *n, int count, const SymbolGroupValueContext &ctx)
+{
+ if (count) {
+ // QVector<T>: p/array is declared as array of T. Dereference first
+ // element to obtain address.
+ const SymbolGroupValue vec(n, ctx);
+ if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)])
+ if (const ULONG64 arrayAddress = firstElementV.address())
+ return arrayChildList(n->symbolGroup(), arrayAddress, count,
+ firstElementV.type());
+ }
+ return SymbolGroupNodePtrVector();
+}
+
+// QList<> of type array
+static inline SymbolGroupNodePtrVector
+ qListOfArraryTypeChildren(SymbolGroup *sg, const SymbolGroupValue &v, int count)
+{
+ // QList<T>: d/array is declared as array of void *[]. Dereference first
+ // element to obtain address.
+ if (count) {
+ if (const SymbolGroupValue firstElementV = v["d"]["array"][unsigned(0)])
+ if (const ULONG64 arrayAddress = firstElementV.address()) {
+ const std::vector<std::string> innerTypes = v.innerTypes();
+ if (innerTypes.size() == 1)
+ return arrayChildList(sg, arrayAddress,
+ count, innerTypes.front());
+ }
+ }
+ return SymbolGroupNodePtrVector();
+}
+
+SymbolGroupNodePtrVector containerChildren(SymbolGroupNode *node, int type,
+ int size, const SymbolGroupValueContext &ctx)
+{
+ if (!size)
+ return SymbolGroupNodePtrVector();
+ if (size > 100)
+ size = 100;
+ switch (type) {
+ case KT_QVector:
+ return qVectorChildList(node, size, ctx);
+ case KT_StdVector:
+ return stdVectorChildList(node, size, ctx);
+ case KT_QList:
+ // Differentiate between array and list
+ break;
+ case KT_QStringList:
+ if (const SymbolGroupValue qList = SymbolGroupValue(node, ctx)[unsigned(0)])
+ return qListOfArraryTypeChildren(node->symbolGroup(), qList, size);
+ break;
+ }
+ return SymbolGroupNodePtrVector();
+}
diff --git a/src/libs/qtcreatorcdbext/containers.h b/src/libs/qtcreatorcdbext/containers.h
new file mode 100644
index 0000000000..a488a2dfa9
--- /dev/null
+++ b/src/libs/qtcreatorcdbext/containers.h
@@ -0,0 +1,46 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CONTAINERS_H
+#define CONTAINERS_H
+
+struct SymbolGroupValueContext;
+class SymbolGroupNode;
+
+#include "common.h"
+
+#include <vector>
+
+/* Create a list of children of containers. */
+std::vector<SymbolGroupNode *> containerChildren(SymbolGroupNode *node,
+ int type,
+ int size,
+ const SymbolGroupValueContext &ctx);
+
+#endif // CONTAINERS_H
diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbext_build.pro b/src/libs/qtcreatorcdbext/qtcreatorcdbext_build.pro
index 1ddfc45a9b..62fcbb037c 100644
--- a/src/libs/qtcreatorcdbext/qtcreatorcdbext_build.pro
+++ b/src/libs/qtcreatorcdbext/qtcreatorcdbext_build.pro
@@ -54,7 +54,8 @@ SOURCES += qtcreatorcdbextension.cpp \
gdbmihelpers.cpp \
outputcallback.cpp \
base64.cpp \
- symbolgroupvalue.cpp
+ symbolgroupvalue.cpp \
+ containers.cpp
HEADERS += extensioncontext.h \
common.h \
@@ -65,4 +66,5 @@ HEADERS += extensioncontext.h \
gdbmihelpers.h \
outputcallback.h \
base64.h \
- symbolgroupvalue.h
+ symbolgroupvalue.h \
+ containers.h
diff --git a/src/libs/qtcreatorcdbext/symbolgroup.cpp b/src/libs/qtcreatorcdbext/symbolgroup.cpp
index 9ad79a2388..f08b02a2dd 100644
--- a/src/libs/qtcreatorcdbext/symbolgroup.cpp
+++ b/src/libs/qtcreatorcdbext/symbolgroup.cpp
@@ -31,6 +31,7 @@
#include "symbolgroupvalue.h"
#include "stringutils.h"
#include "base64.h"
+#include "containers.h"
#include <algorithm>
#include <sstream>
@@ -383,8 +384,10 @@ SymbolGroupNode::SymbolGroupNode(SymbolGroup *symbolGroup,
const std::string &name,
const std::string &iname,
SymbolGroupNode *parent) :
- m_symbolGroup(symbolGroup), m_parent(parent), m_index(index),
- m_name(name), m_iname(iname), m_flags(0)
+ m_symbolGroup(symbolGroup), m_parent(parent),
+ m_index(index), m_referencedBy(0),
+ m_name(name), m_iname(iname), m_flags(0), m_dumperType(-1),
+ m_dumperContainerSize(-1)
{
memset(&m_parameters, 0, sizeof(DEBUG_SYMBOL_PARAMETERS));
m_parameters.ParentSymbol = DEBUG_ANY_ID;
@@ -394,12 +397,23 @@ void SymbolGroupNode::removeChildren()
{
if (!m_children.empty()) {
const SymbolGroupNodePtrVectorIterator end = m_children.end();
- for (SymbolGroupNodePtrVectorIterator it = m_children.begin(); it != end; ++it)
- delete *it;
+ for (SymbolGroupNodePtrVectorIterator it = m_children.begin(); it != end; ++it) {
+ SymbolGroupNode *child = *it;
+ if (child->parent() == this) // Do not delete references
+ delete child;
+ }
m_children.clear();
}
}
+void SymbolGroupNode::setReferencedBy(SymbolGroupNode *n)
+{
+ if (m_referencedBy)
+ dprintf("Internal error: Node %s Clearing reference by %s",
+ name().c_str(), m_referencedBy->name().c_str());
+ m_referencedBy = n;
+}
+
bool SymbolGroupNode::isArrayElement() const
{
return m_parent && (m_parent->m_parameters.Flags & DEBUG_SYMBOL_IS_ARRAY);
@@ -415,9 +429,12 @@ bool SymbolGroupNode::notifyExpanded(ULONG index, ULONG insertedCount)
// Looping backwards over the children. If a subtree has no modifications,
// (meaning all other indexes are smaller) we can stop.
const ReverseIt rend = m_children.rend();
- for (ReverseIt it = m_children.rbegin(); it != rend; ++it)
- if (!(*it)->notifyExpanded(index, insertedCount))
- return false;
+ for (ReverseIt it = m_children.rbegin(); it != rend; ++it) {
+ SymbolGroupNode *c = *it;
+ if (c->parent() == this) // Skip fake children that are referenced only
+ if (!(*it)->notifyExpanded(index, insertedCount))
+ return false;
+ }
// Correct our own + parent index if applicable.
if (m_index == DEBUG_ANY_ID || m_index < index)
@@ -433,7 +450,7 @@ bool SymbolGroupNode::notifyExpanded(ULONG index, ULONG insertedCount)
std::string SymbolGroupNode::fullIName() const
{
std::string rc = iName();
- for (const SymbolGroupNode *p = parent(); p; p = p->parent()) {
+ for (const SymbolGroupNode *p = referencedParent(); p; p = p->referencedParent()) {
rc.insert(0, 1, '.');
rc.insert(0, p->iName());
}
@@ -706,15 +723,45 @@ std::wstring SymbolGroupNode::symbolGroupFixedValue() const
return value;
}
-// Value to be reported to debugger
-std::wstring SymbolGroupNode::displayValue(const SymbolGroupValueContext &ctx)
+// Complex dumpers: Get container/fake children
+void SymbolGroupNode::runComplexDumpers(const SymbolGroupValueContext &ctx)
+{
+ if (m_dumperContainerSize <= 0 || (m_flags & ComplexDumperOk) || !(m_flags & SimpleDumperOk))
+ return;
+ m_flags |= ComplexDumperOk;
+ const SymbolGroupNodePtrVector children =
+ containerChildren(this, m_dumperType, m_dumperContainerSize, ctx);
+ m_dumperContainerSize = int(children.size()); // Just in case...
+ if (children.empty())
+ return;
+
+ clearFlags(ExpandedByDumper);
+ // Mark current children as obscured. We cannot show both currently
+ // as this would upset the numerical sorting of the watch model
+ SymbolGroupNodePtrVectorConstIterator cend = m_children.end();
+ for (SymbolGroupNodePtrVectorConstIterator it = m_children.begin(); it != cend; ++it)
+ (*it)->addFlags(Obscured);
+ // Add children and mark them as referenced by us.
+ cend = children.end();
+ for (SymbolGroupNodePtrVectorConstIterator it = children.begin(); it != cend; ++it) {
+ SymbolGroupNode *c = *it;
+ c->setReferencedBy(this);
+ m_children.push_back(c);
+ }
+}
+
+// Run dumpers, format simple in-line dumper value and retrieve fake children
+std::wstring SymbolGroupNode::simpleDumpValue(const SymbolGroupValueContext &ctx,
+ const DumpParameters &)
{
if (m_flags & Uninitialized)
return L"<not in scope>";
- if ((m_flags & DumperMask) == 0)
- m_flags |= dumpSimpleType(this , ctx, &m_dumperValue);
- if (m_flags & DumperOk)
- return m_dumperValue;
+ if ((m_flags & SimpleDumperMask) == 0) {
+ m_flags |= dumpSimpleType(this , ctx, &m_dumperValue,
+ &m_dumperType, &m_dumperContainerSize);
+ if (m_flags & SimpleDumperOk)
+ return m_dumperValue;
+ }
return symbolGroupFixedValue();
}
@@ -765,7 +812,7 @@ void SymbolGroupNode::dump(std::ostream &str,
bool valueEnabled = !uninitialized;
// Shall it be recoded?
- std::wstring value = displayValue(ctx);
+ std::wstring value = simpleDumpValue(ctx, p);
int encoding = 0;
if (p.recode(t, iname, ctx, &value, &encoding)) {
str << ",valueencoded=\"" << encoding
@@ -780,9 +827,19 @@ void SymbolGroupNode::dump(std::ostream &str,
str << '"';
}
}
- // Children: Dump all known or subelements (guess).
- const VectorIndexType childCountGuess = uninitialized ? 0 :
- (m_children.empty() ? m_parameters.SubElements : m_children.size());
+ // Children: Dump all known non-obscured or subelements
+ unsigned childCountGuess = 0;
+ if (!uninitialized) {
+ if (m_dumperContainerSize > 0) {
+ childCountGuess = m_dumperContainerSize; // See Obscured handling
+ } else {
+ if (m_children.empty()) {
+ childCountGuess = m_parameters.SubElements; // Guess
+ } else {
+ childCountGuess = unsigned(m_children.size());
+ }
+ }
+ }
// No children..suppose we are editable and enabled
if (childCountGuess != 0)
valueEditable = false;
@@ -822,6 +879,8 @@ void SymbolGroupNode::debug(std::ostream &str, unsigned verbosity, unsigned dept
{
indentStream(str, depth);
str << '"' << fullIName() << "\",index=" << m_index;
+ if (m_referencedBy)
+ str << ",referenced by \"" << m_referencedBy->fullIName() << '"';
if (const VectorIndexType childCount = m_children.size())
str << ", Children=" << childCount;
str << ' ' << m_parameters;
@@ -829,23 +888,36 @@ void SymbolGroupNode::debug(std::ostream &str, unsigned verbosity, unsigned dept
str << " node-flags=" << m_flags;
if (m_flags & Uninitialized)
str << " UNINITIALIZED";
- if (m_flags & DumperNotApplicable)
+ if (m_flags & SimpleDumperNotApplicable)
str << " DumperNotApplicable";
- if (m_flags & DumperOk)
+ if (m_flags & SimpleDumperOk)
str << " DumperOk";
- if (m_flags & DumperFailed)
+ if (m_flags & SimpleDumperFailed)
str << " DumperFailed";
if (m_flags & ExpandedByDumper)
str << " ExpandedByDumper";
if (m_flags & AdditionalSymbol)
str << " AdditionalSymbol";
+ if (m_flags & Obscured)
+ str << " Obscured";
+ if (m_flags & ComplexDumperOk)
+ str << " ComplexDumperOk";
str << ' ';
}
if (verbosity) {
str << ",name=\"" << m_name << "\", Address=0x" << std::hex << address() << std::dec
<< " Type=\"" << type() << '"';
+ if (m_dumperType >= 0) {
+ str << " ,dumperType=" << m_dumperType;
+ if (m_dumperType & KT_Qt_Type)
+ str << " qt";
+ if (m_dumperType & KT_STL_Type)
+ str << " STL";
+ if (m_dumperType & KT_ContainerType)
+ str << " container(" << m_dumperContainerSize << ')';
+ }
if (!(m_flags & Uninitialized))
- str << "\" Value=\"" << gdbmiWStringFormat(symbolGroupRawValue()) << '"';
+ str << " Value=\"" << gdbmiWStringFormat(symbolGroupRawValue()) << '"';
}
str << '\n';
}
@@ -997,6 +1069,9 @@ std::string SymbolGroup::dump(const std::string &iname,
if (node->canExpand() && !node->expand(errorMessage))
return false;
}
+ // After expansion, run the complex dumpers
+ if (p.dumpFlags & DumpParameters::DumpComplexDumpers)
+ node->runComplexDumpers(ctx);
std::ostringstream str;
if (p.humanReadable())
str << '\n';
@@ -1237,22 +1312,28 @@ DumpSymbolGroupNodeVisitor::DumpSymbolGroupNodeVisitor(std::ostream &os,
const SymbolGroupValueContext &context,
const DumpParameters &parameters) :
m_os(os), m_context(context), m_parameters(parameters),
- m_visitChildren(false)
+ m_visitChildren(false),m_lastDepth(unsigned(-1))
{
}
SymbolGroupNodeVisitor::VisitResult
- DumpSymbolGroupNodeVisitor::visit(SymbolGroupNode *node, unsigned child, unsigned depth)
+ DumpSymbolGroupNodeVisitor::visit(SymbolGroupNode *node, unsigned /* child */, unsigned depth)
{
- // Recurse to children if expanded by explicit watchmodel request
+ // Show container children only
+ if (node->flags() & SymbolGroupNode::Obscured)
+ return VisitSkipChildren;
+ // Recurse to children only if expanded by explicit watchmodel request
// and initialized.
const unsigned flags = node->flags();
m_visitChildren = node->isExpanded()
&& (flags & (SymbolGroupNode::Uninitialized|SymbolGroupNode::ExpandedByDumper)) == 0;
- // Do not recurse into children unless the node was expanded by the watch model
- if (child)
- m_os << ','; // Separator in parents list
+ // Comma between same level children given obscured children
+ if (depth == m_lastDepth) {
+ m_os << ',';
+ } else {
+ m_lastDepth = depth;
+ }
if (m_parameters.humanReadable()) {
m_os << '\n';
indentStream(m_os, depth * 2);
@@ -1269,9 +1350,9 @@ SymbolGroupNodeVisitor::VisitResult
return m_visitChildren ? VisitContinue : VisitSkipChildren;
}
-void DumpSymbolGroupNodeVisitor::childrenVisited(const SymbolGroupNode *, unsigned)
+void DumpSymbolGroupNodeVisitor::childrenVisited(const SymbolGroupNode *n, unsigned)
{
m_os << "]}"; // Close children array and self
if (m_parameters.humanReadable())
- m_os << '\n';
+ m_os << " /* end of '" << n->fullIName() << "' */\n";
}
diff --git a/src/libs/qtcreatorcdbext/symbolgroup.h b/src/libs/qtcreatorcdbext/symbolgroup.h
index 2f5dd73332..5991164253 100644
--- a/src/libs/qtcreatorcdbext/symbolgroup.h
+++ b/src/libs/qtcreatorcdbext/symbolgroup.h
@@ -68,13 +68,21 @@ struct DumpParameters
FormatMap individualFormats;
};
-// Thin wrapper around a symbol group entry. Provides accessors for fixed-up
-// symbol group value and a dumping facility triggered by dump()/displayValue()
-// calling dumpSimpleType() based on SymbolGroupValue expressions. These values
-// values should be displayed, still allowing for expansion of the structure
-// in the debugger. Evaluating the dumpers might expand symbol nodes, which are
-// then marked as 'ExpandedByDumper'. This stops the dump recursion to prevent
-// outputting data that were not explicitly expanded by the watch handler.
+/* Thin wrapper around a symbol group entry. Provides accessors for fixed-up
+ * symbol group value and a dumping facility consisting of:
+ * - 'Simple' dumping done when running the DumpVisitor. This produces one
+ * line of formatted output shown for the class. These values
+ * values should are displayed, while still allowing for expansion of the structure
+ * in the debugger.
+ * It also pre-determines some information for complex dumping (type, container).
+ * - 'Complex' dumping: Obscures the symbol group children by fake children, for
+ * example container children, run when calling SymbolGroup::dump with an iname.
+ * The fake children are appended to the child list (other children are just marked as
+ * obscured for GDBMI dumping so that SymbolGroupValue expressions still work as before).
+ * The dumping is mostly based on SymbolGroupValue expressions.
+ * in the debugger. Evaluating those dumpers might expand symbol nodes, which are
+ * then marked as 'ExpandedByDumper'. This stops the dump recursion to prevent
+ * outputting data that were not explicitly expanded by the watch handler. */
class SymbolGroupNode {
SymbolGroupNode(const SymbolGroupNode&);
@@ -89,12 +97,14 @@ class SymbolGroupNode {
public:
enum Flags {
Uninitialized = 0x1,
- DumperNotApplicable = 0x2, // No dumper available for type
- DumperOk = 0x4, // Internal dumper ran, value set
- DumperFailed = 0x8, // Internal dumper failed
- DumperMask = DumperNotApplicable|DumperOk|DumperFailed,
+ SimpleDumperNotApplicable = 0x2, // No dumper available for type
+ SimpleDumperOk = 0x4, // Internal dumper ran, value set
+ SimpleDumperFailed = 0x8, // Internal dumper failed
+ SimpleDumperMask = SimpleDumperNotApplicable|SimpleDumperOk|SimpleDumperFailed,
ExpandedByDumper = 0x10,
- AdditionalSymbol = 0x20 // Introduced by addSymbol, should not be visible
+ AdditionalSymbol = 0x20, // Introduced by addSymbol, should not be visible
+ Obscured = 0x40, // Symbol is obscured by (for example) fake container children
+ ComplexDumperOk = 0x80
};
typedef std::vector<DEBUG_SYMBOL_PARAMETERS> SymbolParameterVector;
@@ -104,6 +114,9 @@ public:
~SymbolGroupNode() { removeChildren(); }
+ // Indicate reference
+ void setReferencedBy(SymbolGroupNode *n);
+
void removeChildren();
void parseParameters(SymbolParameterVector::size_type index,
SymbolParameterVector::size_type parameterOffset,
@@ -126,6 +139,7 @@ public:
SymbolGroupNode *childByIName(const char *) const;
const SymbolGroupNode *parent() const { return m_parent; }
+ const SymbolGroupNode *referencedParent() const { return m_referencedBy ? m_referencedBy : m_parent; }
SymbolGroup *symbolGroup() const { return m_symbolGroup; }
// I/O: Gdbmi dump for Visitors
@@ -135,9 +149,10 @@ public:
std::wstring symbolGroupRawValue() const;
std::wstring symbolGroupFixedValue() const;
- std::wstring displayValue(const SymbolGroupValueContext &ctx);
std::string type() const;
+ int dumperType() const { return m_dumperType; } // Valid after dumper run
+ int dumperContainerSize() { return m_dumperContainerSize; } // Valid after dumper run
unsigned size() const; // Size of value
ULONG64 address() const;
@@ -146,6 +161,7 @@ public:
bool expand(std::string *errorMessage);
bool isExpanded() const { return !m_children.empty(); }
bool canExpand() const { return m_parameters.SubElements > 0; }
+ void runComplexDumpers(const SymbolGroupValueContext &ctx);
// Cast to a different type. Works only on unexpanded nodes
bool typeCast(const std::string &desiredType, std::string *errorMessage);
@@ -161,9 +177,13 @@ private:
bool isArrayElement() const;
// Notify about expansion of a node, shift indexes
bool notifyExpanded(ULONG index, ULONG insertedCount);
+ std::wstring simpleDumpValue(const SymbolGroupValueContext &ctx,
+ const DumpParameters &p);
SymbolGroup *const m_symbolGroup;
SymbolGroupNode *m_parent;
+ // Indicates a fake child (container value). Used for the full iname
+ SymbolGroupNode *m_referencedBy;
ULONG m_index;
DEBUG_SYMBOL_PARAMETERS m_parameters; // Careful when using ParentSymbol. It might not be correct.
SymbolGroupNodePtrVector m_children;
@@ -171,6 +191,8 @@ private:
const std::string m_iname;
unsigned m_flags;
std::wstring m_dumperValue;
+ int m_dumperType;
+ int m_dumperContainerSize;
};
/* Visitor that takes care of iterating over the nodes
@@ -312,6 +334,7 @@ private:
const SymbolGroupValueContext &m_context;
const DumpParameters &m_parameters;
bool m_visitChildren;
+ unsigned m_lastDepth;
};
#endif // SYMBOLGROUP_H
diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
index ebfe475b55..ca3544fbde 100644
--- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
+++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
@@ -220,6 +220,62 @@ std::string SymbolGroupValue::stripPointerType(const std::string &t)
return endsWith(t, " *") ? t.substr(0, t.size() - 2) : t;
}
+std::string SymbolGroupValue::stripArrayType(const std::string &t)
+{
+ const std::string::size_type bracket = t.rfind('[');
+ if (bracket != std::string::npos) {
+ std::string rc = t.substr(0, bracket);
+ trimBack(rc);
+ return rc;
+ }
+ return t;
+}
+
+// get the inner types: "QMap<int, double>" -> "int", "double"
+std::vector<std::string> SymbolGroupValue::innerTypesOf(const std::string &t)
+{
+ std::vector<std::string> rc;
+
+ std::string::size_type pos = t.find('<');
+ if (pos == std::string::npos)
+ return rc;
+
+ rc.reserve(5);
+ const std::string::size_type size = t.size();
+ // Record all elements of level 1 to work correctly for
+ // 'std::map<std::basic_string< .. > >'
+ unsigned level = 0;
+ std::string::size_type start = 0;
+ for ( ; pos < size ; pos++) {
+ const char c = t.at(pos);
+ switch (c) {
+ case '<':
+ if (++level == 1)
+ start = pos + 1;
+ break;
+ case '>':
+ if (--level == 0) { // last element
+ std::string innerType = t.substr(start, pos - start);
+ trimFront(innerType);
+ trimBack(innerType);
+ rc.push_back(innerType);
+ return rc;
+ }
+ break;
+ case ',':
+ if (level == 1) { // std::map<a, b>: start anew at ','.
+ std::string innerType = t.substr(start, pos - start);
+ trimFront(innerType);
+ trimBack(innerType);
+ rc.push_back(innerType);
+ start = pos + 1;
+ }
+ break;
+ }
+ }
+ return rc;
+}
+
// -------------------- Simple dumping helpers
// Courtesy of qdatetime.cpp
@@ -893,89 +949,98 @@ static inline std::wstring msgContainerSize(int s)
}
// Dump builtin simple types using SymbolGroupValue expressions.
-unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, std::wstring *s)
+unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
+ std::wstring *s, int *knownTypeIn /* = 0 */,
+ int *containerSizeIn /* = 0 */)
{
+ if (containerSizeIn)
+ *containerSizeIn = -1;
// Check for class types and strip pointer types (references appear as pointers as well)
s->clear();
const KnownType kt = knownType(n->type());
+ if (knownTypeIn)
+ *knownTypeIn = kt;
+
if (kt == KT_Unknown)
- return SymbolGroupNode::DumperNotApplicable;
+ return SymbolGroupNode::SimpleDumperNotApplicable;
const SymbolGroupValue v(n, ctx);
// Simple dump of size for containers
if (kt & KT_ContainerType) {
const int size = containerSize(kt, v);
+ if (containerSizeIn)
+ *containerSizeIn = size;
if (size >= 0) {
*s = msgContainerSize(size);
- return SymbolGroupNode::DumperOk;
+ return SymbolGroupNode::SimpleDumperOk;
}
- return SymbolGroupNode::DumperFailed;
+ return SymbolGroupNode::SimpleDumperFailed;
}
std::wostringstream str;
- unsigned rc = SymbolGroupNode::DumperNotApplicable;
+ unsigned rc = SymbolGroupNode::SimpleDumperNotApplicable;
switch (kt) {
case KT_QChar:
- rc = dumpQChar(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQChar(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QByteArray:
- rc = dumpQByteArray(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQByteArray(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QString:
- rc = dumpQString(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQString(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QColor:
- rc = dumpQColor(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQColor(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QFlags:
- rc = dumpQFlags(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQFlags(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QDate:
- rc = dumpQDate(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQDate(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QTime:
- rc = dumpQTime(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQTime(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QPoint:
case KT_QPointF:
- rc = dumpQPoint_F(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQPoint_F(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QSize:
case KT_QSizeF:
- rc = dumpQSize_F(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQSize_F(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QLine:
case KT_QLineF:
- rc = dumpQLine_F(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQLine_F(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QRect:
- rc = dumpQRect(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQRect(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QRectF:
- rc = dumpQRectF(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQRectF(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QVariant:
- rc = dumpQVariant(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQVariant(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QAtomicInt:
- rc = dumpQAtomicInt(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQAtomicInt(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QBasicAtomicInt:
- rc = dumpQBasicAtomicInt(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQBasicAtomicInt(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QObject:
- rc = dumpQObject(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQObject(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QWidget:
- rc = dumpQObject(v[unsigned(0)], str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpQObject(v[unsigned(0)], str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_StdString:
case KT_StdWString:
- rc = dumpStd_W_String(v, str) ? SymbolGroupNode::DumperOk : SymbolGroupNode::DumperFailed;
+ rc = dumpStd_W_String(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
default:
break;
}
- if (rc == SymbolGroupNode::DumperOk)
+ if (rc == SymbolGroupNode::SimpleDumperOk)
*s = str.str();
return rc;
}
diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.h b/src/libs/qtcreatorcdbext/symbolgroupvalue.h
index 107f3f89e5..365c2455cb 100644
--- a/src/libs/qtcreatorcdbext/symbolgroupvalue.h
+++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.h
@@ -33,6 +33,7 @@
#include "common.h"
#include <string>
+#include <vector>
class SymbolGroupNode;
@@ -67,6 +68,7 @@ public:
SymbolGroupValue pointerTypeCast(const char *type) const;
std::string type() const;
+ std::vector<std::string> innerTypes() const { return innerTypesOf(type()); }
std::wstring value() const;
unsigned size() const;
@@ -83,6 +85,9 @@ public:
static inline unsigned sizeOf(const char *type) { return GetTypeSize(type); }
static std::string stripPointerType(const std::string &);
+ static std::string stripArrayType(const std::string &);
+ // get the inner types: "QMap<int, double>" -> "int", "double"
+ static std::vector<std::string> innerTypesOf(const std::string &t);
private:
bool ensureExpanded() const;
@@ -143,7 +148,10 @@ KnownType knownType(const std::string &type);
// Dump builtin simple types using SymbolGroupValue expressions,
// returning SymbolGroupNode dumper flags.
-unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, std::wstring *s);
+unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
+ std::wstring *s,
+ int *knownType = 0,
+ int *containerSizeIn = 0);
// Return size of container or -1
int containerSize(KnownType ct, const SymbolGroupValue &v);