OSDN Git Service

debugger: refactor breakpoint type, add function name to resolved jsbreakpoints
authorhjk <qtc-committer@nokia.com>
Thu, 28 Oct 2010 10:18:38 +0000 (12:18 +0200)
committerhjk <qtc-committer@nokia.com>
Fri, 29 Oct 2010 12:31:16 +0000 (14:31 +0200)
share/qtcreator/qml/qmljsdebugger/jsdebuggeragent.cpp
src/plugins/debugger/breakhandler.cpp
src/plugins/debugger/breakpoint.cpp
src/plugins/debugger/breakpoint.h
src/plugins/debugger/breakwindow.cpp
src/plugins/debugger/cdb/cdbbreakpoint.cpp
src/plugins/debugger/gdb/gdbengine.cpp
src/plugins/debugger/qml/qmlengine.cpp
src/plugins/debugger/watchhandler.cpp

index 60d691f..db314d5 100644 (file)
@@ -90,7 +90,34 @@ QDataStream &operator<<(QDataStream &s, const JSAgentStackData &data)
     return s << data.functionName << data.fileName << data.lineNumber;
 }
 
-typedef JSAgentStackData JSBreakpointData;
+struct JSAgentBreakpointData
+{
+    QByteArray functionName;
+    QByteArray fileName;
+    qint32 lineNumber;
+};
+
+typedef QSet<JSAgentBreakpointData> JSAgentBreakpoints;
+
+QDataStream &operator<<(QDataStream &s, const JSAgentBreakpointData &data)
+{
+    return s << data.functionName << data.fileName << data.lineNumber;
+}
+
+QDataStream &operator>>(QDataStream &s, JSAgentBreakpointData &data)
+{
+    return s >> data.functionName >> data.fileName >> data.lineNumber;
+}
+
+bool operator==(const JSAgentBreakpointData &b1, const JSAgentBreakpointData &b2)
+{
+    return b1.lineNumber == b2.lineNumber && b1.fileName == b2.fileName;
+}
+
+uint qHash(const JSAgentBreakpointData &b)
+{
+    return b.lineNumber ^ qHash(b.fileName);
+}
 
 class JSDebuggerAgentPrivate
 {
@@ -115,8 +142,8 @@ public:
     int stepCount;
 
     QEventLoop loop;
-    QHash <qint64, QString> filenames;
-    QSet< QPair<QString, qint32> > breakpointList;
+    QHash<qint64, QString> filenames;
+    JSAgentBreakpoints breakpoints;
     QStringList watchExpressions;
     QSet<qint64> knownObjectIds;
 };
@@ -348,7 +375,7 @@ void JSDebuggerAgentPrivate::positionChange
         return; //no re-entrency
 
     // check breakpoints
-    if (!breakpointList.isEmpty()) {
+    if (!breakpoints.isEmpty()) {
         QHash<qint64, QString>::const_iterator it = filenames.constFind(scriptId);
         QScriptContext *ctx = engine()->currentContext();
         QScriptContextInfo info(ctx);
@@ -362,8 +389,10 @@ void JSDebuggerAgentPrivate::positionChange
             QPair<QString, qint32> key = qMakePair(filename, lineNumber);
             it = filenames.insert(scriptId, filename);
         }
-        QPair<QString, qint32> key = qMakePair(*it, lineNumber);
-        if (breakpointList.contains(key)) {
+        JSAgentBreakpointData bp;
+        bp.fileName = it->toUtf8();
+        bp.lineNumber = lineNumber;
+        if (breakpoints.contains(bp)) {
             stopped();
             return;
         }
@@ -440,7 +469,10 @@ void JSDebuggerAgentPrivate::messageReceived(const QByteArray &message)
     QByteArray command;
     ds >> command;
     if (command == "BREAKPOINTS") {
-        ds >> breakpointList;
+        ds >> breakpoints;
+        //qDebug() << "BREAKPOINTS";
+        //foreach (const JSAgentBreakpointData &bp, breakpoints)
+        //    qDebug() << "BREAKPOINT: " << bp.fileName << bp.lineNumber;
     } else if (command == "WATCH_EXPRESSIONS") {
         ds >> watchExpressions;
     } else if (command == "STEPOVER") {
index 1bcfafc..90ef5b0 100644 (file)
@@ -148,7 +148,7 @@ int BreakHandler::findWatchPointIndexByAddress(quint64 address) const
 {
     for (int index = size() - 1; index >= 0; --index) {
         BreakpointData *bd = at(index);
-        if (bd->type == BreakpointData::WatchpointType && bd->address == address)
+        if (bd->isWatchpoint() && bd->address == address)
             return index;
     }
     return -1;
@@ -168,9 +168,9 @@ void BreakHandler::saveBreakpoints()
         const BreakpointData *data = at(index);
         QMap<QString, QVariant> map;
         // Do not persist Watchpoints.
-        //if (data->type == BreakpointData::WatchpointType)
+        //if (data->isWatchpoint())
         //    continue;
-        if (data->type != BreakpointData::BreakpointType)
+        if (data->type != BreakpointByFileAndLine)
             map.insert(_("type"), data->type);
         if (!data->fileName.isEmpty())
             map.insert(_("filename"), data->fileName);
@@ -235,7 +235,7 @@ void BreakHandler::loadBreakpoints()
             data->useFullPath = bool(v.toInt());
         v = map.value(_("type"));
         if (v.isValid())
-            data->type = BreakpointData::Type(v.toInt());
+            data->type = BreakpointType(v.toInt());
         data->setMarkerFileName(data->fileName);
         data->setMarkerLineNumber(data->lineNumber);
         append(data);
@@ -344,7 +344,7 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
                 return str.isEmpty() ? empty : str;
             }
             if (role == Qt::DecorationRole) {
-                if (data->type == BreakpointData::WatchpointType)
+                if (data->isWatchpoint())
                     return m_watchpointIcon;
                 if (!data->enabled)
                     return m_disabledBreakpointIcon;
@@ -414,8 +414,8 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
         case 7:
             if (role == Qt::DisplayRole) {
                 QString displayValue;
-                const quint64 effectiveAddress = data->type == BreakpointData::WatchpointType ?
-                              data->address : data->bpAddress;
+                const quint64 effectiveAddress
+                    = data->isWatchpoint() ? data->address : data->bpAddress;
                 if (effectiveAddress)
                     displayValue += QString::fromAscii("0x%1").arg(effectiveAddress, 0, 16);
                 if (!data->bpState.isEmpty()) {
index 9f07324..ece3945 100644 (file)
@@ -61,7 +61,7 @@ static quint64 nextBPId() {
 
 BreakpointData::BreakpointData() :
     id(nextBPId()), enabled(true),
-    pending(true), type(BreakpointType),
+    pending(true), type(BreakpointByFileAndLine),
     ignoreCount(0), lineNumber(0), address(0),
     useFullPath(false),
     bpIgnoreCount(0), bpLineNumber(0),
@@ -84,7 +84,7 @@ BreakpointData *BreakpointData::clone() const
     data->threadSpec = threadSpec;
     data->funcName = funcName;
     data->useFullPath = useFullPath;
-    if (isSetByFunction()) {
+    if (data->type == BreakpointByFunction) {
         // FIXME: Would removing it be better then leaving this 
         // "history" around?
         data->m_markerFileName = m_markerFileName;
@@ -142,6 +142,22 @@ static inline void formatAddress(QTextStream &str, quint64 address)
 
 QString BreakpointData::toToolTip() const
 {
+    QString t = tr("Unknown Breakpoint Type");
+    switch (type) {
+        case BreakpointByFileAndLine:
+            t = tr("Breakpoint by File and Line");
+            break;
+        case BreakpointByFunction:
+            t = tr("Breakpoint by Function");
+            break;
+        case BreakpointByAddress:
+            t = tr("Breakpoint by Address");
+            break;
+        case Watchpoint:
+            t = tr("Watchpoint");
+            break;
+    }
+
     QString rc;
     QTextStream str(&rc);
     str << "<html><body><table>"
@@ -152,11 +168,7 @@ QString BreakpointData::toToolTip() const
         << "<tr><td>" << tr("Breakpoint Number:")
         << "</td><td>" << bpNumber << "</td></tr>"
         << "<tr><td>" << tr("Breakpoint Type:")
-        << "</td><td>"
-        << (type == BreakpointType ? tr("Breakpoint")
-            : type == WatchpointType ? tr("Watchpoint")
-            : tr("Unknown breakpoint type"))
-        << "</td></tr>"
+        << "</td><td>" << t << "</td></tr>"
         << "<tr><td>" << tr("State:")
         << "</td><td>" << bpState << "</td></tr>"
         << "</table><br><hr><table>"
@@ -166,7 +178,8 @@ QString BreakpointData::toToolTip() const
         << "<tr><td>" << tr("Internal Number:")
         << "</td><td>&mdash;</td><td>" << bpNumber << "</td></tr>"
         << "<tr><td>" << tr("File Name:")
-        << "</td><td>" << QDir::toNativeSeparators(fileName) << "</td><td>" << QDir::toNativeSeparators(bpFileName) << "</td></tr>"
+        << "</td><td>" << QDir::toNativeSeparators(fileName)
+        << "</td><td>" << QDir::toNativeSeparators(bpFileName) << "</td></tr>"
         << "<tr><td>" << tr("Function Name:")
         << "</td><td>" << funcName << "</td><td>" << bpFuncName << "</td></tr>"
         << "<tr><td>" << tr("Line Number:") << "</td><td>";
index eaf6d54..8bdc3f1 100644 (file)
@@ -47,6 +47,14 @@ class BreakHandler;
 //
 //////////////////////////////////////////////////////////////////
 
+enum BreakpointType
+{
+    BreakpointByFileAndLine,
+    BreakpointByFunction,
+    BreakpointByAddress,
+    Watchpoint,
+};
+
 class BreakpointData
 {
 public:
@@ -77,13 +85,11 @@ private:
     friend class BreakHandler;
 
 public:
-    enum Type { BreakpointType, WatchpointType };
-
     quint64 id;
 
     bool enabled;            // Should we talk to the debugger engine?
     bool pending;            // Does the debugger engine know about us already?
-    Type type;               // Type of breakpoint.
+    BreakpointType type;     // Type of breakpoint.
 
     // This "user requested information" will get stored in the session.
     QString fileName;        // Short name of source file.
@@ -118,12 +124,13 @@ public:
     void setMarkerLineNumber(int lineNumber);
     int markerLineNumber() const { return m_markerLineNumber; }
 
-    bool isSetByFunction() const { return !funcName.isEmpty(); }
-    bool isSetByFileAndLine() const { return !fileName.isEmpty(); }
+    bool isWatchpoint() const { return type == Watchpoint; }
+    bool isBreakpoint() const { return type != Watchpoint; } // Enough for now.
 
     Q_DECLARE_TR_FUNCTIONS(BreakHandler)
 
     // TODO: move those to breakhandler
+private:
     // Taken from either user input or gdb responses.
     QString m_markerFileName; // Used to locate the marker.
     int m_markerLineNumber;
index d54bd82..e672d80 100644 (file)
@@ -81,7 +81,8 @@ BreakpointDialog::BreakpointDialog(QWidget *parent) : QDialog(parent)
     comboBoxType->insertItem(3, tr("Address"));
     pathChooserFileName->setExpectedKind(Utils::PathChooser::File);
     connect(comboBoxType, SIGNAL(activated(int)), SLOT(typeChanged(int)));
-    lineEditIgnoreCount->setValidator(new QIntValidator(0, 2147483647, lineEditIgnoreCount));
+    lineEditIgnoreCount->setValidator(
+        new QIntValidator(0, 2147483647, lineEditIgnoreCount));
 }
 
 bool BreakpointDialog::showDialog(BreakpointData *data)
index f9eaca6..154fd37 100644 (file)
@@ -38,11 +38,12 @@ namespace Internal {
 enum { debugBP = 0 };
 
 // Convert breakpoint structs
-CdbCore::BreakPoint breakPointFromBreakPointData(const Debugger::Internal::BreakpointData &bpd)
+CdbCore::BreakPoint breakPointFromBreakPointData(const BreakpointData &bpd)
 {
     CdbCore::BreakPoint rc;
-    rc.type = bpd.type == Debugger::Internal::BreakpointData::BreakpointType ?
-              CdbCore::BreakPoint::Code : CdbCore::BreakPoint::Data;
+    rc.type = bpd.type == Watchpoint ?
+                  CdbCore::BreakPoint::Data :
+                  CdbCore::BreakPoint::Code ;
 
     rc.address = bpd.address;
     if (!bpd.threadSpec.isEmpty()) {
index 9ca120b..93ac1aa 100644 (file)
@@ -2114,10 +2114,11 @@ void GdbEngine::setBreakpointDataFromOutput(BreakpointData *data, const GdbMi &b
         } else if (child.hasName("thread")) {
             data->bpThreadSpec = child.data();
         } else if (child.hasName("type")) {
-            if (child.data().contains("reakpoint")) // "breakpoint", "hw breakpoint"
-                data->type = BreakpointData::BreakpointType;
-            else // FIXME: Incomplete list of cases.
-                data->type = BreakpointData::WatchpointType;
+            // FIXME: This should not change the type.
+            //if (child.data().contains("reakpoint")) // "breakpoint", "hw breakpoint"
+            //    ; // data->type = BreakpointData::BreakpointType;
+            //else // FIXME: Incomplete list of cases.
+            //    data->type = Watchpoint;
         }
         // This field is not present.  Contents needs to be parsed from
         // the plain "ignore" response.
@@ -2179,7 +2180,7 @@ void GdbEngine::sendInsertBreakpoint(int index)
     const BreakpointData *data = breakHandler()->at(index);
     // Set up fallback in case of pending breakpoints which aren't handled
     // by the MI interface.
-    if (data->type == BreakpointData::WatchpointType) {
+    if (data->type == Watchpoint) {
         postCommand("watch " + bpAddressSpec(data->address),
             NeedsStop | RebuildBreakpointModel,
             CB(handleWatchInsert), index);
index cae06f0..464de7e 100644 (file)
@@ -84,6 +84,36 @@ enum {
 namespace Debugger {
 namespace Internal {
 
+struct JSAgentBreakpointData
+{
+    QByteArray functionName;
+    QByteArray fileName;
+    qint32 lineNumber;
+};
+
+uint qHash(const JSAgentBreakpointData &b)
+{
+    return b.lineNumber ^ qHash(b.fileName);
+}
+
+QDataStream &operator<<(QDataStream &s, const JSAgentBreakpointData &data)
+{
+    return s << data.functionName << data.fileName << data.lineNumber;
+}
+
+QDataStream &operator>>(QDataStream &s, JSAgentBreakpointData &data)
+{
+    return s >> data.functionName >> data.fileName >> data.lineNumber;
+}
+
+bool operator==(const JSAgentBreakpointData &b1, const JSAgentBreakpointData &b2)
+{
+    return b1.lineNumber == b2.lineNumber && b1.fileName == b2.fileName;
+}
+
+typedef QSet<JSAgentBreakpointData> JSAgentBreakpoints;
+
+
 QDataStream &operator>>(QDataStream &s, WatchData &data)
 {
     data = WatchData();
@@ -466,27 +496,31 @@ void QmlEngine::attemptBreakpointSynchronization()
 {
     Internal::BreakHandler *handler = breakHandler();
     //bool updateNeeded = false;
-    QSet< QPair<QString, qint32> > breakList;
+    Internal::JSAgentBreakpoints breakpoints;
     for (int index = 0; index != handler->size(); ++index) {
         Internal::BreakpointData *data = handler->at(index);
         QString processedFilename = data->fileName;
         if (isShadowBuildProject())
             processedFilename = toShadowBuildFilename(data->fileName);
-        breakList << qMakePair(processedFilename, data->lineNumber);
+        Internal::JSAgentBreakpointData bp;
+        bp.fileName = processedFilename.toUtf8();
+        bp.lineNumber = data->lineNumber;
+        bp.functionName = data->funcName.toUtf8();
+        breakpoints.insert(bp);
     }
 
     QByteArray reply;
     QDataStream rs(&reply, QIODevice::WriteOnly);
     rs << QByteArray("BREAKPOINTS");
-    rs << breakList;
-    //qDebug() << Q_FUNC_INFO << breakList;
+    rs << breakpoints;
+    //qDebug() << Q_FUNC_INFO << breakpoints;
     sendMessage(reply);
 }
 
 bool QmlEngine::acceptsBreakpoint(const Internal::BreakpointData *br)
 {
-    return br->fileName.endsWith(QLatin1String("qml"))
-        || br->fileName.endsWith(QLatin1String("js"));
+    return br->fileName.endsWith(QLatin1String(".qml"))
+        || br->fileName.endsWith(QLatin1String(".js"));
 }
 
 void QmlEngine::loadSymbols(const QString &moduleName)
@@ -624,11 +658,12 @@ void QmlEngine::messageReceived(const QByteArray &message)
     QByteArray command;
     stream >> command;
 
-    showMessage(QLatin1String("RECEIVED RESPONSE: ") + Internal::quoteUnprintableLatin1(message));
+    showMessage(QLatin1String("RECEIVED RESPONSE: ")
+        + Internal::quoteUnprintableLatin1(message));
+
     if (command == "STOPPED") {
-        if (state() == InferiorRunOk) {
+        if (state() == InferiorRunOk)
             notifyInferiorSpontaneousStop();
-        }
 
         Internal::StackFrames stackFrames;
         QList<Internal::WatchData> watches;
@@ -684,11 +719,13 @@ void QmlEngine::messageReceived(const QByteArray &message)
             // Make breakpoint non-pending
             //
             QString file;
+            QString function;
             int line = -1;
 
             if (!stackFrames.isEmpty()) {
                 file = stackFrames.at(0).file;
                 line = stackFrames.at(0).line;
+                function = stackFrames.at(0).function;
 
                 if (isShadowBuildProject()) {
                     file = fromShadowBuildFilename(file);
@@ -700,11 +737,11 @@ void QmlEngine::messageReceived(const QByteArray &message)
                 Internal::BreakpointData *data = handler->at(index);
                 QString processedFilename = data->fileName;
 
-                if (processedFilename == file
-                        && data->lineNumber == line) {
+                if (processedFilename == file && data->lineNumber == line) {
                     data->pending = false;
                     data->bpFileName = file;
                     data->bpLineNumber = line;
+                    data->bpFuncName = function;
                     handler->updateMarker(data);
                 }
             }
index 00dd7c3..8bdb23c 100644 (file)
@@ -835,7 +835,7 @@ bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int ro
             const int index = handler->findWatchPointIndexByAddress(address);
             if (index == -1) {
                 BreakpointData *data = new BreakpointData;
-                data->type = BreakpointData::WatchpointType;
+                data->type = Watchpoint;
                 data->address = address;
                 handler->appendBreakpoint(data);
             } else {