OSDN Git Service

Debugger[New CDB]: First stab at containers.
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>
Fri, 10 Dec 2010 16:17:55 +0000 (17:17 +0100)
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>
Fri, 10 Dec 2010 16:17:55 +0000 (17:17 +0100)
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.

src/libs/qtcreatorcdbext/containers.cpp [new file with mode: 0644]
src/libs/qtcreatorcdbext/containers.h [new file with mode: 0644]
src/libs/qtcreatorcdbext/qtcreatorcdbext_build.pro
src/libs/qtcreatorcdbext/symbolgroup.cpp
src/libs/qtcreatorcdbext/symbolgroup.h
src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
src/libs/qtcreatorcdbext/symbolgroupvalue.h

diff --git a/src/libs/qtcreatorcdbext/containers.cpp b/src/libs/qtcreatorcdbext/containers.cpp
new file mode 100644 (file)
index 0000000..3df9514
--- /dev/null
@@ -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 (file)
index 0000000..a488a2d
--- /dev/null
@@ -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
index 1ddfc45..62fcbb0 100644 (file)
@@ -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
index 9ad79a2..f08b02a 100644 (file)
@@ -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";
 }
index 2f5dd73..5991164 100644 (file)
@@ -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
index ebfe475..ca3544f 100644 (file)
@@ -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;
 }
index 107f3f8..365c245 100644 (file)
@@ -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);