From c50dd8508807ba10e816a0e32f7ed60fc990df48 Mon Sep 17 00:00:00 2001
From: hjk <qtc-committer@nokia.com>
Date: Wed, 19 May 2010 12:00:01 +0200
Subject: [PATCH] debugger: show return value of last function call in Locals
 and Watchers view

Works only with gdb/Python so far.
---
 share/qtcreator/gdbmacros/dumper.py          | 18 ++++-
 src/plugins/debugger/debuggermanager.cpp     | 17 ++++-
 src/plugins/debugger/gdb/gdbengine.cpp       | 15 +++-
 src/plugins/debugger/gdb/gdbengine.h         |  4 ++
 src/plugins/debugger/gdb/pythongdbengine.cpp |  6 +-
 src/plugins/debugger/watchhandler.cpp        | 14 ++++
 src/plugins/debugger/watchhandler.h          |  3 +-
 src/plugins/debugger/watchwindow.h           |  2 +-
 tests/manual/gdbdebugger/simple/app.cpp      | 75 ++++++++++++++------
 9 files changed, 124 insertions(+), 30 deletions(-)

diff --git a/share/qtcreator/gdbmacros/dumper.py b/share/qtcreator/gdbmacros/dumper.py
index e31b15471c7..8cf4a744ad2 100644
--- a/share/qtcreator/gdbmacros/dumper.py
+++ b/share/qtcreator/gdbmacros/dumper.py
@@ -385,6 +385,8 @@ def listOfLocals(varList):
     hasBlock = 'block' in __builtin__.dir(frame)
 
     items = []
+    #warn("HAS BLOCK: %s" % hasBlock);
+    #warn("IS GOOD GDB: %s" % isGoodGdb());
     if hasBlock and isGoodGdb():
         #warn("IS GOOD: %s " % varList)
         try:
@@ -780,6 +782,7 @@ class FrameCommand(gdb.Command):
         formats = {}
         watchers = ""
         expandedINames = ""
+        resultVarName = ""
         for arg in args.split(' '):
             pos = arg.find(":") + 1
             if arg.startswith("options:"):
@@ -787,6 +790,8 @@ class FrameCommand(gdb.Command):
             elif arg.startswith("vars:"):
                 if len(arg[pos:]) > 0:
                     varList = arg[pos:].split(",")
+            elif arg.startswith("resultvarname:"):
+                resultVarName = arg[pos:]
             elif arg.startswith("expanded:"):
                 expandedINames = set(arg[pos:].split(","))
             elif arg.startswith("typeformats:"):
@@ -847,7 +852,18 @@ class FrameCommand(gdb.Command):
         #
         # Locals
         #
-        for item in listOfLocals(varList):
+        locals = listOfLocals(varList);
+
+        # Take care of the return value of the last function call.
+        if len(resultVarName) > 0:
+            try:
+                value = parseAndEvaluate(resultVarName)
+                locals.append(Item(value, "return", resultVarName, "return"))
+            except:
+                # Don't bother. It's only supplementary information anyway.
+                pass
+
+        for item in locals:
           with OutputSafer(d, "", ""):
             d.anonNumber = -1
             #warn("ITEM NAME %s: " % item.name)
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index 905495bc3ac..8a3f2e150fe 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -297,14 +297,15 @@ struct DebuggerManagerPrivate
     DebuggerManagerActions m_actions;
 
     QWidget *m_breakWindow;
+    QWidget *m_returnWindow;
     QWidget *m_localsWindow;
+    QWidget *m_watchersWindow;
     QWidget *m_registerWindow;
     QWidget *m_modulesWindow;
     QWidget *m_snapshotWindow;
     SourceFilesWindow *m_sourceFilesWindow;
     QWidget *m_stackWindow;
     QWidget *m_threadsWindow;
-    QWidget *m_watchersWindow;
     DebuggerOutputWindow *m_outputWindow;
 
     bool m_busy;
@@ -401,6 +402,8 @@ void DebuggerManager::init()
     d->m_sourceFilesWindow->setObjectName(QLatin1String("CppDebugSources"));
     d->m_threadsWindow = new ThreadsWindow;
     d->m_threadsWindow->setObjectName(QLatin1String("CppDebugThreads"));
+    d->m_returnWindow = new WatchWindow(WatchWindow::ReturnType, this);
+    d->m_returnWindow->setObjectName(QLatin1String("CppDebugReturn"));
     d->m_localsWindow = new WatchWindow(WatchWindow::LocalsType, this);
     d->m_localsWindow->setObjectName(QLatin1String("CppDebugLocals"));
     d->m_watchersWindow = new WatchWindow(WatchWindow::WatchersType, this);
@@ -484,8 +487,13 @@ void DebuggerManager::init()
     d->m_registerHandler = new RegisterHandler;
     registerView->setModel(d->m_registerHandler->model());
 
-    // Locals
+
+    // Return Value
     d->m_watchHandler = new WatchHandler(this);
+    QTreeView *returnView = qobject_cast<QTreeView *>(d->m_returnWindow);
+    returnView->setModel(d->m_watchHandler->model(ReturnWatch));
+
+    // Locals
     QTreeView *localsView = qobject_cast<QTreeView *>(d->m_localsWindow);
     localsView->setModel(d->m_watchHandler->model(LocalsWatch));
 
@@ -633,6 +641,7 @@ void DebuggerManager::init()
     localsAndWatchers->setObjectName(QLatin1String("CppDebugLocalsAndWatchers"));
     localsAndWatchers->setWindowTitle(d->m_localsWindow->windowTitle());
     localsAndWatchers->addWidget(d->m_localsWindow);
+    localsAndWatchers->addWidget(d->m_returnWindow);
     localsAndWatchers->addWidget(d->m_watchersWindow);
     //localsAndWatchers->addWidget(d->m_tooltipWindow);
     localsAndWatchers->setStretchFactor(0, 3);
@@ -1365,6 +1374,7 @@ void DebuggerManager::setBusyCursor(bool busy)
 
     QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor);
     d->m_breakWindow->setCursor(cursor);
+    d->m_returnWindow->setCursor(cursor);
     d->m_localsWindow->setCursor(cursor);
     d->m_modulesWindow->setCursor(cursor);
     d->m_outputWindow->setCursor(cursor);
@@ -1947,6 +1957,7 @@ static void changeFontSize(QWidget *widget, int size)
 void DebuggerManager::fontSettingsChanged(const TextEditor::FontSettings &settings)
 {
     int size = settings.fontZoom() * settings.fontSize() / 100;
+    changeFontSize(d->m_returnWindow, size);
     changeFontSize(d->m_localsWindow, size);
     changeFontSize(d->m_watchersWindow, size);
     changeFontSize(d->m_breakWindow, size);
@@ -1968,6 +1979,8 @@ void DebuggerManager::updateWatchersWindow()
 {
     d->m_watchersWindow->setVisible(
         d->m_watchHandler->model(WatchersWatch)->rowCount(QModelIndex()) > 0);
+    d->m_returnWindow->setVisible(
+        d->m_watchHandler->model(ReturnWatch)->rowCount(QModelIndex()) > 0);
 }
 
 void DebuggerManager::openTextEditor(const QString &titlePattern,
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index 36037e631d7..1cde8b29ed3 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -274,6 +274,7 @@ void GdbEngine::initializeVariables()
     m_pendingLogStreamOutput.clear();
 
     m_inbuffer.clear();
+    m_resultVarName.clear();
 
     m_commandTimer->stop();
 
@@ -1290,7 +1291,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
     }
 #endif
 
-    // seen on XP after removing a breakpoint while running
+    // This was seen on XP after removing a breakpoint while running
     //  >945*stopped,reason="signal-received",signal-name="SIGTRAP",
     //  signal-meaning="Trace/breakpoint trap",thread-id="2",
     //  frame={addr="0x7c91120f",func="ntdll!DbgUiConnectToDbg",
@@ -1333,6 +1334,18 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
         }
     }
 
+    // Show return value if possible, usually with reason "function-finished".
+    // *stopped,reason="function-finished",frame={addr="0x080556da",
+    // func="testReturnValue",args=[],file="/../app.cpp",
+    // fullname="/../app.cpp",line="1611"},gdb-result-var="$1",
+    // return-value="{d = 0x808d998}",thread-id="1",stopped-threads="all",
+    // core="1"
+    GdbMi resultVar = data.findChild("gdb-result-var");
+    if (resultVar.isValid())
+        m_resultVarName = resultVar.data();
+    else
+        m_resultVarName.clear();
+
     bool initHelpers = m_debuggingHelperState == DebuggingHelperUninitialized
                        || m_debuggingHelperState == DebuggingHelperLoadTried;
     // Don't load helpers on stops triggered by signals unless it's
diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h
index a1b94ae9ec5..3b1f7d49d44 100644
--- a/src/plugins/debugger/gdb/gdbengine.h
+++ b/src/plugins/debugger/gdb/gdbengine.h
@@ -170,6 +170,10 @@ private:
 
     AbstractGdbAdapter *m_gdbAdapter;
 
+    // Name of the convenience variable containing the last
+    // known function return value.
+    QByteArray m_resultVarName;
+
 private: ////////// Gdb Command Management //////////
 
     public: // Otherwise the Qt flag macros are unhappy.
diff --git a/src/plugins/debugger/gdb/pythongdbengine.cpp b/src/plugins/debugger/gdb/pythongdbengine.cpp
index db59f7f6b94..fa46242f52a 100644
--- a/src/plugins/debugger/gdb/pythongdbengine.cpp
+++ b/src/plugins/debugger/gdb/pythongdbengine.cpp
@@ -85,8 +85,12 @@ void GdbEngine::updateLocalsPython(const QByteArray &varList)
         options += "defaults,";
     options.chop(1);
 
+    QByteArray resultVar;
+    if (!m_resultVarName.isEmpty())
+        resultVar = "resultvarname:" + m_resultVarName + ' ';
+
     postCommand("bb options:" + options + " vars:" + varList + ' '
-            + expanded + " watchers:" + watchers.toHex(),
+            + resultVar + expanded + " watchers:" + watchers.toHex(),
         WatchUpdate, CB(handleStackFramePython));
 }
 
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index b4cfd13f26e..f10e8fc5ed3 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -120,6 +120,10 @@ WatchModel::WatchModel(WatchHandler *handler, WatchType type)
     m_root->parent = 0;
 
     switch (m_type) {
+        case ReturnWatch:
+            m_root->iname = "return";
+            m_root->name = WatchHandler::tr("Return Value");
+            break;
         case LocalsWatch:
             m_root->iname = "local";
             m_root->name = WatchHandler::tr("Locals");
@@ -964,6 +968,7 @@ WatchHandler::WatchHandler(DebuggerManager *manager)
     m_expandPointers = true;
     m_inChange = false;
 
+    m_return = new WatchModel(this, ReturnWatch);
     m_locals = new WatchModel(this, LocalsWatch);
     m_watchers = new WatchModel(this, WatchersWatch);
     m_tooltips = new WatchModel(this, TooltipsWatch);
@@ -981,6 +986,7 @@ WatchHandler::WatchHandler(DebuggerManager *manager)
 void WatchHandler::beginCycle()
 {
     ++generationCounter;
+    m_return->beginCycle();
     m_locals->beginCycle();
     m_watchers->beginCycle();
     m_tooltips->beginCycle();
@@ -988,6 +994,7 @@ void WatchHandler::beginCycle()
 
 void WatchHandler::endCycle()
 {
+    m_return->endCycle();
     m_locals->endCycle();
     m_watchers->endCycle();
     m_tooltips->endCycle();
@@ -997,8 +1004,10 @@ void WatchHandler::endCycle()
 void WatchHandler::cleanup()
 {
     m_expandedINames.clear();
+    m_return->reinitialize();
     m_locals->reinitialize();
     m_tooltips->reinitialize();
+    m_return->m_fetchTriggered.clear();
     m_locals->m_fetchTriggered.clear();
     m_watchers->m_fetchTriggered.clear();
     m_tooltips->m_fetchTriggered.clear();
@@ -1014,6 +1023,7 @@ void WatchHandler::cleanup()
 
 void WatchHandler::emitAllChanged()
 {
+    m_return->emitAllChanged();
     m_locals->emitAllChanged();
     m_watchers->emitAllChanged();
     m_tooltips->emitAllChanged();
@@ -1337,6 +1347,7 @@ void WatchHandler::loadSessionData()
 WatchModel *WatchHandler::model(WatchType type) const
 {
     switch (type) {
+        case ReturnWatch: return m_return;
         case LocalsWatch: return m_locals;
         case WatchersWatch: return m_watchers;
         case TooltipsWatch: return m_tooltips;
@@ -1347,6 +1358,8 @@ WatchModel *WatchHandler::model(WatchType type) const
 
 WatchModel *WatchHandler::modelForIName(const QByteArray &iname) const
 {
+    if (iname.startsWith("return"))
+        return m_return;
     if (iname.startsWith("local"))
         return m_locals;
     if (iname.startsWith("tooltip"))
@@ -1374,6 +1387,7 @@ void WatchHandler::setFormat(const QString &type, int format)
 {
     m_typeFormats[type] = format;
     saveTypeFormats();
+    m_return->emitDataChanged(1);
     m_locals->emitDataChanged(1);
     m_watchers->emitDataChanged(1);
     m_tooltips->emitDataChanged(1);
diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h
index 8890dee5079..9a4dad79a80 100644
--- a/src/plugins/debugger/watchhandler.h
+++ b/src/plugins/debugger/watchhandler.h
@@ -51,7 +51,7 @@ namespace Internal {
 
 class WatchItem;
 class WatchHandler;
-enum WatchType { LocalsWatch, WatchersWatch, TooltipsWatch };
+enum WatchType { ReturnWatch, LocalsWatch, WatchersWatch, TooltipsWatch };
 
 enum WatchRoles
 {
@@ -206,6 +206,7 @@ private:
     // Items expanded in the Locals & Watchers view.
     QSet<QByteArray> m_expandedINames; 
 
+    WatchModel *m_return;
     WatchModel *m_locals;
     WatchModel *m_watchers;
     WatchModel *m_tooltips;
diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h
index e252a9f14a7..b08f9282039 100644
--- a/src/plugins/debugger/watchwindow.h
+++ b/src/plugins/debugger/watchwindow.h
@@ -48,7 +48,7 @@ class WatchWindow : public QTreeView
     Q_OBJECT
 
 public:
-    enum Type { LocalsType, TooltipType, WatchersType };
+    enum Type { ReturnType, LocalsType, TooltipType, WatchersType };
 
     WatchWindow(Type type, DebuggerManager *manager, QWidget *parent = 0);
     void setType(Type type) { m_type = type; }
diff --git a/tests/manual/gdbdebugger/simple/app.cpp b/tests/manual/gdbdebugger/simple/app.cpp
index 03c191f9a0f..106e6a32bb8 100644
--- a/tests/manual/gdbdebugger/simple/app.cpp
+++ b/tests/manual/gdbdebugger/simple/app.cpp
@@ -318,18 +318,19 @@ void testAnonymous()
 #endif
 }
 
-void testFunctionPointer()
+typedef void (*func_t)();
+func_t testFunctionPointer()
 {
-    typedef void (*func_t)();
     func_t f1 = testAnonymous;
-    func_t f2 = testFunctionPointer;
-    func_t f3 = testFunctionPointer;
+    func_t f2 = testPeekAndPoke3;
+    func_t f3 = testPeekAndPoke3;
     Q_UNUSED(f1);
     Q_UNUSED(f2);
     Q_UNUSED(f3);
+    return f1;
 }
 
-void testQByteArray()
+QByteArray testQByteArray()
 {
     QByteArray ba = "Hello";
     ba += '"';
@@ -345,6 +346,7 @@ void testQByteArray()
     ba += char(0);
     ba += 1;
     ba += 2;
+    return ba;
 }
 
 static void throwit1()
@@ -368,7 +370,7 @@ int testCatchThrow()
     return gotit;
 }
 
-void testQDateTime()
+QDateTime testQDateTime()
 {
     QDateTime date;
     date = QDateTime::currentDateTime();
@@ -376,18 +378,20 @@ void testQDateTime()
     date = date.addSecs(5);
     date = date.addSecs(5);
     date = date.addSecs(5);
+    return date;
 }
 
-void testQFileInfo()
+QFileInfo testQFileInfo()
 {
     QFileInfo fi("/tmp/t");
     QString s = fi.absoluteFilePath();
     s = fi.bundleName();
     s = fi.bundleName();
     s = fi.bundleName();
+    return fi;
 }
 
-void testQHash()
+QHash<int, float> testQHash()
 {
 #if 1
     QHash<int, float> hgg0;
@@ -439,6 +443,7 @@ void testQHash()
     hash.insert("Welt", QPointer<QObject>(&ob));
     hash.insert(".", QPointer<QObject>(&ob));
 #endif
+    return hgg0;
 }
 
 void testQImage()
@@ -908,7 +913,7 @@ void testStdHashSet()
 #endif
 }
 
-void testStdList()
+std::list<int> testStdList()
 {
     std::list<int> big;
     for (int i = 0; i < 10000; ++i)
@@ -948,6 +953,7 @@ void testStdList()
     vec.push_back(true);
     vec.push_back(false);
 #endif
+    return big;
 }
 
 void testStdMap()
@@ -1008,7 +1014,7 @@ void testStdMap()
 #endif
 }
 
-void testStdSet()
+std::set<int> testStdSet()
 {
     std::set<int> hgg0;
     hgg0.insert(11);
@@ -1022,9 +1028,10 @@ void testStdSet()
     std::set<QPointer<QObject> > hash;
     QPointer<QObject> ptr(&ob);
 #endif
+    return hgg0;
 }
 
-void testStdStack()
+std::stack<int> testStdStack()
 {
     std::stack<int *> plist1;
     plist1.push(new int(1));
@@ -1045,9 +1052,11 @@ void testStdStack()
     std::stack<Foo> flist;
     flist.push(1);
     flist.push(2);
+
+    return flist2;
 }
 
-void testStdString()
+std::string testStdString()
 {
     QString foo;
     std::string str;
@@ -1083,9 +1092,11 @@ void testStdString()
     v.push_back(str);
     v.push_back(str);
     v.push_back(str);
+
+    return str;
 }
 
-void testStdVector()
+std::vector<int> testStdVector()
 {
     std::vector<int *> plist1;
     plist1.push_back(new int(1));
@@ -1119,6 +1130,8 @@ void testStdVector()
     std::vector<bool> vec;
     vec.push_back(true);
     vec.push_back(false);
+
+    return flist2;
 }
 
 void testQStandardItemModel()
@@ -1140,7 +1153,7 @@ void testQStandardItemModel()
     ++i;
 }
 
-void testQStack()
+QStack<int> testQStack()
 {
     QVector<int> bigv;
     for (int i = 0; i < 10; ++i)
@@ -1162,9 +1175,10 @@ void testQStack()
     QStack<bool> vec;
     vec.append(true);
     vec.append(false);
+    return big;
 }
 
-void testQString()
+QString testQString()
 {
     QUrl url(QString("http://www.nokia.com"));
 
@@ -1176,6 +1190,7 @@ void testQString()
     str += " World ";
     str += " World ";
     str += " World ";
+    return str;
 }
 
 void testQString3()
@@ -1194,7 +1209,7 @@ void testQString3()
     delete pstring;
 }
 
-void testQStringList()
+QStringList testQStringList()
 {
     QStringList l;
     l << "Hello ";
@@ -1202,14 +1217,16 @@ void testQStringList()
     l << " fat ";
     l.takeFirst();
     l << " World ";
+    return l;
 }
 
-void testStruct()
+Foo testStruct()
 {
     Foo f(2);
     f.doit();
     f.doit();
     f.doit();
+    return f;
 }
 
 class Thread : public QThread
@@ -1242,7 +1259,7 @@ void testQThread()
     thread2.wait();
 }
 
-void testQVariant1()
+QVariant testQVariant1()
 {
     QVariant v;
     v = 1;
@@ -1250,9 +1267,10 @@ void testQVariant1()
     v = "string";
     v = QRect(100, 200, 300, 400);
     v = 1;
+    return v;
 }
 
-void testQVariant2()
+QVariant testQVariant2()
 {
     QVariant value;
     QVariant::Type t = QVariant::String;
@@ -1295,18 +1313,20 @@ void testQVariant2()
     var.setValue(my);
     var.setValue(my);
 #endif
+    return value;
 }
 
-void testQVariant3()
+QVariant testQVariant3()
 {
     QList<int> list;
     list << 1 << 2 << 3;
     QVariant variant = qVariantFromValue(list);
     list.clear();
     list = qVariantValue<QList<int> >(variant);
+    return variant;
 }
 
-void testQVector()
+QVector<int> testQVector()
 {
     QVector<int> big(10000);
 
@@ -1326,15 +1346,18 @@ void testQVector()
     QVector<bool> vec;
     vec.append(true);
     vec.append(false);
+
+    return big;
 }
 
-void testQVectorOfQList()
+QVector<QList<int> > testQVectorOfQList()
 {
     QVector<QList<int> > v;
     QVector<QList<int> > *pv = &v;
     v.append(QList<int>() << 1);
     v.append(QList<int>() << 2 << 3);
     Q_UNUSED(pv);
+    return v;
 }
 
 
@@ -1600,10 +1623,16 @@ struct Color
     Color() { r = 1, g = 2, b = 3, a = 4; }
 };
 
-void testColor()
+Color testColor()
 {
     Color c;
     c.r = 5;
+    return c;
+}
+
+int fooii()
+{
+    return 3;
 }
 
 int main(int argc, char *argv[])
-- 
GitLab