Commit ebec516e authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Debugge[New CDB]: Refine Symbol qualification for containers.

Resolve all types and always use current module for templates.
Fixes to pointer handling.
Make verbose switchable.
parent 90a1e723
......@@ -43,8 +43,6 @@ typedef AbstractSymbolGroupNode::AbstractSymbolGroupNodePtrVector AbstractSymbol
typedef std::vector<SymbolGroupValue> SymbolGroupValueVector;
typedef std::vector<int>::size_type VectorIndexType;
enum { debugVector = 0 };
// Read a pointer array from debuggee memory (ULONG64/32 according pointer size)
static void *readPointerArray(ULONG64 address, unsigned count, const SymbolGroupValueContext &ctx)
{
......@@ -80,14 +78,23 @@ static inline void dump64bitPointerArray(std::ostream &os, const void *a, int co
// Fix the inner type of containers (that is, make it work smoothly with AddSymbol)
// by prefixing it with the module except for well-known types like STL/Qt types
static inline std::string fixInnerType(std::string type, const SymbolGroupValueContext &ctx)
static inline std::string fixInnerType(std::string type,
const SymbolGroupValue &container)
{
const std::string stripped = SymbolGroupValue::stripClassPrefixes(type);
const KnownType kt = knownType(stripped, false);
// Simple types and STL/Q-types (inexplicably) are fast.
if (kt & (KT_POD_Type|KT_Qt_Type|KT_STL_Type))
return stripped;
return SymbolGroupValue::resolveType(stripped, ctx);
const KnownType kt = knownType(stripped, 0);
// Resolve types unless they are POD or pointers to POD (that is, qualify 'Foo' and 'Foo*')
const bool needResolve = kt == KT_Unknown || kt == KT_PointerType || !(kt & KT_POD_Type);
const std::string fixed = needResolve ?
SymbolGroupValue::resolveType(stripped, container.context(), container.node()->symbolGroup()) :
stripped;
if (SymbolGroupValue::verbose) {
DebugPrint dp;
dp << "fixInnerType (resolved=" << needResolve << ") '" << type << "' [";
formatKnownTypeFlags(dp, kt);
dp << "] -> '" << fixed <<"'\n";
}
return fixed;
}
// Return size from an STL vector (last/first iterators).
......@@ -103,7 +110,7 @@ static inline int msvcStdVectorSize(const SymbolGroupValue &v)
return 0;
// Subtract the pointers: We need to do the pointer arithmetics ourselves
// as we get char *pointers.
const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(myFirstPtrV.type()), v.context());
const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(myFirstPtrV.type()), v);
const size_t size = SymbolGroupValue::sizeOf(innerType.c_str());
if (size == 0)
return -1;
......@@ -249,10 +256,15 @@ private:
static inline AbstractSymbolGroupNodePtrVector stdListChildList(SymbolGroupNode *n, int count,
const SymbolGroupValueContext &ctx)
{
if (count)
if (const SymbolGroupValue head = SymbolGroupValue(n, ctx)[unsigned(0)][unsigned(0)]["_Myhead"]["_Next"])
return linkedListChildList(head, count, MemberByName("_Myval"), MemberByName("_Next"));
return AbstractSymbolGroupNodePtrVector();
if (!count)
return AbstractSymbolGroupNodePtrVector();
const SymbolGroupValue head = SymbolGroupValue(n, ctx)[unsigned(0)][unsigned(0)]["_Myhead"]["_Next"];
if (!head) {
if (SymbolGroupValue::verbose)
DebugPrint() << "std::list failure: " << head;
return AbstractSymbolGroupNodePtrVector();
}
return linkedListChildList(head, count, MemberByName("_Myval"), MemberByName("_Next"));
}
// QLinkedList<T>: Dummy head node and then a linked list of "n", "t".
......@@ -294,9 +306,14 @@ AbstractSymbolGroupNodePtrVector arrayChildList(SymbolGroup *sg, AddressFunc add
if (SymbolGroupNode *child = sg->addSymbol(name, std::string(), &errorMessage)) {
rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, child));
} else {
if (SymbolGroupValue::verbose)
DebugPrint() << "addSymbol fails in arrayChildList";
break;
}
}
if (SymbolGroupValue::verbose)
DebugPrint() << "arrayChildList '" << innerType << "' count=" << count << " returns "
<< rc.size() << " elements";
return rc;
}
......@@ -341,8 +358,8 @@ static inline AbstractSymbolGroupNodePtrVector
if (myFirst) {
if (const ULONG64 address = myFirst.pointerValue()) {
const std::string firstType = myFirst.type();
const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(firstType), ctx);
if (debugVector)
const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(firstType), vec);
if (SymbolGroupValue::verbose)
DebugPrint() << n->name() << " inner type: '" << innerType << "' from '" << firstType << '\'';
return arrayChildList(n->symbolGroup(), address, innerType, count);
}
......@@ -396,9 +413,10 @@ static inline AbstractSymbolGroupNodePtrVector
const std::vector<std::string> innerTypes = deque.innerTypes();
if (innerTypes.empty())
return AbstractSymbolGroupNodePtrVector();
const std::string innerType = fixInnerType(innerTypes.front(), deque);
// Get the deque size (block size) which is an unavailable static member
// (cf <deque> for the actual expression).
const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerTypes.front().c_str());
const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str());
if (!innerTypeSize)
return AbstractSymbolGroupNodePtrVector();
const int dequeSize = innerTypeSize <= 1 ? 16 : innerTypeSize <= 2 ?
......@@ -410,10 +428,10 @@ static inline AbstractSymbolGroupNodePtrVector
const AbstractSymbolGroupNodePtrVector rc = SymbolGroupValue::pointerSize() == 8 ?
stdDequeChildrenHelper(deque.node()->symbolGroup(),
reinterpret_cast<const ULONG64 *>(mapArray), mapSize,
innerTypes.front(), innerTypeSize, startOffset, dequeSize, count) :
innerType, innerTypeSize, startOffset, dequeSize, count) :
stdDequeChildrenHelper(deque.node()->symbolGroup(),
reinterpret_cast<const ULONG32 *>(mapArray), mapSize,
innerTypes.front(), innerTypeSize, startOffset, dequeSize, count);
innerType, innerTypeSize, startOffset, dequeSize, count);
delete [] mapArray;
return rc;
}
......@@ -641,7 +659,7 @@ static inline AbstractSymbolGroupNodePtrVector
const SymbolGroupValue vec(n, ctx);
if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)]) {
if (const ULONG64 arrayAddress = firstElementV.address()) {
const std::string fixedInnerType = fixInnerType(firstElementV.type(), ctx);
const std::string fixedInnerType = fixInnerType(firstElementV.type(), vec);
return arrayChildList(n->symbolGroup(), arrayAddress, fixedInnerType, count);
}
}
......@@ -685,9 +703,9 @@ static inline AbstractSymbolGroupNodePtrVector
const std::vector<std::string> innerTypes = v.innerTypes();
if (innerTypes.size() != 1)
return AbstractSymbolGroupNodePtrVector();
const std::string innerType = fixInnerType(innerTypes.front(), v.context());
const std::string innerType = fixInnerType(innerTypes.front(), v);
const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str());
if (debugVector)
if (SymbolGroupValue::verbose)
DebugPrint() << "QList " << v.name() << " inner type " << innerType << ' ' << innerTypeSize;
if (!innerTypeSize)
return AbstractSymbolGroupNodePtrVector();
......@@ -711,7 +729,7 @@ static inline AbstractSymbolGroupNodePtrVector
if (kt != KT_Unknown && !(kt & (KT_POD_Type|KT_Qt_PrimitiveType|KT_Qt_MovableType)))
isLargeOrStatic = true;
}
if (debugVector)
if (SymbolGroupValue::verbose)
DebugPrint() << "isLargeOrStatic " << isLargeOrStatic;
if (isLargeOrStatic) {
// Retrieve the pointer array ourselves to avoid having to evaluate '*(class foo**)'
......@@ -776,8 +794,6 @@ static inline std::string qHashNodeType(const SymbolGroupValue &v,
return QtInfo::prependModuleAndNameSpace(qHashType, currentModule, qtInfo.nameSpace);
}
enum { debugMap = 0 };
// Return up to count nodes of type "QHashNode<K,V>" of a "class QHash<K,V>".
SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v,
VectorIndexType count)
......@@ -787,7 +803,7 @@ SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v,
const SymbolGroupValue hashData = v["d"];
// 'e' is used as a special value to indicate empty hash buckets in the array.
const ULONG64 ePtr = v["e"].pointerValue();
if (debugMap)
if (SymbolGroupValue::verbose)
DebugPrint() << v << " Count=" << count << ",ePtr=0x" << std::hex << ePtr;
if (!hashData || !ePtr)
return SymbolGroupValueVector();
......@@ -825,7 +841,7 @@ SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v,
dummyNodeList.push_back(next);
if (dummyNodeList.size() >= count) // Stop at maximum count
notEnough = false;
if (debugMap)
if (SymbolGroupValue::verbose > 1)
DebugPrint() << '#' << (dummyNodeList.size() - 1) << " l=" << l << ",next=" << next;
l = next;
} else {
......@@ -835,7 +851,7 @@ SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v,
}
// Finally convert them into real nodes 'QHashNode<K,V> (potentially expensive)
const std::string nodeType = qHashNodeType(v, "Node");
if (debugMap)
if (SymbolGroupValue::verbose)
DebugPrint() << "Converting into " << nodeType;
SymbolGroupValueVector nodeList;
nodeList.reserve(count);
......@@ -901,11 +917,11 @@ static inline SymbolGroupValueVector qMapNodes(const SymbolGroupValue &v, Vector
{
const SymbolGroupValue e = v["e"];
const ULONG64 ePtr = e.pointerValue();
if (debugMap)
if (SymbolGroupValue::verbose)
DebugPrint() << v.type() << " E=0x" << std::hex << ePtr;
if (!ePtr)
return SymbolGroupValueVector();
if (debugMap)
if (SymbolGroupValue::verbose)
DebugPrint() << v.type() << " E=0x" << std::hex << ePtr;
SymbolGroupValueVector rc;
rc.reserve(count);
......@@ -921,7 +937,7 @@ static inline SymbolGroupValueVector qMapNodes(const SymbolGroupValue &v, Vector
static inline AbstractSymbolGroupNodePtrVector
qMapChildList(const SymbolGroupValue &v, VectorIndexType count)
{
if (debugMap)
if (SymbolGroupValue::verbose)
DebugPrint() << v.type() << "," << count;
if (!count)
......@@ -933,7 +949,7 @@ static inline AbstractSymbolGroupNodePtrVector
const std::string mapPayloadNodeType = qHashNodeType(v, "PayloadNode");
// Calculate the offset needed (see QMap::concrete() used by the iterator).
const unsigned payloadNodeSize = SymbolGroupValue::sizeOf(mapPayloadNodeType.c_str());
if (debugMap) {
if (SymbolGroupValue::verbose) {
DebugPrint() << v.type() << "," << mapNodeType << ':'
<< mapPayloadNodeType << ':' << payloadNodeSize
<< ", pointerSize=" << SymbolGroupValue::pointerSize();
......@@ -947,16 +963,18 @@ static inline AbstractSymbolGroupNodePtrVector
const std::vector<std::string> innerTypes = v.innerTypes();
if (innerTypes.size() != 2u)
return AbstractSymbolGroupNodePtrVector();
const unsigned valueSize = SymbolGroupValue::sizeOf(innerTypes.at(1).c_str());
const std::string keyType = fixInnerType(innerTypes.front(), v);
const std::string valueType = fixInnerType(innerTypes.at(1), v);
const unsigned valueSize = SymbolGroupValue::sizeOf(valueType.c_str());
const unsigned valueOffset = SymbolGroupValue::fieldOffset(mapNodeType.c_str(), "value");
if (debugMap)
if (SymbolGroupValue::verbose)
DebugPrint() << "Payload=" << payLoad << ",valueOffset=" << valueOffset << ','
<< innerTypes.front() << ',' << innerTypes.back() << ':' << valueSize;
if (!valueOffset || !valueSize)
return AbstractSymbolGroupNodePtrVector();
// Get the children.
const SymbolGroupValueVector childNodes = qMapNodes(v, count);
if (debugMap)
if (SymbolGroupValue::verbose)
DebugPrint() << "children: " << childNodes.size() << " of " << count;
// Deep expansion of the forward[0] sometimes fails. In that case,
// take what we can get.
......@@ -971,15 +989,14 @@ static inline AbstractSymbolGroupNodePtrVector
rc.reserve(count);
std::string errorMessage;
SymbolGroup *sg = v.node()->symbolGroup();
for (VectorIndexType i = 0; i < count ; i++) {
const ULONG64 nodePtr = childNodes.at(i).pointerValue();
if (!nodePtr)
return AbstractSymbolGroupNodePtrVector();
const ULONG64 keyAddress = nodePtr - payLoad;
const std::string keyExp = pointedToSymbolName(keyAddress, innerTypes.front());
const std::string valueExp = pointedToSymbolName(keyAddress + valueOffset, innerTypes.at(1));
if (debugMap) {
const std::string keyExp = pointedToSymbolName(keyAddress, keyType);
const std::string valueExp = pointedToSymbolName(keyAddress + valueOffset, valueType);
if (SymbolGroupValue::verbose) {
DebugPrint() << '#' << i << '/' << count << ' ' << std::hex << ",node=0x" << nodePtr <<
',' <<keyExp << ',' << valueExp;
}
......@@ -997,6 +1014,14 @@ static inline AbstractSymbolGroupNodePtrVector
AbstractSymbolGroupNodePtrVector containerChildren(SymbolGroupNode *node, int type,
int size, const SymbolGroupValueContext &ctx)
{
if (SymbolGroupValue::verbose) {
DebugPrint dp;
dp << "containerChildren " << node->name() << '/' << node->iName() << '/' << node->type()
<< " at 0x" << std::hex << node->address() << std::dec
<< " count=" << size << ",knowntype=" << type << " [";
formatKnownTypeFlags(dp, static_cast<KnownType>(type));
dp << ']';
}
if (!size)
return AbstractSymbolGroupNodePtrVector();
if (size > 100)
......
......@@ -51,6 +51,8 @@ enum KnownType
KT_IntType = KT_POD_Type + 3, // any signed short, long, int
KT_UnsignedIntType = KT_POD_Type + 4, // any unsigned int
KT_FloatType = KT_POD_Type + 5, // float, double
KT_POD_PointerType = KT_POD_Type + 6, // pointer to some POD
KT_PointerType = KT_POD_Type + 7, // pointer to class or complex type
// Qt Basic
KT_QChar = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 1,
KT_QByteArray = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 2,
......
......@@ -338,7 +338,6 @@ static std::string commmandLocals(ExtensionCommandContext &exc,PCSTR args, int *
break;
case 'v':
SymbolGroupValue::verbose++;
tokens.pop_front();
break;
case 'e':
if (tokens.empty()) {
......
......@@ -238,6 +238,10 @@ std::string SymbolGroup::dump(const std::string &iname,
// Real nodes: Expand and complex dumpers
if (SymbolGroupNode *node = aNode->resolveReference()->asSymbolGroupNode()) {
if (symbolGroupDebug)
DebugPrint() << "SymbolGroup::dump(" << iname << '/'
<< aNode->absoluteFullIName() <<" resolves to " << node->absoluteFullIName()
<< " expanded=" << node->isExpanded();
if (node->isExpanded()) { // Mark expand request by watch model
node->clearFlags(SymbolGroupNode::ExpandedByDumper);
} else {
......
......@@ -55,7 +55,7 @@ SymbolGroupValue::SymbolGroupValue(SymbolGroupNode *node,
if (m_node && !m_node->isMemoryAccessible()) { // Invalid if no value
m_node = 0;
if (SymbolGroupValue::verbose)
DebugPrint() << name() << " memory access error";
DebugPrint() << node->name() << '/' << node->iName() << " memory access error";
}
}
......@@ -265,9 +265,14 @@ std::string SymbolGroupValue::error() const
return m_errorMessage;
}
bool SymbolGroupValue::isPointerType(const std::string &t)
// Return number of characters to strip for pointer type
unsigned SymbolGroupValue::isPointerType(const std::string &t)
{
return endsWith(t, '*');
if (endsWith(t, "**"))
return 1;
if (endsWith(t, " *"))
return 2;
return 0;
}
unsigned SymbolGroupValue::pointerSize()
......@@ -282,21 +287,30 @@ unsigned SymbolGroupValue::intSize()
return is;
}
unsigned SymbolGroupValue::sizeOf(const char *type)
{
const unsigned rc = GetTypeSize(type);
if (!rc && SymbolGroupValue::verbose)
DebugPrint() << "GetTypeSize fails for '" << type << '\'';
return rc;
}
unsigned SymbolGroupValue::fieldOffset(const char *type, const char *field)
{
ULONG rc = 0;
if (GetFieldOffset(type, field, &rc))
if (GetFieldOffset(type, field, &rc)) {
if (SymbolGroupValue::verbose)
DebugPrint() << "GetFieldOffset fails for '" << type << "' '" << field << '\'';
return 0;
}
return rc;
}
std::string SymbolGroupValue::stripPointerType(const std::string &t)
{
// 'Foo *' -> 'Foo', 'Bar **' -> 'Bar *'.
if (endsWith(t, "**"))
return t.substr(0, t.size() - 1);
if (endsWith(t, " *"))
return t.substr(0, t.size() - 2);
if (const unsigned stripLength = isPointerType(t))
return t.substr(0, t.size() - stripLength);
return t;
}
......@@ -468,38 +482,49 @@ std::list<std::string>
}
// Resolve a type, that is, obtain its module name ('QString'->'QtCored4!QString')
std::string SymbolGroupValue::resolveType(const std::string &type, const SymbolGroupValueContext &ctx)
std::string SymbolGroupValue::resolveType(const std::string &typeIn,
const SymbolGroupValueContext &ctx,
const SymbolGroup *current /* = 0 */)
{
enum { BufSize = 512 };
if (type.empty() || type.find('!') != std::string::npos)
return type;
if (typeIn.empty() || typeIn.find('!') != std::string::npos)
return typeIn;
const std::string stripped = SymbolGroupValue::stripClassPrefixes(type);
const std::string stripped = SymbolGroupValue::stripClassPrefixes(typeIn);
// Use the module of the current symbol group for templates.
// This is because resolving some template types (std::list<> has been
// observed to result in 'QtGui4d!std::list', which subseqently fails.
if (current && stripped.find('<') != std::string::npos) {
std::string trc = current->module();
trc.push_back('!');
trc += stripped;
return trc;
}
// Obtain the base address of the module using an obscure ioctl() call.
// See inline implementation of GetTypeSize() and docs.
SYM_DUMP_PARAM symParameters = { sizeof (SYM_DUMP_PARAM), (PUCHAR)stripped.c_str(), DBG_DUMP_NO_PRINT, 0,
NULL, NULL, NULL, 0, NULL };
const ULONG typeSize = Ioctl(IG_GET_TYPE_SIZE, &symParameters, symParameters.size);
if (!typeSize || !symParameters.ModBase) // Failed?
return type;
return stripped;
ULONG index = 0;
ULONG64 base = 0;
// Convert module base address to module index
HRESULT hr = ctx.symbols->GetModuleByOffset(symParameters.ModBase, 0, &index, &base);
if (FAILED(hr))
return type;
return stripped;
// Obtain module name
char buf[BufSize];
buf[0] = '\0';
hr = ctx.symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, index, base, buf, BufSize, 0);
if (FAILED(hr))
return type;
return stripped;
std::string rc = buf;
rc.push_back('!');
rc += type;
rc += stripped;
return rc;
}
......@@ -630,49 +655,52 @@ static inline void formatMilliSeconds(std::wostream &str, int milliSecs)
static const char stdStringTypeC[] = "std::basic_string<char,std::char_traits<char>,std::allocator<char> >";
static const char stdWStringTypeC[] = "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >";
static KnownType knownPODTypeHelper(const std::string &type)
static KnownType knownPODTypeHelper(const std::string &type, std::string::size_type endPos)
{
if (type.empty())
if (type.empty() || !endPos)
return KT_Unknown;
const bool isPointer = type.at(endPos - 1) == '*';
switch (type.at(0)) {
case 'c':
if (type == "char")
return KT_Char;
if (!type.compare(0, endPos, "char"))
return isPointer ? KT_POD_PointerType : KT_Char;
break;
case 'd':
if (type == "double")
return KT_FloatType;
if (!type.compare(0, endPos, "double"))
return isPointer ? KT_POD_PointerType : KT_FloatType;
break;
case 'f':
if (type == "float")
return KT_FloatType;
if (!type.compare(0, endPos, "float"))
return isPointer ? KT_POD_PointerType : KT_FloatType;
break;
case 'l':
if (!type.compare(0, 4, "long"))
return KT_IntType;
return isPointer ? KT_POD_PointerType : KT_IntType;
break;
case 'i':
if (!type.compare(0, 3, "int"))
return KT_IntType;
return isPointer ? KT_POD_PointerType : KT_IntType;
break;
case 's':
if (!type.compare(0, 5, "short"))
return KT_IntType;
return isPointer ? KT_POD_PointerType : KT_IntType;
break;
case 'u':
if (!type.compare(0, 8, "unsigned"))
if (!type.compare(0, 8, "unsigned")) {
if (isPointer)
return KT_POD_PointerType;
return type == "unsigned char" ? KT_UnsignedChar : KT_UnsignedIntType;
}
break;
}
return KT_Unknown;
return isPointer ? KT_PointerType : KT_Unknown;
}
// Determine type starting from a position (with/without 'class '/'struct ' prefix).
static KnownType knownClassTypeHelper(const std::string &type, std::string::size_type pos)
static KnownType knownClassTypeHelper(const std::string &type,
std::string::size_type pos,
std::string::size_type endPos)
{
// Strip pointer types.
const std::wstring::size_type compareLen =
endsWith(type, " *") ? type.size() -2 : type.size();
// STL ?
const std::wstring::size_type templatePos = type.find('<', pos);
static const std::wstring::size_type stlClassLen = 5;
......@@ -708,9 +736,9 @@ static KnownType knownClassTypeHelper(const std::string &type, std::string::size
}
}
// STL strings
if (!type.compare(pos, compareLen - pos, stdStringTypeC))
if (!type.compare(pos, endPos - pos, stdStringTypeC))
return KT_StdString;
if (!type.compare(pos, compareLen - pos, stdWStringTypeC))
if (!type.compare(pos, endPos - pos, stdWStringTypeC))
return KT_StdWString;
return KT_Unknown;
} // std::sth
......@@ -763,8 +791,7 @@ static KnownType knownClassTypeHelper(const std::string &type, std::string::size
}
}
// Remaining non-template types
switch (compareLen - qPos) {
switch (endPos - qPos) {
case 4:
if (!type.compare(qPos, 4, "QPen"))
return KT_QPen;
......@@ -997,31 +1024,69 @@ static KnownType knownClassTypeHelper(const std::string &type, std::string::size
return KT_Unknown;
}
KnownType knownType(const std::string &type, bool hasClassPrefix)
KnownType knownType(const std::string &type, unsigned flags)
{
if (type.empty())
return KT_Unknown;
const KnownType podType = knownPODTypeHelper(type);
// Autostrip one pointer if desired
const std::string::size_type endPos = (flags & KnownTypeAutoStripPointer) ?
type.size() - SymbolGroupValue::isPointerType(type) :
type.size();
// PODs first
const KnownType podType = knownPODTypeHelper(type, endPos);
if (podType != KT_Unknown)
return podType;
if (hasClassPrefix) {
if (flags & KnownTypeHasClassPrefix) {
switch (type.at(0)) { // Check 'class X' or 'struct X'
case 'c':
if (!type.compare(0, 6, "class "))
return knownClassTypeHelper(type, 6);
return knownClassTypeHelper(type, 6, endPos);
break;
case 's':
if (!type.compare(0, 7, "struct "))
return knownClassTypeHelper(type, 7);
return knownClassTypeHelper(type, 7, endPos);
break;
}
} else {
// No prefix, full check
return knownClassTypeHelper(type, 0);
return knownClassTypeHelper(type, 0, endPos);
}
return KT_Unknown;
}
void formatKnownTypeFlags(std::ostream &os, KnownType kt)
{
switch (kt) {
case KT_Unknown:
os << "<unknown>";
return;
case KT_POD_PointerType:
os << " pod_pointer";
break;
case KT_PointerType:
os << " pointer";
break;
default:
break;
}
if (kt & KT_POD_Type)
os << " pod";
if (kt & KT_Qt_Type)
os << " qt";
if (kt & KT_Qt_PrimitiveType)
os << " qt_primitive";
if (kt & KT_Qt_MovableType)
os << " qt_movable";
if (kt & KT_ContainerType)
os << " container";
if (kt & KT_STL_Type)
os << " stl";
if (kt & KT_HasSimpleDumper)
os << " simple_dumper";
}
static inline bool dumpQString(const SymbolGroupValue &v, std::wostream &str)
{
if (const SymbolGroupValue d = v["d"]) {
......@@ -1394,11 +1459,13 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
*containerSizeIn = -1;
// Check for class types and strip pointer types (references appear as pointers as well)
s->clear();
const KnownType kt = knownType(n->type());
const KnownType kt = knownType(n->type(), KnownTypeHasClassPrefix|KnownTypeAutoStripPointer);
if (knownTypeIn)