Debugger: Fix dumpers in case alphabetical sorting is off.

No longer change iname to obtain sorting.

Reviewed-by: hjk
This commit is contained in:
Friedemann Kleint
2010-10-08 14:55:57 +02:00
parent 561cad378e
commit edeccf7307
10 changed files with 74 additions and 56 deletions

View File

@@ -187,15 +187,15 @@ static inline void fixDumperResult(const WatchData &source,
// If the model queries the expanding item by pretending childrenNeeded=1, // If the model queries the expanding item by pretending childrenNeeded=1,
// refuse the request as the children are already known // refuse the request as the children are already known
returned.source |= CdbSymbolGroupContext::ChildrenKnownBit; returned.source |= CdbSymbolGroupContext::ChildrenKnownBit;
// Fix the children: If the address is missing, we cannot query any further. // Fix the children: Assign sort id , if the address is missing, we cannot query any further.
const QList<WatchData>::iterator wend = result->end(); const int resultSize = result->size();
QList<WatchData>::iterator it = result->begin(); for (int i = 1; i < resultSize; i++) {
for (++it; it != wend; ++it) { WatchData &wd = (*result)[i];
WatchData &wd = *it; wd.sortId = i;
// Indicate owner and known children // Indicate owner and known children
it->source = OwnerDumper; wd.source = OwnerDumper;
if (it->isChildrenKnown() && it->isHasChildrenKnown() && it->hasChildren) if (wd.isChildrenKnown() && wd.isHasChildrenKnown() && wd.hasChildren)
it->source |= CdbSymbolGroupContext::ChildrenKnownBit; wd.source |= CdbSymbolGroupContext::ChildrenKnownBit;
// Cannot dump items with missing addresses or missing types // Cannot dump items with missing addresses or missing types
const bool typeFixed = fixDumperType(&wd); // Order of evaluation! const bool typeFixed = fixDumperType(&wd); // Order of evaluation!
if ((wd.address == 0 && wd.isSomethingNeeded()) || typeFixed) { if ((wd.address == 0 && wd.isSomethingNeeded()) || typeFixed) {

View File

@@ -52,6 +52,7 @@ bool CdbSymbolGroupContext::getDumpChildSymbols(const QString &prefix,
// children, so, re-evaluate size in end condition. // children, so, re-evaluate size in end condition.
// Note the that the internal dumpers might expand children, // Note the that the internal dumpers might expand children,
// so the size might change. // so the size might change.
int sortId = 0;
for (int s = start; s < size(); ++s) { for (int s = start; s < size(); ++s) {
const DEBUG_SYMBOL_PARAMETERS &p = symbolParameterAt(s); const DEBUG_SYMBOL_PARAMETERS &p = symbolParameterAt(s);
if (p.ParentSymbol == parentId && isSymbolDisplayable(p)) { if (p.ParentSymbol == parentId && isSymbolDisplayable(p)) {
@@ -59,6 +60,7 @@ bool CdbSymbolGroupContext::getDumpChildSymbols(const QString &prefix,
const unsigned rc = watchDataAt(s, &wd); const unsigned rc = watchDataAt(s, &wd);
if (rc & InternalDumperMask) if (rc & InternalDumperMask)
wd.source = dumpedOwner; wd.source = dumpedOwner;
wd.sortId = sortId++;
*it = wd; *it = wd;
++it; ++it;
} }

View File

@@ -425,10 +425,7 @@ void GdbEngine::handleDebuggingHelperValue2Classic(const GdbResponse &response)
setWatchDataType(data, response.data.findChild("type")); setWatchDataType(data, response.data.findChild("type"));
setWatchDataDisplayedType(data, response.data.findChild("displaytype")); setWatchDataDisplayedType(data, response.data.findChild("displaytype"));
QList<WatchData> list; QList<WatchData> list;
parseWatchData(watchHandler()->expandedINames(), parseWatchData(watchHandler()->expandedINames(), data, contents, &list);
data, contents,
theDebuggerBoolSetting(SortStructMembers),
&list);
//for (int i = 0; i != list.size(); ++i) //for (int i = 0; i != list.size(); ++i)
// qDebug() << "READ: " << list.at(i).toString(); // qDebug() << "READ: " << list.at(i).toString();
watchHandler()->insertBulkData(list); watchHandler()->insertBulkData(list);

View File

@@ -133,14 +133,12 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
GdbMi data = all.findChild("data"); GdbMi data = all.findChild("data");
QList<WatchData> list; QList<WatchData> list;
const bool sortMembers = theDebuggerBoolSetting(SortStructMembers);
foreach (const GdbMi &child, data.children()) { foreach (const GdbMi &child, data.children()) {
WatchData dummy; WatchData dummy;
dummy.iname = child.findChild("iname").data(); dummy.iname = child.findChild("iname").data();
dummy.name = _(child.findChild("name").data()); dummy.name = _(child.findChild("name").data());
//qDebug() << "CHILD: " << child.toString(); //qDebug() << "CHILD: " << child.toString();
parseWatchData(watchHandler()->expandedINames(), dummy, child, parseWatchData(watchHandler()->expandedINames(), dummy, child, &list);
sortMembers, &list);
} }
watchHandler()->insertBulkData(list); watchHandler()->insertBulkData(list);
//for (int i = 0; i != list.size(); ++i) //for (int i = 0; i != list.size(); ++i)

View File

@@ -826,13 +826,12 @@ void PdbEngine::handleListLocals(const PdbResponse &response)
//GdbMi data = all.findChild("data"); //GdbMi data = all.findChild("data");
QList<WatchData> list; QList<WatchData> list;
WatchHandler *handler = watchHandler(); WatchHandler *handler = watchHandler();
bool sortMembers = theDebuggerBoolSetting(SortStructMembers);
foreach (const GdbMi &child, all.children()) { foreach (const GdbMi &child, all.children()) {
WatchData dummy; WatchData dummy;
dummy.iname = child.findChild("iname").data(); dummy.iname = child.findChild("iname").data();
dummy.name = _(child.findChild("name").data()); dummy.name = _(child.findChild("name").data());
//qDebug() << "CHILD: " << child.toString(); //qDebug() << "CHILD: " << child.toString();
parseWatchData(handler->expandedINames(), dummy, child, sortMembers, &list); parseWatchData(handler->expandedINames(), dummy, child, &list);
} }
handler->insertBulkData(list); handler->insertBulkData(list);
} }

View File

@@ -28,7 +28,8 @@ WatchData::WatchData() :
source(0), source(0),
objectId(0), objectId(0),
state(InitialState), state(InitialState),
changed(false) changed(false),
sortId(0)
{ {
} }
@@ -172,6 +173,7 @@ QString WatchData::toString() const
str << QLatin1Char('{'); str << QLatin1Char('{');
if (!iname.isEmpty()) if (!iname.isEmpty())
str << "iname=\"" << iname << doubleQuoteComma; str << "iname=\"" << iname << doubleQuoteComma;
str << "sortId=\"" << sortId << doubleQuoteComma;
if (!name.isEmpty() && name != iname) if (!name.isEmpty() && name != iname)
str << "name=\"" << name << doubleQuoteComma; str << "name=\"" << name << doubleQuoteComma;
if (error) if (error)

View File

@@ -136,6 +136,7 @@ public:
quint64 objectId; // Object id used for the QMLEngine quint64 objectId; // Object id used for the QMLEngine
int state; int state;
bool changed; bool changed;
int sortId;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -960,40 +960,62 @@ QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int ro
return QVariant(); return QVariant();
} }
struct IName : public QByteArray // Determine sort order of watch items by sort order or alphabetical inames
// according to setting 'SortStructMembers'. We need a map key for bulkInsert
// and a predicate for finding the insertion position of a single item.
// Set this before using any of the below according to action
static bool sortWatchDataAlphabetically = true;
static bool watchDataLessThan(const QByteArray &iname1, int sortId1, const QByteArray &iname2, int sortId2)
{ {
IName(const QByteArray &iname) : QByteArray(iname) {} if (!sortWatchDataAlphabetically)
return sortId1 < sortId2;
// Get positions of last part of iname 'local.this.i1" -> "i1"
int cmpPos1 = iname1.lastIndexOf('.');
if (cmpPos1 == -1) {
cmpPos1 = 0;
} else {
cmpPos1++;
}
int cmpPos2 = iname2.lastIndexOf('.');
if (cmpPos2 == -1) {
cmpPos2 = 0;
} else {
cmpPos2++;
}
// Are we looking at an array with numerical inames 'local.this.i1.0" ->
// Go by sort id.
if (cmpPos1 < iname1.size() && cmpPos2 < iname2.size()
&& isdigit(iname1.at(cmpPos1)) && isdigit(iname2.at(cmpPos2)))
return sortId1 < sortId2;
// Alphabetically
return qstrcmp(iname1.constData() + cmpPos1, iname2.constData() + cmpPos2) < 0;
}
// Sort key for watch data consisting of iname and numerical sort id.
struct WatchDataSortKey {
explicit WatchDataSortKey(const WatchData &wd) :
iname(wd.iname), sortId(wd.sortId) {}
QByteArray iname;
int sortId;
}; };
bool iNameLess(const QString &iname1, const QString &iname2) inline bool operator<(const WatchDataSortKey &k1, const WatchDataSortKey &k2)
{ {
QString name1 = iname1.section('.', -1); return watchDataLessThan(k1.iname, k1.sortId, k2.iname, k2.sortId);
QString name2 = iname2.section('.', -1);
if (!name1.isEmpty() && !name2.isEmpty()) {
if (name1.at(0).isDigit() && name2.at(0).isDigit()) {
bool ok1 = false, ok2 = false;
int i1 = name1.toInt(&ok1), i2 = name2.toInt(&ok2);
if (ok1 && ok2)
return i1 < i2;
}
}
return name1 < name2;
} }
bool operator<(const IName &iname1, const IName &iname2) bool watchItemSorter(const WatchItem *item1, const WatchItem *item2)
{ {
return iNameLess(iname1, iname2); return watchDataLessThan(item1->iname, item1->sortId, item2->iname, item2->sortId);
}
static bool iNameSorter(const WatchItem *item1, const WatchItem *item2)
{
return iNameLess(item1->iname, item2->iname);
} }
static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *item) static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *item)
{ {
QList<WatchItem *>::const_iterator it = sortWatchDataAlphabetically = theDebuggerBoolSetting(SortStructMembers);
qLowerBound(list.begin(), list.end(), item, iNameSorter); const QList<WatchItem *>::const_iterator it =
qLowerBound(list.begin(), list.end(), item, watchItemSorter);
return it - list.begin(); return it - list.begin();
} }
@@ -1045,7 +1067,7 @@ void WatchModel::insertData(const WatchData &data)
item->parent = parent; item->parent = parent;
item->generation = generationCounter; item->generation = generationCounter;
item->changed = true; item->changed = true;
int n = findInsertPosition(parent->children, item); const int n = findInsertPosition(parent->children, item);
beginInsertRows(index, n, n); beginInsertRows(index, n, n);
parent->children.insert(n, item); parent->children.insert(n, item);
endInsertRows(); endInsertRows();
@@ -1078,10 +1100,11 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
} }
QModelIndex index = watchIndex(parent); QModelIndex index = watchIndex(parent);
QMap<IName, WatchData> newList; sortWatchDataAlphabetically = theDebuggerBoolSetting(SortStructMembers);
typedef QMap<IName, WatchData>::iterator Iterator; QMap<WatchDataSortKey, WatchData> newList;
typedef QMap<WatchDataSortKey, WatchData>::iterator Iterator;
foreach (const WatchItem &data, list) foreach (const WatchItem &data, list)
newList[data.iname] = data; newList.insert(WatchDataSortKey(data), data);
if (newList.size() != list.size()) { if (newList.size() != list.size()) {
qDebug() << "LIST: "; qDebug() << "LIST: ";
foreach (const WatchItem &data, list) foreach (const WatchItem &data, list)
@@ -1100,11 +1123,12 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
QTC_ASSERT(newList.size() == list.size(), return); QTC_ASSERT(newList.size() == list.size(), return);
foreach (WatchItem *oldItem, parent->children) { foreach (WatchItem *oldItem, parent->children) {
Iterator it = newList.find(oldItem->iname); const WatchDataSortKey oldSortKey(*oldItem);
Iterator it = newList.find(oldSortKey);
if (it == newList.end()) { if (it == newList.end()) {
WatchData data = *oldItem; WatchData data = *oldItem;
data.generation = generationCounter; data.generation = generationCounter;
newList[oldItem->iname] = data; newList.insert(oldSortKey, data);
} else { } else {
bool changed = !it->value.isEmpty() bool changed = !it->value.isEmpty()
&& it->value != oldItem->value && it->value != oldItem->value

View File

@@ -1666,7 +1666,7 @@ void setWatchDataDisplayedType(WatchData &data, const GdbMi &item)
void parseWatchData(const QSet<QByteArray> &expandedINames, void parseWatchData(const QSet<QByteArray> &expandedINames,
const WatchData &data0, const GdbMi &item, const WatchData &data0, const GdbMi &item,
bool sortMembers, QList<WatchData> *list) QList<WatchData> *list)
{ {
//qDebug() << "HANDLE CHILDREN: " << data0.toString() << item.toString(); //qDebug() << "HANDLE CHILDREN: " << data0.toString() << item.toString();
WatchData data = data0; WatchData data = data0;
@@ -1711,6 +1711,7 @@ void parseWatchData(const QSet<QByteArray> &expandedINames,
int i = 0; int i = 0;
foreach (const GdbMi &child, children.children()) { foreach (const GdbMi &child, children.children()) {
WatchData data1 = childtemplate; WatchData data1 = childtemplate;
data1.sortId = i++;
GdbMi name = child.findChild("name"); GdbMi name = child.findChild("name");
if (name.isValid()) if (name.isValid())
data1.name = _(name.data()); data1.name = _(name.data());
@@ -1722,11 +1723,6 @@ void parseWatchData(const QSet<QByteArray> &expandedINames,
} else { } else {
data1.iname = data.iname; data1.iname = data.iname;
data1.iname += '.'; data1.iname += '.';
if (!sortMembers) {
char buf[10];
qsnprintf(buf, sizeof(buf) - 1, "%04d", i);
data1.iname += buf;
}
data1.iname += data1.name.toLatin1(); data1.iname += data1.name.toLatin1();
} }
if (!data1.name.isEmpty() && data1.name.at(0).isDigit()) if (!data1.name.isEmpty() && data1.name.at(0).isDigit())
@@ -1747,8 +1743,7 @@ void parseWatchData(const QSet<QByteArray> &expandedINames,
//data1.name += " (" + skey + ")"; //data1.name += " (" + skey + ")";
data1.name = skey; data1.name = skey;
} }
parseWatchData(expandedINames, data1, child, sortMembers, list); parseWatchData(expandedINames, data1, child, list);
++i;
} }
} }

View File

@@ -257,7 +257,7 @@ void setWatchDataType(WatchData &data, const GdbMi &mi);
void setWatchDataDisplayedType(WatchData &data, const GdbMi &mi); void setWatchDataDisplayedType(WatchData &data, const GdbMi &mi);
void parseWatchData(const QSet<QByteArray> &expandedINames, void parseWatchData(const QSet<QByteArray> &expandedINames,
const WatchData &parent, const GdbMi &child, bool sortMembers, const WatchData &parent, const GdbMi &child,
QList<WatchData> *insertions); QList<WatchData> *insertions);
} // namespace Internal } // namespace Internal