forked from qt-creator/qt-creator
Debugger: Fix QHash display of "compact" keys
Add make std::string usable as "compact" key.
Change-Id: Idbfcf9d299e2dde392025166a20c3d0ab60239a6
(cherry picked from commit 2776536a7e
)
Reviewed-by: Christian Stenger <christian.stenger@digia.com>
This commit is contained in:
@@ -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()
|
||||||
@@ -959,7 +977,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)
|
||||||
|
@@ -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:
|
||||||
|
@@ -882,7 +882,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):
|
||||||
|
@@ -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):
|
||||||
|
@@ -618,6 +618,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)
|
||||||
@@ -631,9 +632,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)
|
||||||
|
|
||||||
@@ -1231,7 +1233,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"])
|
||||||
|
|
||||||
|
@@ -1658,8 +1658,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>")
|
||||||
@@ -1713,7 +1713,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")
|
||||||
|
Reference in New Issue
Block a user