From e9b1e493c2d3b745d3c7cb3c56698cfbc2f51f69 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 5 Apr 2016 11:14:40 +0200 Subject: [PATCH] Debugger: Move struct sorting logic to generic parser Backends only have to specify whether an object members are sortable in principle (e.g. all structs), and some numeric 'sortgroup' value for member items (higher values are always sorted on top). Change-Id: I10ce94580374fed48a35f058a575a1408d6801af Reviewed-by: David Schulz Reviewed-by: Christian Stenger --- share/qtcreator/debugger/gdbbridge.py | 13 +++--------- share/qtcreator/debugger/lldbbridge.py | 6 +----- src/plugins/debugger/debuggerengine.cpp | 4 +++- src/plugins/debugger/gdb/gdbengine.cpp | 1 - src/plugins/debugger/lldb/lldbengine.cpp | 1 - src/plugins/debugger/pdb/pdbengine.cpp | 3 ++- src/plugins/debugger/watchdata.cpp | 27 ++++++++++++++++++++---- src/plugins/debugger/watchdata.h | 5 +++-- tests/auto/debugger/tst_dumpers.cpp | 4 ++-- 9 files changed, 37 insertions(+), 27 deletions(-) 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); } }