Add infrastructure for simple dumpers in Symbol group.
Fix display of class values.
symGroup->expandList(expandedInames, errorMessage);
if (!uninitializedInames.empty())
symGroup->markUninitialized(uninitializedInames);
- // Complete dump
- if (iname.empty())
- return debugOutput ? symGroup->debug(debugOutput - 1) : symGroup->dump(humanReadableGdbmi);
- // Look up iname
- return symGroup->dump(iname, humanReadableGdbmi, errorMessage);
+
+ if (debugOutput)
+ return symGroup->debug(iname, debugOutput - 1);
+
+ const SymbolGroupValueContext dumpContext(exc.dataSpaces());
+ return iname.empty() ?
+ symGroup->dump(dumpContext, humanReadableGdbmi) :
+ symGroup->dump(iname, dumpContext, humanReadableGdbmi, errorMessage);
}
extern "C" HRESULT CALLBACK locals(CIDebugClient *client, PCSTR args)
**************************************************************************/
#include "symbolgroup.h"
+#include "symbolgroupvalue.h"
#include "stringutils.h"
#include "base64.h"
value->erase(0, 2);
return;
}
+ // Fix long class names on std containers 'class std::tree<...>' -> 'class std::tree<>'
+ if (value->compare(0, 6, L"class ") == 0) {
+ const std::string::size_type openTemplate = value->find(L'<');
+ if (openTemplate != std::string::npos) {
+ value->erase(openTemplate + 1, value->size() - openTemplate - 2);
+ return;
+ }
+ }
}
// Check for ASCII-encode-able stuff. Plain characters + tabs at the most, no newline.
-static bool isSevenBitClean(const wchar_t *buf, ULONG size)
+static bool isSevenBitClean(const wchar_t *buf, size_t size)
{
const wchar_t *bufEnd = buf + size;
for (const wchar_t *bufPtr = buf; bufPtr < bufEnd; bufPtr++) {
return SUCCEEDED(hr) ? std::string(buf) : std::string();
}
-wchar_t *SymbolGroupNode::getValue(ULONG *obtainedSizeIn /* = 0 */) const
+ULONG64 SymbolGroupNode::address() const
+{
+ ULONG64 address = 0;
+ const HRESULT hr = m_symbolGroup->debugSymbolGroup()->GetSymbolOffset(m_index, &address);
+ if (SUCCEEDED(hr))
+ return address;
+ return 0;
+}
+
+std::wstring SymbolGroupNode::symbolGroupRawValue() const
{
// Determine size and return allocated buffer
- if (obtainedSizeIn)
- *obtainedSizeIn = 0;
const ULONG maxValueSize = 262144;
ULONG obtainedSize = 0;
HRESULT hr = m_symbolGroup->debugSymbolGroup()->GetSymbolValueTextWide(m_index, NULL, maxValueSize, &obtainedSize);
if (FAILED(hr))
- return 0;
+ return std::wstring();
if (obtainedSize > maxValueSize)
obtainedSize = maxValueSize;
wchar_t *buffer = new wchar_t[obtainedSize];
hr = m_symbolGroup->debugSymbolGroup()->GetSymbolValueTextWide(m_index, buffer, obtainedSize, &obtainedSize);
- if (FAILED(hr)) { // Whoops, should not happen
- delete [] buffer;
- return 0;
- }
- if (obtainedSizeIn)
- *obtainedSizeIn = obtainedSize;
- return buffer;
+ if (FAILED(hr)) // Whoops, should not happen
+ buffer[0] = 0;
+ const std::wstring rc(buffer);
+ delete [] buffer;
+ return rc;
}
-ULONG64 SymbolGroupNode::address() const
+std::wstring SymbolGroupNode::symbolGroupFixedValue() const
{
- ULONG64 address = 0;
- const HRESULT hr = m_symbolGroup->debugSymbolGroup()->GetSymbolOffset(m_index, &address);
- if (SUCCEEDED(hr))
- return address;
- return 0;
+ std::wstring value = symbolGroupRawValue();
+ fixValue(type(), &value);
+ return value;
}
-std::wstring SymbolGroupNode::rawValue() const
+// Value to be reported to debugger
+std::wstring SymbolGroupNode::displayValue(const SymbolGroupValueContext &ctx)
{
- std::wstring rc;
- if (const wchar_t *wbuf = getValue()) {
- rc = wbuf;
- delete[] wbuf;
- }
- return rc;
+ 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;
+ return symbolGroupFixedValue();
}
-std::wstring SymbolGroupNode::fixedValue() const
+SymbolGroupNode *SymbolGroupNode::childAt(unsigned i) const
{
- std::wstring value = rawValue();
- fixValue(type(), &value);
- return value;
+ return i < m_children.size() ? m_children.at(i) : static_cast<SymbolGroupNode *>(0);
}
-SymbolGroupNode *SymbolGroupNode::childAt(unsigned i) const
+unsigned SymbolGroupNode::indexByIName(const char *n) const
{
- return i < m_children.size() ? m_children.at(i) : static_cast<SymbolGroupNode *>(0);
+ const VectorIndexType size = m_children.size();
+ for (VectorIndexType i = 0; i < size; i++)
+ if ( m_children.at(i)->iName() == n )
+ return unsigned(i);
+ return unsigned(-1);
}
SymbolGroupNode *SymbolGroupNode::childByIName(const char *n) const
{
- const SymbolGroupNodePtrVector::const_iterator childrenEnd = m_children.end();
- for (SymbolGroupNodePtrVector::const_iterator it = m_children.begin(); it != childrenEnd; ++it)
- if ( (*it)->iName() == n )
- return *it;
+ const unsigned index = indexByIName(n);
+ if (index != unsigned(-1))
+ return m_children.at(index);
return 0;
}
str << " ";
}
-void SymbolGroupNode::dump(std::ostream &str, unsigned child, unsigned depth,
- bool humanReadable) const
+void SymbolGroupNode::dump(std::ostream &str, const SymbolGroupValueContext &ctx)
{
const std::string iname = fullIName();
const std::string t = type();
- if (child) { // Separate list of children
- str << ',';
- if (humanReadable)
- str << '\n';
- }
-
- if (humanReadable)
- indentStream(str, depth);
- str << "{iname=\"" << iname << "\",exp=\"" << iname << "\",name=\"" << m_name
+ str << "iname=\"" << iname << "\",exp=\"" << iname << "\",name=\"" << m_name
<< "\",type=\"" << t << '"';
if (const ULONG64 addr = address())
str << ",addr=\"" << std::hex << std::showbase << addr << std::noshowbase << std::dec
<< '"';
- bool valueEditable = true;
- bool valueEnabled = true;
-
const bool uninitialized = m_flags & Uninitialized;
- if (uninitialized) {
- valueEditable = valueEnabled = false;
- str << ",valueencoded=\"0\",value=\"<not in scope>\"";
+ bool valueEditable = !uninitialized;
+ bool valueEnabled = !uninitialized;
+
+ const std::wstring value = displayValue(ctx);
+ // ASCII or base64?
+ if (isSevenBitClean(value.c_str(), value.size())) {
+ str << ",valueencoded=\"0\",value=\"" << gdbmiWStringFormat(value) << '"';
} else {
- ULONG obtainedSize = 0;
- if (const wchar_t *wbuf = getValue(&obtainedSize)) {
- const ULONG valueSize = obtainedSize - 1;
- // ASCII or base64?
- if (isSevenBitClean(wbuf, valueSize)) {
- std::wstring value = wbuf;
- fixValue(t, &value);
- str << ",valueencoded=\"0\",value=\"" << gdbmiWStringFormat(value) << '"';
- } else {
- str << ",valueencoded=\"2\",value=\"";
- base64Encode(str, reinterpret_cast<const unsigned char *>(wbuf), valueSize * sizeof(wchar_t));
- str << '"';
- }
- delete [] wbuf;
- }
+ str << ",valueencoded=\"2\",value=\"";
+ base64Encode(str, reinterpret_cast<const unsigned char *>(value.c_str()), value.size() * sizeof(wchar_t));
+ str << '"';
}
+
// Children: Dump all known or subelements (guess).
const VectorIndexType childCountGuess = uninitialized ? 0 :
(m_children.empty() ? m_parameters.SubElements : m_children.size());
str << ",valueenabled=\"" << (valueEnabled ? "true" : "false") << '"'
<< ",valueeditable=\"" << (valueEditable ? "true" : "false") << '"'
<< ",numchild=\"" << childCountGuess << '"';
- if (!uninitialized && !m_children.empty()) {
- str << ",children=[";
- if (humanReadable)
- str << '\n';
- }
}
-void SymbolGroupNode::dumpChildrenVisited(std::ostream &str, bool humanReadable) const
-{
- if (!m_children.empty())
- str << ']';
- str << '}';
- if (humanReadable)
- str << '\n';
-
-}
-bool SymbolGroupNode::accept(SymbolGroupNodeVisitor &visitor, unsigned child, unsigned depth) const
+bool SymbolGroupNode::accept(SymbolGroupNodeVisitor &visitor, unsigned child, unsigned depth)
{
// If we happen to be the root node, just skip over
const bool invisibleRoot = m_index == DEBUG_ANY_ID;
const unsigned childDepth = invisibleRoot ? 0 : depth + 1;
- if (!invisibleRoot) { // Visit us and move index forward.
- if (visitor.visit(this, child, depth))
- return true;
+ const SymbolGroupNodeVisitor::VisitResult vr =
+ invisibleRoot ? SymbolGroupNodeVisitor::VisitContinue :
+ visitor.visit(this, child, depth);
+ switch (vr) {
+ case SymbolGroupNodeVisitor::VisitStop:
+ return true;
+ case SymbolGroupNodeVisitor::VisitSkipChildren:
+ break;
+ case SymbolGroupNodeVisitor::VisitContinue: {
+ const unsigned childCount = unsigned(m_children.size());
+ for (unsigned c = 0; c < childCount; c++)
+ if (m_children.at(c)->accept(visitor, c, childDepth))
+ return true;
+ if (!invisibleRoot)
+ visitor.childrenVisited(this, depth);
+ }
+ break;
}
-
- const unsigned childCount = unsigned(m_children.size());
- for (unsigned c = 0; c < childCount; c++)
- if (m_children.at(c)->accept(visitor, c, childDepth))
- return true;
- if (!invisibleRoot)
- visitor.childrenVisited(this, depth);
return false;
}
if (const VectorIndexType childCount = m_children.size())
str << ", Children=" << childCount;
str << ' ' << m_parameters;
- if (m_flags)
+ if (m_flags) {
str << " node-flags=" << m_flags;
+ if (m_flags & Uninitialized)
+ str << " UNINITIALIZED";
+ if (m_flags & DumperNotApplicable)
+ str << " DumperNotApplicable";
+ if (m_flags & DumperOk)
+ str << " DumperOk";
+ if (m_flags & DumperFailed)
+ str << " DumperFailed";
+ if (m_flags & ExpandedByDumper)
+ str << " ExpandedByDumper";
+ str << ' ';
+ }
if (verbosity) {
str << ",name=\"" << m_name << "\", Address=0x" << std::hex << address() << std::dec
<< " Type=\"" << type() << '"';
if (!(m_flags & Uninitialized))
- str << "\" Value=\"" << gdbmiWStringFormat(rawValue()) << '"';
+ str << "\" Value=\"" << gdbmiWStringFormat(symbolGroupRawValue()) << '"';
}
str << '\n';
}
{
if (::debug > 1)
DebugPrint() << "SymbolGroupNode::expand " << m_name << ' ' << m_index;
- if (!m_children.empty())
+ if (isExpanded()) {
+ // Clear the flag indication dumper expansion on a second, explicit request
+ clearFlags(ExpandedByDumper);
return true;
- if (m_parameters.SubElements == 0) {
+ }
+ if (!canExpand()) {
*errorMessage = "No subelements to expand in node: " + fullIName();
return false;
}
return str.str();
}
-std::string SymbolGroup::dump(bool humanReadable) const
+std::string SymbolGroup::dump(const SymbolGroupValueContext &ctx, bool humanReadable) const
{
std::ostringstream str;
- DumpSymbolGroupNodeVisitor visitor(str, humanReadable);
+ DumpSymbolGroupNodeVisitor visitor(str, ctx, humanReadable);
if (humanReadable)
str << '\n';
str << '[';
}
// Dump a node, potentially expand
-std::string SymbolGroup::dump(const std::string &name, bool humanReadable, std::string *errorMessage)
+std::string SymbolGroup::dump(const std::string &iname, const SymbolGroupValueContext &ctx, bool humanReadable, std::string *errorMessage)
{
- SymbolGroupNode *const node = find(name);
+ SymbolGroupNode *const node = find(iname);
if (node == 0) {
- *errorMessage = msgNotFound(name);
+ *errorMessage = msgNotFound(iname);
return std::string();
}
- if (node->subElements() && node->children().empty()) {
- if (!expand(name, errorMessage))
+ if (node->isExpanded()) { // Mark expand request by watch model
+ node->clearFlags(SymbolGroupNode::ExpandedByDumper);
+ } else {
+ if (node->canExpand() && !node->expand(errorMessage))
return false;
}
std::ostringstream str;
if (humanReadable)
str << '\n';
- DumpSymbolGroupNodeVisitor visitor(str, humanReadable);
+ DumpSymbolGroupNodeVisitor visitor(str, ctx, humanReadable);
str << '[';
node->accept(visitor, 0, 0);
str << ']';
return str.str();
}
-std::string SymbolGroup::debug(unsigned verbosity) const
+std::string SymbolGroup::debug(const std::string &iname, unsigned verbosity) const
{
std::ostringstream str;
str << '\n';
DebugSymbolGroupNodeVisitor visitor(str, verbosity);
- accept(visitor);
+ if (iname.empty()) {
+ accept(visitor);
+ } else {
+ if (SymbolGroupNode *const node = find(iname)) {
+ node->accept(visitor, 0, 0);
+ } else {
+ str << msgNotFound(iname);
+ }
+ }
return str.str();
}
const SymbolGroupNodePtrVector::const_iterator childrenEnd = m_root->children().end();
for (SymbolGroupNodePtrVector::const_iterator it = m_root->children().begin(); it != childrenEnd; ++it) {
if (std::find(unIniNodesBegin, unIniNodesEnd, (*it)->fullIName()) != unIniNodesEnd)
- (*it)->setFlags((*it)->flags() | SymbolGroupNode::Uninitialized);
+ (*it)->addFlags(SymbolGroupNode::Uninitialized);
}
}
}
{
}
-bool DebugSymbolGroupNodeVisitor::visit(const SymbolGroupNode *node,
- unsigned /* child */, unsigned depth)
+SymbolGroupNodeVisitor::VisitResult
+ DebugSymbolGroupNodeVisitor::visit(SymbolGroupNode *node,
+ unsigned /* child */, unsigned depth)
{
node->debug(m_os, m_verbosity, depth);
- return false;
+ return VisitContinue;
}
// --------------------- DumpSymbolGroupNodeVisitor
DumpSymbolGroupNodeVisitor::DumpSymbolGroupNodeVisitor(std::ostream &os,
+ const SymbolGroupValueContext &context,
bool humanReadable) :
- m_os(os), m_humanReadable(humanReadable)
+ m_os(os), m_humanReadable(humanReadable),m_context(context), m_visitChildren(false)
{
}
-bool DumpSymbolGroupNodeVisitor::visit(const SymbolGroupNode *node, unsigned child, unsigned depth)
+SymbolGroupNodeVisitor::VisitResult
+ DumpSymbolGroupNodeVisitor::visit(SymbolGroupNode *node, unsigned child, unsigned depth)
{
- node->dump(m_os, child, depth, m_humanReadable);
- return false;
+ // Recurse to children 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
+ if (m_humanReadable) {
+ m_os << '\n';
+ indentStream(m_os, depth * 2);
+ }
+ m_os << '{';
+ node->dump(m_os, m_context);
+ if (m_visitChildren) { // open children array
+ m_os << ",children=[";
+ } else { // No children, close array.
+ m_os << '}';
+ }
+ if (m_humanReadable)
+ m_os << '\n';
+ return m_visitChildren ? VisitContinue : VisitSkipChildren;
}
-void DumpSymbolGroupNodeVisitor::childrenVisited(const SymbolGroupNode *node, unsigned)
+void DumpSymbolGroupNodeVisitor::childrenVisited(const SymbolGroupNode *, unsigned)
{
- node->dumpChildrenVisited(m_os, m_humanReadable);
+ m_os << "]}"; // Close children array and self
+ if (m_humanReadable)
+ m_os << '\n';
}
class SymbolGroupNodeVisitor;
class SymbolGroup;
+struct SymbolGroupValueContext;
+
+// 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.
class SymbolGroupNode {
SymbolGroupNode(const SymbolGroupNode&);
SymbolGroupNode& operator=(const SymbolGroupNode&);
public:
enum Flags {
- Uninitialized = 0x1
+ 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,
+ ExpandedByDumper = 0x10
};
typedef std::vector<DEBUG_SYMBOL_PARAMETERS> SymbolParameterVector;
typedef std::vector<SymbolGroupNode *> SymbolGroupNodePtrVector;
const SymbolGroupNodePtrVector &children() const { return m_children; }
SymbolGroupNode *childAt(unsigned) const;
+
+ unsigned indexByIName(const char *) const; // (unsigned(-1) on failure
SymbolGroupNode *childByIName(const char *) const;
const SymbolGroupNode *parent() const { return m_parent; }
// I/O: Gdbmi dump for Visitors
- void dump(std::ostream &str, unsigned child, unsigned depth,
- bool humanReadable) const;
- void dumpChildrenVisited(std::ostream &str, bool humanReadable) const;
+ void dump(std::ostream &str, const SymbolGroupValueContext &ctx);
// I/O: debug for Visitors
void debug(std::ostream &os, unsigned verbosity, unsigned depth) const;
- std::wstring rawValue() const;
- std::wstring fixedValue() const;
+ std::wstring symbolGroupRawValue() const;
+ std::wstring symbolGroupFixedValue() const;
+ std::wstring displayValue(const SymbolGroupValueContext &ctx);
+
std::string type() const;
ULONG64 address() const;
- bool accept(SymbolGroupNodeVisitor &visitor, unsigned child, unsigned depth) const;
+ bool accept(SymbolGroupNodeVisitor &visitor, unsigned child, unsigned depth);
bool expand(std::string *errorMessage);
+ bool isExpanded() const { return !m_children.empty(); }
+ bool canExpand() const { return m_parameters.SubElements > 0; }
ULONG subElements() const { return m_parameters.SubElements; }
ULONG index() const { return m_index; }
unsigned flags() const { return m_flags; }
void setFlags(unsigned f) { m_flags = f; }
+ void addFlags(unsigned f) { m_flags |= f; }
+ void clearFlags(unsigned f) { m_flags &= ~f; }
private:
- // Return allocated wide string array of value
- wchar_t *getValue(ULONG *obtainedSize = 0) const;
bool isArrayElement() const;
// Notify about expansion of a node, shift indexes
bool notifyExpanded(ULONG index, ULONG insertedCount);
const std::string m_name;
const std::string m_iname;
unsigned m_flags;
+ std::wstring m_dumperValue;
};
/* Visitor that takes care of iterating over the nodes
public:
virtual ~SymbolGroupNodeVisitor() {}
+protected:
+ enum VisitResult {
+ VisitContinue,
+ VisitSkipChildren,
+ VisitStop
+ };
+
private:
- virtual bool visit(const SymbolGroupNode *node, unsigned child, unsigned depth) = 0;
+ virtual VisitResult visit(SymbolGroupNode *node, unsigned child, unsigned depth) = 0;
// Helper for formatting output.
virtual void childrenVisited(const SymbolGroupNode * /* node */, unsigned /* depth */) {}
};
~SymbolGroup();
// Dump all
- std::string dump(bool humanReadable = false) const;
+ std::string dump(const SymbolGroupValueContext &ctx, bool humanReadable = false) const;
// Expand node and dump
- std::string dump(const std::string &name, bool humanReadable, std::string *errorMessage);
- std::string debug(unsigned verbosity = 0) const;
+ std::string dump(const std::string &iname, const SymbolGroupValueContext &ctx,
+ bool humanReadable, std::string *errorMessage);
+ std::string debug(const std::string &iname = std::string(), unsigned verbosity = 0) const;
unsigned frame() const { return m_frame; }
ULONG threadId() const { return m_threadId; }
explicit DebugSymbolGroupNodeVisitor(std::ostream &os, unsigned verbosity = 0);
private:
- virtual bool visit(const SymbolGroupNode *node, unsigned child, unsigned depth);
+ virtual VisitResult visit(SymbolGroupNode *node, unsigned child, unsigned depth);
std::ostream &m_os;
const unsigned m_verbosity;
// Gdbmi dump output visitor.
class DumpSymbolGroupNodeVisitor : public SymbolGroupNodeVisitor {
public:
- explicit DumpSymbolGroupNodeVisitor(std::ostream &os, bool humanReadable);
+ explicit DumpSymbolGroupNodeVisitor(std::ostream &os,
+ const SymbolGroupValueContext &context,
+ bool humanReadable);
private:
- virtual bool visit(const SymbolGroupNode *node, unsigned child, unsigned depth);
+ virtual VisitResult visit(SymbolGroupNode *node, unsigned child, unsigned depth);
virtual void childrenVisited(const SymbolGroupNode * node, unsigned depth);
std::ostream &m_os;
const bool m_humanReadable;
+ const SymbolGroupValueContext &m_context;
+ bool m_visitChildren;
};
#endif // SYMBOLGROUP_H
#include "symbolgroup.h"
#include "stringutils.h"
-SymbolGroupValueContext::SymbolGroupValueContext(CIDebugDataSpaces *ds)
- : dataspaces(ds)
-{
-}
-
-SymbolGroupValueContext::SymbolGroupValueContext() : dataspaces(0)
-{
-}
-
SymbolGroupValue::SymbolGroupValue(SymbolGroupNode *node,
const SymbolGroupValueContext &ctx) :
m_node(node), m_context(ctx)
return m_node != 0 && m_context.dataspaces != 0;
}
+SymbolGroupValue SymbolGroupValue::operator[](unsigned index) const
+{
+ if (ensureExpanded())
+ if (index < m_node->children().size())
+ return SymbolGroupValue(m_node->children().at(index), m_context);
+ return SymbolGroupValue();
+}
+
+bool SymbolGroupValue::ensureExpanded() const
+{
+ if (!isValid() || !m_node->canExpand())
+ return false;
+
+ if (m_node->isExpanded())
+ return true;
+
+ // Set a flag indicating the node was expanded by SymbolGroupValue
+ // and not by an explicit request from the watch model.
+ if (m_node->expand(&m_errorMessage)) {
+ m_node->addFlags(SymbolGroupNode::ExpandedByDumper);
+ return true;
+ }
+ return false;
+}
+
SymbolGroupValue SymbolGroupValue::operator[](const char *name) const
{
- if (isValid() && m_node->expand(&m_errorMessage))
+ if (ensureExpanded())
if (SymbolGroupNode *child = m_node->childByIName(name))
return SymbolGroupValue(child, m_context);
return SymbolGroupValue();
std::wstring SymbolGroupValue::value() const
{
- return isValid() ? m_node->fixedValue() : std::wstring();
+ return isValid() ? m_node->symbolGroupFixedValue() : std::wstring();
+}
+
+double SymbolGroupValue::floatValue(double defaultValue) const
+{
+ double f = defaultValue;
+ if (isValid()) {
+ std::wistringstream str(value());
+ str >> f;
+ if (str.fail())
+ f = defaultValue;
+ }
+ return f;
}
int SymbolGroupValue::intValue(int defaultValue) const
return m_errorMessage;
}
+static const char stdStringTypeC[] = "class std::basic_string<char,std::char_traits<char>,std::allocator<char> >";
+static const char stdWStringTypeC[] = "class std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >";
+
// Dump a QString.
-static bool dumpQString(const SymbolGroupValue &v, std::wstring *s)
-{
- if (endsWith(v.type(), "QString")) {
- if (SymbolGroupValue d = v["d"]) {
- if (SymbolGroupValue sizeValue = d["size"]) {
- const int size = sizeValue.intValue();
- if (size >= 0) {
- *s = d["data"].wcharPointerData(size);
- return true;
- }
+static unsigned dumpQString(const std::string &type, const SymbolGroupValue &v, std::wstring *s)
+{
+ if (!endsWith(type, "QString")) // namespaced Qt?
+ return SymbolGroupNode::DumperNotApplicable;
+
+ if (SymbolGroupValue d = v["d"]) {
+ if (SymbolGroupValue sizeValue = d["size"]) {
+ const int size = sizeValue.intValue();
+ if (size >= 0) {
+ *s = d["data"].wcharPointerData(size);
+ return SymbolGroupNode::DumperOk;
}
}
}
- return false;
+ return SymbolGroupNode::DumperFailed;
+}
+
+// Dump a QByteArray
+static unsigned dumpQByteArray(const std::string &type, const SymbolGroupValue &v, std::wstring *s)
+{
+ if (!endsWith(type, "QByteArray")) // namespaced Qt?
+ return SymbolGroupNode::DumperNotApplicable;
+ // TODO: More sophisticated dumping of binary data?
+ if (SymbolGroupValue data = v["d"]["data"]) {
+ *s = data.value();
+ return SymbolGroupNode::DumperOk;
+ }
+ return SymbolGroupNode::DumperFailed;
+}
+
+// Dump a rectangle in X11 syntax
+template <class T>
+inline void dumpRect(std::wostringstream &str, T x, T y, T width, T height)
+{
+ str << width << 'x' << height;
+ if (x >= 0)
+ str << '+';
+ str << x;
+ if (y >= 0)
+ str << '+';
+ str << y;
+}
+
+template <class T>
+inline void dumpRectPoints(std::wostringstream &str, T x1, T y1, T x2, T y2)
+{
+ dumpRect(str, x1, y1, (x2 - x1), (y2 - y1));
+}
+
+// Dump Qt's simple geometrical types
+static unsigned dumpQtGeometryTypes(const std::string &type, const SymbolGroupValue &v, std::wstring *s)
+{
+ if (endsWith(type, "QSize") || endsWith(type, "QSizeF")) { // namespaced Qt?
+ std::wostringstream str;
+ str << '(' << v["wd"].value() << ", " << v["ht"].value() << ')';
+ *s = str.str();
+ return SymbolGroupNode::DumperOk;
+ }
+ if (endsWith(type, "QPoint") || endsWith(type, "QPointF")) { // namespaced Qt?
+ std::wostringstream str;
+ str << '(' << v["xp"].value() << ", " << v["yp"].value() << ')';
+ *s = str.str();
+ return SymbolGroupNode::DumperOk;
+ }
+ if (endsWith(type, "QLine") || endsWith(type, "QLineF")) { // namespaced Qt?
+ const SymbolGroupValue p1 = v["pt1"];
+ const SymbolGroupValue p2 = v["pt2"];
+ if (p1 && p2) {
+ std::wostringstream str;
+ str << '(' << p1["xp"].value() << ", " << p1["yp"].value() << ") ("
+ << p2["xp"].value() << ", " << p2["yp"].value() << ')';
+ *s = str.str();
+ return SymbolGroupNode::DumperOk;
+ }
+ return SymbolGroupNode::DumperFailed;
+ }
+ if (endsWith(type, "QRect")) {
+ std::wostringstream str;
+ dumpRectPoints(str, v["x1"].intValue(), v["y1"].intValue(), v["x2"].intValue(), v["y2"].intValue());
+ *s = str.str();
+ return SymbolGroupNode::DumperOk;
+ }
+ if (endsWith(type, "QRectF")) {
+ std::wostringstream str;
+ dumpRect(str, v["xp"].floatValue(), v["yp"].floatValue(), v["w"].floatValue(), v["h"].floatValue());
+ *s = str.str();
+ return SymbolGroupNode::DumperOk;
+ }
+ return SymbolGroupNode::DumperNotApplicable;
+}
+
+// Dump a std::string.
+static unsigned dumpStdString(const std::string &type, const SymbolGroupValue &v, std::wstring *s)
+{
+ if (type != stdStringTypeC && type != stdWStringTypeC)
+ return SymbolGroupNode::DumperNotApplicable;
+ // MSVC 2010: Access Bx/_Buf in base class
+ SymbolGroupValue buf = v[unsigned(0)]["_Bx"]["_Buf"];
+ if (!buf) // MSVC2008: Bx/Buf are members
+ buf = v["_Bx"]["_Buf"];
+ if (buf) {
+ *s = buf.value();
+ return SymbolGroupNode::DumperOk;
+ }
+ return SymbolGroupNode::DumperFailed;
}
// Dump builtin simple types using SymbolGroupValue expressions.
-bool dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, std::wstring *s)
+unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, std::wstring *s)
{
+ // Check for class types and strip pointer types (references appear as pointers as well)
+ std::string type = n->type();
+ if (type.compare(0, 6, "class ") != 0)
+ return SymbolGroupNode::DumperNotApplicable;
+ if (endsWith(type, " *"))
+ type.erase(type.size() - 2, 2);
const SymbolGroupValue v(n, ctx);
- return dumpQString(v, s);
+ unsigned rc = dumpQString(type, v, s);
+ if (rc != SymbolGroupNode::DumperNotApplicable)
+ return rc;
+ rc = dumpQByteArray(type, v, s);
+ if (rc != SymbolGroupNode::DumperNotApplicable)
+ return rc;
+ rc = dumpStdString(type, v, s);
+ if (rc != SymbolGroupNode::DumperNotApplicable)
+ return rc;
+ rc = dumpQtGeometryTypes(type, v, s);
+ if (rc != SymbolGroupNode::DumperNotApplicable)
+ return rc;
+ return rc;
}
// Structure to pass all IDebug interfaces used for SymbolGroupValue
struct SymbolGroupValueContext
{
- SymbolGroupValueContext(CIDebugDataSpaces *ds);
- SymbolGroupValueContext();
+ SymbolGroupValueContext(CIDebugDataSpaces *ds) : dataspaces(ds) {}
+ SymbolGroupValueContext::SymbolGroupValueContext() : dataspaces(0) {}
CIDebugDataSpaces *dataspaces;
};
operator bool() const { return isValid(); }
bool isValid() const;
+ // Access children by name or index (0-based)
SymbolGroupValue operator[](const char *name) const;
+ SymbolGroupValue operator[](unsigned) const;
std::string type() const;
std::wstring value() const;
int intValue(int defaultValue = -1) const;
+ double floatValue(double defaultValue = -999) const;
ULONG64 pointerValue(ULONG64 defaultValue = 0) const;
// Return allocated array of data pointed to
unsigned char *pointerData(unsigned length) const;
std::string error() const;
private:
+ bool ensureExpanded() const;
+
SymbolGroupNode *m_node;
SymbolGroupValueContext m_context;
mutable std::string m_errorMessage;
};
-// Dump builtin simple types using SymbolGroupValue expressions.
-bool dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, std::wstring *s);
+// Dump builtin simple types using SymbolGroupValue expressions,
+// returning SymbolGroupNode dumper flags.
+unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, std::wstring *s);
#endif // SYMBOLGROUPVALUE_H
#define _USE_MATH_DEFINES
#include <math.h>
#include <QDebug>
+#include <QRect>
+#include <QRectF>
+#include <QLine>
+#include <QLineF>
+#include <QPoint>
+#include <QPointF>
+#include <QSize>
+#include <QSizeF>
+
#include <QThread>
#include <string>
-#include <list>
#include <set>
#include <QLibrary>
#include <QLibraryInfo>
{
int array[2] = {1,2};
m_w++;
- QString x = "h\"allo";
+ QString x = QLatin1String("h\344all\366");
QString *xp = &x;
qDebug() << inc << inx << *xp;
Q_UNUSED(array)
std::vector<std::string> stringVector(1, "bla");
std::vector<std::wstring> wStringVector(1, L"bla");
}
+
+void Foo::MainWindow::on_actionVariousQtTypes_triggered()
+{
+ const QByteArray ba = "hallo\t";
+ QSize size = QSize(42, 43);
+ QSizeF sizeF(size);
+ QPoint p1 = QPoint(42, 43);
+ QPoint p2 = QPoint(100, 100);
+ QLine line(p1, p2);
+ QPointF p1f(p1);
+ QPointF p2f(p2);
+ QLineF linef(p1f, p2f);
+ QRect rect(p1, p2);
+ QRectF rectf(rect);
+ qDebug() << sizeF << linef << rectf;
+
+}
void on_actionStdTypes_triggered();
+ void on_actionVariousQtTypes_triggered();
+
private:
void terminateThread();
int m_w;
<x>0</x>
<y>0</y>
<width>600</width>
- <height>27</height>
+ <height>26</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<addaction name="actionScopes"/>
<addaction name="actionLongString"/>
<addaction name="actionStdTypes"/>
+ <addaction name="actionVariousQtTypes"/>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QToolBar" name="toolBar">
<string>stdTypes</string>
</property>
</action>
+ <action name="actionVariousQtTypes">
+ <property name="text">
+ <string>variousQtTypes</string>
+ </property>
+ </action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>