diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp index f5f6edad87b..631c53e2b78 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp @@ -762,6 +762,14 @@ static void fixValue(const std::string &type, std::wstring *value) } } + // Strip a vtable "0x13f37b7c8 module!Class::`vftable'" to a plain pointer. + if (SymbolGroupValue::isVTableType(type)) { + const std::wstring::size_type blankPos = value->find(L' ', 2); + if (blankPos != std::wstring::npos) + value->erase(blankPos, value->size() - blankPos); + return; + } + // Pointers: fix '0x00000000`00000AD class bla' ... to "0xAD", but leave // 'const char *' values as is ('0x00000000`00000AD "hallo"). if (!type.empty() && type.at(type.size() - 1) == L'*') { diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp index 86f5386d84c..22cda177dbf 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp @@ -417,6 +417,13 @@ unsigned SymbolGroupValue::isPointerType(const std::string &t) return 0; } +// Return number of characters to strip for pointer type +bool SymbolGroupValue::isVTableType(const std::string &t) +{ + const char vtableTypeC[] = "__fptr() ["; + return t.compare(0, sizeof(vtableTypeC) - 1, vtableTypeC) == 0; +} + // add pointer type 'Foo' -> 'Foo *', 'Foo *' -> 'Foo **' std::string SymbolGroupValue::pointerType(const std::string &type) { diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.h b/src/libs/qtcreatorcdbext/symbolgroupvalue.h index d31ff7f81f3..7e8c433ed12 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.h +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.h @@ -113,6 +113,7 @@ public: static std::string moduleOfType(const std::string &type); // pointer type, return number of characters to strip static unsigned isPointerType(const std::string &); + static bool isVTableType(const std::string &t); // add pointer type 'Foo' -> 'Foo *', 'Foo *' -> 'Foo **' static std::string pointerType(const std::string &type); // Symbol Name/(Expression) of a pointed-to instance ('Foo' at 0x10') ==> '*(Foo *)0x10' diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index 72da172346e..242eaf1b491 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -68,6 +68,13 @@ bool isPointerType(const QByteArray &type) return type.endsWith('*') || type.endsWith("* const"); } +bool isVTablePointer(const QByteArray &type) +{ + // FIXME: That is cdb only. + // But no user type can be named like this, so this is safe. + return type.startsWith("__fptr()"); +} + bool isCharPointerType(const QByteArray &type) { return type == "char *" || type == "const char *" || type == "char const *"; diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 4b442f9ea35..02c1152e0d0 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -371,7 +371,7 @@ static inline QString formattedValue(const WatchData &data, int format) return reformatInteger(data.value.toLongLong(), format); } - if (!isPointerType(data.type)) { + if (!isPointerType(data.type) && !isVTablePointer(data.type)) { bool ok = false; qulonglong integer = data.value.toULongLong(&ok, 0); if (ok) diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h index 37ce0169695..b120c49bb32 100644 --- a/src/plugins/debugger/watchutils.h +++ b/src/plugins/debugger/watchutils.h @@ -81,6 +81,7 @@ bool hasLetterOrNumber(const QString &exp); bool hasSideEffects(const QString &exp); bool isKeyWord(const QString &exp); bool isPointerType(const QByteArray &type); +bool isVTablePointer(const QByteArray &type); bool isCharPointerType(const QByteArray &type); bool startsWithDigit(const QString &str); QByteArray stripPointerType(QByteArray type);