Commit 97789c2d authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Fixed breakpoints for CDB.

Set/modify breakpoints using the new takeXX() APIs of the breakhandler.
Add API for inserted breakpoints (as a 2-step process for pending
breakpoints). Format breakpoint tooltip properly with tr() and
more esthetically pleasing. Get rid of the old scheme of retrieving
and matching the breakpoints from the debugger engine, use ids.
parent 3b1e1231
......@@ -34,6 +34,7 @@
#include <utils/qtcassert.h>
#include <QtCore/QDebug>
#include <QtCore/QTextStream>
#include <QtCore/QFileInfo>
using namespace Debugger;
......@@ -191,23 +192,25 @@ void BreakpointData::updateMarker()
QString BreakpointData::toToolTip() const
{
QString str;
str += "<table>";
str += "<tr><td>Marker File:</td><td>" + markerFileName + "</td></tr>";
str += "<tr><td>Marker Line:</td><td>" + QString::number(markerLineNumber) + "</td></tr>";
str += "<tr><td>BP Number:</td><td>" + bpNumber + "</td></tr>";
str += "<tr><td>BP Address:</td><td>" + bpAddress + "</td></tr>";
str += "<tr><td>----------</td><td></td><td></td></tr>";
str += "<tr><td>Property:</td><td>Wanted:</td><td>Actual:</td></tr>";
str += "<tr><td></td><td></td><td></td></tr>";
str += "<tr><td>Internal Number:</td><td>-</td><td>" + bpNumber + "</td></tr>";
str += "<tr><td>File Name:</td><td>" + fileName + "</td><td>" + bpFileName + "</td></tr>";
str += "<tr><td>Function Name:</td><td>" + funcName + "</td><td>" + bpFuncName + "</td></tr>";
str += "<tr><td>Line Number:</td><td>" + lineNumber + "</td><td>" + bpLineNumber + "</td></tr>";
str += "<tr><td>Condition:</td><td>" + condition + "</td><td>" + bpCondition + "</td></tr>";
str += "<tr><td>Ignore count:</td><td>" + ignoreCount + "</td><td>" + bpIgnoreCount + "</td></tr>";
str += "</table>";
return str;
QString rc;
QTextStream str(&rc);
str << "<html><body><table>";
str << "<tr><td>" << BreakHandler::tr("Marker File:") << "</td><td>" << markerFileName << "</td></tr>";
str << "<tr><td>" << BreakHandler::tr("Marker Line:") << "</td><td>" << markerLineNumber << "</td></tr>";
str << "<tr><td>" << BreakHandler::tr("Breakpoint Number:") << "</td><td>" << bpNumber << "</td></tr>";
str << "<tr><td>" << BreakHandler::tr("Breakpoint Address:") << "</td><td>" << bpAddress << "</td></tr>";
str << "</table><br><hr><table>";
str << "<tr><th>" << BreakHandler::tr("Property")
<< "</th><th>" << BreakHandler::tr("Requested")
<< "</th><th>" << BreakHandler::tr("Obtained") << "</th></tr>";
str << "<tr><td>" << BreakHandler::tr("Internal Number:") << "</td><td>&mdash;</td><td>" << bpNumber << "</td></tr>";
str << "<tr><td>" << BreakHandler::tr("File Name:") << "</td><td>" << fileName << "</td><td>" << bpFileName << "</td></tr>";
str << "<tr><td>" << BreakHandler::tr("Function Name:") << "</td><td>" << funcName << "</td><td>" << bpFuncName << "</td></tr>";
str << "<tr><td>" << BreakHandler::tr("Line Number:") << "</td><td>" << lineNumber << "</td><td>" << bpLineNumber << "</td></tr>";
str << "<tr><td>" << BreakHandler::tr("Condition:") << "</td><td>" << condition << "</td><td>" << bpCondition << "</td></tr>";
str << "<tr><td>" << BreakHandler::tr("Ignore Count:") << "</td><td>" << ignoreCount << "</td><td>" << bpIgnoreCount << "</td></tr>";
str << "</table></body></html>";
return rc;
}
bool BreakpointData::isLocatedAt(const QString &fileName_, int lineNumber_) const
......@@ -524,6 +527,22 @@ bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int rol
}
}
void BreakHandler::append(BreakpointData *data)
{
m_bp.append(data);
m_inserted.append(data);
}
QList<BreakpointData *> BreakHandler::insertedBreakpoints() const
{
return m_inserted;
}
void BreakHandler::takeInsertedBreakPoint(BreakpointData *d)
{
m_inserted.removeAll(d);
}
QList<BreakpointData *> BreakHandler::takeRemovedBreakpoints()
{
QList<BreakpointData *> result = m_removed;
......
......@@ -123,7 +123,7 @@ public:
BreakpointData *at(int index) const { return index < size() ? m_bp.at(index) : 0; }
int size() const { return m_bp.size(); }
bool hasPendingBreakpoints() const;
void append(BreakpointData *data) { m_bp.append(data); }
void append(BreakpointData *data);
void removeAt(int index); // also deletes the marker
void clear(); // also deletes all the marker
int indexOf(BreakpointData *data) { return m_bp.indexOf(data); }
......@@ -132,6 +132,8 @@ public:
int findBreakpoint(int bpNumber); // returns index
void updateMarkers();
QList<BreakpointData *> insertedBreakpoints() const;
void takeInsertedBreakPoint(BreakpointData *);
QList<BreakpointData *> takeRemovedBreakpoints(); // owned
QList<BreakpointData *> takeEnabledBreakpoints(); // not owned
QList<BreakpointData *> takeDisabledBreakpoints(); // not owned
......@@ -171,6 +173,7 @@ private:
void removeBreakpointHelper(int index);
QList<BreakpointData *> m_bp;
QList<BreakpointData *> m_inserted; // lately inserted breakpoints
QList<BreakpointData *> m_removed; // lately removed breakpoints
QList<BreakpointData *> m_enabled; // lately enabled breakpoints
QList<BreakpointData *> m_disabled; // lately disabled breakpoints
......
......@@ -37,6 +37,8 @@
#include <QtCore/QDebug>
#include <QtCore/QMap>
enum { debugBP = 0 };
namespace Debugger {
namespace Internal {
......@@ -49,17 +51,19 @@ static const char sourceFileQuoteC = '`';
CDBBreakPoint::CDBBreakPoint() :
ignoreCount(0),
lineNumber(-1),
oneShot(false)
oneShot(false),
enabled(true)
{
}
CDBBreakPoint::CDBBreakPoint(const BreakpointData &bpd) :
fileName(bpd.fileName),
fileName(QDir::toNativeSeparators(bpd.fileName)),
condition(bpd.condition),
ignoreCount(0),
funcName(bpd.funcName),
lineNumber(-1),
oneShot(false)
oneShot(false),
enabled(bpd.enabled)
{
if (!bpd.ignoreCount.isEmpty())
ignoreCount = bpd.ignoreCount.toInt();
......@@ -81,6 +85,10 @@ int CDBBreakPoint::compare(const CDBBreakPoint& rhs) const
return 1;
if (!oneShot && rhs.oneShot)
return -1;
if (enabled && !rhs.enabled)
return 1;
if (!enabled && rhs.enabled)
return -1;
if (const int fileCmp = fileName.compare(rhs.fileName))
return fileCmp;
if (const int funcCmp = funcName.compare(rhs.funcName))
......@@ -94,6 +102,7 @@ void CDBBreakPoint::clear()
{
ignoreCount = 0;
oneShot = false;
enabled = true;
clearExpressionData();
}
......@@ -117,6 +126,8 @@ QDebug operator<<(QDebug dbg, const CDBBreakPoint &bp)
nsp << " condition='" << bp.condition << '\'';
if (bp.ignoreCount)
nsp << " ignoreCount=" << bp.ignoreCount;
if (bp.enabled)
nsp << " enabled";
if (bp.oneShot)
nsp << " oneShot";
return dbg;
......@@ -153,27 +164,48 @@ bool CDBBreakPoint::apply(CIDebugBreakpoint *ibp, QString *errorMessage) const
}
// Pass Count is ignoreCount + 1
ibp->SetPassCount(ignoreCount + 1u);
ULONG flags = DEBUG_BREAKPOINT_ENABLED;
ULONG flags = 0;
if (enabled)
flags |= DEBUG_BREAKPOINT_ENABLED;
if (oneShot)
flags |= DEBUG_BREAKPOINT_ONE_SHOT;
ibp->AddFlags(flags);
return true;
}
bool CDBBreakPoint::add(CIDebugControl* debugControl, QString *errorMessage) const
static inline QString msgCannotAddBreakPoint(const QString &why)
{
return QString::fromLatin1("Unable to add breakpoint: %1").arg(why);
}
bool CDBBreakPoint::add(CIDebugControl* debugControl,
quint64 *address, unsigned long *id,
QString *errorMessage) const
{
IDebugBreakpoint2* ibp = 0;
const HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp);
*address = 0;
*id = 0;
HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp);
if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("Unable to add breakpoint: %1").
arg(msgComFailed("AddBreakpoint2", hr));
*errorMessage = msgCannotAddBreakPoint(msgComFailed("AddBreakpoint2", hr));
return false;
}
if (!ibp) {
*errorMessage = QString::fromLatin1("Unable to add breakpoint: <Unknown error>");
*errorMessage = msgCannotAddBreakPoint(QLatin1String("<Unknown error>"));
return false;
}
if (!apply(ibp, errorMessage))
return false;
// GetOffset can fail when attaching to remote processes.
hr = ibp->GetOffset(address);
if (FAILED(hr))
*address = 0;
hr = ibp->GetId(id);
if (FAILED(hr)) {
*errorMessage = msgCannotAddBreakPoint(msgComFailed("GetId", hr));
return false;
}
return apply(ibp, errorMessage);
return true;
}
// Make sure file can be found in editor manager and text markers
......@@ -204,8 +236,8 @@ bool CDBBreakPoint::retrieve(CIDebugBreakpoint *ibp, QString *errorMessage)
ignoreCount--;
ULONG flags = 0;
ibp->GetFlags(&flags);
if (flags & DEBUG_BREAKPOINT_ONE_SHOT)
oneShot = true;
oneShot = (flags & DEBUG_BREAKPOINT_ONE_SHOT);
enabled = (flags & DEBUG_BREAKPOINT_ENABLED);
const QString expr = QString::fromUtf16(wszBuf);
if (!parseExpression(expr)) {
*errorMessage = QString::fromLatin1("Parsing of '%1' failed.").arg(expr);
......@@ -296,31 +328,107 @@ bool CDBBreakPoint::getBreakPoints(CIDebugControl* debugControl, QList<CDBBreakP
return true;
}
// Find a breakpoint by id
static inline QString msgNoBreakPointWithId(unsigned long id, const QString &why)
{
return QString::fromLatin1("Unable to find breakpoint with id %1: %2").arg(id).arg(why);
}
static IDebugBreakpoint2 *breakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage)
{
CIDebugBreakpoint *ibp = 0;
const HRESULT hr = ctl->GetBreakpointById2(id, &ibp);
if (FAILED(hr)) {
*errorMessage = msgNoBreakPointWithId(id, msgComFailed("GetBreakpointById2", hr));
return 0;
}
if (!ibp) {
*errorMessage = msgNoBreakPointWithId(id, QLatin1String("<not found>"));
return 0;
}
return ibp;
}
// Remove breakpoint by id
static bool removeBreakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage)
{
if (debugBP)
qDebug() << Q_FUNC_INFO << id;
CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage);
if (!ibp)
return false;
const HRESULT hr = ctl->RemoveBreakpoint2(ibp);
if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("Cannot remove breakpoint %1: %2").arg(id).arg(msgComFailed("RemoveBreakpointById2", hr));
return false;
}
return true;
}
// Set enabled by id
// Change enabled state of a breakpoint by id
static inline QString msgCannotSetBreakPointEnabled(unsigned long id, bool enabled, const QString &why)
{
return QString::fromLatin1("Cannot %1 breakpoint %2: %3").
arg(QLatin1String(enabled ? "enable" : "disable")).arg(id).arg(why);
}
static bool setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id, bool enabled, QString *errorMessage)
{
if (debugBP)
qDebug() << Q_FUNC_INFO << id << enabled;
CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage);
if (!ibp) {
*errorMessage = msgCannotSetBreakPointEnabled(id, enabled, *errorMessage);
return false;
}
// Compare flags
ULONG flags;
HRESULT hr = ibp->GetFlags(&flags);
if (FAILED(hr)) {
*errorMessage = msgCannotSetBreakPointEnabled(id, enabled, msgComFailed("GetFlags", hr));
return false;
}
const bool wasEnabled = (flags & DEBUG_BREAKPOINT_ENABLED);
if (wasEnabled == enabled)
return true;
// Set new value
if (enabled) {
flags |= DEBUG_BREAKPOINT_ENABLED;
} else {
flags &= ~DEBUG_BREAKPOINT_ENABLED;
}
hr = ibp->SetFlags(flags);
if (FAILED(hr)) {
*errorMessage = msgCannotSetBreakPointEnabled(id, enabled, msgComFailed("SetFlags", hr));
return false;
}
return true;
}
// Synchronize (halted) engine breakpoints with those of the BreakHandler.
bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl,
IDebugSymbols3 *syms,
bool CDBBreakPoint::synchronizeBreakPoints(CIDebugControl* debugControl,
CIDebugSymbols *syms,
BreakHandler *handler,
QString *errorMessage)
{
typedef QMap<CDBBreakPoint, int> BreakPointIndexMap;
if (debugCDB)
qDebug() << Q_FUNC_INFO;
BreakPointIndexMap breakPointIndexMap;
// convert BreakHandler's bps into a map of BreakPoint->BreakHandler->Index
// Ignore invalid functions (that could not be found) as they make
// the debugger hang.
const int handlerCount = handler->size();
const QChar moduleDelimiter = QLatin1Char('!');
for (int i=0; i < handlerCount; ++i) {
BreakpointData *bd = handler->at(i);
// Do an initial check whether we are in a state that allows
// for modifying breakPoints
ULONG engineCount;
if (!getBreakPointCount(debugControl, &engineCount, errorMessage)) {
*errorMessage = QString::fromLatin1("Cannot modify breakpoints: %1").arg(*errorMessage);
return false;
}
// Insert new ones
bool updateMarkers = false;
foreach (BreakpointData *nbd, handler->insertedBreakpoints()) {
// Function breakpoints: Are the module names specified?
bool breakPointOk = false;
if (bd->funcName.isEmpty()) {
if (nbd->funcName.isEmpty()) {
breakPointOk = true;
} else {
switch (resolveSymbol(syms, &bd->funcName, errorMessage)) {
switch (resolveSymbol(syms, &nbd->funcName, errorMessage)) {
case ResolveSymbolOk:
breakPointOk = true;
break;
......@@ -334,66 +442,49 @@ bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl,
break;
};
} // function breakpoint
if (breakPointOk)
breakPointIndexMap.insert(CDBBreakPoint(*bd), i);
}
errorMessage->clear();
// get number of engine breakpoints
ULONG engineCount;
if (!getBreakPointCount(debugControl, &engineCount, errorMessage))
return false;
// Starting from end, check if engine breakpoints are still in handler.
// If not->remove
if (engineCount) {
for (ULONG eb = engineCount - 1u; ; eb--) {
// get engine breakpoint.
IDebugBreakpoint2 *ibp = 0;
HRESULT hr = debugControl->GetBreakpointByIndex2(eb, &ibp);
if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("Cannot retrieve breakpoint %1: %2").
arg(eb).arg(msgComFailed("GetBreakpointByIndex2", hr));
return false;
// Now add...
if (breakPointOk) {
quint64 address;
unsigned long id;
CDBBreakPoint ncdbbp(*nbd);
breakPointOk = ncdbbp.add(debugControl, &address, &id, errorMessage);
if (breakPointOk) {
if (debugBP)
qDebug() << "Added " << id << " at " << address << ncdbbp;
handler->takeInsertedBreakPoint(nbd);
updateMarkers = true;
nbd->pending = false;
nbd->bpNumber = QString::number(id);
nbd->bpAddress = QLatin1String("0x") + QString::number(address, 16);
// Take over rest as is
nbd->bpCondition = nbd->condition;
nbd->bpIgnoreCount = nbd->ignoreCount;
nbd->bpFileName = nbd->fileName;
nbd->bpLineNumber = nbd->lineNumber;
nbd->bpFuncName = nbd->funcName;
}
// Ignore one shot break points set by "Step out"
ULONG flags = 0;
hr = ibp->GetFlags(&flags);
if (!(flags & DEBUG_BREAKPOINT_ONE_SHOT)) {
CDBBreakPoint engineBreakPoint;
if (!engineBreakPoint.retrieve(ibp, errorMessage))
return false;
// Still in handler?
if (!breakPointIndexMap.contains(engineBreakPoint)) {
if (debugCDB)
qDebug() << " Removing" << engineBreakPoint;
hr = debugControl->RemoveBreakpoint2(ibp);
if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("Cannot remove breakpoint %1: %2").
arg(engineBreakPoint.expression(), msgComFailed("RemoveBreakpoint2", hr));
return false;
}
} // not in handler
} // one shot
if (!eb)
break;
}
} // had symbol
if (!breakPointOk)
qWarning("%s\n", qPrintable(*errorMessage));
}
// Add pending breakpoints
const BreakPointIndexMap::const_iterator pcend = breakPointIndexMap.constEnd();
for (BreakPointIndexMap::const_iterator it = breakPointIndexMap.constBegin(); it != pcend; ++it) {
const int index = it.value();
if (handler->at(index)->pending) {
if (debugCDB)
qDebug() << " Adding " << it.key();
if (it.key().add(debugControl, errorMessage)) {
handler->at(index)->pending = false;
} else {
const QString msg = QString::fromLatin1("Failed to add breakpoint '%1': %2").arg(it.key().expression(), *errorMessage);
qWarning("%s\n", qPrintable(msg));
}
}
// Delete
foreach (BreakpointData *rbd, handler->takeRemovedBreakpoints()) {
if (!removeBreakPointById(debugControl, rbd->bpNumber.toUInt(), errorMessage))
qWarning("%s\n", qPrintable(*errorMessage));
delete rbd;
}
if (debugCDB > 1) {
// Enable/Disable
foreach (BreakpointData *ebd, handler->takeEnabledBreakpoints())
if (!setBreakPointEnabledById(debugControl, ebd->bpNumber.toUInt(), true, errorMessage))
qWarning("%s\n", qPrintable(*errorMessage));
foreach (BreakpointData *dbd, handler->takeDisabledBreakpoints())
if (!setBreakPointEnabledById(debugControl, dbd->bpNumber.toUInt(), false, errorMessage))
qWarning("%s\n", qPrintable(*errorMessage));
if (updateMarkers)
handler->updateMarkers();
if (debugBP > 1) {
QList<CDBBreakPoint> bps;
CDBBreakPoint::getBreakPoints(debugControl, &bps, errorMessage);
qDebug().nospace() << "### Breakpoints in engine: " << bps;
......
......@@ -63,7 +63,7 @@ struct CDBBreakPoint
// Apply parameters
bool apply(IDebugBreakpoint2 *ibp, QString *errorMessage) const;
// Convenience to add to a IDebugControl4
bool add(CIDebugControl* debugControl, QString *errorMessage) const;
bool add(CIDebugControl* debugControl, quint64 *address, unsigned long *id, QString *errorMessage) const;
// Retrieve/parse breakpoints from the interfaces
bool retrieve(IDebugBreakpoint2 *ibp, QString *errorMessage);
......@@ -84,6 +84,7 @@ struct CDBBreakPoint
int lineNumber; // line in source file
QString funcName; // name of containing function
bool oneShot;
bool enabled;
};
QDebug operator<<(QDebug, const CDBBreakPoint &bp);
......@@ -92,9 +93,6 @@ inline bool operator==(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
{ return b1.compare(b2) == 0; }
inline bool operator!=(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
{ return b1.compare(b2) != 0; }
inline bool operator<(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
{ return b1.compare(b2) < 0; }
} // namespace Internal
} // namespace Debugger
......
......@@ -135,9 +135,11 @@ bool CdbStackFrameContext::populateModelInitially(WatchHandler *wh, QString *err
qDebug() << "populateModelInitially";
const bool rc = m_useDumpers ?
CdbSymbolGroupContext::populateModelInitially(m_symbolContext,
WatchHandlerSorterInserter(wh, m_dumper),
wh->expandedINames(),
WatchHandlerSorterInserter(wh, m_dumper),
errorMessage) :
CdbSymbolGroupContext::populateModelInitially(m_symbolContext,
wh->expandedINames(),
WatchHandlerModelInserter(wh),
errorMessage);
return rc;
......
......@@ -213,11 +213,23 @@ CdbSymbolGroupContext::SymbolState CdbSymbolGroupContext::symbolState(const QStr
{
if (prefix == m_prefix) // root
return ExpandedSymbol;
unsigned long index;
if (!lookupPrefix(prefix, &index)) {
qWarning("WARNING %s: %s\n", Q_FUNC_INFO, msgSymbolNotFound(prefix));
return LeafSymbol;
}
return symbolState(index);
}
// Find index of a prefix
bool CdbSymbolGroupContext::lookupPrefix(const QString &prefix, unsigned long *index) const
{
*index = 0;
const NameIndexMap::const_iterator it = m_inameIndexMap.constFind(prefix);
if (it != m_inameIndexMap.constEnd())
return symbolState(it.value());
qWarning("WARNING %s: %s\n", Q_FUNC_INFO, msgSymbolNotFound(prefix));
return LeafSymbol;
if (it == m_inameIndexMap.constEnd())
return false;
*index = it.value();
return true;
}
/* Retrieve children and get the position. */
......
......@@ -39,6 +39,7 @@
#include <QtCore/QStringList>
#include <QtCore/QPair>
#include <QtCore/QMap>
#include <QtCore/QSet>
namespace Debugger {
namespace Internal {
......@@ -74,7 +75,9 @@ public:
QString *newValue /* = 0 */, QString *errorMessage);
template <class OutputIterator>
static bool populateModelInitially(CdbSymbolGroupContext *sg, OutputIterator it, QString *errorMessage);
static bool populateModelInitially(CdbSymbolGroupContext *sg,
QSet<QString> expandedINames,
OutputIterator it, QString *errorMessage);
template <class OutputIterator>
static bool completeModel(CdbSymbolGroupContext *sg,
......@@ -116,6 +119,7 @@ private:
void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long start, unsigned long count);
WatchData symbolAt(unsigned long index) const;
QString symbolINameAt(unsigned long index) const;
bool lookupPrefix(const QString &prefix, unsigned long *index) const;
int getDisplayableChildCount(unsigned long index) const;
inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); }
......
......@@ -154,6 +154,7 @@ template <class OutputIterator>
template <class OutputIterator>
bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg,
QSet<QString> expandedINames,
OutputIterator it,
QString *errorMessage)
{
......@@ -164,7 +165,26 @@ bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg,
QList<WatchData> watchList;
if (!sg->getChildSymbols(sg->prefix(), WatchDataBackInserter(watchList), errorMessage))
return false;
// (Recursively) expand symbols stored as expanded in the history until no more matches
// are found.
while (!expandedINames.empty()) {
unsigned matchCount = 0;
for (QSet<QString>::iterator it = expandedINames.begin(); it != expandedINames.end(); ) {
// Try to expand. We might hit on a leaf due to name mismatches, ignore errors.
unsigned long index;
if (sg->lookupPrefix(*it, &index)) {
if (!sg->expandSymbol(*it, index, errorMessage))
qWarning("%s\n", qPrintable(*errorMessage));
matchCount++;
it = expandedINames.erase(it);
} else {
++it;
}
} // loop set