diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index 7d054e68dd430d24dd42de3d94ad47ad38d3c04b..b8db4f753bae551d72657cdeb92c07dadb29b70c 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -145,6 +145,7 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEn m_debuggerManager(parent), m_debuggerManagerAccess(parent->engineInterface()), m_currentStackTrace(0), + m_firstActivatedFrame(true), m_mode(AttachCore) { } @@ -428,22 +429,15 @@ void CdbDebugEngine::exitDebugger() killWatchTimer(); } -class ModelBuildIterator { -public: - explicit ModelBuildIterator(WatchHandler *wh) : m_wh(wh) {} - - ModelBuildIterator & operator*() { return *this; } - ModelBuildIterator &operator=(const WatchData &wd); - ModelBuildIterator &operator++() { return *this; } - -private: - WatchHandler *m_wh; -}; - -ModelBuildIterator &ModelBuildIterator::operator=(const WatchData &wd) +CdbSymbolGroupContext *CdbDebugEnginePrivate::getStackFrameSymbolGroupContext(int frameIndex, QString *errorMessage) const { - m_wh->insertData(wd); - return *this; + if (!m_currentStackTrace) { + *errorMessage = QLatin1String(msgNoStackTraceC); + return 0; + } + if (CdbSymbolGroupContext *sg = m_currentStackTrace->symbolGroupContextAt(frameIndex, errorMessage)) + return sg; + return 0; } bool CdbDebugEnginePrivate::updateLocals(int frameIndex, @@ -452,36 +446,29 @@ bool CdbDebugEnginePrivate::updateLocals(int frameIndex, { if (debugCDB) qDebug() << Q_FUNC_INFO << frameIndex; - bool success = false; wh->cleanup(); - do { - if (!m_currentStackTrace) { - *errorMessage = QLatin1String(msgNoStackTraceC); - break; - } - CdbSymbolGroupContext *sgc = m_currentStackTrace->symbolGroupContextAt(frameIndex, errorMessage); - if (!sgc) { - break; - } - ModelBuildIterator it(wh); - sgc->getSymbols(sgc->prefix(), it); - success = true; - } while (false); - wh->rebuildModel(); + bool success = false; + if (CdbSymbolGroupContext *sgc = getStackFrameSymbolGroupContext(frameIndex, errorMessage)) + success = CdbSymbolGroupContext::populateModelInitially(sgc, wh, errorMessage); + wh->rebuildModel(); return success; } void CdbDebugEngine::updateWatchModel() { - WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler(); - const QList<WatchData> incomplete = watchHandler->takeCurrentIncompletes(); - + const int frameIndex = m_d->m_debuggerManagerAccess->stackHandler()->currentIndex(); if (debugCDB) - qDebug() << Q_FUNC_INFO << incomplete.size(); - foreach (const WatchData& wd, incomplete) - qDebug() << Q_FUNC_INFO << wd.toString(); + qDebug() << Q_FUNC_INFO << "fi=" << frameIndex; + + bool success = false; + QString errorMessage; + if (CdbSymbolGroupContext *sg = m_d->m_currentStackTrace->symbolGroupContextAt(frameIndex, &errorMessage)) + success = CdbSymbolGroupContext::completeModel(sg, m_d->m_debuggerManagerAccess->watchHandler(), &errorMessage); + + if (!success) + qWarning("%s : %s", Q_FUNC_INFO, qPrintable(errorMessage)); } void CdbDebugEngine::stepExec() @@ -655,17 +642,18 @@ void CdbDebugEngine::activateFrame(int frameIndex) bool success = false; do { StackHandler *stackHandler = m_d->m_debuggerManagerAccess->stackHandler(); + WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler(); const int oldIndex = stackHandler->currentIndex(); if (frameIndex >= stackHandler->stackSize()) { errorMessage = msgStackIndexOutOfRange(frameIndex, stackHandler->stackSize()); break; } - if (oldIndex != frameIndex) { + if (oldIndex != frameIndex) stackHandler->setCurrentIndex(frameIndex); - if (!m_d->updateLocals(frameIndex, m_d->m_debuggerManagerAccess->watchHandler(), &errorMessage)) + if (oldIndex != frameIndex || m_d->m_firstActivatedFrame) + if (!m_d->updateLocals(frameIndex, watchHandler, &errorMessage)) break; - } const StackFrame &frame = stackHandler->currentFrame(); if (!frame.isUsable()) { @@ -678,6 +666,7 @@ void CdbDebugEngine::activateFrame(int frameIndex) } while (false); if (!success) qWarning("%s", qPrintable(errorMessage)); + m_d->m_firstActivatedFrame = false; } void CdbDebugEngine::selectThread(int index) @@ -917,6 +906,7 @@ void CdbDebugEnginePrivate::updateStackTrace() m_debuggerManager->gotoLocation(stackFrames.at(current).file, stackFrames.at(current).line, true); } + m_firstActivatedFrame = true; } void CdbDebugEnginePrivate::handleDebugOutput(const char *szOutputString) diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h index e1991f707deedc75d73b052014eb6653372aaf13..cd28883a713f63c29cf08ecf38522e64b8deb7ba 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine_p.h +++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h @@ -79,6 +79,7 @@ struct CdbDebugEnginePrivate void handleDebugOutput(const char* szOutputString); void handleBreakpointEvent(PDEBUG_BREAKPOINT pBP); void cleanStackTrace(); + CdbSymbolGroupContext *getStackFrameSymbolGroupContext(int frameIndex, QString *errorMessage) const; HANDLE m_hDebuggeeProcess; HANDLE m_hDebuggeeThread; @@ -98,6 +99,7 @@ struct CdbDebugEnginePrivate DebuggerManager *m_debuggerManager; IDebuggerManagerAccessForEngines *m_debuggerManagerAccess; CdbStackTraceContext *m_currentStackTrace; + bool m_firstActivatedFrame; DebuggerStartMode m_mode; Core::Utils::ConsoleProcess m_consoleStubProc; diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp index d569c6a9baefb6a6b93500c6d06a85b31611d293..f80766941db22f7f3812b6563d28c2a8241127a9 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp @@ -127,7 +127,9 @@ CdbSymbolGroupContext *CdbStackTraceContext::symbolGroupContextAt(int index, QSt IDebugSymbolGroup2 *sg = createSymbolGroup(index, errorMessage); if (!sg) return 0; - CdbSymbolGroupContext *sc = new CdbSymbolGroupContext(QLatin1String("local"), sg); + CdbSymbolGroupContext *sc = CdbSymbolGroupContext::create(QLatin1String("local"), sg, errorMessage); + if (!sc) + return 0; \ m_symbolContexts[index] = sc; return sc; } diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp index aa52ef55e1a304a4d95b832cbefcaf8b24de7702..2bedaa875fa4b87b43f28301e9f7544ad5e0079f 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -30,6 +30,37 @@ #include "cdbsymbolgroupcontext.h" #include "cdbdebugengine_p.h" #include "watchhandler.h" +#include "watchutils.h" +#include <QtCore/QTextStream> + +static inline void debugSymbolFlags(unsigned long f, QTextStream &str) +{ + if (f & DEBUG_SYMBOL_EXPANDED) + str << "DEBUG_SYMBOL_EXPANDED"; + if (f & DEBUG_SYMBOL_READ_ONLY) + str << "|DEBUG_SYMBOL_READ_ONLY"; + if (f & DEBUG_SYMBOL_IS_ARRAY) + str << "|DEBUG_SYMBOL_IS_ARRAY"; + if (f & DEBUG_SYMBOL_IS_FLOAT) + str << "|DEBUG_SYMBOL_IS_FLOAT"; + if (f & DEBUG_SYMBOL_IS_ARGUMENT) + str << "|DEBUG_SYMBOL_IS_ARGUMENT"; + if (f & DEBUG_SYMBOL_IS_LOCAL) + str << "|DEBUG_SYMBOL_IS_LOCAL"; +} + + QTextStream &operator<<(QTextStream &str, const DEBUG_SYMBOL_PARAMETERS& p) +{ + str << " Type=" << p.TypeId << " parent="; + if (p.ParentSymbol == DEBUG_ANY_ID) { + str << "<ROOT>"; + } else { + str << p.ParentSymbol; + } + str << " Subs=" << p.SubElements << " flags=" << p.Flags << '/'; + debugSymbolFlags(p.Flags, str); + return str; +} // A helper function to extract a string value from a member function of // IDebugSymbolGroup2 taking the symbol index and a character buffer. @@ -68,84 +99,182 @@ CdbSymbolGroupContext::~CdbSymbolGroupContext() m_symbolGroup->Release(); } -CdbSymbolGroupContext::Range - CdbSymbolGroupContext::getSymbolRange(const QString &prefix) +CdbSymbolGroupContext *CdbSymbolGroupContext::create(const QString &prefix, + IDebugSymbolGroup2 *symbolGroup, + QString *errorMessage) +{ + CdbSymbolGroupContext *rc= new CdbSymbolGroupContext(prefix, symbolGroup); + if (!rc->init(errorMessage)) { + delete rc; + return 0; + } + return rc; +} + +bool CdbSymbolGroupContext::init(QString *errorMessage) +{ + // retrieve the root symbols + ULONG count; + HRESULT hr = m_symbolGroup->GetNumberSymbols(&count); + if (FAILED(hr)) { + *errorMessage = msgComFailed("GetNumberSymbols", hr); + return false; + } + + m_symbolParameters.reserve(3u * count); + m_symbolParameters.resize(count); + + hr = m_symbolGroup->GetSymbolParameters(0, count, symbolParameters()); + if (FAILED(hr)) { + *errorMessage = msgComFailed("GetSymbolParameters", hr); + return false; + } + populateINameIndexMap(m_prefix, 0, count); + return true; +} + +void CdbSymbolGroupContext::populateINameIndexMap(const QString &prefix, unsigned long start, unsigned long count) +{ + 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); + } +} + +QString CdbSymbolGroupContext::toString() const +{ + QString rc; + QTextStream str(&rc); + const int count = m_symbolParameters.size(); + for (int i = 0; i < count; i++) { + str << i << ' '; + const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(i); + if (p.ParentSymbol != DEBUG_ANY_ID) + 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'; + } + return rc; +} + +bool CdbSymbolGroupContext::isSymbolDisplayable(const DEBUG_SYMBOL_PARAMETERS &p) +{ + return p.Flags & (DEBUG_SYMBOL_IS_LOCAL|DEBUG_SYMBOL_IS_ARGUMENT); +} + +static inline bool isSymbolExpanded(const DEBUG_SYMBOL_PARAMETERS &p) { return p.Flags & DEBUG_SYMBOL_EXPANDED; } + +bool CdbSymbolGroupContext::isExpanded(unsigned long index) const +{ + return isSymbolExpanded(m_symbolParameters.at(index)); +} + +/* Retrieve children and get the position. */ +bool CdbSymbolGroupContext::getChildSymbolsPosition(const QString &prefix, + unsigned long *start, + unsigned long *parentId, + QString *errorMessage) { if (debugCDB) - qDebug() << Q_FUNC_INFO << prefix; - const ChildRangeMap::const_iterator it = m_childRanges.constFind(prefix); - if (it != m_childRanges.constEnd()) - return it.value(); - const Range r = prefix == m_prefix ? allocateRootSymbols() : allocateChildSymbols(prefix); - m_childRanges.insert(prefix, r); - return r; -} - -CdbSymbolGroupContext::Range - CdbSymbolGroupContext::allocateChildSymbols(const QString &prefix) -{ - unsigned long startPos = 0; - unsigned long count = 0; - - bool success = false; - QString errorMessage; - do { - const int parentIndex = m_symbolINames.indexOf(prefix); - if (parentIndex == -1) { - errorMessage = QString::fromLatin1("Prefix not found '%1'").arg(prefix); - break; - } + qDebug() << Q_FUNC_INFO << '\n'<< prefix; - success = true; - } while (false); - if (!success) { - qWarning("%s\n", qPrintable(errorMessage)); + *start = *parentId = 0; + // Root item? + if (prefix == m_prefix) { + *start = 0; + *parentId = DEBUG_ANY_ID; + if (debugCDB) + qDebug() << '<' << prefix << "at" << *start << '\n' << toString(); + return true; + } + // Get parent index, make sure it is expanded + NameIndexMap::const_iterator nit = m_inameIndexMap.constFind(prefix); + if (nit == m_inameIndexMap.constEnd()) { + *errorMessage = QString::fromLatin1("'%1' not found.").arg(prefix); + return false; } - return Range(startPos, count); + *parentId = nit.value(); + *start = nit.value() + 1; + if (!expandSymbol(prefix, *parentId, errorMessage)) + return false; + if (debugCDB) + qDebug() << '<' << prefix << "at" << *start << '\n' << toString(); + return true; } -CdbSymbolGroupContext::Range - CdbSymbolGroupContext::allocateRootSymbols() +// Expand a symbol using the symbol group interface. +bool CdbSymbolGroupContext::expandSymbol(const QString &prefix, unsigned long index, QString *errorMessage) { - unsigned long startPos = 0; - unsigned long count = 0; - bool success = false; + if (debugCDB) + qDebug() << Q_FUNC_INFO << '\n' << prefix << index; - QString errorMessage; - do { - HRESULT hr = m_symbolGroup->GetNumberSymbols(&count); - if (FAILED(hr)) { - errorMessage = msgComFailed("GetNumberSymbols", hr); - break; - } + if (isExpanded(index)) + return true; - m_symbolParameters.reserve(3u * count); - m_symbolParameters.resize(count); + HRESULT hr = m_symbolGroup->ExpandSymbol(index, TRUE); + if (FAILED(hr)) { + *errorMessage = QString::fromLatin1("Unable to expand '%1' %2: %3"). + arg(prefix).arg(index).arg(msgComFailed("ExpandSymbol", hr)); + return false; + } + // Hopefully, this will never fail, else data structure will be foobar. + const ULONG oldSize = m_symbolParameters.size(); + ULONG newSize; + hr = m_symbolGroup->GetNumberSymbols(&newSize); + if (FAILED(hr)) { + *errorMessage = msgComFailed("GetNumberSymbols", hr); + return false; + } - hr = m_symbolGroup->GetSymbolParameters(0, count, symbolParameters()); - if (FAILED(hr)) { - errorMessage = msgComFailed("GetSymbolParameters", hr); - break; - } - const QString symbolPrefix = m_prefix + m_nameDelimiter; - for (unsigned long i = 0; i < count; i++) - m_symbolINames.push_back(symbolPrefix + getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i)); + // Retrieve the new parameter structs which will be inserted + // after the parents, offsetting consecutive indexes. + m_symbolParameters.resize(newSize); - success = true; - } while (false); - if (!success) { - clear(); - count = 0; - qWarning("%s\n", qPrintable(errorMessage)); + hr = m_symbolGroup->GetSymbolParameters(0, newSize, symbolParameters()); + if (FAILED(hr)) { + *errorMessage = msgComFailed("GetSymbolParameters", hr); + return false; } - return Range(startPos, count); + // The new symbols are inserted after the parent symbol. + // We need to correct the following values in the name->index map + const unsigned long newSymbolCount = newSize - oldSize; + const NameIndexMap::iterator nend = m_inameIndexMap.end(); + for (NameIndexMap::iterator it = m_inameIndexMap.begin(); it != nend; ++it) + if (it.value() > index) + it.value() += newSymbolCount; + // insert the new symbols + populateINameIndexMap(prefix, index + 1, newSymbolCount); + return true; } void CdbSymbolGroupContext::clear() { m_symbolParameters.clear(); - m_childRanges.clear(); - m_symbolINames.clear(); + m_inameIndexMap.clear(); +} + +int CdbSymbolGroupContext::getDisplayableChildCount(unsigned long index) const +{ + if (!isExpanded(index)) + return 0; + int rc = 0; + // Skip over expanded children, count displayable ones + const unsigned long childCount = m_symbolParameters.at(index).SubElements; + unsigned long seenChildren = 0; + for (unsigned long c = index + 1; seenChildren < childCount; c++) { + const DEBUG_SYMBOL_PARAMETERS ¶ms = m_symbolParameters.at(c); + if (params.ParentSymbol == index) { + seenChildren++; + if (isSymbolDisplayable(params)) + rc++; + } + } + return rc; } WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const @@ -154,23 +283,131 @@ WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const qDebug() << Q_FUNC_INFO << index; WatchData wd; - wd.iname = m_symbolINames.at(index); + wd.iname = m_inameIndexMap.key(index); const int lastDelimiterPos = wd.iname.lastIndexOf(m_nameDelimiter); wd.name = lastDelimiterPos == -1 ? wd.iname : wd.iname.mid(lastDelimiterPos + 1); - wd.type = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, index); - wd.value = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index); + wd.setType(getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, index)); + wd.setValue(getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index).toUtf8()); + wd.setChildrenNeeded(); // compensate side effects of above setters + 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. const DEBUG_SYMBOL_PARAMETERS ¶ms = m_symbolParameters.at(index); if (params.SubElements) { - wd.setTypeUnneeded(); - wd.setValueUnneeded(); - wd.setChildCount(1); + if (isSymbolExpanded(params)) + wd.setChildCount(getDisplayableChildCount(index)); + wd.setChildrenUnneeded(); } else { - wd.setAllUnneeded(); + wd.setChildCount(0); } + if (debugCDB) + qDebug() << Q_FUNC_INFO << '\n' << wd.toString(); + return wd; +} + +class WatchDataBackInserter { +public: + explicit WatchDataBackInserter(QList<WatchData> &wh) : m_wh(wh) {} + + WatchDataBackInserter & operator*() { return *this; } + WatchDataBackInserter &operator=(const WatchData &wd) { + m_wh.push_back(wd); + return *this; + } + WatchDataBackInserter &operator++() { return *this; } + +private: + QList<WatchData> &m_wh; +}; + +static bool insertChildrenRecursion(const QString &iname, + CdbSymbolGroupContext *sg, + WatchHandler *watchHandler, + int level, + QString *errorMessage, + int *childCount = 0); + +// Insert a symbol and its children recursively if +// they are known. +static bool insertSymbolRecursion(const WatchData wd, + CdbSymbolGroupContext *sg, + WatchHandler *watchHandler, + int level, + QString *errorMessage + ) +{ + if (debugCDB) + qDebug() << Q_FUNC_INFO << '\n' << wd.iname << level; + + watchHandler->insertData(wd); + if (wd.childCount && wd.isChildCountKnown()) + return insertChildrenRecursion(wd.iname, sg, watchHandler, level + 1, errorMessage); + return true; +} + +// Insert the children of prefix. +static bool insertChildrenRecursion(const QString &iname, + CdbSymbolGroupContext *sg, + WatchHandler *watchHandler, + int level, + QString *errorMessage, + int *childCount) +{ + if (debugCDB) + qDebug() << Q_FUNC_INFO << '\n' << iname << level; + + QList<WatchData> watchList; + 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; + return true; +} + +bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg, + WatchHandler *watchHandler, + QString *errorMessage) +{ + if (debugCDB) + qDebug() << Q_FUNC_INFO; + + // Insert root items and known children. + QList<WatchData> watchList; + if (!sg->getChildSymbols(sg->prefix(), WatchDataBackInserter(watchList), errorMessage)) + return false; + + foreach(const WatchData &wd, watchList) + if (!insertSymbolRecursion(wd, sg, watchHandler, 0, errorMessage)) + return false; + return true; +} + +bool CdbSymbolGroupContext::completeModel(CdbSymbolGroupContext *sg, + WatchHandler *watchHandler, + QString *errorMessage) +{ + const QList<WatchData> incomplete = watchHandler->takeCurrentIncompletes(); if (debugCDB) { - qDebug() << Q_FUNC_INFO << wd.toString(); + QDebug nsp = qDebug().nospace(); + nsp << Q_FUNC_INFO << '\n' << incomplete.size(); + foreach(const WatchData& wd, incomplete) + nsp << ' ' << wd.iname; + nsp << '\n'; } - return wd; + // At this point, it should be nodes with unknown children. + int childCount; + foreach(WatchData wd, incomplete) { + if (insertChildrenRecursion(wd.iname, sg, watchHandler, 0, errorMessage, &childCount)) { + wd.setChildCount(childCount); + watchHandler->insertData(wd); + } else { + return false; + } + } + return true; } } diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h index e5c4ea7c9c731fba630ba1dca161ecdfa0caf2ae..8a3cf4dc80e3d8ae10000eff5ebdcd4b13e1eb63 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h @@ -44,65 +44,85 @@ namespace Debugger { namespace Internal { class WatchData; +class WatchHandler; /* A thin wrapper around the IDebugSymbolGroup2 interface which represents - * a flat list of symbols using an index (for example, belonging to a stack frame). - * It uses the hierarchical naming convention of WatchHandler as: + * a flat list of symbols using an index (for example, belonging to a stack + * frame). It uses the hierarchical naming convention of WatchHandler as in: * "local" (invisible root) * "local.string" (local class variable) - * "local.string.data" (class member). - * IDebugSymbolGroup2 can "expand" expandable symbols, appending to the flat list. - */ + * "local.string.data" (class member) + * and maintains a mapping iname -> index. + * IDebugSymbolGroup2 can "expand" expandable symbols, inserting them into the + * flat list after their parent. */ class CdbSymbolGroupContext { Q_DISABLE_COPY(CdbSymbolGroupContext); - - // Start position and length of range in m_symbolParameters - typedef QPair<unsigned long, unsigned long> Range; + explicit CdbSymbolGroupContext(const QString &prefix, + IDebugSymbolGroup2 *symbolGroup); public: - explicit CdbSymbolGroupContext(const QString &prefix, - IDebugSymbolGroup2 *symbolGroup); ~CdbSymbolGroupContext(); + static CdbSymbolGroupContext *create(const QString &prefix, + IDebugSymbolGroup2 *symbolGroup, + QString *errorMessage); QString prefix() const { return m_prefix; } + static bool populateModelInitially(CdbSymbolGroupContext *sg, WatchHandler *wh, QString *errorMessage); + static bool completeModel(CdbSymbolGroupContext *sg, WatchHandler *wh, QString *errorMessage); + // Retrieve child symbols of prefix as a sequence of WatchData. template <class OutputIterator> - void getSymbols(const QString &prefix, OutputIterator it); + bool getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage); private: + typedef QMap<QString, unsigned long> NameIndexMap; + + static inline bool isSymbolDisplayable(const DEBUG_SYMBOL_PARAMETERS &p); + + bool init(QString *errorMessage); void clear(); - Range getSymbolRange(const QString &prefix); - Range allocateChildSymbols(const QString &prefix); - Range allocateRootSymbols(); + QString toString() const; + bool getChildSymbolsPosition(const QString &prefix, + unsigned long *startPos, + 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); WatchData symbolAt(unsigned long index) const; + bool isExpanded(unsigned long index) const; + int getDisplayableChildCount(unsigned long index) const; inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); } inline const DEBUG_SYMBOL_PARAMETERS *symbolParameters() const { return &(*m_symbolParameters.constBegin()); } const QString m_prefix; const QChar m_nameDelimiter; - IDebugSymbolGroup2 *m_symbolGroup; - QStringList m_symbolINames; + IDebugSymbolGroup2 *m_symbolGroup; + NameIndexMap m_inameIndexMap; QVector<DEBUG_SYMBOL_PARAMETERS> m_symbolParameters; - - typedef QMap<QString, Range> ChildRangeMap; - - ChildRangeMap m_childRanges; }; template <class OutputIterator> -void CdbSymbolGroupContext::getSymbols(const QString &prefix, OutputIterator it) +bool CdbSymbolGroupContext::getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage) { - const Range r = getSymbolRange(prefix); - const unsigned long end = r.first + r.second; - for (unsigned long i = r.first; i < end; i++) { - *it = symbolAt(i); - ++it; + unsigned long start; + unsigned long parentId; + if (!getChildSymbolsPosition(prefix, &start, &parentId, errorMessage)) + return false; + // Skip over expanded children + const unsigned long end = m_symbolParameters.size(); + for (unsigned long s = start; s < end; ++s) { + const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(s); + if (p.ParentSymbol == parentId && isSymbolDisplayable(p)) { + *it = symbolAt(s); + ++it; + } } + return true; } }