Debugger: Always sort local variables alphabetically.

It was there for GDB at a time, but never for the other backends.
Fix the GDB regression and make the sorting consistent across
backends.

Task-number: QTCREATORBUG-15296
Change-Id: If728c65f0c8ca4a8378c7cf5e53f1dadbfb72b29
Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
hjk
2016-04-05 13:27:24 +02:00
parent 9bc60e0b9d
commit e73a9c1b0d
5 changed files with 62 additions and 51 deletions

View File

@@ -435,7 +435,6 @@ class Dumper(DumperBase):
# Don't bother. It's only supplementary information anyway. # Don't bother. It's only supplementary information anyway.
pass pass
locals.sort(key = lambda item: item.name)
for item in locals: for item in locals:
value = self.downcast(item.value) if self.useDynamicType else item.value value = self.downcast(item.value) if self.useDynamicType else item.value
with OutputSafer(self): with OutputSafer(self):

View File

@@ -168,12 +168,6 @@ enum RemoteSetupState { RemoteSetupNone, RemoteSetupRequested,
RemoteSetupSucceeded, RemoteSetupFailed, RemoteSetupSucceeded, RemoteSetupFailed,
RemoteSetupCancelled }; RemoteSetupCancelled };
struct TypeInfo
{
TypeInfo(uint s = 0) : size(s) {}
uint size;
};
class DebuggerEnginePrivate : public QObject class DebuggerEnginePrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -342,7 +336,6 @@ public:
bool m_isStateDebugging; bool m_isStateDebugging;
Utils::FileInProjectFinder m_fileFinder; Utils::FileInProjectFinder m_fileFinder;
QHash<QByteArray, TypeInfo> m_typeInfoCache;
QByteArray m_qtNamespace; QByteArray m_qtNamespace;
}; };
@@ -1987,33 +1980,13 @@ void DebuggerEngine::updateLocalsView(const GdbMi &all)
{ {
WatchHandler *handler = watchHandler(); WatchHandler *handler = watchHandler();
const bool partial = all["partial"].toInt();
const GdbMi typeInfo = all["typeinfo"]; const GdbMi typeInfo = all["typeinfo"];
if (typeInfo.type() == GdbMi::List) { handler->recordTypeInfo(typeInfo);
foreach (const GdbMi &s, typeInfo.children()) {
const GdbMi name = s["name"];
const GdbMi size = s["size"];
if (name.isValid() && size.isValid())
d->m_typeInfoCache.insert(QByteArray::fromHex(name.data()),
TypeInfo(size.data().toUInt()));
}
}
const bool sortStructMembers = boolSetting(SortStructMembers); const GdbMi data = all["data"];
handler->insertItems(data);
GdbMi data = all["data"]; const GdbMi ns = all["qtnamespace"];
foreach (const GdbMi &child, data.children()) {
WatchItem *item = new WatchItem;
item->parse(child, sortStructMembers);
const TypeInfo ti = d->m_typeInfoCache.value(item->type);
if (ti.size && !item->size)
item->size = ti.size;
handler->insertItem(item);
}
GdbMi ns = all["qtnamespace"];
if (ns.isValid()) { if (ns.isValid()) {
setQtNamespace(ns.data()); setQtNamespace(ns.data());
showMessage(_("FOUND NAMESPACED QT: " + ns.data())); showMessage(_("FOUND NAMESPACED QT: " + ns.data()));
@@ -2026,6 +1999,7 @@ void DebuggerEngine::updateLocalsView(const GdbMi &all)
DebuggerToolTipManager::updateEngine(this); DebuggerToolTipManager::updateEngine(this);
const bool partial = all["partial"].toInt();
if (!partial) if (!partial)
emit stackFrameCompleted(); emit stackFrameCompleted();
} }

View File

@@ -513,14 +513,7 @@ void PdbEngine::refreshLocals(const GdbMi &vars)
{ {
WatchHandler *handler = watchHandler(); WatchHandler *handler = watchHandler();
handler->resetValueCache(); handler->resetValueCache();
handler->insertItems(vars);
const bool sortStructMembers = boolSetting(SortStructMembers);
foreach (const GdbMi &child, vars.children()) {
WatchItem *item = new WatchItem;
item->parse(child, sortStructMembers);
handler->insertItem(item);
}
handler->notifyUpdateFinished(); handler->notifyUpdateFinished();
DebuggerToolTipManager::updateEngine(this); DebuggerToolTipManager::updateEngine(this);

View File

@@ -80,6 +80,12 @@ static int theUnprintableBase = -1;
const char INameProperty[] = "INameProperty"; const char INameProperty[] = "INameProperty";
const char KeyProperty[] = "KeyProperty"; const char KeyProperty[] = "KeyProperty";
struct TypeInfo
{
TypeInfo(uint s = 0) : size(s) {}
uint size;
};
static const WatchModel *watchModel(const WatchItem *item) static const WatchModel *watchModel(const WatchItem *item)
{ {
return reinterpret_cast<const WatchModel *>(item->model()); return reinterpret_cast<const WatchModel *>(item->model());
@@ -345,7 +351,6 @@ public:
WatchItem *findItem(const QByteArray &iname) const; WatchItem *findItem(const QByteArray &iname) const;
const WatchItem *watchItem(const QModelIndex &idx) const; const WatchItem *watchItem(const QModelIndex &idx) const;
void insertItem(WatchItem *item);
void reexpandItems(); void reexpandItems();
void showEditValue(const WatchItem *item); void showEditValue(const WatchItem *item);
@@ -373,6 +378,7 @@ public:
QSet<QByteArray> m_expandedINames; QSet<QByteArray> m_expandedINames;
QTimer m_requestUpdateTimer; QTimer m_requestUpdateTimer;
QHash<QByteArray, TypeInfo> m_reportedTypeInfo;
QHash<QString, DisplayFormats> m_reportedTypeFormats; // Type name -> Dumper Formats QHash<QString, DisplayFormats> m_reportedTypeFormats; // Type name -> Dumper Formats
QHash<QByteArray, QString> m_valueCache; QHash<QByteArray, QString> m_valueCache;
}; };
@@ -1249,23 +1255,46 @@ void WatchHandler::cleanup()
m_model->m_separatedView->hide(); m_model->m_separatedView->hide();
} }
void WatchHandler::insertItem(WatchItem *item) static bool sortByName(const TreeItem *a, const TreeItem *b)
{ {
m_model->insertItem(item); auto aa = static_cast<const WatchItem *>(a);
auto bb = static_cast<const WatchItem *>(b);
return aa->name < bb->name;
} }
void WatchModel::insertItem(WatchItem *item) void WatchHandler::insertItems(const GdbMi &data)
{ {
QTC_ASSERT(!item->iname.isEmpty(), return); QSet<TreeItem *> itemsToSort;
WatchItem *parent = findItem(parentName(item->iname)); const bool sortStructMembers = boolSetting(SortStructMembers);
QTC_ASSERT(parent, return); foreach (const GdbMi &child, data.children()) {
auto item = new WatchItem;
item->parse(child, sortStructMembers);
const TypeInfo ti = m_model->m_reportedTypeInfo.value(item->type);
if (ti.size && !item->size)
item->size = ti.size;
const bool added = insertItem(item);
if (added && item->level() == 2)
itemsToSort.insert(item->parent());
}
foreach (TreeItem *toplevel, itemsToSort)
toplevel->sortChildren(&sortByName);
}
bool WatchHandler::insertItem(WatchItem *item)
{
QTC_ASSERT(!item->iname.isEmpty(), return false);
WatchItem *parent = m_model->findItem(parentName(item->iname));
QTC_ASSERT(parent, return false);
bool found = false; bool found = false;
const QVector<TreeItem *> siblings = parent->children(); const QVector<TreeItem *> siblings = parent->children();
for (int row = 0, n = siblings.size(); row < n; ++row) { for (int row = 0, n = siblings.size(); row < n; ++row) {
if (static_cast<WatchItem *>(siblings.at(row))->iname == item->iname) { if (static_cast<WatchItem *>(siblings.at(row))->iname == item->iname) {
delete takeItem(parent->children().at(row)); delete m_model->takeItem(parent->children().at(row));
parent->insertChild(row, item); parent->insertChild(row, item);
found = true; found = true;
break; break;
@@ -1276,7 +1305,9 @@ void WatchModel::insertItem(WatchItem *item)
item->update(); item->update();
item->walkTree([this](TreeItem *sub) { showEditValue(static_cast<WatchItem *>(sub)); }); item->walkTree([this](TreeItem *sub) { m_model->showEditValue(static_cast<WatchItem *>(sub)); });
return !found;
} }
void WatchModel::reexpandItems() void WatchModel::reexpandItems()
@@ -1403,7 +1434,7 @@ void WatchHandler::watchExpression(const QString &exp0, const QString &name)
item->exp = exp; item->exp = exp;
item->name = name.isEmpty() ? exp0 : name; item->name = name.isEmpty() ? exp0 : name;
item->iname = watcherName(exp); item->iname = watcherName(exp);
m_model->insertItem(item); insertItem(item);
saveWatchers(); saveWatchers();
if (m_model->m_engine->state() == DebuggerNotReady) { if (m_model->m_engine->state() == DebuggerNotReady) {
@@ -1856,5 +1887,16 @@ QSet<QByteArray> WatchHandler::expandedINames() const
return m_model->m_expandedINames; return m_model->m_expandedINames;
} }
void WatchHandler::recordTypeInfo(const GdbMi &typeInfo)
{
if (typeInfo.type() == GdbMi::List) {
foreach (const GdbMi &s, typeInfo.children()) {
QByteArray typeName = QByteArray::fromHex(s["name"].data());
TypeInfo ti(s["size"].data().toUInt());
m_model->m_reportedTypeInfo.insert(typeName, ti);
}
}
}
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -109,7 +109,9 @@ public:
void setCurrentItem(const QByteArray &iname); void setCurrentItem(const QByteArray &iname);
void updateWatchersWindow(); void updateWatchersWindow();
void insertItem(WatchItem *item); // Takes ownership. bool insertItem(WatchItem *item); // Takes ownership, returns whether item was added, not overwritten.
void insertItems(const GdbMi &data);
void removeItemByIName(const QByteArray &iname); void removeItemByIName(const QByteArray &iname);
void removeAllData(bool includeInspectData = false); void removeAllData(bool includeInspectData = false);
void resetValueCache(); void resetValueCache();
@@ -119,6 +121,7 @@ public:
void notifyUpdateFinished(); void notifyUpdateFinished();
void reexpandItems(); void reexpandItems();
void recordTypeInfo(const GdbMi &typeInfo);
private: private:
WatchModel *m_model; // Owned. WatchModel *m_model; // Owned.