diff options
author | Friedemann Kleint <Friedemann.Kleint@nokia.com> | 2010-12-10 17:17:55 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@nokia.com> | 2010-12-10 17:17:55 +0100 |
commit | d3619e806d6ee61a9457057b924d607876b87abb (patch) | |
tree | 8f6b2c15a70e6ce5826d566ce830165fecf269ad /src/libs/qtcreatorcdbext | |
parent | ddf360d4a9718ae5a80f4a266515a76348198d3c (diff) | |
download | qt-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.cpp | 135 | ||||
-rw-r--r-- | src/libs/qtcreatorcdbext/containers.h | 46 | ||||
-rw-r--r-- | src/libs/qtcreatorcdbext/qtcreatorcdbext_build.pro | 6 | ||||
-rw-r--r-- | src/libs/qtcreatorcdbext/symbolgroup.cpp | 141 | ||||
-rw-r--r-- | src/libs/qtcreatorcdbext/symbolgroup.h | 49 | ||||
-rw-r--r-- | src/libs/qtcreatorcdbext/symbolgroupvalue.cpp | 113 | ||||
-rw-r--r-- | src/libs/qtcreatorcdbext/symbolgroupvalue.h | 10 |
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 ¶meters) : 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); |