diff --git a/src/libs/qtcreatorcdbext/gdbmihelpers.cpp b/src/libs/qtcreatorcdbext/gdbmihelpers.cpp index 12c5c7c94d4..ef5902618fd 100644 --- a/src/libs/qtcreatorcdbext/gdbmihelpers.cpp +++ b/src/libs/qtcreatorcdbext/gdbmihelpers.cpp @@ -633,7 +633,11 @@ std::string widgetAt(const SymbolGroupValueContext &ctx, int x, int y, std::stri typedef SymbolGroupValue::SymbolList SymbolList; // First, resolve symbol since there are ambiguities. Take the first one which is the // overload for (int,int) and call by address instead off name to overcome that. - const std::string func = QtInfo::get(ctx).prependQtGuiModule("QApplication::widgetAt"); + const QtInfo &qtInfo = QtInfo::get(ctx); + const std::string func = + qtInfo.prependQtModule("QApplication::widgetAt", + qtInfo.version >= 5 && QtInfo::qt5WidgetSplit ? + QtInfo::Widgets : QtInfo::Gui); const SymbolList symbols = SymbolGroupValue::resolveSymbol(func.c_str(), ctx, errorMessage); if (symbols.empty()) return std::string(); // Not a gui application, likely diff --git a/src/libs/qtcreatorcdbext/knowntype.h b/src/libs/qtcreatorcdbext/knowntype.h index 67574be6eb2..0d668d85f7a 100644 --- a/src/libs/qtcreatorcdbext/knowntype.h +++ b/src/libs/qtcreatorcdbext/knowntype.h @@ -75,8 +75,9 @@ enum KnownType KT_QBasicAtomicInt = KT_Qt_Type + KT_HasSimpleDumper + 18, KT_QAtomicInt = KT_Qt_Type + KT_HasSimpleDumper + 19, KT_QObject = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 20, - KT_QWidget = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 21, - KT_QSharedPointer = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 22, + KT_QWindow = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 21, + KT_QWidget = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 22, + KT_QSharedPointer = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 23, // Types: Various QT movable types KT_QPen = KT_Qt_Type + KT_Qt_MovableType + 30, KT_QUrl = KT_Qt_Type + KT_Qt_MovableType + 31 + KT_HasSimpleDumper, diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp index 0dfa66a161f..fbf2b52d01a 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp @@ -624,38 +624,23 @@ static inline std::string resolveQtSymbol(const char *symbolC, const QtInfo &QtInfo::get(const SymbolGroupValueContext &ctx) { - static const char qtCoreDefaultModule[] = "QtCored"; - static const char qtGuiDefaultModule[] = "QtGuid"; - static const char qtNetworkDefaultModule[] = "QtNetworkd"; - static const char qtScriptDefaultModule[] = "QtScriptd"; static QtInfo rc; - if (!rc.coreModule.empty()) + if (!rc.libInfix.empty()) return rc; do { // Lookup qstrdup() to hopefully get module (potential libinfix) and namespace // Typically, this resolves to 'QtGuid4!qstrdup' and 'QtCored4!qstrdup'... - const std::string qualifiedSymbol = resolveQtSymbol("qstrdup", qtCoreDefaultModule, "Core", ctx); + const std::string qualifiedSymbol = resolveQtSymbol("qstrdup", "QtCored", "Core", ctx); const std::string::size_type exclPos = qualifiedSymbol.find('!'); // Resolved: 'QtCored4!qstrdup' if (exclPos == std::string::npos) { - const char defaultVersion = '4'; + rc.libInfix = "d4"; rc.version = 4; - rc.coreModule = qtCoreDefaultModule + defaultVersion; - rc.guiModule = qtGuiDefaultModule + defaultVersion; - rc.networkModule = qtNetworkDefaultModule + defaultVersion; - rc.scriptModule = qtScriptDefaultModule + defaultVersion; break; } // Should be 'QtCored4!qstrdup' - rc.coreModule = qualifiedSymbol.substr(0, exclPos); + rc.libInfix = qualifiedSymbol.substr(6, exclPos - 6); rc.version = qualifiedSymbol.at(exclPos - 1) - '0'; - // Derive other module names 'QtXXd4' - rc.guiModule = rc.coreModule; - rc.guiModule.replace(0, 6, "QtGui"); - rc.networkModule = rc.coreModule; - rc.networkModule.replace(0, 6, "QtNetwork"); - rc.scriptModule = rc.coreModule; - rc.scriptModule.replace(0, 6, "QtScript"); // Any namespace? 'QtCored4!nsp::qstrdup' const std::string::size_type nameSpaceStart = exclPos + 1; const std::string::size_type colonPos = qualifiedSymbol.find(':', nameSpaceStart); @@ -665,12 +650,23 @@ const QtInfo &QtInfo::get(const SymbolGroupValueContext &ctx) } while (false); rc.qObjectType = rc.prependQtCoreModule("QObject"); rc.qObjectPrivateType = rc.prependQtCoreModule("QObjectPrivate"); - rc.qWidgetPrivateType = rc.prependQtGuiModule("QWidgetPrivate"); + rc.qWindowPrivateType = rc.prependQtGuiModule("QWindowPrivate"); + rc.qWidgetPrivateType = + rc.prependQtModule("QWidgetPrivate", + rc.version >= 5 && qt5WidgetSplit ? Widgets : Gui); if (SymbolGroupValue::verbose) DebugPrint() << rc; return rc; } +std::string QtInfo::moduleName(Module m) const +{ + // Must match the enumeration + static const char* modNames[] = + {"QtCore", "QtGui", "QtWidgets", "QtNetwork", "QtScript" }; + return modNames[m] + libInfix; +} + std::string QtInfo::prependModuleAndNameSpace(const std::string &type, const std::string &module, const std::string &aNameSpace) @@ -703,7 +699,7 @@ std::string QtInfo::prependModuleAndNameSpace(const std::string &type, std::ostream &operator<<(std::ostream &os, const QtInfo &i) { os << "Qt Info: Version: " << i.version << " Modules '" - << i.coreModule << "', '" << i.guiModule + << i.moduleName(QtInfo::Core) << "', '" << i.moduleName(QtInfo::Gui) << "', Namespace='" << i.nameSpace << "', types: " << i.qObjectType << ',' << i.qObjectPrivateType << ',' << i.qWidgetPrivateType; @@ -1144,6 +1140,8 @@ static KnownType knownClassTypeHelper(const std::string &type, return KT_QObject; if (!type.compare(qPos, 7, "QWidget")) return KT_QWidget; + if (!type.compare(qPos, 7, "QWindow")) + return KT_QWindow; if (!type.compare(qPos, 7, "QLocale")) return KT_QLocale; if (!type.compare(qPos, 7, "QMatrix")) @@ -1944,29 +1942,44 @@ static inline bool dumpQRectF(const SymbolGroupValue &v, std::wostream &str) return true; } +/* Return a SymbolGroupValue containing the private class of + * a type (multiple) derived from QObject and something else + * (QWidget: QObject,QPaintDevice or QWindow: QObject,QSurface). + * We get differing behaviour for pointers and values on stack. + * For 'QWidget *', the base class QObject usually can be accessed + * by name (past the vtable). When browsing class hierarchies (stack), + * typically only the uninteresting QPaintDevice is seen. */ + +SymbolGroupValue qobjectDerivedPrivate(const SymbolGroupValue &v, + const std::string &qwPrivateType, + const QtInfo &qtInfo) +{ + if (const SymbolGroupValue base = v[SymbolGroupValue::stripModuleFromType(qtInfo.qObjectType).c_str()]) + if (const SymbolGroupValue qwPrivate = base["d_ptr"]["d"].pointerTypeCast(qwPrivateType.c_str())) + return qwPrivate; + if (!SymbolGroupValue::isPointerType(v.type())) + return SymbolGroupValue(); + // Class hierarchy: Using brute force, add new symbol based on that + // QScopedPointer is basically a 'X *' (first member). + std::string errorMessage; + std::ostringstream str; + str << '(' << qwPrivateType << "*)(" << std::showbase << std::hex << v.address() << ')'; + const std::string name = str.str(); + SymbolGroupNode *qwPrivateNode + = v.node()->symbolGroup()->addSymbol(v.module(), name, std::string(), &errorMessage); + return SymbolGroupValue(qwPrivateNode, v.context()); +} + // Dump the object name static inline bool dumpQWidget(const SymbolGroupValue &v, std::wostream &str, void **specialInfoIn = 0) { const QtInfo &qtInfo = QtInfo::get(v.context()); - const std::string &qwPrivateType = qtInfo.qWidgetPrivateType; - // We get differing behaviour caused by multiple inheritance of QWidget from QObject,QPaintDevice: - // For 'QWidget *', the base class QObject usually can be accessed (past the vtable). - // When browsing class hierarchies, typically only the uninteresting QPaintDevice is seen. - SymbolGroupValue qwPrivate; - if (const SymbolGroupValue base = v[SymbolGroupValue::stripModuleFromType(qtInfo.qObjectType).c_str()]) - qwPrivate = base["d_ptr"]["d"].pointerTypeCast(qwPrivateType.c_str()); - if (!qwPrivate && !SymbolGroupValue::isPointerType(v.type())) { - // Class hierarchy: Using brute force, add new symbol based on that - // QScopedPointer is basically a 'X *' (first member). - std::string errorMessage; - std::ostringstream str; - str << '(' << qwPrivateType << "*)(" << std::showbase << std::hex << v.address() << ')'; - const std::string name = str.str(); - SymbolGroupNode *qwPrivateNode - = v.node()->symbolGroup()->addSymbol(v.module(), name, std::string(), &errorMessage); - qwPrivate = SymbolGroupValue(qwPrivateNode, v.context()); - } - const SymbolGroupValue oName = qwPrivate[unsigned(0)]["objectName"]; // QWidgetPrivate inherits QObjectPrivate + const SymbolGroupValue qwPrivate = + qobjectDerivedPrivate(v, qtInfo.qWidgetPrivateType, qtInfo); + if (!qwPrivate) + return false; + // QWidgetPrivate inherits QObjectPrivate + const SymbolGroupValue oName = qwPrivate[unsigned(0)]["objectName"]; if (!oName) return false; if (specialInfoIn) @@ -1990,6 +2003,24 @@ static inline bool dumpQObject(const SymbolGroupValue &v, std::wostream &str, vo return false; } +// Dump the object name +static inline bool dumpQWindow(const SymbolGroupValue &v, std::wostream &str, void **specialInfoIn = 0) +{ + const QtInfo &qtInfo = QtInfo::get(v.context()); + const SymbolGroupValue qwPrivate = + qobjectDerivedPrivate(v, qtInfo.qWindowPrivateType, qtInfo); + if (!qwPrivate) + return false; + // QWindowPrivate inherits QObjectPrivate + const SymbolGroupValue oName = qwPrivate[unsigned(0)]["objectName"]; // QWidgetPrivate inherits QObjectPrivate + if (!oName) + return false; + if (specialInfoIn) + *specialInfoIn = qwPrivate.node(); + dumpQString(oName, str); + return true; +} + // Dump a std::string. static bool dumpStd_W_String(const SymbolGroupValue &v, int type, std::wostream &str) { @@ -2357,6 +2388,9 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, case KT_QWidget: rc = dumpQWidget(v, str, specialInfoIn) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed; break; + case KT_QWindow: + rc = dumpQWindow(v, str, specialInfoIn) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed; + break; case KT_QSharedPointer: rc = dumpQSharedPointer(v, str, specialInfoIn) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed; break; @@ -2696,6 +2730,7 @@ std::vector rc = complexDumpQByteArray(n, ctx); break; case KT_QWidget: // Special info by simple dumper is the QWidgetPrivate node + case KT_QWindow: // Special info by simple dumper is the QWindowPrivate node case KT_QObject: // Special info by simple dumper is the QObjectPrivate node if (specialInfo) { SymbolGroupNode *qObjectPrivateNode = reinterpret_cast(specialInfo); diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.h b/src/libs/qtcreatorcdbext/symbolgroupvalue.h index 6be186cad9a..8d2ee2dbe4f 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.h +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.h @@ -171,20 +171,32 @@ std::ostream &operator<<(std::ostream &, const SymbolGroupValue &v); struct QtInfo { + enum { qt5WidgetSplit = 0 }; + + enum Module + { + Core, Gui, Widgets, Network, Script + }; + QtInfo() : version(0) {} static const QtInfo &get(const SymbolGroupValueContext &ctx); // Prepend core module and Qt namespace. To be able to work with some // 'complicated' types like QMapNode, specifying the module helps + std::string prependQtModule(const std::string &type, Module m = Core) const + { return QtInfo::prependModuleAndNameSpace(type, moduleName(m), nameSpace); } + std::string prependQtCoreModule(const std::string &type) const - { return QtInfo::prependModuleAndNameSpace(type, coreModule, nameSpace); } + { return prependQtModule(type, Core); } std::string prependQtGuiModule(const std::string &type) const - { return QtInfo::prependModuleAndNameSpace(type, guiModule, nameSpace); } + { return QtInfo::prependQtModule(type, Gui); } + std::string prependQtWidgetsModule(const std::string &type) const + { return QtInfo::prependQtModule(type, Widgets); } std::string prependQtNetworkModule(const std::string &type) const - { return QtInfo::prependModuleAndNameSpace(type, networkModule, nameSpace); } + { return QtInfo::prependQtModule(type, Network); } std::string prependQtScriptModule(const std::string &type) const - { return QtInfo::prependModuleAndNameSpace(type, scriptModule, nameSpace); } + { return QtInfo::prependQtModule(type, Script); } // Prepend module and namespace if missing with some smartness // ('Foo' or -> 'nsp::Foo') => 'QtCored4!nsp::Foo' @@ -192,15 +204,15 @@ struct QtInfo const std::string &module, const std::string &nameSpace); + std::string moduleName(Module m) const; + int version; std::string nameSpace; - std::string coreModule; - std::string guiModule; - std::string networkModule; - std::string scriptModule; + std::string libInfix; // Fully qualified types with module and namespace std::string qObjectType; std::string qObjectPrivateType; + std::string qWindowPrivateType; std::string qWidgetPrivateType; };