Debugger: Fix QHash display of "compact" keys

Add make std::string usable as "compact" key.

Change-Id: Idbfcf9d299e2dde392025166a20c3d0ab60239a6
Reviewed-by: Christian Stenger <christian.stenger@digia.com>
This commit is contained in:
hjk
2014-09-12 13:31:12 +02:00
parent d38e8283df
commit 2776536a7e
6 changed files with 59 additions and 39 deletions

View File

@@ -190,18 +190,6 @@ def showException(msg, exType, exValue, exTraceback):
pass pass
def stripClassTag(typeName):
if typeName.startswith("class "):
return typeName[6:]
if typeName.startswith("struct "):
return typeName[7:]
if typeName.startswith("const "):
return typeName[6:]
if typeName.startswith("volatile "):
return typeName[9:]
return typeName
class Children: class Children:
def __init__(self, d, numChild = 1, childType = None, childNumChild = None, def __init__(self, d, numChild = 1, childType = None, childNumChild = None,
maxNumChild = None, addrBase = None, addrStep = None): maxNumChild = None, addrBase = None, addrStep = None):
@@ -215,7 +203,7 @@ class Children:
if childType is None: if childType is None:
self.childType = None self.childType = None
else: else:
self.childType = stripClassTag(str(childType)) self.childType = d.stripClassTag(str(childType))
if not self.d.isCli: if not self.d.isCli:
self.d.put('childtype="%s",' % self.childType) self.d.put('childtype="%s",' % self.childType)
if childNumChild is None: if childNumChild is None:
@@ -271,8 +259,11 @@ class PairedChildrenData:
self.isCompact = d.isMapCompact(self.keyType, self.valueType) self.isCompact = d.isMapCompact(self.keyType, self.valueType)
self.childType = valueType if self.isCompact else pairType self.childType = valueType if self.isCompact else pairType
ns = d.qtNamespace() ns = d.qtNamespace()
self.keyIsQString = str(self.keyType) == ns + "QString" keyTypeName = d.stripClassTag(str(self.keyType))
self.keyIsQByteArray = str(self.keyType) == ns + "QByteArray" self.keyIsQString = keyTypeName == ns + "QString"
self.keyIsQByteArray = keyTypeName == ns + "QByteArray"
self.keyIsStdString = keyTypeName == "std::string" \
or keyTypeName.startswith("std::basic_string<char")
class PairedChildren(Children): class PairedChildren(Children):
def __init__(self, d, numChild, useKeyAndValue = False, def __init__(self, d, numChild, useKeyAndValue = False,
@@ -367,12 +358,23 @@ class DumperBase:
def putNewline(self): def putNewline(self):
pass pass
def stripClassTag(self, typeName):
if typeName.startswith("class "):
return typeName[6:]
if typeName.startswith("struct "):
return typeName[7:]
if typeName.startswith("const "):
return typeName[6:]
if typeName.startswith("volatile "):
return typeName[9:]
return typeName
def stripForFormat(self, typeName): def stripForFormat(self, typeName):
if typeName in self.cachedFormats: if typeName in self.cachedFormats:
return self.cachedFormats[typeName] return self.cachedFormats[typeName]
stripped = "" stripped = ""
inArray = 0 inArray = 0
for c in stripClassTag(typeName): for c in self.stripClassTag(typeName):
if c == '<': if c == '<':
break break
if c == ' ': if c == ' ':
@@ -503,6 +505,15 @@ class DumperBase:
def stringData(self, value): def stringData(self, value):
return self.byteArrayDataHelper(self.extractPointer(value)) return self.byteArrayDataHelper(self.extractPointer(value))
def encodeStdString(self, value, limit = 0):
data = value["_M_dataplus"]["_M_p"]
sizePtr = data.cast(self.sizetType().pointer())
size = int(sizePtr[-3])
alloc = int(sizePtr[-2])
self.check(0 <= size and size <= alloc and alloc <= 100*1000*1000)
elided, shown = self.computeLimit(size, limit)
return self.readMemory(data, shown)
def extractTemplateArgument(self, typename, position): def extractTemplateArgument(self, typename, position):
level = 0 level = 0
skipSpace = False skipSpace = False
@@ -589,24 +600,28 @@ class DumperBase:
return False return False
#warn("CHILDREN: %s %s %s" % (numChild, childType, childNumChild)) #warn("CHILDREN: %s %s %s" % (numChild, childType, childNumChild))
def putMapName(self, value, index = -1): def putMapName(self, value, index = None):
ns = self.qtNamespace() ns = self.qtNamespace()
if str(value.type) == ns + "QString": typeName = self.stripClassTag(str(value.type))
if typeName == ns + "QString":
self.put('key="%s",' % self.encodeString(value)) self.put('key="%s",' % self.encodeString(value))
self.put('keyencoded="%s",' % Hex4EncodedLittleEndian) self.put('keyencoded="%s",' % Hex4EncodedLittleEndian)
elif str(value.type) == ns + "QByteArray": elif typeName == ns + "QByteArray":
self.put('key="%s",' % self.encodeByteArray(value)) self.put('key="%s",' % self.encodeByteArray(value))
self.put('keyencoded="%s",' % Hex2EncodedLatin1) self.put('keyencoded="%s",' % Hex2EncodedLatin1)
elif typeName == "std::string":
self.put('key="%s",' % self.encodeStdString(value))
self.put('keyencoded="%s",' % Hex2EncodedLatin1)
else: else:
val = str(value.GetValue()) if self.isLldb else str(value) val = str(value.GetValue()) if self.isLldb else str(value)
if index == -1: if index is None:
key = 'key="%s",' % val key = '%s' % val
else: else:
key = 'key="[%d] %s",' % (index, val) key = '[%s] %s' % (index, val)
self.put('key="%s",' % self.hexencode(key)) self.put('key="%s",' % self.hexencode(key))
self.put('keyencoded="%s",' % Hex2EncodedLatin1) self.put('keyencoded="%s",' % Hex2EncodedUtf8WithoutQuotes)
def putPair(self, pair, index = -1): def putPair(self, pair, index = None):
if self.pairData.useKeyAndValue: if self.pairData.useKeyAndValue:
key = pair["key"] key = pair["key"]
value = pair["value"] value = pair["value"]
@@ -620,12 +635,15 @@ class DumperBase:
elif self.pairData.keyIsQByteArray: elif self.pairData.keyIsQByteArray:
self.put('key="%s",' % self.encodeByteArray(key)) self.put('key="%s",' % self.encodeByteArray(key))
self.put('keyencoded="%s",' % Hex2EncodedLatin1) self.put('keyencoded="%s",' % Hex2EncodedLatin1)
elif self.pairData.keyIsStdString:
self.put('key="%s",' % self.encodeStdString(key))
self.put('keyencoded="%s",' % Hex2EncodedLatin1)
else: else:
name = str(key.GetValue()) if self.isLldb else str(key) name = str(key.GetValue()) if self.isLldb else str(key)
if index == -1: if index == -1:
self.put('name="%s",' % name) self.put('name="%s",' % name)
else: else:
self.put('key="[%d] %s",' % (index, name)) self.put('key="[%s] %s",' % (index, name))
self.putItem(value) self.putItem(value)
else: else:
self.putEmptyValue() self.putEmptyValue()
@@ -969,7 +987,7 @@ class DumperBase:
and innerTypeName != "wchar_t": and innerTypeName != "wchar_t":
self.putType(innerTypeName) self.putType(innerTypeName)
savedCurrentChildType = self.currentChildType savedCurrentChildType = self.currentChildType
self.currentChildType = stripClassTag(innerTypeName) self.currentChildType = self.stripClassTag(innerTypeName)
self.putItem(value.dereference()) self.putItem(value.dereference())
self.currentChildType = savedCurrentChildType self.currentChildType = savedCurrentChildType
#self.putPointerValue(value) #self.putPointerValue(value)

View File

@@ -544,7 +544,7 @@ class Dumper(DumperBase):
self.putValue("<not accessible>") self.putValue("<not accessible>")
try: try:
if self.currentType.value: if self.currentType.value:
typeName = stripClassTag(self.currentType.value) typeName = self.stripClassTag(self.currentType.value)
if len(typeName) > 0 and typeName != self.currentChildType: if len(typeName) > 0 and typeName != self.currentChildType:
self.put('type="%s",' % typeName) # str(type.unqualified()) ? self.put('type="%s",' % typeName) # str(type.unqualified()) ?
@@ -583,7 +583,7 @@ class Dumper(DumperBase):
arg += a arg += a
#warn("CALL: %s -> %s(%s)" % (value, func, arg)) #warn("CALL: %s -> %s(%s)" % (value, func, arg))
typeName = stripClassTag(str(value.type)) typeName = self.stripClassTag(str(value.type))
if typeName.find(":") >= 0: if typeName.find(":") >= 0:
typeName = "'" + typeName + "'" typeName = "'" + typeName + "'"
# 'class' is needed, see http://sourceware.org/bugzilla/show_bug.cgi?id=11912 # 'class' is needed, see http://sourceware.org/bugzilla/show_bug.cgi?id=11912
@@ -604,7 +604,7 @@ class Dumper(DumperBase):
return None return None
def makeValue(self, type, init): def makeValue(self, type, init):
type = "::" + stripClassTag(str(type)); type = "::" + self.stripClassTag(str(type));
# Avoid malloc symbol clash with QVector. # Avoid malloc symbol clash with QVector.
gdb.execute("set $d = (%s*)calloc(sizeof(%s), 1)" % (type, type)) gdb.execute("set $d = (%s*)calloc(sizeof(%s), 1)" % (type, type))
gdb.execute("set *$d = {%s}" % init) gdb.execute("set *$d = {%s}" % init)
@@ -615,7 +615,7 @@ class Dumper(DumperBase):
return value return value
def makeExpression(self, value): def makeExpression(self, value):
type = "::" + stripClassTag(str(value.type)) type = "::" + self.stripClassTag(str(value.type))
#warn(" TYPE: %s" % type) #warn(" TYPE: %s" % type)
#exp = "(*(%s*)(&%s))" % (type, value.address) #exp = "(*(%s*)(&%s))" % (type, value.address)
exp = "(*(%s*)(%s))" % (type, value.address) exp = "(*(%s*)(%s))" % (type, value.address)
@@ -917,7 +917,7 @@ class Dumper(DumperBase):
self.lookupType("unsigned long")), None, -1) self.lookupType("unsigned long")), None, -1)
def stripNamespaceFromType(self, typeName): def stripNamespaceFromType(self, typeName):
type = stripClassTag(typeName) type = self.stripClassTag(typeName)
ns = self.qtNamespace() ns = self.qtNamespace()
if len(ns) > 0 and type.startswith(ns): if len(ns) > 0 and type.startswith(ns):
type = type[len(ns):] type = type[len(ns):]
@@ -1727,7 +1727,7 @@ class CliDumper(Dumper):
self.putValue("<not accessible>") self.putValue("<not accessible>")
try: try:
if self.currentType.value: if self.currentType.value:
typeName = stripClassTag(self.currentType.value) typeName = self.stripClassTag(self.currentType.value)
self.put('<%s> = {' % typeName) self.put('<%s> = {' % typeName)
if self.currentValue.value is None: if self.currentValue.value is None:

View File

@@ -879,7 +879,7 @@ class Dumper(DumperBase):
return self.target.FindFirstGlobalVariable(symbolName) return self.target.FindFirstGlobalVariable(symbolName)
def stripNamespaceFromType(self, typeName): def stripNamespaceFromType(self, typeName):
#type = stripClassTag(typeName) #type = self.stripClassTag(typeName)
type = typeName type = typeName
ns = self.qtNamespace() ns = self.qtNamespace()
if len(ns) > 0 and type.startswith(ns): if len(ns) > 0 and type.startswith(ns):

View File

@@ -78,7 +78,7 @@ def qdebug(options = None,
def itemFormat(self, item): def itemFormat(self, item):
format = self.formats.get(str(cleanAddress(item.value.address))) format = self.formats.get(str(cleanAddress(item.value.address)))
if format is None: if format is None:
format = self.typeformats.get(stripClassTag(str(item.value.type))) format = self.typeformats.get(self.stripClassTag(str(item.value.type)))
return format return format
def dumpFrame(self, frame): def dumpFrame(self, frame):

View File

@@ -619,6 +619,7 @@ def qdump__QHash(d, value):
isCompact = d.isMapCompact(keyType, valueType) isCompact = d.isMapCompact(keyType, valueType)
childType = valueType if isCompact else innerType childType = valueType if isCompact else innerType
with Children(d, size, maxNumChild=1000, childType=childType): with Children(d, size, maxNumChild=1000, childType=childType):
j = 0
for i in d.childRange(): for i in d.childRange():
if i == 0: if i == 0:
node = hashDataFirstNode(d_ptr, numBuckets) node = hashDataFirstNode(d_ptr, numBuckets)
@@ -632,9 +633,10 @@ def qdump__QHash(d, value):
# LLDB can't access directly since it's in anonymous union # LLDB can't access directly since it's in anonymous union
# for Qt4 optimized int keytype # for Qt4 optimized int keytype
key = it[1]["key"] key = it[1]["key"]
d.putMapName(key) d.putMapName(key, j)
d.putItem(it["value"]) d.putItem(it["value"])
d.putType(valueType) d.putType(valueType)
j += 1
else: else:
d.putItem(it) d.putItem(it)
@@ -1232,7 +1234,7 @@ def _qdump__QObject(d, value):
d.putFields(value) d.putFields(value)
# Parent and children. # Parent and children.
if stripClassTag(str(value.type)) == ns + "QObject": if d.stripClassTag(str(value.type)) == ns + "QObject":
d.putSubItem("parent", d_ptr["parent"]) d.putSubItem("parent", d_ptr["parent"])
d.putSubItem("children", d_ptr["children"]) d.putSubItem("children", d_ptr["children"])

View File

@@ -1652,8 +1652,8 @@ void tst_Dumpers::dumper_data()
+ Check("h1.2.value.1", "[1]", "2", "int") + Check("h1.2.value.1", "[1]", "2", "int")
+ Check("h2", "<2 items>", "@QHash<int, float>") + Check("h2", "<2 items>", "@QHash<int, float>")
+ Check("h2.22", "[22]", "22", "float") + Check("h2.0", "[0] 22", "22", "float")
+ Check("h2.11", "[11]", "11", "float") + Check("h2.1", "[1] 11", "11", "float")
+ Check("h3", "<9 items>", "@QHash<@QString, int>") + Check("h3", "<9 items>", "@QHash<@QString, int>")
+ Check("h3.0", "[0]", "", "@QHashNode<@QString, int>") + Check("h3.0", "[0]", "", "@QHashNode<@QString, int>")
@@ -1707,7 +1707,7 @@ void tst_Dumpers::dumper_data()
+ CheckType("h7.2.value", "@QPointer<@QObject>") + CheckType("h7.2.value", "@QPointer<@QObject>")
+ Check("h8", "<3 items>", "Hash") + Check("h8", "<3 items>", "Hash")
+ Check("h8.11", "[11]", "11", "float") + Check("h8.0", "[0] 22", "22", "float")
+ Check("it1.key", "22", "int") + Check("it1.key", "22", "int")
+ Check("it1.value", "22", "float") + Check("it1.value", "22", "float")
+ Check("it3.key", "33", "int") + Check("it3.key", "33", "int")