diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index 46086a0c2b9..90c33a10613 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -285,7 +285,6 @@ class Dumper(DumperBase): self.autoDerefPointers = int(args.get("autoderef", "0")) self.partialUpdate = int(args.get("partial", "0")) self.fallbackQtVersion = 0x50200 - self.sortStructMembers = bool(args.get("sortstructs", True)) #warn("NAMESPACE: '%s'" % self.qtNamespace()) #warn("EXPANDED INAMES: %s" % self.expandedINames) @@ -1144,6 +1143,7 @@ class Dumper(DumperBase): if self.currentIName in self.expandedINames: innerType = None + self.put('sortable="1"') with Children(self, 1, childType=innerType): self.putFields(value) if not self.showQObjectNames: @@ -1215,15 +1215,6 @@ class Dumper(DumperBase): def putFields(self, value, dumpBase = True): fields = value.type.fields() - if self.sortStructMembers: - def sortOrder(field): - if field.is_base_class: - return 0 - if field.name and field.name.startswith("_vptr."): - return 1 - return 2 - fields.sort(key = lambda field: "%d%s" % (sortOrder(field), field.name)) - #warn("TYPE: %s" % value.type) #warn("FIELDS: %s" % fields) baseNumber = 0 @@ -1257,6 +1248,7 @@ class Dumper(DumperBase): # int (**)(void) n = 100 self.putType(" ") + self.put('sortgroup="1"') self.putValue(value[field.name]) self.putNumChild(n) if self.isExpanded(): @@ -1280,6 +1272,7 @@ class Dumper(DumperBase): baseNumber += 1 with UnnamedSubItem(self, "@%d" % baseNumber): baseValue = value.cast(field.type) + self.put('sortgroup="2"') self.putBaseClassName(field.name) self.putAddress(baseValue.address) self.putItem(baseValue, False) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index 0570533dc63..3ccad30dcc6 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -1092,6 +1092,7 @@ class Dumper(DumperBase): self.putQObjectNameValue(value) if self.currentIName in self.expandedINames: + self.put('sortable="1"') with Children(self): self.putFields(value) if not self.showQObjectNames: @@ -1134,8 +1135,6 @@ class Dumper(DumperBase): baseObject = value.Cast(baseClass) baseObjects.append(ChildItem(baseClass.GetName(), baseObject)) - if self.sortStructMembers: - baseObjects.sort(key = lambda baseObject: str(baseObject.name)) for i in xrange(len(baseObjects)): baseObject = baseObjects[i] with UnnamedSubItem(self, "@%d" % (i + 1)): @@ -1147,8 +1146,6 @@ class Dumper(DumperBase): if memberCount > 10000: memberCount = 10000 children = [value.GetChildAtIndex(memberBase + i) for i in xrange(memberCount)] - if self.sortStructMembers: - children.sort(key = lambda child: str(child.GetName())) for child in children: # Only needed in the QVariant4 test. if int(child.GetLoadAddress()) == 0xffffffffffffffff: @@ -1169,7 +1166,6 @@ class Dumper(DumperBase): self.expandedINames = set(args.get('expanded', [])) self.autoDerefPointers = int(args.get('autoderef', '0')) - self.sortStructMembers = bool(args.get('sortstructs', True)); self.useDynamicType = int(args.get('dyntype', '0')) self.useFancy = int(args.get('fancy', '0')) self.passExceptions = int(args.get('passexceptions', '0')) diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 42c3e80ee59..ce7249f6fa3 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -2000,10 +2000,12 @@ void DebuggerEngine::updateLocalsView(const GdbMi &all) } } + const bool sortStructMembers = boolSetting(SortStructMembers); + GdbMi data = all["data"]; foreach (const GdbMi &child, data.children()) { WatchItem *item = new WatchItem; - item->parse(child); + item->parse(child, sortStructMembers); const TypeInfo ti = d->m_typeInfoCache.value(item->type); if (ti.size && !item->size) item->size = ti.size; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 2c25473c2e6..2975c5cd824 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4596,7 +4596,6 @@ void GdbEngine::doUpdateLocals(const UpdateParameters ¶ms) cmd.arg("resultvarname", m_resultVarName); cmd.arg("partialvar", params.partialVariable); - cmd.arg("sortstructs", boolSetting(SortStructMembers)); cmd.callback = CB(handleFetchVariables); runCommand(cmd); diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 1657ab5bd2a..28bae13c45f 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -793,7 +793,6 @@ void LldbEngine::doUpdateLocals(const UpdateParameters ¶ms) cmd.arg("autoderef", boolSetting(AutoDerefPointers)); cmd.arg("dyntype", boolSetting(UseDynamicType)); cmd.arg("partialvar", params.partialVariable); - cmd.arg("sortstructs", boolSetting(SortStructMembers)); cmd.arg("qobjectnames", boolSetting(ShowQObjectNames)); StackFrame frame = stackHandler()->currentFrame(); diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index 1c6dc62e652..1106c29e8a5 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -514,9 +514,10 @@ void PdbEngine::refreshLocals(const GdbMi &vars) WatchHandler *handler = watchHandler(); handler->resetValueCache(); + const bool sortStructMembers = boolSetting(SortStructMembers); foreach (const GdbMi &child, vars.children()) { WatchItem *item = new WatchItem; - item->parse(child); + item->parse(child, sortStructMembers); handler->insertItem(item); } diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index 96421d1bcf7..9cc7f944fa7 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -118,6 +118,7 @@ WatchItem::WatchItem() : bitsize(0), elided(0), arrayIndex(-1), + sortGroup(0), wantsChildren(false), valueEnabled(true), valueEditable(true), @@ -380,7 +381,18 @@ static void decodeArrayData(WatchItem *item, const QByteArray &rawData, qDebug() << "ENCODING ERROR: " << encoding.toString(); } -void WatchItem::parseHelper(const GdbMi &input) +static bool sortByName(const Utils::TreeItem *a, const Utils::TreeItem *b) +{ + auto aa = static_cast(a); + auto bb = static_cast(b); + + if (aa->sortGroup != bb->sortGroup) + return aa->sortGroup > bb->sortGroup; + + return aa->name < bb->name; +} + +void WatchItem::parseHelper(const GdbMi &input, bool maySort) { setChildrenUnneeded(); @@ -437,6 +449,10 @@ void WatchItem::parseHelper(const GdbMi &input) if (mi.isValid()) exp = mi.data(); + mi = input["sortgroup"]; + if (mi.isValid()) + sortGroup = mi.toInt(); + mi = input["valueenabled"]; if (mi.data() == "true") valueEnabled = true; @@ -500,14 +516,17 @@ void WatchItem::parseHelper(const GdbMi &input) QByteArray key = subinput["key"].data(); if (!key.isEmpty()) child->name = decodeData(key, subinput["keyencoded"].data()); - child->parseHelper(subinput); + child->parseHelper(subinput, maySort); appendChild(child); } + + if (maySort && input["sortable"].toInt()) + sortChildren(&sortByName); } } } -void WatchItem::parse(const GdbMi &data) +void WatchItem::parse(const GdbMi &data, bool maySort) { iname = data["iname"].data(); @@ -517,7 +536,7 @@ void WatchItem::parse(const GdbMi &data) else name = QString::fromLatin1(data["name"].data()); - parseHelper(data); + parseHelper(data, maySort); if (wname.isValid()) exp = name.toUtf8(); diff --git a/src/plugins/debugger/watchdata.h b/src/plugins/debugger/watchdata.h index 4fe97157836..160117608a7 100644 --- a/src/plugins/debugger/watchdata.h +++ b/src/plugins/debugger/watchdata.h @@ -45,7 +45,7 @@ class WatchItem : public Utils::TreeItem public: WatchItem(); - void parse(const GdbMi &input); + void parse(const GdbMi &input, bool maySort); bool isLocal() const; bool isWatcher() const; @@ -117,13 +117,14 @@ public: uint bitsize; // Size in case of bit fields int elided; // Full size if value was cut off, -1 if cut on unknown size, 0 otherwise int arrayIndex; // -1 if not an array member + uchar sortGroup; // 0 - ordinary member, 1 - vptr, 2 - base class bool wantsChildren; bool valueEnabled; // Value will be enabled or not bool valueEditable; // Value will be editable bool outdated; // \internal item is to be removed. private: - void parseHelper(const GdbMi &input); + void parseHelper(const GdbMi &input, bool maySort); Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::WatchHandler) }; diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index c82d401bf22..c8f33edda09 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -1296,7 +1296,7 @@ void tst_Dumpers::dumper() "python theDumper.setupDumpers()\n" "run " + nograb + "\n" "python theDumper.fetchVariables({" - "'token':2,'fancy':1,'forcens':1,'sortstructs':1," + "'token':2,'fancy':1,'forcens':1," "'autoderef':1,'dyntype':1,'passexceptions':1," "'qobjectnames':1," "'expanded':[" + expandedq + "]})\n"; @@ -1435,7 +1435,7 @@ void tst_Dumpers::dumper() context.boostVersion = child["value"].toInt(); else { WatchItem *item = new WatchItem; - item->parse(child); + item->parse(child, true); local.appendChild(item); } }