From 8d54b23311d8233bc7710ab7a6d35818a96ab104 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@nokia.com> Date: Wed, 1 Apr 2009 08:55:57 +0200 Subject: [PATCH] Continue on CDB watchmodel. --- .../debugger/cdb/cdbsymbolgroupcontext.cpp | 244 ++++++++++++++---- .../debugger/cdb/cdbsymbolgroupcontext.h | 13 +- src/plugins/debugger/watchhandler.cpp | 26 +- 3 files changed, 213 insertions(+), 70 deletions(-) diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp index 2bedaa875fa..2cb51e9f4d7 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -33,6 +33,10 @@ #include "watchutils.h" #include <QtCore/QTextStream> +enum { maxRecursionDepth = 10 }; + +static inline bool isTopLevelSymbol(const DEBUG_SYMBOL_PARAMETERS &p) { return p.ParentSymbol == DEBUG_ANY_ID; } + static inline void debugSymbolFlags(unsigned long f, QTextStream &str) { if (f & DEBUG_SYMBOL_EXPANDED) @@ -52,7 +56,7 @@ static inline void debugSymbolFlags(unsigned long f, QTextStream &str) QTextStream &operator<<(QTextStream &str, const DEBUG_SYMBOL_PARAMETERS& p) { str << " Type=" << p.TypeId << " parent="; - if (p.ParentSymbol == DEBUG_ANY_ID) { + if (isTopLevelSymbol(p)) { str << "<ROOT>"; } else { str << p.ParentSymbol; @@ -86,6 +90,15 @@ static inline QString getSymbolString(IDebugSymbolGroup2 *sg, namespace Debugger { namespace Internal { +static inline CdbSymbolGroupContext::SymbolState getSymbolState(const DEBUG_SYMBOL_PARAMETERS &p) +{ + if (p.SubElements == 0u) + return CdbSymbolGroupContext::LeafSymbol; + return (p.Flags & DEBUG_SYMBOL_EXPANDED) ? + CdbSymbolGroupContext::ExpandedSymbol : + CdbSymbolGroupContext::CollapsedSymbol; +} + CdbSymbolGroupContext::CdbSymbolGroupContext(const QString &prefix, IDebugSymbolGroup2 *symbolGroup) : m_prefix(prefix), @@ -129,18 +142,32 @@ bool CdbSymbolGroupContext::init(QString *errorMessage) *errorMessage = msgComFailed("GetSymbolParameters", hr); return false; } - populateINameIndexMap(m_prefix, 0, count); + populateINameIndexMap(m_prefix, DEBUG_ANY_ID, 0, count); + if (debugCDB) + qDebug() << Q_FUNC_INFO << '\n'<< toString(); return true; } -void CdbSymbolGroupContext::populateINameIndexMap(const QString &prefix, unsigned long start, unsigned long count) +void CdbSymbolGroupContext::populateINameIndexMap(const QString &prefix, unsigned long parentId, + unsigned long start, unsigned long count) { + // Make the entries for iname->index mapping. We might encounter + // already expanded subitems when doing it for top-level, recurse in that case. const QString symbolPrefix = prefix + m_nameDelimiter; - const unsigned long end = start + count; - for (unsigned long i = start; i < end; i++) - if (isSymbolDisplayable(m_symbolParameters.at(i))) { - const QString name = symbolPrefix + getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i); - m_inameIndexMap.insert(name, i); + if (debugCDB) + qDebug() << Q_FUNC_INFO << '\n'<< symbolPrefix << start << count; + const unsigned long end = m_symbolParameters.size(); + unsigned long seenChildren = 0; + // Skip over expanded children + for (unsigned long i = start; i < end && seenChildren < count; i++) { + const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(i); + if (parentId == p.ParentSymbol) { + seenChildren++; + const QString name = symbolPrefix + getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i); + m_inameIndexMap.insert(name, i); + if (getSymbolState(p) == ExpandedSymbol) + populateINameIndexMap(name, i, i + 1, p.SubElements); + } } } @@ -152,26 +179,44 @@ QString CdbSymbolGroupContext::toString() const for (int i = 0; i < count; i++) { str << i << ' '; const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(i); - if (p.ParentSymbol != DEBUG_ANY_ID) + if (!isTopLevelSymbol(p)) str << " "; str << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i); if (p.Flags & DEBUG_SYMBOL_IS_LOCAL) str << " '" << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, i); str << p << '\n'; } + str << "NameIndexMap\n"; + NameIndexMap::const_iterator ncend = m_inameIndexMap.constEnd(); + for (NameIndexMap::const_iterator it = m_inameIndexMap.constBegin() ; it != ncend; ++it) + str << it.key() << ' ' << it.value() << '\n'; return rc; } bool CdbSymbolGroupContext::isSymbolDisplayable(const DEBUG_SYMBOL_PARAMETERS &p) { - return p.Flags & (DEBUG_SYMBOL_IS_LOCAL|DEBUG_SYMBOL_IS_ARGUMENT); + if (p.Flags & (DEBUG_SYMBOL_IS_LOCAL|DEBUG_SYMBOL_IS_ARGUMENT)) + return true; + // Do not display static members. + if (p.Flags & DEBUG_SYMBOL_READ_ONLY) + return false; + return true; } -static inline bool isSymbolExpanded(const DEBUG_SYMBOL_PARAMETERS &p) { return p.Flags & DEBUG_SYMBOL_EXPANDED; } +CdbSymbolGroupContext::SymbolState CdbSymbolGroupContext::symbolState(unsigned long index) const +{ + return getSymbolState(m_symbolParameters.at(index)); +} -bool CdbSymbolGroupContext::isExpanded(unsigned long index) const +CdbSymbolGroupContext::SymbolState CdbSymbolGroupContext::symbolState(const QString &prefix) const { - return isSymbolExpanded(m_symbolParameters.at(index)); + if (prefix == m_prefix) // root + return ExpandedSymbol; + const NameIndexMap::const_iterator it = m_inameIndexMap.constFind(prefix); + if (it != m_inameIndexMap.constEnd()) + return symbolState(it.value()); + qWarning("WARNING %s: %s not found.\n", Q_FUNC_INFO, qPrintable(prefix)); + return LeafSymbol; } /* Retrieve children and get the position. */ @@ -189,7 +234,7 @@ bool CdbSymbolGroupContext::getChildSymbolsPosition(const QString &prefix, *start = 0; *parentId = DEBUG_ANY_ID; if (debugCDB) - qDebug() << '<' << prefix << "at" << *start << '\n' << toString(); + qDebug() << '<' << prefix << "at" << *start; return true; } // Get parent index, make sure it is expanded @@ -203,7 +248,7 @@ bool CdbSymbolGroupContext::getChildSymbolsPosition(const QString &prefix, if (!expandSymbol(prefix, *parentId, errorMessage)) return false; if (debugCDB) - qDebug() << '<' << prefix << "at" << *start << '\n' << toString(); + qDebug() << '<' << prefix << "at" << *start; return true; } @@ -211,10 +256,17 @@ bool CdbSymbolGroupContext::getChildSymbolsPosition(const QString &prefix, bool CdbSymbolGroupContext::expandSymbol(const QString &prefix, unsigned long index, QString *errorMessage) { if (debugCDB) - qDebug() << Q_FUNC_INFO << '\n' << prefix << index; + qDebug() << '>' << Q_FUNC_INFO << '\n' << prefix << index; - if (isExpanded(index)) + switch (symbolState(index)) { + case LeafSymbol: + *errorMessage = QString::fromLatin1("Attempt to expand leaf node '%1' %2!").arg(prefix).arg(index); + return false; + case ExpandedSymbol: return true; + case CollapsedSymbol: + break; + } HRESULT hr = m_symbolGroup->ExpandSymbol(index, TRUE); if (FAILED(hr)) { @@ -248,7 +300,9 @@ bool CdbSymbolGroupContext::expandSymbol(const QString &prefix, unsigned long in if (it.value() > index) it.value() += newSymbolCount; // insert the new symbols - populateINameIndexMap(prefix, index + 1, newSymbolCount); + populateINameIndexMap(prefix, index, index + 1, newSymbolCount); + if (debugCDB) + qDebug() << '<' << Q_FUNC_INFO << '\n' << prefix << index << '\n' << toString(); return true; } @@ -258,6 +312,23 @@ void CdbSymbolGroupContext::clear() m_inameIndexMap.clear(); } +// Expand all top level symbols +bool CdbSymbolGroupContext::expandTopLevel(QString *errorMessage) +{ + if (debugCDB) + qDebug() << '>' << Q_FUNC_INFO; + + for (int i = m_symbolParameters.size() - 1; i >= 0; i --) { + const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(i); + if (isTopLevelSymbol(p) && (getSymbolState(p) == CollapsedSymbol) && isSymbolDisplayable(p)) + if (!expandSymbol(symbolINameAt(i), i, errorMessage)) + return false; + } + if (debugCDB) + qDebug() << '<' << Q_FUNC_INFO << '\n' << toString(); + return true; +} + int CdbSymbolGroupContext::getDisplayableChildCount(unsigned long index) const { if (!isExpanded(index)) @@ -277,13 +348,15 @@ int CdbSymbolGroupContext::getDisplayableChildCount(unsigned long index) const return rc; } -WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const +QString CdbSymbolGroupContext::symbolINameAt(unsigned long index) const { - if (debugCDB) - qDebug() << Q_FUNC_INFO << index; + return m_inameIndexMap.key(index); +} +WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const +{ WatchData wd; - wd.iname = m_inameIndexMap.key(index); + wd.iname = symbolINameAt(index); const int lastDelimiterPos = wd.iname.lastIndexOf(m_nameDelimiter); wd.name = lastDelimiterPos == -1 ? wd.iname : wd.iname.mid(lastDelimiterPos + 1); wd.setType(getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, index)); @@ -292,16 +365,17 @@ WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const wd.setChildCountNeeded(); // Figure out children. The SubElement is only a guess unless the symbol, // is expanded, so, we leave this as a guess for later updates. + // If the symbol has children (expanded or not), we leave the 'Children' flag + // in 'needed' state. const DEBUG_SYMBOL_PARAMETERS ¶ms = m_symbolParameters.at(index); if (params.SubElements) { - if (isSymbolExpanded(params)) + if (getSymbolState(params) == ExpandedSymbol) wd.setChildCount(getDisplayableChildCount(index)); - wd.setChildrenUnneeded(); } else { wd.setChildCount(0); } - if (debugCDB) - qDebug() << Q_FUNC_INFO << '\n' << wd.toString(); + if (debugCDB > 1) + qDebug() << Q_FUNC_INFO << index << '\n' << wd.toString(); return wd; } @@ -323,47 +397,89 @@ private: static bool insertChildrenRecursion(const QString &iname, CdbSymbolGroupContext *sg, WatchHandler *watchHandler, + int visibleLevel, int level, QString *errorMessage, int *childCount = 0); // Insert a symbol and its children recursively if // they are known. -static bool insertSymbolRecursion(const WatchData wd, +static bool insertSymbolRecursion(WatchData wd, CdbSymbolGroupContext *sg, WatchHandler *watchHandler, + int visibleLevel, int level, - QString *errorMessage - ) -{ - if (debugCDB) - qDebug() << Q_FUNC_INFO << '\n' << wd.iname << level; + QString *errorMessage) +{ + if (level > maxRecursionDepth) { + *errorMessage = QString::fromLatin1("Max recursion level %1 reached for '%2', bailing out.").arg(level).arg(wd.iname); + return false; + } + // Find out whether to recurse (either children are already + // available in the context or the parent item is visible + // in the view (which means its children must be complete) + // or the view item is expanded). + bool recurse = false; + if (wd.childCount || wd.isChildrenNeeded()) { + const bool contextExpanded = sg->isExpanded(wd.iname); + const bool viewExpanded = watchHandler->isExpandedIName(wd.iname); + if (viewExpanded) + visibleLevel = level; + recurse = contextExpanded || (level - visibleLevel < 2); + } + if (debugCDB) + qDebug() << Q_FUNC_INFO << '\n' << wd.iname << "level=" << level << "visibleLevel=" << visibleLevel << "recurse=" << recurse; + bool rc = true; + if (recurse) { // Determine number of children and indicate in model + int childCount; + rc = insertChildrenRecursion(wd.iname, sg, watchHandler, visibleLevel, level, errorMessage, &childCount); + if (rc) { + wd.setChildCount(childCount); + wd.setChildrenUnneeded(); + } + } + if (debugCDB) + qDebug() << " INSERTING: at " << level << wd.toString(); watchHandler->insertData(wd); - if (wd.childCount && wd.isChildCountKnown()) - return insertChildrenRecursion(wd.iname, sg, watchHandler, level + 1, errorMessage); - return true; + return rc; } // Insert the children of prefix. static bool insertChildrenRecursion(const QString &iname, CdbSymbolGroupContext *sg, WatchHandler *watchHandler, + int visibleLevel, int level, QString *errorMessage, - int *childCount) + int *childCountPtr) { - if (debugCDB) + if (debugCDB > 1) qDebug() << Q_FUNC_INFO << '\n' << iname << level; QList<WatchData> watchList; + // Implicitly enforces expansion if (!sg->getChildSymbols(iname, WatchDataBackInserter(watchList), errorMessage)) return false; - if (childCount) - *childCount = watchList.size(); - foreach(const WatchData &wd, watchList) - if (!insertSymbolRecursion(wd, sg, watchHandler, level + 1, errorMessage)) - return false; + + const int childCount = watchList.size(); + if (childCountPtr) + *childCountPtr = childCount; + int succeededChildCount = 0; + for (int c = 0; c < childCount; c++) { + const WatchData &wd = watchList.at(c); + if (wd.isValid()) { // We sometimes get empty names for deeply nested data + if (!insertSymbolRecursion(wd, sg, watchHandler, visibleLevel, level + 1, errorMessage)) + return false; + succeededChildCount++; + } else { + const QString msg = QString::fromLatin1("WARNING: Skipping invalid child symbol #%2 (type %3) of '%4'."). + arg(QLatin1String(Q_FUNC_INFO)).arg(c).arg(wd.type, iname); + qWarning("%s\n", qPrintable(msg)); + } + } + if (childCountPtr) + *childCountPtr = succeededChildCount; return true; } @@ -372,7 +488,10 @@ bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg, QString *errorMessage) { if (debugCDB) - qDebug() << Q_FUNC_INFO; + qDebug() << "###" << Q_FUNC_INFO; + + if (!sg->expandTopLevel(errorMessage)) + return false; // Insert root items and known children. QList<WatchData> watchList; @@ -380,33 +499,44 @@ bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg, return false; foreach(const WatchData &wd, watchList) - if (!insertSymbolRecursion(wd, sg, watchHandler, 0, errorMessage)) + if (!insertSymbolRecursion(wd, sg, watchHandler, 0, 0, errorMessage)) return false; return true; } +static inline QString parentIName(QString iname) +{ + const int lastDotPos = iname.lastIndexOf(QLatin1Char('.')); + if (lastDotPos == -1) { + iname.clear(); + } else { + iname.truncate(lastDotPos); + } + return iname; +} + bool CdbSymbolGroupContext::completeModel(CdbSymbolGroupContext *sg, WatchHandler *watchHandler, QString *errorMessage) { const QList<WatchData> incomplete = watchHandler->takeCurrentIncompletes(); - if (debugCDB) { - QDebug nsp = qDebug().nospace(); - nsp << Q_FUNC_INFO << '\n' << incomplete.size(); - foreach(const WatchData& wd, incomplete) - nsp << ' ' << wd.iname; - nsp << '\n'; - } + if (debugCDB) + qDebug().nospace() << "###>" << Q_FUNC_INFO << ' ' << incomplete.size() << '\n'; // At this point, it should be nodes with unknown children. - int childCount; + // Complete and re-insert provided their grand parent is expanded + // (rule being that children are displayed only if they are complete, that is, + // their children are known). foreach(WatchData wd, incomplete) { - if (insertChildrenRecursion(wd.iname, sg, watchHandler, 0, errorMessage, &childCount)) { - wd.setChildCount(childCount); - watchHandler->insertData(wd); - } else { - return false; + const bool grandParentExpanded = watchHandler->isExpandedIName(parentIName(parentIName(wd.iname))); + if (debugCDB) + qDebug() << " " << wd.iname << "grandParentExpanded=" << grandParentExpanded; + if (grandParentExpanded) { + if (!insertSymbolRecursion(wd, sg, watchHandler, 0, 1, errorMessage)) + return false; } } + if (debugCDB) + qDebug() << "###<" << Q_FUNC_INFO; return true; } diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h index 8a3cf4dc80e..f7fba92f605 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h @@ -77,6 +77,15 @@ public: template <class OutputIterator> bool getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage); + bool expandTopLevel(QString *errorMessage); + + enum SymbolState { LeafSymbol, ExpandedSymbol, CollapsedSymbol }; + SymbolState symbolState(unsigned long index) const; + SymbolState symbolState(const QString &prefix) const; + + inline bool isExpanded(unsigned long index) const { return symbolState(index) == ExpandedSymbol; } + inline bool isExpanded(const QString &prefix) const { return symbolState(prefix) == ExpandedSymbol; } + private: typedef QMap<QString, unsigned long> NameIndexMap; @@ -90,9 +99,9 @@ private: unsigned long *parentId, QString *errorMessage); bool expandSymbol(const QString &prefix, unsigned long index, QString *errorMessage); - void populateINameIndexMap(const QString &prefix, unsigned long start, unsigned long count); + void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long start, unsigned long count); WatchData symbolAt(unsigned long index) const; - bool isExpanded(unsigned long index) const; + QString symbolINameAt(unsigned long index) const; int getDisplayableChildCount(unsigned long index) const; inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); } diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 88349072e46..e9a651e622f 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -195,18 +195,22 @@ QString WatchData::toString() const const char *doubleQuoteComma = "\","; QString res; QTextStream str(&res); - str <<"{state=\"0x" << QString::number(state, 16) << doubleQuoteComma - << "level=\"" << level << doubleQuoteComma - << "parent=\"" << parentIndex << doubleQuoteComma - << "row=\"" << row << doubleQuoteComma - << "child=\""; - const int childCount = childIndex.size(); - for (int i = 0; i < childCount; i++) { - if (i) - str << ','; - str << childIndex.at(i); + str <<"{state=\"0x" << QString::number(state, 16) << doubleQuoteComma; + if (level != -1) + str << "level=\"" << level << doubleQuoteComma; + if (parentIndex != -1) + str << "parent=\"" << parentIndex << doubleQuoteComma; + if (row != -1) + str << "row=\"" << row << doubleQuoteComma; + if (const int childCount = childIndex.size()) { + str << "child=\""; + for (int i = 0; i < childCount; i++) { + if (i) + str << ','; + str << childIndex.at(i); + } + str << doubleQuoteComma; } - str << doubleQuoteComma; if (!iname.isEmpty()) str << "iname=\"" << iname << doubleQuoteComma; -- GitLab