[nemiver] New varobj aware variable walker



commit 59329f222e48d0a317a6804106f358fed97a1082
Author: Dodji Seketeli <dodji redhat com>
Date:   Sat May 30 11:45:30 2009 +0200

    New varobj aware variable walker
    
    	* configure.ac: Generate src/dbgengine/varobjwalker.conf from
    	src/dbgengine/varobjwalker.conf.in
    	* src/dbgengine/nmv-gdb-engine.cc:
    	(OnCreateVariableHandler::can_handle): Add more logging.
    	* src/dbgengine/nmv-i-var-walker.h: Cleanup the IVarWalker iface.
    	Remove some needless references from the APIs.
    	* src/dbgengine/nmv-var-walker.cc: Adjust API implementations.
    	* src/dbgengine/nmv-varobj-walker.cc: New implementation of
    	the IVarWalker interface. This one walks a variable that is backed
    	by GDB/MI a Variable Object and recursively unfolds it.
    	* src/dbgengine/Makefile.am: Add nmv-varobj-walker.cc to the build
    	system.
    	* src/dbgengine/varobjwalker.conf.in: The conf file of the
    	new varobjwalker DynMod.
    	* tests/test-varobj-walker.cc: New test for the varobj-walker.
    	* tests/Makefile.am: Add the new test-varobj-walker.cc to the build
    	system.
---
 configure.ac                                       |    1 +
 src/dbgengine/Makefile.am                          |   18 +-
 src/dbgengine/nmv-gdb-engine.cc                    |    2 +
 src/dbgengine/nmv-i-var-walker.h                   |   16 +-
 src/dbgengine/nmv-var-walker.cc                    |   40 ++--
 src/dbgengine/nmv-varobj-walker.cc                 |  303 ++++++++++++++++++++
 src/dbgengine/varobjwalker.conf.in                 |   10 +
 .../dbgperspective/menus/varinspectorpopup.xml     |    2 +
 tests/Makefile.am                                  |   10 +-
 tests/test-varobj-walker.cc                        |  190 ++++++++++++
 10 files changed, 560 insertions(+), 32 deletions(-)

diff --git a/configure.ac b/configure.ac
index 7de2564..63006ea 100644
--- a/configure.ac
+++ b/configure.ac
@@ -415,6 +415,7 @@ src/Makefile
   src/dbgengine/cpptrait.conf
   src/dbgengine/varlist.conf
   src/dbgengine/varwalker.conf
+  src/dbgengine/varobjwalker.conf
   src/dbgengine/varlistwalker.conf
   src/confmgr/Makefile
   src/confmgr/gconfmgr.conf
diff --git a/src/dbgengine/Makefile.am b/src/dbgengine/Makefile.am
index ad55059..06050d1 100644
--- a/src/dbgengine/Makefile.am
+++ b/src/dbgengine/Makefile.am
@@ -7,13 +7,19 @@ varlistmoddir= NEMIVER_MODULES_DIR@
 varwalkermod_LTLIBRARIES=libvarwalkermod.la
 varwalkermoddir= NEMIVER_MODULES_DIR@
 
+varobjwalkermod_LTLIBRARIES=libvarobjwalkermod.la
+varobjwalkermoddir= NEMIVER_MODULES_DIR@
+
 varlistwalkermod_LTLIBRARIES=libvarlistwalkermod.la
 varlistwalkermoddir= NEMIVER_MODULES_DIR@
 
 cpptraitmod_LTLIBRARIES=libcpptraitmod.la
 cpptraitmoddir= NEMIVER_MODULES_DIR@
 
-noinst_LTLIBRARIES=libgdbmiparser.la libdbgcommon.la libgdbengine.la
+noinst_LTLIBRARIES=\
+libgdbmiparser.la \
+libdbgcommon.la \
+libgdbengine.la
 
 idebuggerheaders= \
 nmv-i-debugger.h
@@ -46,6 +52,10 @@ libvarwalkermod_la_SOURCES= \
 $(ivarwalkerheaders) \
 nmv-var-walker.cc
 
+libvarobjwalkermod_la_SOURCES= \
+$(ivarwalkerheaders) \
+nmv-varobj-walker.cc
+
 libvarlistwalkermod_la_SOURCES= \
 $(ivarlistwalkerheaders) \
 nmv-var-list-walker.cc
@@ -93,6 +103,10 @@ libvarwalkermod_la_LDFLAGS=-module -avoid-version
 libvarwalkermod_la_LIBADD= NEMIVERCOMMON_LIBS@ \
 	$(top_builddir)/src/common/libnemivercommon.la
 
+libvarobjwalkermod_la_LDFLAGS=-module -avoid-version
+libvarobjwalkermod_la_LIBADD= NEMIVERCOMMON_LIBS@ \
+	$(top_builddir)/src/common/libnemivercommon.la
+
 libvarlistwalkermod_la_LDFLAGS=-module -avoid-version
 libvarlistwalkermod_la_LIBADD= NEMIVERCOMMON_LIBS@ \
 	$(top_builddir)/src/common/libnemivercommon.la
@@ -101,7 +115,7 @@ libgdbmiparser_la_LIBADD= \
 @NEMIVERCOMMON_LIBS@ \
 $(top_builddir)/src/common/libnemivercommon.la
 
-config_DATA=gdbengine.conf varlist.conf varwalker.conf varlistwalker.conf cpptrait.conf
+config_DATA=gdbengine.conf varlist.conf varwalker.conf varobjwalker.conf varlistwalker.conf cpptrait.conf
 configdir= NEMIVER_SYSTEM_CONFIG_DIR@
 
 INCLUDES= NEMIVERCOMMON_CFLAGS@ -DENABLE_NLS=1 -DDATADIR=\"${datadir}\" \
diff --git a/src/dbgengine/nmv-gdb-engine.cc b/src/dbgengine/nmv-gdb-engine.cc
index 273c07e..b3068e8 100644
--- a/src/dbgengine/nmv-gdb-engine.cc
+++ b/src/dbgengine/nmv-gdb-engine.cc
@@ -2145,10 +2145,12 @@ struct OnCreateVariableHandler : public OutputHandler
         // Call the slot associated to IDebugger::create_variable (), if
         // any.
         if (a_in.command ().has_slot ()) {
+            LOG_DD ("calling IDebugger::create_variable slot");
             typedef sigc::slot<void, IDebugger::VariableSafePtr> SlotType;
             SlotType slot = a_in.command ().get_slot<SlotType> ();
             slot (a_in.output ().result_record ().variable ());
         }
+        LOG_DD ("emit IDebugger::variable_create_signal");
         // Emit the general IDebugger::variable_create_signal () signal
         m_engine->variable_created_signal ().emit
                             (a_in.output ().result_record ().variable (),
diff --git a/src/dbgengine/nmv-i-var-walker.h b/src/dbgengine/nmv-i-var-walker.h
index 825b292..ade767e 100644
--- a/src/dbgengine/nmv-i-var-walker.h
+++ b/src/dbgengine/nmv-i-var-walker.h
@@ -60,30 +60,30 @@ public:
     /// emitted each time one of the members node of a variable is
     /// visited.
     virtual sigc::signal<void,
-                         const IDebugger::VariableSafePtr&>&
-                                                visited_variable_node_signal () const = 0;
+                         const IDebugger::VariableSafePtr>
+                                    visited_variable_node_signal () const = 0;
     /// emitted when the root variable (the one the walker has been connected
     /// has been totally visited. That means when all its members nodes have
     /// been visited.
     virtual sigc::signal<void,
-                         const IDebugger::VariableSafePtr&>&
+                         const IDebugger::VariableSafePtr>
                                         visited_variable_signal () const = 0;
     ///@}
 
     /// connect the walker to a variable and to a debugger
     /// that will be use to walk that variable
-    virtual void connect (IDebuggerSafePtr &a_debugger,
+    virtual void connect (IDebuggerSafePtr a_debugger,
                           const UString &a_var_name) = 0;
 
-    virtual void connect (IDebuggerSafePtr &a_debugger,
-                          const IDebugger::VariableSafePtr &a_var) = 0;
+    virtual void connect (IDebuggerSafePtr a_debugger,
+                          const IDebugger::VariableSafePtr a_var) = 0;
 
-    virtual void do_walk_variable (const UString &a_cookie="") = 0;
+    virtual void do_walk_variable (const UString &a_cookie = "") = 0;
 
     /// gets the root variable this walker is connected to.
     /// this will return a non null variable if and only if
     /// the visited_root_variabls_signal() has been emited already.
-    virtual const IDebugger::VariableSafePtr& get_variable () const = 0;
+    virtual const IDebugger::VariableSafePtr get_variable () const = 0;
 
     /// gets the debugger the walker is connected to
     virtual IDebuggerSafePtr get_debugger () const = 0;
diff --git a/src/dbgengine/nmv-var-walker.cc b/src/dbgengine/nmv-var-walker.cc
index 86512b0..ba61343 100644
--- a/src/dbgengine/nmv-var-walker.cc
+++ b/src/dbgengine/nmv-var-walker.cc
@@ -57,13 +57,14 @@ struct SafePtrCmp {
         return (l.get () < r.get ());
     }
 };
+
 class VarWalker : public IVarWalker , public sigc::trackable {
 
     mutable sigc::signal<void,
-                 const IDebugger::VariableSafePtr&> m_visited_variable_node_signal;
+                 const IDebugger::VariableSafePtr> m_visited_variable_node_signal;
 
     mutable sigc::signal<void,
-                 const IDebugger::VariableSafePtr&>
+                         const IDebugger::VariableSafePtr>
                                             m_visited_variable_signal;
 
     mutable GDBEngineSafePtr m_debugger;
@@ -74,13 +75,13 @@ class VarWalker : public IVarWalker , public sigc::trackable {
     IDebugger::VariableSafePtr m_root_var;
 
     void on_variable_value_signal (const UString &a_name,
-                                   const IDebugger::VariableSafePtr &a_var,
+                                   const IDebugger::VariableSafePtr a_var,
                                    const UString &a_cookie);
 
-    void on_variable_value_set_signal (const IDebugger::VariableSafePtr &a_var,
+    void on_variable_value_set_signal (const IDebugger::VariableSafePtr a_var,
                                        const UString &a_cookie);
 
-    void on_variable_type_set_signal (const IDebugger::VariableSafePtr &a_var,
+    void on_variable_type_set_signal (const IDebugger::VariableSafePtr a_var,
                                       const UString &a_cookie);
 
     void get_type_of_all_members (const IDebugger::VariableSafePtr a_from);
@@ -95,28 +96,29 @@ public:
     //********************
     //<event getters>
     //********************
-    sigc::signal<void, const IDebugger::VariableSafePtr&>&
+    sigc::signal<void, const IDebugger::VariableSafePtr>
                                         visited_variable_node_signal () const;
-    sigc::signal<void, const IDebugger::VariableSafePtr&>&
+    sigc::signal<void, const IDebugger::VariableSafePtr>
                                         visited_variable_signal () const;
     //********************
     //</event getters>
     //********************
 
-    void connect (IDebuggerSafePtr &a_debugger, const UString &a_var_name);
+    void connect (IDebuggerSafePtr a_debugger, const UString &a_var_name);
 
-    void connect (IDebuggerSafePtr &a_debugger, const IDebugger::VariableSafePtr &a_var);
+    void connect (IDebuggerSafePtr a_debugger,
+                  const IDebugger::VariableSafePtr a_var);
 
     void do_walk_variable (const UString &a_cookie="");
 
-    const IDebugger::VariableSafePtr& get_variable () const;
+    const IDebugger::VariableSafePtr get_variable () const;
 
     IDebuggerSafePtr get_debugger () const ;
 };//end class VarWalker
 
 void
 VarWalker::on_variable_value_signal (const UString &a_name,
-                                     const IDebugger::VariableSafePtr &a_var,
+                                     const IDebugger::VariableSafePtr a_var,
                                      const UString &a_cookie)
 {
     if (a_name.raw () == "") {}
@@ -135,7 +137,7 @@ VarWalker::on_variable_value_signal (const UString &a_name,
 }
 
 void
-VarWalker::on_variable_value_set_signal (const IDebugger::VariableSafePtr &a_var,
+VarWalker::on_variable_value_set_signal (const IDebugger::VariableSafePtr a_var,
                                          const UString &a_cookie)
 {
     if (a_cookie.raw () != m_cookie.raw ()) {
@@ -153,7 +155,7 @@ VarWalker::on_variable_value_set_signal (const IDebugger::VariableSafePtr &a_var
 }
 
 void
-VarWalker::on_variable_type_set_signal (const IDebugger::VariableSafePtr &a_var,
+VarWalker::on_variable_type_set_signal (const IDebugger::VariableSafePtr a_var,
                                         const UString &a_cookie)
 {
     if (a_cookie.raw () != m_cookie.raw ()) {
@@ -234,20 +236,20 @@ VarWalker::get_type_of_all_members (const IDebugger::VariableSafePtr a_from)
     LOG_DD ("m_vars_to_visit.size () = " << (int)m_vars_to_visit.size ());
 }
 
-sigc::signal<void, const IDebugger::VariableSafePtr&>&
+sigc::signal<void, const IDebugger::VariableSafePtr>
 VarWalker::visited_variable_node_signal () const
 {
     return m_visited_variable_node_signal;
 }
 
-sigc::signal<void, const IDebugger::VariableSafePtr&>&
+sigc::signal<void, const IDebugger::VariableSafePtr>
 VarWalker::visited_variable_signal () const
 {
     return m_visited_variable_signal;
 }
 
 void
-VarWalker::connect (IDebuggerSafePtr &a_debugger,
+VarWalker::connect (IDebuggerSafePtr a_debugger,
                     const UString &a_var_name)
 {
     m_debugger = a_debugger.do_dynamic_cast<GDBEngine> ();
@@ -265,8 +267,8 @@ VarWalker::connect (IDebuggerSafePtr &a_debugger,
 }
 
 void
-VarWalker::connect (IDebuggerSafePtr &a_debugger,
-                    const IDebugger::VariableSafePtr &a_var)
+VarWalker::connect (IDebuggerSafePtr a_debugger,
+                    const IDebugger::VariableSafePtr a_var)
 {
     m_debugger = a_debugger.do_dynamic_cast<GDBEngine> ();
     THROW_IF_FAIL (m_debugger);
@@ -304,7 +306,7 @@ VarWalker::do_walk_variable (const UString &a_cookie)
     }
 }
 
-const IDebugger::VariableSafePtr&
+const IDebugger::VariableSafePtr
 VarWalker::get_variable () const
 {
     return m_root_var;
diff --git a/src/dbgengine/nmv-varobj-walker.cc b/src/dbgengine/nmv-varobj-walker.cc
new file mode 100644
index 0000000..a60b1cd
--- /dev/null
+++ b/src/dbgengine/nmv-varobj-walker.cc
@@ -0,0 +1,303 @@
+//Author: Dodji Seketeli
+/*
+ *This file is part of the Nemiver project
+ *
+ *Nemiver is free software; you can redistribute
+ *it and/or modify it under the terms of
+ *the GNU General Public License as published by the
+ *Free Software Foundation; either version 2,
+ *or (at your option) any later version.
+ *
+ *Nemiver is distributed in the hope that it will
+ *be useful, but WITHOUT ANY WARRANTY;
+ *without even the implied warranty of
+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *See the GNU General Public License for more details.
+ *
+ *You should have received a copy of the
+ *GNU General Public License along with Nemiver;
+ *see the file COPYING.
+ *If not, write to the Free Software Foundation,
+ *Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *See COPYRIGHT file copyright information.
+ */
+#include <list>
+#include <map>
+#include "nmv-i-var-walker.h"
+#include "nmv-gdb-engine.h"
+#include "common/nmv-sequence.h"
+
+using std::list;
+using std::map;
+using nemiver::common::DynamicModule;
+using nemiver::common::DynamicModuleSafePtr;
+using nemiver::common::DynModIface;
+using nemiver::common::DynModIfaceSafePtr;
+using nemiver::common::ObjectRef;
+using nemiver::common::ObjectUnref;
+
+typedef SafePtr<nemiver::GDBEngine, ObjectRef, ObjectUnref> GDBEngineSafePtr;
+
+NEMIVER_BEGIN_NAMESPACE (nemiver)
+
+const UString VAR_WALKER_COOKIE="var-walker-cookie";
+
+
+class VarobjWalker : public IVarWalker, public sigc::trackable
+{
+    mutable sigc::signal<void,
+                         const IDebugger::VariableSafePtr>
+                                         m_visited_variable_node_signal;
+    mutable sigc::signal<void,
+                         const IDebugger::VariableSafePtr>
+                                        m_visited_variable_signal;
+    IDebuggerSafePtr m_debugger;
+    IDebugger::VariableSafePtr m_variable;
+    UString m_var_name;
+    bool m_do_walk;
+    // The count of on going variable unfolding
+    int m_variable_unfolds;
+
+    VarobjWalker (); // Don't call this constructor.
+
+public:
+    VarobjWalker (DynamicModule *a_dynmod) :
+        IVarWalker (a_dynmod),
+        m_do_walk (false),
+        m_variable_unfolds (0)
+    {
+    }
+
+    ~VarobjWalker ()
+    {
+        if (m_variable && m_debugger)
+            m_debugger->delete_variable (m_variable);
+    }
+
+    sigc::signal<void,
+                 const IDebugger::VariableSafePtr>
+                                    visited_variable_node_signal () const;
+    sigc::signal<void,
+                 const IDebugger::VariableSafePtr>
+                                    visited_variable_signal () const;
+
+    void connect (IDebuggerSafePtr a_debugger,
+                  const UString &a_var_name);
+
+    void connect (IDebuggerSafePtr a_debugger,
+                  const IDebugger::VariableSafePtr a_var);
+
+    void do_walk_variable (const UString &a_cookie="");
+
+    const IDebugger::VariableSafePtr get_variable () const;
+
+    IDebuggerSafePtr get_debugger () const;
+
+    void do_walk_variable_real (const IDebugger::VariableSafePtr);
+
+    void on_variable_unfolded_signal (const IDebugger::VariableSafePtr a_var);
+
+    void on_variable_created_signal (const IDebugger::VariableSafePtr a_var);
+}; // end class VarobjWalker.
+
+sigc::signal<void,
+             const IDebugger::VariableSafePtr>
+VarobjWalker::visited_variable_node_signal () const
+{
+    return m_visited_variable_node_signal;
+}
+
+sigc::signal<void,
+             const IDebugger::VariableSafePtr>
+VarobjWalker::visited_variable_signal () const
+{
+    return m_visited_variable_signal;
+}
+
+void
+VarobjWalker::connect (IDebuggerSafePtr a_debugger,
+                       const UString &a_var_name)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+    THROW_IF_FAIL (a_debugger);
+    THROW_IF_FAIL (!a_var_name.empty ());
+
+    m_debugger = a_debugger;
+    m_var_name = a_var_name;
+    m_debugger->create_variable
+        (a_var_name,
+         sigc::mem_fun (*this, &VarobjWalker::on_variable_created_signal));
+
+}
+
+void
+VarobjWalker::connect (IDebuggerSafePtr a_debugger,
+                       const IDebugger::VariableSafePtr a_var)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+    THROW_IF_FAIL (a_debugger);
+    THROW_IF_FAIL (a_var);
+    // The variable must be backed by variable objects.
+    THROW_IF_FAIL (!a_var->internal_name ().empty ());
+
+    m_debugger = a_debugger;
+    m_variable = a_var;
+}
+
+void
+VarobjWalker::do_walk_variable (const UString &)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+    if (!m_variable) {
+        if (!m_var_name.empty ()) {
+            LOG_DD ("setting m_do_walk to true");
+            m_do_walk = true;
+            return;
+        } else {
+            THROW ("expecting a non null m_variable!");
+        }
+    }
+    do_walk_variable_real (m_variable);
+
+}
+
+const IDebugger::VariableSafePtr
+VarobjWalker::get_variable () const
+{
+    LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+    return m_variable;
+}
+
+IDebuggerSafePtr
+VarobjWalker::get_debugger () const
+{
+    LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+    return m_debugger;
+}
+
+void
+VarobjWalker::do_walk_variable_real (const IDebugger::VariableSafePtr a_var)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+    THROW_IF_FAIL (a_var);
+
+    if (a_var->needs_unfolding ()) {
+        LOG_DD ("needs unfolding");
+        m_variable_unfolds++;
+        m_debugger->unfold_variable
+            (a_var, sigc::mem_fun (*this,
+                                   &VarobjWalker::on_variable_unfolded_signal));
+    } else if (!a_var->members ().empty ()) {
+        LOG_DD ("children need visiting");
+        visited_variable_node_signal ().emit (a_var);
+        IDebugger::VariableList::const_iterator it;
+        for (it = a_var->members ().begin ();
+             it != a_var->members ().end ();
+             ++ it) {
+            do_walk_variable_real (*it);
+        }
+    } else {
+        LOG_DD ("else finished ?. m_variable_unfolds: "
+                << (int) m_variable_unfolds);
+        visited_variable_node_signal ().emit (a_var);
+        if (m_variable_unfolds == 0)
+            visited_variable_signal ().emit (a_var);
+    }
+
+}
+
+void
+VarobjWalker::on_variable_unfolded_signal (const IDebugger::VariableSafePtr a_var)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+    NEMIVER_TRY
+
+    m_variable_unfolds--;
+    visited_variable_node_signal ().emit (a_var);
+    do_walk_variable_real (a_var);
+    if (m_variable_unfolds == 0) {
+        THROW_IF_FAIL (m_variable);
+        visited_variable_signal ().emit (m_variable);
+    }
+
+    NEMIVER_CATCH_NOX
+}
+
+void
+VarobjWalker::on_variable_created_signal (const IDebugger::VariableSafePtr a_var)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+    NEMIVER_TRY
+
+    THROW_IF_FAIL (a_var);
+
+    m_variable = a_var;
+
+    if (m_do_walk) {
+        do_walk_variable ();
+        m_do_walk = false;
+    } else {
+        LOG_DD ("m_do_walk is false");
+    }
+
+    NEMIVER_CATCH_NOX
+}
+
+// the dynmod used to instanciate the VarWalker service object
+// and return an interface on it.
+struct VarobjWalkerDynMod : public  DynamicModule
+{
+
+    void
+    get_info (Info &a_info) const
+    {
+        const static Info s_info ("VarobjWalker",
+                                  "The Variable Object Walker dynmod. "
+                                  "Implements the IVarWalker interface",
+                                  "1.0");
+        a_info = s_info;
+    }
+
+    void
+    do_init ()
+    {
+    }
+
+    bool
+    lookup_interface (const std::string &a_iface_name,
+                      DynModIfaceSafePtr &a_iface)
+    {
+        if (a_iface_name == "IVarWalker") {
+            a_iface.reset (new VarobjWalker (this));
+        } else {
+            return false;
+        }
+        return true;
+    }
+}; //end class VarobjListDynMod
+
+//the dynmod initial factory.
+extern "C"
+{
+
+bool
+NEMIVER_API nemiver_common_create_dynamic_module_instance (void **a_new_instance)
+{
+    *a_new_instance = new nemiver::VarobjWalkerDynMod ();
+    return (*a_new_instance != 0);
+}
+
+}
+
+NEMIVER_END_NAMESPACE(nemiver)
+
+
diff --git a/src/dbgengine/varobjwalker.conf.in b/src/dbgengine/varobjwalker.conf.in
new file mode 100644
index 0000000..cd39d37
--- /dev/null
+++ b/src/dbgengine/varobjwalker.conf.in
@@ -0,0 +1,10 @@
+<moduleconfig>
+    <module>
+        <name>varobjwalker</name>
+        <libraryname>varobjwalkermod</libraryname>
+    </module>
+    <customsearchpaths>
+        <path>@NEMIVER_LIBDIR@/nemiver/modules</path>
+    </customsearchpaths>
+</moduleconfig>
+
diff --git a/src/persp/dbgperspective/menus/varinspectorpopup.xml b/src/persp/dbgperspective/menus/varinspectorpopup.xml
index dd42b04..7343c93 100644
--- a/src/persp/dbgperspective/menus/varinspectorpopup.xml
+++ b/src/persp/dbgperspective/menus/varinspectorpopup.xml
@@ -3,6 +3,8 @@
     <popup name="VarInspectorPopup">
         <menuitem action="CopyVariablePathMenuItemAction"
             name="CopyVariablePathMenuItem" />
+        <menuitem action="CopyVariableValueMenuItemAction"
+            name="CopyVariableValueMenuItem" />
     </popup>
 </ui>
 
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 19058b8..ebeb902 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,6 +1,7 @@
 if VAROBJS
     WATCHPOINT_TEST=runtestwatchpoint
     VAR_PATH_EXPR_TEST=runtestvarpathexpr
+    VAROBJ_WALKER_TEST=runtestvarobjwalker
 else
     WATCHPOINT_TEST=
 endif
@@ -14,14 +15,13 @@ if AUTOTESTS
 TESTS=\
 runtestgdbmi runtestunicode \
 runtestvars runtestcpptrait runtestvarlist \
-runtestvarwalker runtestbreakpoint \
+runtestvarwalker $(VAROBJ_WALKER_TEST) runtestbreakpoint \
 $(WATCHPOINT_TEST) runtestderef \
 runtestlocalvarslist runtestcpplexer \
 runtestcppparser $(VAR_PATH_EXPR_TEST) \
 runtestlibtoolwrapperdetection \
 runtestenv runtesttypes
 
-
 else
 
 TESTS=
@@ -63,6 +63,11 @@ $(top_builddir)/src/common/libnemivercommon.la
 runtestvarpathexpr_SOURCES=test-var-path-expr.cc
 runtestvarpathexpr_LDADD= NEMIVERCOMMON_LIBS@ \
 $(top_builddir)/src/common/libnemivercommon.la
+
+runtestvarobjwalker_SOURCES=test-varobj-walker.cc
+runtestvarobjwalker_LDADD= NEMIVERCOMMON_LIBS@ @BOOST_TEST_EXEC_MONITOR_LIB@ \
+$(top_builddir)/src/common/libnemivercommon.la
+
 endif
 
 #runtestoverloads_SOURCES=test-overloads.cc
@@ -82,7 +87,6 @@ runtestcpptrait_LDADD= NEMIVERCOMMON_LIBS@ \
 @BOOST_UNIT_TEST_FRAMEWORK_STATIC_LIB@ \
 $(top_builddir)/src/common/libnemivercommon.la
 
-
 runtestunicode_SOURCES=test-unicode.cc
 runtestunicode_LDADD= NEMIVERCOMMON_LIBS@ \
 @BOOST_UNIT_TEST_FRAMEWORK_STATIC_LIB@ \
diff --git a/tests/test-varobj-walker.cc b/tests/test-varobj-walker.cc
new file mode 100644
index 0000000..8050415
--- /dev/null
+++ b/tests/test-varobj-walker.cc
@@ -0,0 +1,190 @@
+#include <iostream>
+#include <sstream>
+#include <map>
+#include <string>
+#include <boost/test/test_tools.hpp>
+#include <boost/test/minimal.hpp>
+#include <glibmm.h>
+#include "common/nmv-initializer.h"
+#include "common/nmv-exception.h"
+#include "nmv-i-var-list-walker.h"
+
+using namespace nemiver;
+using namespace nemiver::common;
+
+Glib::RefPtr<Glib::MainLoop> s_loop =
+    Glib::MainLoop::create (Glib::MainContext::get_default ());
+
+static std::string serialized_variable;
+
+static IVarWalkerSafePtr
+create_varobj_walker ()
+{
+    IVarWalkerSafePtr result  =
+        DynamicModuleManager::load_iface_with_default_manager<IVarWalker>
+                                            ("varobjwalker", "IVarWalker");
+    return result;
+}
+
+static IVarWalkerSafePtr
+get_varobj_walker ()
+{
+    static IVarWalkerSafePtr var;
+    if (!var)
+        var = create_varobj_walker ();
+    return var;
+}
+
+static void
+gen_white_spaces (int a_nb_ws,
+                  std::string &a_ws_str)
+{
+    for (int i = 0; i < a_nb_ws; i++) {
+        a_ws_str += ' ';
+    }
+
+}
+
+
+static void
+dump_variable_value (IDebugger::VariableSafePtr a_var,
+                     int a_indent_num,
+                     std::ostringstream &a_os)
+{
+    THROW_IF_FAIL (a_var);
+
+    std::string ws_string;
+    gen_white_spaces (a_indent_num, ws_string);
+
+    a_os << ws_string << a_var->name ();
+
+    if (!a_var->members ().empty ()) {
+        a_os << "\n"  << ws_string << "{\n";
+        IDebugger::VariableList::const_iterator it;
+        for (it = a_var->members ().begin ();
+             it != a_var->members ().end ();
+             ++it) {
+            dump_variable_value (*it, a_indent_num + 2, a_os);
+        }
+        a_os << "\n" << ws_string <<  "}";
+    } else {
+        a_os << " = " << a_var->value ();
+    }
+}
+
+static void
+dump_variable_value (IDebugger::VariableSafePtr a_var,
+                     int a_indent_num,
+                     std::string &a_out_str)
+{
+    std::ostringstream os;
+    dump_variable_value (a_var, a_indent_num, os);
+    a_out_str = os.str ();
+}
+
+static void
+on_engine_died_signal ()
+{
+    s_loop->quit ();
+}
+
+static void
+on_program_finished_signal ()
+{
+    s_loop->quit ();
+}
+
+static void
+on_variable_visited_signal (const IDebugger::VariableSafePtr a_var)
+{
+    MESSAGE ("dumping the variable ...");
+    dump_variable_value (a_var, 0, serialized_variable);
+    MESSAGE ("dumping the variable: DONE");
+    s_loop->quit ();
+}
+
+
+static void
+do_varobj_walker_stuff (IDebuggerSafePtr a_debugger)
+{
+    MESSAGE ("do varobj walker stuff");
+
+    IVarWalkerSafePtr var_walker = get_varobj_walker ();
+
+    var_walker->visited_variable_signal ().connect (&on_variable_visited_signal);
+    var_walker->connect (a_debugger, "person");
+    var_walker->do_walk_variable ();
+}
+
+static void
+on_stopped_signal (IDebugger::StopReason a_reason,
+                   bool /*a_has_frame*/,
+                   const IDebugger::Frame &a_frame,
+                   int /*a_thread_id*/,
+                   int /*bp num*/,
+                   const UString &/*a_cookie*/,
+                   IDebuggerSafePtr &a_debugger)
+{
+    NEMIVER_TRY
+
+    BOOST_REQUIRE (a_debugger);
+
+    if (a_reason == IDebugger::BREAKPOINT_HIT) {
+        MESSAGE ("broke in main");
+        // We did break in main. We need to step once to pass the
+        // initialization of the person variable.
+        a_debugger->step_over ();
+        return;
+    } else if (a_frame.function_name () == "main") {
+        MESSAGE ("okay, stopped in main right after stepping");
+        do_varobj_walker_stuff (a_debugger);
+    }
+
+    NEMIVER_CATCH_NOX
+
+}
+
+NEMIVER_API int
+test_main (int, char **)
+{
+    NEMIVER_TRY
+
+    Initializer::do_init ();
+
+    //load the IDebugger interface
+    IDebuggerSafePtr debugger =
+        DynamicModuleManager::load_iface_with_default_manager<IDebugger>
+                                                                ("gdbengine",
+                                                                 "IDebugger");
+    //setup the debugger with the glib mainloop
+    debugger->set_event_loop_context (Glib::MainContext::get_default ());
+
+    //*******************************
+    //<connect to IDebugger events>
+    //******************************
+    debugger->engine_died_signal ().connect (&on_engine_died_signal);
+    debugger->program_finished_signal ().connect (&on_program_finished_signal);
+    debugger->stopped_signal ().connect (sigc::bind (&on_stopped_signal,
+                                                      debugger));
+    //*******************************
+    //</connect to IDebugger events>
+    //******************************
+
+    debugger->load_program ("fooprog", ".");
+    debugger->set_breakpoint ("main");
+
+    debugger->run ();
+
+    //****************************************
+    //run the event loop.
+    //****************************************
+    s_loop->run ();
+
+    NEMIVER_CATCH_AND_RETURN_NOX (-1)
+
+    BOOST_REQUIRE (!serialized_variable.empty ());
+    MESSAGE (serialized_variable);
+
+    return 0;
+}
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]