From a57a925b76785c1269ca5bcbacd553f01c0f238d Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 12 Feb 2024 14:03:00 +0100 Subject: [PATCH] Debugger: defer type look up Change-Id: I425c2bfc3c88ebf46af161c5434c0c05a3bb9c97 Reviewed-by: Christian Stenger --- share/qtcreator/debugger/cdbbridge.py | 493 +++++++++++++++++++++++-- share/qtcreator/debugger/dumper.py | 68 ++-- share/qtcreator/debugger/lldbbridge.py | 2 +- src/libs/qtcreatorcdbext/pytype.cpp | 46 +-- src/libs/qtcreatorcdbext/pytype.h | 1 + 5 files changed, 533 insertions(+), 77 deletions(-) diff --git a/share/qtcreator/debugger/cdbbridge.py b/share/qtcreator/debugger/cdbbridge.py index d323714ba44..b5fc683cbae 100644 --- a/share/qtcreator/debugger/cdbbridge.py +++ b/share/qtcreator/debugger/cdbbridge.py @@ -11,7 +11,7 @@ from utils import TypeCode sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) -from dumper import DumperBase, SubItem +from dumper import DumperBase, SubItem, Children, DisplayFormat, UnnamedSubItem class FakeVoidType(cdbext.Type): @@ -84,10 +84,9 @@ class Dumper(DumperBase): self.check(isinstance(nativeValue, cdbext.Value)) val = self.Value(self) val.name = nativeValue.name() - val._type = self.fromNativeType(nativeValue.type()) # There is no cdb api for the size of bitfields. # Workaround this issue by parsing the native debugger text for integral types. - if val._type.code == TypeCode.Integral: + if nativeValue.type().code() == TypeCode.Integral: try: integerString = nativeValue.nativeDebuggerValue() except UnicodeDecodeError: @@ -106,16 +105,18 @@ class Dumper(DumperBase): base = 16 else: base = 10 - signed = not val._type.name.startswith('unsigned') + signed = not nativeValue.type().name().startswith('unsigned') try: - val.ldata = int(integerString, base).to_bytes(val._type.size(), + val.ldata = int(integerString, base).to_bytes((nativeValue.type().bitsize() +7) // 8, byteorder='little', signed=signed) except: # read raw memory in case the integerString can not be interpreted pass - if val._type.code == TypeCode.Enum: + if nativeValue.type().code() == TypeCode.Enum: val.ldisplay = self.enumValue(nativeValue) - val.isBaseClass = val.name == val._type.name + elif not nativeValue.type().resolved and nativeValue.type().code() == TypeCode.Struct and not nativeValue.hasChildren(): + val.ldisplay = self.enumValue(nativeValue) + val.isBaseClass = val.name == nativeValue.type().name() val.nativeValue = nativeValue val.laddress = nativeValue.address() val.lbitsize = nativeValue.bitsize() @@ -136,6 +137,9 @@ class Dumper(DumperBase): for f in nativeType.fields()]) return typeId + def nativeValueType(self, nativeValue): + return self.fromNativeType(nativeValue.type()) + def fromNativeType(self, nativeType): self.check(isinstance(nativeType, cdbext.Type)) typeId = self.nativeTypeId(nativeType) @@ -150,51 +154,66 @@ class Dumper(DumperBase): if nativeType.name().startswith(''): code = TypeCode.Function elif nativeType.targetName() != nativeType.name(): - targetType = self.lookupType(nativeType.targetName(), nativeType.moduleId()) - if targetType is not None and targetType is not nativeType: - return self.createPointerType(targetType) + return self.createPointerType(nativeType.targetName()) if code == TypeCode.Array: # cdb reports virtual function tables as arrays those ar handled separetly by # the DumperBase. Declare those types as structs prevents a lookup to a # none existing type if not nativeType.name().startswith('__fptr()') and not nativeType.name().startswith(' 0: namespace = name[:namespaceIndex + 2] + self.qtNamespace = lambda: namespace self.qtCustomEventFunc = self.parseAndEvaluate( '%s!%sQObject::customEvent' % (self.qtCoreModuleName(), namespace)).address() @@ -498,7 +518,7 @@ class Dumper(DumperBase): else: val = self.Value(self) val.laddress = value.pointer() - val._type = value.type.dereference() + val._type = DumperBase.Type(self, value.type.targetName) val.nativeValue = value.nativeValue return val @@ -519,3 +539,424 @@ class Dumper(DumperBase): def symbolAddress(self, symbolName): res = self.nativeParseAndEvaluate(symbolName) return None if res is None else res.address() + + def putItemX(self, value): + #DumperBase.warn('PUT ITEM: %s' % value.stringify()) + + typeobj = value.type # unqualified() + typeName = typeobj.name + + self.addToCache(typeobj) # Fill type cache + + if not value.lIsInScope: + self.putSpecialValue('optimizedout') + #self.putType(typeobj) + #self.putSpecialValue('outofscope') + self.putNumChild(0) + return + + if not isinstance(value, self.Value): + raise RuntimeError('WRONG TYPE IN putItem: %s' % type(self.Value)) + + # Try on possibly typedefed type first. + if self.tryPutPrettyItem(typeName, value): + if typeobj.code == TypeCode.Pointer: + self.putOriginalAddress(value.address()) + else: + self.putAddress(value.address()) + return + + if typeobj.code == TypeCode.Pointer: + self.putFormattedPointer(value) + return + + self.putAddress(value.address()) + if value.lbitsize is not None: + self.putField('size', value.lbitsize // 8) + + if typeobj.code == TypeCode.Function: + #DumperBase.warn('FUNCTION VALUE: %s' % value) + self.putType(typeobj) + self.putSymbolValue(value.pointer()) + self.putNumChild(0) + return + + if typeobj.code == TypeCode.Enum: + #DumperBase.warn('ENUM VALUE: %s' % value.stringify()) + self.putType(typeobj.name) + self.putValue(value.display()) + self.putNumChild(0) + return + + if typeobj.code == TypeCode.Array: + #DumperBase.warn('ARRAY VALUE: %s' % value) + self.putCStyleArray(value) + return + + if typeobj.code == TypeCode.Integral: + #DumperBase.warn('INTEGER: %s %s' % (value.name, value)) + val = value.value() + self.putNumChild(0) + self.putValue(val) + self.putType(typeName) + return + + if typeobj.code == TypeCode.Float: + #DumperBase.warn('FLOAT VALUE: %s' % value) + self.putValue(value.value()) + self.putNumChild(0) + self.putType(typeobj.name) + return + + if typeobj.code in (TypeCode.Reference, TypeCode.RValueReference): + #DumperBase.warn('REFERENCE VALUE: %s' % value) + val = value.dereference() + if val.laddress != 0: + self.putItem(val) + else: + self.putSpecialValue('nullreference') + self.putBetterType(typeName) + return + + if typeobj.code == TypeCode.Complex: + self.putType(typeobj) + self.putValue(value.display()) + self.putNumChild(0) + return + + self.putType(typeName) + + if value.summary is not None and self.useFancy: + self.putValue(self.hexencode(value.summary), 'utf8:1:0') + self.putNumChild(0) + return + + self.putExpandable() + self.putEmptyValue() + #DumperBase.warn('STRUCT GUTS: %s ADDRESS: 0x%x ' % (value.name, value.address())) + if self.showQObjectNames: + #with self.timer(self.currentIName): + self.putQObjectNameValue(value) + if self.isExpanded(): + self.putField('sortable', 1) + with Children(self): + baseIndex = 0 + for item in self.listValueChildren(value): + if item.name.startswith('__vfptr'): + with SubItem(self, '[vptr]'): + # int (**)(void) + self.putType(' ') + self.putSortGroup(20) + self.putValue(item.name) + n = 100 + if self.isExpanded(): + with Children(self): + n = self.putVTableChildren(item, n) + self.putNumChild(n) + continue + + if item.isBaseClass: + baseIndex += 1 + # We cannot use nativeField.name as part of the iname as + # it might contain spaces and other strange characters. + with UnnamedSubItem(self, "@%d" % baseIndex): + self.putField('iname', self.currentIName) + self.putField('name', '[%s]' % item.name) + self.putSortGroup(1000 - baseIndex) + self.putAddress(item.address()) + self.putItem(item) + continue + + + with SubItem(self, item.name): + self.putItem(item) + if self.showQObjectNames: + self.tryPutQObjectGuts(value) + + + def putFormattedPointerX(self, value: DumperBase.Value): + self.putOriginalAddress(value.address()) + pointer = value.pointer() + self.putAddress(pointer) + if pointer == 0: + self.putType(value.type) + self.putValue('0x0') + return + + typeName = value.type.name + + try: + self.readRawMemory(pointer, 1) + except: + # Failure to dereference a pointer should at least + # show the value of a pointer. + #DumperBase.warn('BAD POINTER: %s' % value) + self.putValue('0x%x' % pointer) + self.putType(typeName) + return + + if self.currentIName.endswith('.this'): + self.putDerefedPointer(value) + return + + displayFormat = self.currentItemFormat(value.type.name) + + if value.type.targetName == 'void': + #DumperBase.warn('VOID POINTER: %s' % displayFormat) + self.putType(typeName) + self.putSymbolValue(pointer) + return + + if displayFormat == DisplayFormat.Raw: + # Explicitly requested bald pointer. + #DumperBase.warn('RAW') + self.putType(typeName) + self.putValue('0x%x' % pointer) + self.putExpandable() + if self.currentIName in self.expandedINames: + with Children(self): + with SubItem(self, '*'): + self.putItem(value.dereference()) + return + + limit = self.displayStringLimit + if displayFormat in (DisplayFormat.SeparateLatin1String, DisplayFormat.SeparateUtf8String): + limit = 1000000 + if self.tryPutSimpleFormattedPointer(pointer, typeName, + value.type.targetName, displayFormat, limit): + self.putExpandable() + return + + if DisplayFormat.Array10 <= displayFormat and displayFormat <= DisplayFormat.Array10000: + n = (10, 100, 1000, 10000)[displayFormat - DisplayFormat.Array10] + self.putType(typeName) + self.putItemCount(n) + self.putArrayData(value.pointer(), n, value.type.targetName) + return + + #DumperBase.warn('AUTODEREF: %s' % self.autoDerefPointers) + #DumperBase.warn('INAME: %s' % self.currentIName) + if self.autoDerefPointers: + # Generic pointer type with AutomaticFormat, but never dereference char types: + if value.type.targetName not in ( + 'char', + 'signed char', + 'int8_t', + 'qint8', + 'unsigned char', + 'uint8_t', + 'quint8', + 'wchar_t', + 'CHAR', + 'WCHAR', + 'char8_t', + 'char16_t', + 'char32_t' + ): + self.putDerefedPointer(value) + return + + #DumperBase.warn('GENERIC PLAIN POINTER: %s' % value.type) + #DumperBase.warn('ADDR PLAIN POINTER: 0x%x' % value.laddress) + self.putType(typeName) + self.putSymbolValue(pointer) + self.putExpandable() + if self.currentIName in self.expandedINames: + with Children(self): + with SubItem(self, '*'): + self.putItem(value.dereference()) + + + def putCStyleArray(self, value): + arrayType = value.type + innerType = arrayType.ltarget + address = value.address() + if address: + self.putValue('@0x%x' % address, priority=-1) + else: + self.putEmptyValue() + self.putType(arrayType) + + displayFormat = self.currentItemFormat() + arrayByteSize = arrayType.size() + n = self.arrayItemCountFromTypeName(value.type.name, 100) + + p = value.address() + if displayFormat != DisplayFormat.Raw and p: + if innerType.name in ( + 'char', + 'int8_t', + 'qint8', + 'wchar_t', + 'unsigned char', + 'uint8_t', + 'quint8', + 'signed char', + 'CHAR', + 'WCHAR', + 'char8_t', + 'char16_t', + 'char32_t' + ): + self.putCharArrayHelper(p, n, innerType, self.currentItemFormat(), + makeExpandable=False) + else: + self.tryPutSimpleFormattedPointer(p, arrayType, innerType, + displayFormat, arrayByteSize) + self.putNumChild(n) + + if self.isExpanded(): + if n > 100: + addrStep = innerType.size() + with Children(self, n, innerType, addrBase=address, addrStep=addrStep): + for i in self.childRange(): + self.putSubItem(i, self.createValue(address + i * addrStep, innerType)) + else: + with Children(self): + n = 0 + for item in self.listValueChildren(value): + with SubItem(self, n): + n += 1 + self.putItem(item) + + + def putArrayData(self, base, n, innerType, childNumChild=None): + self.checkIntType(base) + self.checkIntType(n) + addrBase = base + innerType = self.createType(innerType) + innerSize = innerType.size() + self.putNumChild(n) + #DumperBase.warn('ADDRESS: 0x%x INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType)) + enc = innerType.simpleEncoding() + maxNumChild = self.maxArrayCount() + if enc: + self.put('childtype="%s",' % innerType.name) + self.put('addrbase="0x%x",' % addrBase) + self.put('addrstep="0x%x",' % innerSize) + self.put('arrayencoding="%s",' % enc) + self.put('endian="%s",' % self.packCode) + if n > maxNumChild: + self.put('childrenelided="%s",' % n) + n = maxNumChild + self.put('arraydata="') + self.put(self.readMemory(addrBase, n * innerSize)) + self.put('",') + else: + with Children(self, n, innerType, childNumChild, maxNumChild, + addrBase=addrBase, addrStep=innerSize): + for i in self.childRange(): + self.putSubItem(i, self.createValue(addrBase + i * innerSize, innerType)) + + def tryPutSimpleFormattedPointer(self, ptr, typeName, innerType, displayFormat, limit): + if isinstance(innerType, self.Type): + innerType = innerType.name + if displayFormat == DisplayFormat.Automatic: + if innerType in ('char', 'signed char', 'unsigned char', 'uint8_t', 'CHAR'): + # Use UTF-8 as default for char *. + self.putType(typeName) + (length, shown, data) = self.readToFirstZero(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) + if self.isExpanded(): + self.putArrayData(ptr, shown, innerType) + return True + + if innerType in ('wchar_t', 'WCHAR'): + self.putType(typeName) + charSize = self.lookupType('wchar_t').size() + (length, data) = self.encodeCArray(ptr, charSize, limit) + if charSize == 2: + self.putValue(data, 'utf16', length=length) + else: + self.putValue(data, 'ucs4', length=length) + return True + + if displayFormat == DisplayFormat.Latin1String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'latin1', length=length) + return True + + if displayFormat == DisplayFormat.SeparateLatin1String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'latin1', length=length) + self.putDisplay('latin1:separate', data) + return True + + if displayFormat == DisplayFormat.Utf8String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) + return True + + if displayFormat == DisplayFormat.SeparateUtf8String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) + self.putDisplay('utf8:separate', data) + return True + + if displayFormat == DisplayFormat.Local8BitString: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'local8bit', length=length) + return True + + if displayFormat == DisplayFormat.Utf16String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 2, limit) + self.putValue(data, 'utf16', length=length) + return True + + if displayFormat == DisplayFormat.Ucs4String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 4, limit) + self.putValue(data, 'ucs4', length=length) + return True + + return False + + def putDerefedPointer(self, value): + derefValue = value.dereference() + savedCurrentChildType = self.currentChildType + self.currentChildType = value.type.targetName + self.putType(value.type.targetName) + derefValue.name = '*' + derefValue.autoDerefCount = value.autoDerefCount + 1 + + if derefValue.type.code == TypeCode.Pointer: + self.putField('autoderefcount', '{}'.format(derefValue.autoDerefCount)) + + self.putItem(derefValue) + self.currentChildType = savedCurrentChildType + + def extractPointer(self, value): + code = 'I' if self.ptrSize() == 4 else 'Q' + return self.extractSomething(value, code, 8 * self.ptrSize()) + + def createValue(self, datish, typish): + if self.isInt(datish): # Used as address. + return self.createValueFromAddressAndType(datish, typish) + if isinstance(datish, bytes): + val = self.Value(self) + if isinstance(typish, self.Type): + val._type = typish + else: + val._type = self.Type(self, typish) + #DumperBase.warn('CREATING %s WITH DATA %s' % (val.type.name, self.hexencode(datish))) + val.ldata = datish + val.check() + return val + raise RuntimeError('EXPECTING ADDRESS OR BYTES, GOT %s' % type(datish)) + + def createValueFromAddressAndType(self, address, typish): + val = self.Value(self) + if isinstance(typish, self.Type): + val._type = typish + else: + val._type = self.Type(self, typish) + val.laddress = address + if self.useDynamicType: + val._type = val.type.dynamicType(address) + return val diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 2fa7d31da50..836b1860cb2 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -3041,7 +3041,7 @@ class DumperBase(): or self.type.name.startswith('unsigned ') \ or self.type.name.find(' unsigned ') != -1 if bitsize is None: - bitsize = self.type.bitsize() + bitsize = self.type.lbitsize return self.extractInteger(bitsize, unsigned) def floatingPoint(self): @@ -3512,26 +3512,40 @@ class DumperBase(): tdata.moduleName = self.moduleName return tdata + @property + def bitsize(self): + if callable(self.lbitsize): + self.lbitsize = self.lbitsize() + return self.lbitsize + class Type(): def __init__(self, dumper, typeId): - self.typeId = typeId + self.typeId = typeId.replace('@', dumper.qtNamespace()) self.dumper = dumper - self.tdata = dumper.typeData.get(typeId, None) - if self.tdata is None: - #DumperBase.warn('USING : %s' % self.typeId) - self.dumper.lookupType(self.typeId) - self.tdata = self.dumper.typeData.get(self.typeId) + self.initialized = False def __str__(self): #return self.typeId return self.stringify() + @property + def tdata(self): + if not self.initialized: + self.initialized = True + self.data = self.dumper.typeData.get(self.typeId, None) + if self.data is None: + #DumperBase.warn('USING : %s' % self.typeId) + self.dumper.lookupType(self.typeId) + self.data = self.dumper.typeData.get(self.typeId) + return self.data + + def setTdata(self, tdata): + self.initialized = True + self.data = tdata + @property def name(self): - tdata = self.dumper.typeData.get(self.typeId) - if tdata is None: - return self.typeId - return tdata.name + return self.typeId if self.tdata is None else self.tdata.name @property def code(self): @@ -3539,7 +3553,7 @@ class DumperBase(): @property def lbitsize(self): - return self.tdata.lbitsize + return self.tdata.bitsize @property def lbitpos(self): @@ -3547,15 +3561,25 @@ class DumperBase(): @property def ltarget(self): + if isinstance(self.tdata.ltarget, str): + self.tdata.ltarget = self.dumper.createType(self.tdata.ltarget) return self.tdata.ltarget + @property + def targetName(self): + if self.tdata.ltarget is None: + return '' + return self.tdata.ltarget if isinstance(self.tdata.ltarget, str) else self.tdata.ltarget.name + @property def moduleName(self): + if callable(self.tdata.moduleName): + self.tdata.moduleName = self.tdata.moduleName() return self.tdata.moduleName def stringify(self): return 'Type(name="%s",bsize=%s,code=%s)' \ - % (self.tdata.name, self.tdata.lbitsize, self.tdata.code) + % (self.tdata.name, self.lbitsize, self.tdata.code) def __getitem__(self, index): if self.dumper.isInt(index): @@ -3659,7 +3683,7 @@ class DumperBase(): def alignment(self): if self.tdata.code == TypeCode.Typedef: - return self.tdata.ltarget.alignment() + return self.ltarget.alignment() if self.tdata.code in (TypeCode.Integral, TypeCode.Float, TypeCode.Enum): if self.tdata.name in ('double', 'long long', 'unsigned long long'): # Crude approximation. @@ -3678,7 +3702,7 @@ class DumperBase(): return self.dumper.createPointerType(self) def target(self): - return self.tdata.ltarget + return self.ltarget def stripTypedefs(self): if isinstance(self, self.dumper.Type) and self.code != TypeCode.Typedef: @@ -3687,7 +3711,7 @@ class DumperBase(): return self.ltarget def size(self): - bs = self.bitsize() + bs = self.lbitsize if bs % 8 != 0: DumperBase.warn('ODD SIZE: %s' % self) return (7 + bs) >> 3 @@ -3797,12 +3821,12 @@ class DumperBase(): return val def createPointerType(self, targetType): - if not isinstance(targetType, self.Type): - raise RuntimeError('Expected type in createPointerType(), got %s' + if not isinstance(targetType, (str, self.Type)): + raise RuntimeError('Expected type or str in createPointerType(), got %s' % type(targetType)) - typeId = targetType.typeId + ' *' + typeId = (targetType if isinstance(targetType, str) else targetType.typeId) + ' *' tdata = self.TypeData(self, typeId) - tdata.name = targetType.name + '*' + tdata.name = (targetType if isinstance(targetType, str) else targetType.name) + '*' tdata.lbitsize = 8 * self.ptrSize() tdata.code = TypeCode.Pointer tdata.ltarget = targetType @@ -3927,7 +3951,7 @@ class DumperBase(): tdata = self.typeData.get(typish, None) if tdata is not None: if tdata.lbitsize is not None: - if tdata.lbitsize > 0: + if callable(tdata.lbitsize) or tdata.lbitsize > 0: return self.Type(self, typish) knownType = self.lookupType(typish) @@ -3944,7 +3968,7 @@ class DumperBase(): if typish.endswith('*'): tdata.code = TypeCode.Pointer tdata.lbitsize = 8 * self.ptrSize() - tdata.ltarget = self.createType(typish[:-1].strip()) + tdata.ltarget = typish[:-1].strip() typeobj = self.Type(self, tdata.typeId) #DumperBase.warn('CREATE TYPE: %s' % typeobj.stringify()) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index 7558bcdfa47..c6aae0c2e48 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -419,7 +419,7 @@ class Dumper(DumperBase): targetTypeName = typeName[0:pos1].strip() #DumperBase.warn("TARGET TYPENAME: %s" % targetTypeName) targetType = self.fromNativeType(nativeTargetType) - targetType.tdata = targetType.tdata.copy() + targetType.setTdata(targetType.tdata.copy()) targetType.tdata.name = targetTypeName return self.createArrayType(targetType, count) if hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x diff --git a/src/libs/qtcreatorcdbext/pytype.cpp b/src/libs/qtcreatorcdbext/pytype.cpp index 0621793b7e0..9345c1d91af 100644 --- a/src/libs/qtcreatorcdbext/pytype.cpp +++ b/src/libs/qtcreatorcdbext/pytype.cpp @@ -121,6 +121,9 @@ static std::string stripPointerType(const std::string &typeNameIn) std::string typeName = typeNameIn; if (typeName.back() == '*') { typeName.pop_back(); + trimBack(typeName); + if (endsWith(typeName, "const")) + typeName = typeName.erase(typeName.size() - 5, 5); } else { const auto arrayPosition = typeName.find_first_of('['); if (arrayPosition != std::string::npos @@ -296,35 +299,19 @@ int PyType::code() const return std::nullopt; }; - if (!resolve()) - return parseTypeName(name()).value_or(TypeCodeUnresolvable); - - if (m_tag < 0) { - if (const std::optional typeCode = parseTypeName(name())) - return *typeCode; - - IDebugSymbolGroup2 *sg = 0; - if (FAILED(ExtensionCommandContext::instance()->symbols()->CreateSymbolGroup2(&sg))) - return TypeCodeStruct; - - const std::string helperValueName = SymbolGroupValue::pointedToSymbolName(0, name(true)); - ULONG index = DEBUG_ANY_ID; - if (SUCCEEDED(sg->AddSymbol(helperValueName.c_str(), &index))) - m_tag = PyValue(index, sg).tag(); - sg->Release(); + if (m_tag >= 0) { + switch (m_tag) { + case SymTagUDT: return TypeCodeStruct; + case SymTagEnum: return TypeCodeEnum; + case SymTagTypedef: return TypeCodeTypedef; + case SymTagFunctionType: return TypeCodeFunction; + case SymTagPointerType: return TypeCodePointer; + case SymTagArrayType: return TypeCodeArray; + case SymTagBaseType: return isIntegralType(name()) ? TypeCodeIntegral : TypeCodeFloat; + default: break; + } } - switch (m_tag) { - case SymTagUDT: return TypeCodeStruct; - case SymTagEnum: return TypeCodeEnum; - case SymTagTypedef: return TypeCodeTypedef; - case SymTagFunctionType: return TypeCodeFunction; - case SymTagPointerType: return TypeCodePointer; - case SymTagArrayType: return TypeCodeArray; - case SymTagBaseType: return isIntegralType(name()) ? TypeCodeIntegral : TypeCodeFloat; - default: break; - } - - return TypeCodeStruct; + return parseTypeName(name()).value_or(TypeCodeStruct); } PyType PyType::target() const @@ -533,6 +520,7 @@ PY_FUNC_RET_OBJECT_LIST(fields, PY_OBJ_NAME) PY_FUNC_RET_STD_STRING(module, PY_OBJ_NAME) PY_FUNC(moduleId, PY_OBJ_NAME, "K") PY_FUNC(arrayElements, PY_OBJ_NAME, "k") +PY_FUNC_RET_BOOL(resolved, PY_OBJ_NAME) PY_FUNC_DECL(templateArguments, PY_OBJ_NAME) { PY_IMPL_GUARD; @@ -568,6 +556,8 @@ static PyMethodDef typeMethods[] = { "Returns the number of elements in an array or 0 for non array types"}, {"templateArguments", PyCFunction(templateArguments), METH_NOARGS, "Returns all template arguments."}, + {"resolved", PyCFunction(resolved), METH_NOARGS, + "Returns whether the type is resolved"}, {NULL} /* Sentinel */ }; diff --git a/src/libs/qtcreatorcdbext/pytype.h b/src/libs/qtcreatorcdbext/pytype.h index 8b05fffe0ad..b71eae1ab02 100644 --- a/src/libs/qtcreatorcdbext/pytype.h +++ b/src/libs/qtcreatorcdbext/pytype.h @@ -29,6 +29,7 @@ public: std::string module() const; ULONG64 moduleId() const; int arrayElements() const; + bool resolved() const { return m_resolved.value_or(false); } struct TemplateArgument {