[nemiver] Tie life time of IDebugger::Variable and varobjs



commit 0b9b09981c2f661ae99668375da85042257972a2
Author: Dodji Seketeli <dodji seketeli org>
Date:   Sun Dec 11 17:08:51 2011 +0100

    Tie life time of IDebugger::Variable and varobjs
    
    	* src/dbgengine/nmv-i-debugger.h (IDebugger::delete_variable): Add
    	an overload declaration that takes the internal name of the
    	backend-side variable object to delete.  Add comments to all the
    	overloads.
    	(IDebugger::DefaultSlot): Move typedef before declaration of
    	IDebugger::Variable.
    	(IDebugger::Variable::m_debugger): New member.
    	(IDebubber::Variable::Variable): Adjust constructors to initialize
    	the new m_debugger member.
    	(IDebugger::Variable::debugger): New accessor.
    	(IDebugger::Variable::~Variable): If the debugging engine is still
    	connected to the Delete the backend-side variable
    	object if any.
    	(IDebugger::variable_deleted_signal): Add comments.
    	* src/dbgengine/nmv-gdb-engine.h (GDBEngine::delete_variable):
    	Declare new overload.
    	* src/dbgengine/nmv-gdb-engine.cc
    	(OnCreateVariableHandler::do_handle): Associate the instance of
    	IDebugger::Variable with the instance of IDebugger::Variable it
    	was created from, iff there is backend-side variable object for
    	that variable.
    	(OnDeleteVariableHandler::do_handle): Some requests for deleting
    	variable can have null instances of IDebugger::Variable
    	associated.  Handle those.
    	(GDBEngine::delete_variable): Implement the new overload to delete
    	a variable object from its "internal name".  Add comments to the
    	other overloads.
    	* src/dbgengine/nmv-varobj-walker.cc (~VarobjWalker): Remove.
    	(delete_varobj_if_necessary): Remove.
    	(connect): Remove call to delete_varobj_if_necessary.
    	* src/persp/dbgperspective/nmv-local-vars-inspector.cc
    	(LocalVarsInspector::Priv::clear_local_variables)
    	(LocalVarsInspector::Priv::clear_function_arguments): Remove uses
    	of delete_vars_backend_peers.
    	(LocalVarsInspector::Priv::delete_vars_backend_peers): Remove.
    	* src/persp/dbgperspective/nmv-var-inspector.cc
    	(VarInspector::Priv::graphically_set_variable)
    	(VarInspector::Priv::~Priv, VarInspector::inspect_variable)
    	(VarInspector::clear): Remove use of delete_variable_if_needed.
    	(VarInspector::Priv::delete_variable_if_needed): Remove.
    	* tests/fooprog.cc (main): Don't name unused parameters.
    	* tests/test-var-path-expr.cc (variables): New global
    	container of variables.
    	(on_variable_deleted_signal): New signal handler.
    	(on_breakpoints_set_signal): Clear variables instead of quitting
    	the event loop.
    	(on_variable_unfolded, on_variable_created): Add the variable to
    	the "variables" container.
    	(on_stopped_signal): Count the number of variable created.
    	Avoid needlessly passing a reference to the debugger engine.
    	(test_main): Don't name unused arguments.  Handle the
    	IDebugger::variable_deleted_signal event.
    	* tests/test-var-walker.cc (VariableList): Rename
    	DebuggerVariableList into this.
    	(variables): New global variable to hold variables.
    	(on_frames_arguments_listed_signal, on_local_variables_listed_signal):
    	Don't name unused parameters.  Add function arguments to the
    	"variables" global.
    	(test_main): Adjust b/c fooprog's main function doesn't have any
    	named parameter anymore.  Clear the "variables" global after the
    	event loop is closed.
    	* tests/test-vars.cc (variables): New global to handle variables.
    	(person_var): Rename var_to_delete into this.
    	(on_variable_created_signal, on_varible_created_signal2): Add
    	variable to the "variables" global.
    	(on_changed_variables_listed_signal):  Don't explicitly
    	delete_variable anymore.  Keep stepping, and don't hold a
    	reference on the person_var reference.
    	(on_variable_deleted_signal, on_variable_deleted_signal2): Be
    	aware that a_var can be empty for backend-side variable objects.
    	(on_stopped_signal): Adjust.
    	(test_main):  Don't expect any variable to be have been deleted
    	during this test, and clear the "variables" global.

 src/dbgengine/nmv-gdb-engine.cc                    |   88 +++++++++++++--
 src/dbgengine/nmv-gdb-engine.h                     |    4 +
 src/dbgengine/nmv-i-debugger.h                     |  120 +++++++++++++++++--
 src/dbgengine/nmv-varobj-walker.cc                 |   25 ----
 .../dbgperspective/nmv-local-vars-inspector.cc     |   15 ---
 src/persp/dbgperspective/nmv-var-inspector.cc      |   18 ---
 tests/fooprog.cc                                   |    3 +-
 tests/test-var-path-expr.cc                        |   46 +++++++-
 tests/test-var-walker.cc                           |   35 ++++--
 tests/test-vars.cc                                 |   57 ++++++---
 10 files changed, 295 insertions(+), 116 deletions(-)
---
diff --git a/src/dbgengine/nmv-gdb-engine.cc b/src/dbgengine/nmv-gdb-engine.cc
index b9b7436..3d44c07 100644
--- a/src/dbgengine/nmv-gdb-engine.cc
+++ b/src/dbgengine/nmv-gdb-engine.cc
@@ -2735,6 +2735,8 @@ struct OnCreateVariableHandler : public OutputHandler
     void do_handle (CommandAndOutput &a_in)
     {
         VariableSafePtr var = a_in.output ().result_record ().variable ();
+        if (!var->internal_name ().empty ())
+        var->debugger (m_engine);
 
         // Set the name of the variable to the name that got stored
         // in the tag0 member of the command.
@@ -2785,20 +2787,30 @@ struct OnDeleteVariableHandler : public OutputHandler {
 
     void do_handle (CommandAndOutput &a_in)
     {
-        THROW_IF_FAIL (a_in.command ().variable ());
+        IDebugger::VariableSafePtr var;
         THROW_IF_FAIL (m_engine);
 
-        // Call the slot associated to IDebugger::delete_variable (), if
-        // Any.
+        // Call the slot associated to IDebugger::delete_variable (),
+        // if Any.
         if (a_in.command ().has_slot ()) {
-            typedef sigc::slot<void, const IDebugger::VariableSafePtr> SlotType;
-            SlotType slot = a_in.command ().get_slot<SlotType> ();
-            slot (a_in.command ().variable ());
+            // The resulting command can either have an associated
+            // instance of IDebugger::Variable attached to it or not,
+            // depending on the flavor of IDebugger::delete_variable
+            // that was called.  Make sure to handle both cases.
+            if (a_in.command ().variable ()) {
+                typedef sigc::slot<void, const IDebugger::VariableSafePtr> SlotType;
+                SlotType slot = a_in.command ().get_slot<SlotType> ();
+                var = a_in.command ().variable ();
+                slot (var);
+            } else {
+                typedef IDebugger::DefaultSlot DefaultSlot;
+                IDebugger::DefaultSlot slot = a_in.command ().get_slot<DefaultSlot> ();
+                slot ();
+            }
         }
         // Emit the general IDebugger::variable_deleted_signal ().
-        m_engine->variable_deleted_signal ().emit
-                (a_in.command ().variable (),
-                 a_in.command ().cookie ());
+        m_engine->variable_deleted_signal ().emit (var,
+                                                   a_in.command ().cookie ());
     }
 }; // end OnDeleteVariableHandler
 
@@ -5755,6 +5767,19 @@ GDBEngine::create_variable (const UString &a_name,
     queue_command (command);
 }
 
+/// If a variable has a GDB variable object then this method deletes
+/// the backend.  You should not use this method because the life
+/// cycle of variables backend counter parts is automatically tied to
+/// the life cycle of instances of IDebugger::Variable, unless you
+/// know what you are doing.
+///
+/// Note that when the varobj is deleted, the
+/// IDebugger::variable_deleted signal is invoked.
+///
+/// \param a_var the variable which backend counter to delete.
+///
+/// \param a_cookie a string cookie passed to the
+/// IDebugger::variable_deleted_signal.
 void
 GDBEngine::delete_variable (const VariableSafePtr a_var,
                             const UString &a_cookie)
@@ -5765,6 +5790,22 @@ GDBEngine::delete_variable (const VariableSafePtr a_var,
                      a_cookie);
 }
 
+/// If a variable has a GDB variable object, then this method deletes
+/// the varobj.  You should not use this method because the life cycle
+/// of variables backend counter parts is automatically tied to the
+/// life cycle of instances of IDebugger::Variable, unless you know
+/// what you are doing.
+///
+/// Note that when the varobj is deleted, the
+/// IDebugger::variable_deleted signal is invoked.
+///
+/// \param a_var the variable which backend counter to delete.
+///
+/// \param a_slot a slot asynchronously called when the backend
+/// variable oject is deleted.
+///
+/// \param a_cookie a string cookie passed to the
+/// IDebugger::variable_deleted_signal.
 void
 GDBEngine::delete_variable (const VariableSafePtr a_var,
                             const ConstVariableSlot &a_slot,
@@ -5783,6 +5824,35 @@ GDBEngine::delete_variable (const VariableSafePtr a_var,
     queue_command (command);
 }
 
+/// Deletes a variable object named by a given string.  You should not
+/// use this method because the life cycle of variables backend
+/// counter parts is automatically tied to the life cycle of instances
+/// of IDebugger::Variable, unless you know what you are doing.
+///
+/// Note that when the backend counter part is deleted, the
+/// IDebugger::variable_deleted signal is invoked.
+///
+/// \param a_internal_name the name of the backend variable object we
+/// want to delete.
+///
+/// \param a_slot a slot that is going to be called asynchronuously
+/// when the backend object is deleted.
+void
+GDBEngine::delete_variable (const UString &a_internal_name,
+                            const DefaultSlot &a_slot,
+                            const UString &a_cookie)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+    THROW_IF_FAIL (!a_internal_name.empty ());
+
+    Command command ("delete-variable",
+                     "-var-delete " + a_internal_name,
+                     a_cookie);
+    command.set_slot (a_slot);
+    queue_command (command);
+}
+
 /// Unfold a given variable.
 ///
 /// Query the backend for the member variables of the given variable.
diff --git a/src/dbgengine/nmv-gdb-engine.h b/src/dbgengine/nmv-gdb-engine.h
index 11b1668..cea76ed 100644
--- a/src/dbgengine/nmv-gdb-engine.h
+++ b/src/dbgengine/nmv-gdb-engine.h
@@ -584,6 +584,10 @@ public:
                           const ConstVariableSlot &a_s,
                           const UString &a_cookie);
 
+    void delete_variable (const UString &a_internal_name,
+			  const DefaultSlot &a_slot,
+			  const UString &a_cookie);
+
     void unfold_variable (VariableSafePtr a_var,
                           const UString &a_cookie);
 
diff --git a/src/dbgengine/nmv-i-debugger.h b/src/dbgengine/nmv-i-debugger.h
index 6fb5fff..56bea4a 100644
--- a/src/dbgengine/nmv-i-debugger.h
+++ b/src/dbgengine/nmv-i-debugger.h
@@ -345,6 +345,8 @@ public:
             m_args.clear ();
         }
     };//end class Frame
+
+    typedef sigc::slot<void> DefaultSlot;
     typedef sigc::slot<void, const vector<IDebugger::Frame>&>
         FrameVectorSlot;
     typedef sigc::slot<void, const map<int, IDebugger::VariableList>& >
@@ -378,6 +380,14 @@ public:
         // (e.g: backend side variable objects in GDB), then this
         // is the name of the backend side counterpart of this variable.
         UString m_internal_name;
+        // If the variable was created with a backend counterpart
+        // (e.g, GDB Variable objects), then this client-side
+        // variable instance needs to have a hold on the instance of
+        // IDebugger that was used to create the variable.  This is
+        // needed so that that instance of IDebugger can be used to
+        // tie the life cycle of the remote variable object peer with
+        // the life cycle of this instance.
+        mutable IDebugger *m_debugger;
         UString m_name;
         UString m_name_caption;
         UString m_value;
@@ -412,8 +422,10 @@ public:
                   const UString &a_name,
                   const UString &a_value,
                   const UString &a_type,
-                  bool a_in_scope = true)
+                  bool a_in_scope = true,
+                  IDebugger *a_dbg = 0)
             : m_internal_name (a_internal_name),
+            m_debugger (a_dbg),
             m_name (a_name),
             m_value (a_value),
             m_type (a_type),
@@ -428,8 +440,10 @@ public:
         Variable (const UString &a_name,
                   const UString &a_value,
                   const UString &a_type,
-                  bool a_in_scope = true)
-            : m_name (a_name),
+                  bool a_in_scope = true,
+                  IDebugger *a_dbg = 0)
+            : m_debugger (a_dbg),
+            m_name (a_name),
             m_value (a_value),
             m_type (a_type),
             m_parent (0),
@@ -441,24 +455,41 @@ public:
         {
         }
 
-        Variable (const UString &a_name)
-            : m_name (a_name),
+        Variable (const UString &a_name,
+                  IDebugger *a_dbg = 0)
+            : m_debugger (a_dbg),
+            m_name (a_name),
             m_parent (0),
             m_num_expected_children (0),
             m_in_scope (true),
             m_format (UNDEFINED_FORMAT),
             m_needs_revisualizing (false)
-                
-        {}
+        {
+        }
 
-        Variable ()
-            : m_parent (0),
+        Variable (IDebugger *a_dbg = 0)
+            : m_debugger (a_dbg),
+            m_parent (0),
             m_num_expected_children (0),
             m_in_scope (true),
             m_format (UNDEFINED_FORMAT),
             m_needs_revisualizing (false)
-                
-        {}
+        {
+        }
+
+        ~Variable ()
+        {
+            // If this variable is peered with an engine-side variable
+            // object then ask the debugging engine to delete the peer
+            // variable object now.
+            if (m_debugger
+                && !internal_name ().empty ()
+                && m_debugger->is_attached_to_target ()) {
+                IDebugger::DefaultSlot empty_slot;
+                m_debugger->delete_variable (internal_name (),
+                                             empty_slot);
+            }
+        }
 
         const VariableList& members () const {return m_members;}
 
@@ -552,6 +583,10 @@ public:
         /// \param a_in the new name of backend side counterpart variable object.
         void internal_name (const UString &a_in) {m_internal_name = a_in;}
 
+
+        IDebugger* debugger () const {return m_debugger;}
+        void debugger (IDebugger *a_dbg) {m_debugger = a_dbg;}
+
         const UString& name () const {return m_name;}
         void name (const UString &a_name)
         {
@@ -871,8 +906,6 @@ public:
         return false;
     }
 
-    typedef sigc::slot<void> DefaultSlot;
-
     typedef sigc::slot<void,
                        const std::pair<int, const IDebugger::Breakpoint&>&>
         BreakpointSlot;
@@ -1086,6 +1119,12 @@ public:
     virtual sigc::signal<void, const VariableSafePtr, const UString&>&
                                  variable_created_signal () const = 0;
 
+    /// This signal is emitted after IDebugger::delete_variable is
+    /// called and the underlying backend-side variable object has
+    /// been effectively deleted.  Note that when no instance of
+    /// VariableSafePtr has been passed to the
+    /// IDebugger::delete_variable method, the first argument of this
+    /// signal slot is a null pointer to VariableSafePtr.
     virtual sigc::signal<void, const VariableSafePtr, const UString&>&
                                  variable_deleted_signal () const = 0;
 
@@ -1386,13 +1425,68 @@ public:
                                   const ConstVariableSlot &a_slot,
                                   const UString &a_cookie = "") = 0;
 
+    /// If a variable has a backend counterpart (e.g, a variable object
+    /// when using the GDB backend), then this method deletes the
+    /// backend.  You should not use this method because the life cycle
+    /// of variables backend counter parts is automatically
+    /// tied to the life cycle of instances of IDebugger::Variable,
+    /// unless you know what you are doing.
+    ///
+    /// Note that when the backend counter part is deleted, the
+    /// IDebugger::variable_deleted_signal is invoked with the a_var
+    /// variable in argument.
+    ///
+    /// \param a_var the variable which backend counter to delete.
+    ///
+    /// \param a_cookie a string cookie passed to the
+    /// IDebugger::variable_deleted_signal.
     virtual void delete_variable (const VariableSafePtr a_var,
                                   const UString &a_cookie = "") = 0;
 
+    /// If a variable has a backend counterpart (e.g, a variable object
+    /// when using the GDB backend), then this method deletes the
+    /// backend.  You should not use this method because the life cycle
+    /// of variables backend counter parts is automatically
+    /// tied to the life cycle of instances of IDebugger::Variable,
+    /// unless you know what you are doing.
+    ///
+    /// Note that when the backend counter part is deleted, the
+    /// IDebugger::variable_deleted_signal is invoked with the a_var
+    /// variable in argument.
+    ///
+    /// \param a_var the variable which backend counter to delete.
+    ///
+    /// \param a_slot a slot asynchronously called when the backend
+    /// variable oject is deleted.
+    ///
+    /// \param a_cookie a string cookie passed to the
+    /// IDebugger::variable_deleted_signal.
     virtual void delete_variable (const VariableSafePtr a_var,
                                   const ConstVariableSlot&,
                                   const UString &a_cookie = "") = 0;
 
+    /// Deletes a backend variable object (e.g, for GDB, a so called
+    /// variable object) named by a given string.
+    /// You should not use this method because the life cycle
+    /// of variables backend counter parts is automatically
+    /// tied to the life cycle of instances of IDebugger::Variable,
+    /// unless you know what you are doing.
+    ///
+    /// Note that when the backend counter part is deleted, the
+    /// IDebugger::variable_deleted_signal is invoked, with null pointer
+    /// to IDebugger::Variable.
+    ///
+    /// \param a_internal_name the name of the backend variable object
+    /// we want to delete.
+    ///
+    /// \param a_slot a slot that is going to be called
+    /// asynchronuously when the backend object is deleted.
+    ///
+    /// \param a_cookie
+    virtual void delete_variable (const UString &a_internal_name,
+                                  const DefaultSlot &a_slot,
+                                  const UString &a_cookie = "") = 0;
+
     virtual void unfold_variable (VariableSafePtr a_var,
                                   const UString &a_cookie = "") = 0;
     virtual void unfold_variable
diff --git a/src/dbgengine/nmv-varobj-walker.cc b/src/dbgengine/nmv-varobj-walker.cc
index 462b3b5..9fab8f1 100644
--- a/src/dbgengine/nmv-varobj-walker.cc
+++ b/src/dbgengine/nmv-varobj-walker.cc
@@ -73,11 +73,6 @@ public:
     {
     }
 
-    ~VarobjWalker ()
-    {
-        delete_varobj_if_necessary ();
-    }
-
     sigc::signal<void,
                  const IDebugger::VariableSafePtr>
                                     visited_variable_node_signal () const;
@@ -101,8 +96,6 @@ public:
 
     unsigned get_maximum_member_depth () const;
 
-    void delete_varobj_if_necessary ();
-
     void do_walk_variable_real (const IDebugger::VariableSafePtr,
                                 unsigned a_max_depth);
 
@@ -135,8 +128,6 @@ VarobjWalker::connect (IDebuggerSafePtr a_debugger,
     THROW_IF_FAIL (a_debugger);
     THROW_IF_FAIL (!a_var_name.empty ());
 
-    delete_varobj_if_necessary ();
-
     m_debugger = a_debugger;
     m_var_name = a_var_name;
     m_debugger->create_variable
@@ -156,8 +147,6 @@ VarobjWalker::connect (IDebuggerSafePtr a_debugger,
     // The variable must be backed by variable objects.
     THROW_IF_FAIL (!a_var->internal_name ().empty ());
 
-    delete_varobj_if_necessary ();
-
     m_debugger = a_debugger;
     m_variable = a_var;
 }
@@ -213,20 +202,6 @@ VarobjWalker::get_maximum_member_depth () const
 }
 
 void
-VarobjWalker::delete_varobj_if_necessary ()
-{
-    LOG_FUNCTION_SCOPE_NORMAL_DD;
-
-    if (!m_var_name.empty ()
-        && m_variable
-        && m_debugger
-        && m_debugger->is_attached_to_target ()) {
-        m_debugger->delete_variable (m_variable);
-    }
-
-}
-
-void
 VarobjWalker::do_walk_variable_real (const IDebugger::VariableSafePtr a_var,
                                      unsigned a_max_depth)
 {
diff --git a/src/persp/dbgperspective/nmv-local-vars-inspector.cc b/src/persp/dbgperspective/nmv-local-vars-inspector.cc
index 05659c3..e1c222c 100644
--- a/src/persp/dbgperspective/nmv-local-vars-inspector.cc
+++ b/src/persp/dbgperspective/nmv-local-vars-inspector.cc
@@ -329,7 +329,6 @@ public:
                 row_it = tree_store->erase (row_it);
             }
         }
-        delete_vars_backend_peers (local_vars);
         local_vars.clear ();
         local_vars_changed_at_prev_stop.clear ();
     }
@@ -347,7 +346,6 @@ public:
                 row_it = tree_store->erase (*row_it);
             }
         }
-        delete_vars_backend_peers (function_arguments);
         function_arguments.clear ();
         func_args_changed_at_prev_stop.clear ();
     }
@@ -591,19 +589,6 @@ public:
         }
     }
 
-    void
-    delete_vars_backend_peers (IDebugger::VariableList &a_vars)
-    {
-        for (IDebugger::VariableList::const_iterator it = a_vars.begin ();
-             it != a_vars.end ();
-             ++it) {
-            if (!(*it) || (*it)->internal_name ().empty ()) {
-                continue;
-            }
-            debugger->delete_variable (*it);
-        }
-    }
-
     Glib::RefPtr<Gtk::UIManager>
     get_ui_manager ()
     {
diff --git a/src/persp/dbgperspective/nmv-var-inspector.cc b/src/persp/dbgperspective/nmv-var-inspector.cc
index c95ad97..d5f109f 100644
--- a/src/persp/dbgperspective/nmv-var-inspector.cc
+++ b/src/persp/dbgperspective/nmv-var-inspector.cc
@@ -163,20 +163,6 @@ class VarInspector::Priv : public sigc::trackable {
         get_ui_manager ()->insert_action_group (var_inspector_action_group);
     }
 
-    // If the variable we are inspected was created
-    // with a backend counterpart (variable objects for GDB),
-    // instruct the backend to delete its variable counterpart.
-    void
-    delete_variable_if_needed ()
-    {
-        LOG_FUNCTION_SCOPE_NORMAL_DD;
-        if (variable
-            && !variable->internal_name ().empty ()
-            && debugger) {
-            debugger->delete_variable (variable);
-        }
-    }
-
     void
     graphically_set_variable (const IDebugger::VariableSafePtr a_variable,
                               bool a_expand)
@@ -213,7 +199,6 @@ class VarInspector::Priv : public sigc::trackable {
         re_visualize = a_re_visualize;
 
         re_init_tree_view ();
-        delete_variable_if_needed ();
         variable = a_variable;
         if (a_re_visualize) {
             debugger->revisualize_variable (a_variable,
@@ -629,7 +614,6 @@ public:
 
     ~Priv ()
     {
-        delete_variable_if_needed ();
     }
 };//end class VarInspector::Priv
 
@@ -670,7 +654,6 @@ VarInspector::inspect_variable (const UString &a_variable_name,
     if (a_variable_name == "") {return;}
     THROW_IF_FAIL (m_priv);
     m_priv->re_init_tree_view ();
-    m_priv->delete_variable_if_needed ();
     m_priv->create_variable (a_variable_name, a_expand);
 }
 
@@ -701,7 +684,6 @@ VarInspector::clear ()
 {
     THROW_IF_FAIL (m_priv);
     m_priv->re_init_tree_view ();
-    m_priv->delete_variable_if_needed ();
 }
 
 NEMIVER_END_NAMESPACE (nemiver)
diff --git a/tests/fooprog.cc b/tests/fooprog.cc
index 61bdb96..b2a8900 100644
--- a/tests/fooprog.cc
+++ b/tests/fooprog.cc
@@ -92,8 +92,7 @@ func4 (Person &a_person)
 }
 
 int
-main (int a_argc __attribute__((unused)),
-      char *a_argv[] __attribute__((unused)))
+main (int, char **)
 {
     Person person ("Bob", "Barton", 15);
     func1 ();
diff --git a/tests/test-var-path-expr.cc b/tests/test-var-path-expr.cc
index f215c36..34063cf 100644
--- a/tests/test-var-path-expr.cc
+++ b/tests/test-var-path-expr.cc
@@ -11,6 +11,15 @@
 using namespace nemiver;
 using namespace nemiver::common;
 
+typedef std::list<IDebugger::VariableSafePtr> VariablesList;
+
+static int num_variables_created;
+
+// This container holds variables backed up by backend-side
+// variable objects created during this test, so that they stay
+// alive during the life of this test.
+VariablesList variables;
+
 Glib::RefPtr<Glib::MainLoop> loop =
     Glib::MainLoop::create (Glib::MainContext::get_default ());
 
@@ -28,6 +37,23 @@ on_program_finished_signal ()
     loop->quit ();
 }
 
+/// Counts the number of deleted variables.  If it equals the number
+/// of created variables, then exit the event loop, effectively
+/// allowing the test to exit.
+static void
+on_variable_deleted_signal (const IDebugger::VariableSafePtr a_var,
+                            const UString&)
+{
+    BOOST_REQUIRE (!a_var);
+    MESSAGE ("a backend-side variable object got deleted!");
+
+    static int num_variables_deleted;
+    num_variables_deleted++;
+
+    if (num_variables_deleted == num_variables_created)
+        loop->quit ();
+}
+
 static void
 on_breakpoints_set_signal (const std::map<int, IDebugger::Breakpoint> &a_breaks,
                            const UString &a_cookie)
@@ -49,7 +75,11 @@ on_variable_expr_path (const IDebugger::VariableSafePtr a_var)
     MESSAGE ("var expr path: " << a_var->path_expression ());
     BOOST_REQUIRE (a_var->path_expression ()
                    == "((((person).m_first_name)).npos)");
-    loop->quit ();
+
+    // This should help delete all the variables (and their
+    // backend-side variable objects) created during this test, along
+    // with a_var, after this function returns.
+    variables.clear ();
 }
 
 static void
@@ -68,6 +98,8 @@ on_variable_unfolded (const IDebugger::VariableSafePtr a_var,
         a_debugger->query_variable_path_expr (a_var->members ().front (),
                                               &on_variable_expr_path);
     }
+    // Ensure that a_var lives throughout the test.
+    variables.push_back (a_var);
 }
 
 static void
@@ -76,6 +108,9 @@ on_variable_created (const IDebugger::VariableSafePtr a_var,
 {
     MESSAGE ("variable created: " << a_var->name ());
 
+    // Add a_var to the list of live variables, so that it remains
+    // alive during the whole life of the main function.
+    variables.push_back (a_var);
     if (a_var->needs_unfolding ()) {
         MESSAGE ("unfolding variable " << a_var->name ());
         a_debugger->unfold_variable (a_var,
@@ -91,7 +126,7 @@ on_stopped_signal (IDebugger::StopReason a_reason,
                    int /*a_thread_id*/,
                    int /*a_bp_num*/,
                    const UString &/*a_cookie*/,
-                   IDebuggerSafePtr &a_debugger)
+                   IDebuggerSafePtr a_debugger)
 {
     MESSAGE ("stopped at: "
              << a_frame.function_name ()
@@ -104,16 +139,15 @@ on_stopped_signal (IDebugger::StopReason a_reason,
         a_debugger->create_variable ("person",
                                      sigc::bind (&on_variable_created,
                                                  a_debugger));
+        ++num_variables_created;
     } else {
         a_debugger->do_continue ();
     }
 }
 
 NEMIVER_API int
-test_main (int argc, char *argv[])
+test_main (int, char **)
 {
-    if (argc || argv) {/*keep compiler happy*/}
-
     NEMIVER_TRY
 
     Initializer::do_init ();
@@ -133,6 +167,8 @@ test_main (int argc, char *argv[])
     debugger->program_finished_signal ().connect
                                             (&on_program_finished_signal);
 
+    debugger->variable_deleted_signal ().connect (&on_variable_deleted_signal);
+
     debugger->breakpoints_list_signal ().connect
                                             (&on_breakpoints_set_signal);
 
diff --git a/tests/test-var-walker.cc b/tests/test-var-walker.cc
index 11654de..768f3c8 100644
--- a/tests/test-var-walker.cc
+++ b/tests/test-var-walker.cc
@@ -12,14 +12,19 @@
 using namespace nemiver;
 using namespace nemiver::common;
 
+typedef std::list<IDebugger::VariableSafePtr> Variables;
+typedef std::map<std::string, IVarListWalkerSafePtr> VarListWalkerMap;
+typedef std::map<std::string, string> StringMap;
+
+// This is to hold variables which should live throughout the life
+// time of this test.
+Variables variables;
+
 Glib::RefPtr<Glib::MainLoop> s_loop =
     Glib::MainLoop::create (Glib::MainContext::get_default ());
 
 IDebugger::Frame s_current_frame;
 
-typedef std::list<IDebugger::VariableSafePtr> DebuggerVariableList;
-typedef std::map<std::string, IVarListWalkerSafePtr> VarListWalkerMap;
-typedef std::map<std::string, string> StringMap;
 
 VarListWalkerMap&
 var_list_walker ()
@@ -123,15 +128,19 @@ on_stopped_signal (IDebugger::StopReason a_reason,
 void
 on_frames_arguments_listed_signal
         (const map<int, list<IDebugger::VariableSafePtr> > &a_frames_params,
-         const UString &a_cookie)
+         const UString &)
 {
-    if (a_cookie.empty ()) {/*keep compiler happy*/}
     map<int, list<IDebugger::VariableSafePtr> >::const_iterator it;
     it = a_frames_params.find (0);
     if (it == a_frames_params.end ()) {
         LOG_ERROR ("Could not find current frame");
         return;
     }
+    Variables::const_iterator i = it->second.begin ();
+    for (; i != it->second.end (); ++i) {
+        variables.push_back (*i);
+    }
+
     BOOST_REQUIRE (var_list_walker ().find (s_current_frame.function_name ())
                    != var_list_walker ().end ());
     IVarListWalkerSafePtr walker = var_list_walker ()[s_current_frame.function_name ()];
@@ -142,13 +151,17 @@ on_frames_arguments_listed_signal
 }
 
 void
-on_local_variables_listed_signal (const DebuggerVariableList &a_variables,
-                                  const UString &a_cookie)
+on_local_variables_listed_signal (const Variables &a_variables,
+                                  const UString &)
 {
-    if (a_variables.empty () || a_cookie.empty ()) {
-    }
     BOOST_REQUIRE (var_list_walker ().find (s_current_frame.function_name ())
                    != var_list_walker ().end ());
+
+    Variables::const_iterator i = a_variables.begin ();
+    for (; i != a_variables.end (); ++i) {
+        variables.push_back (*i);
+    }
+
     IVarListWalkerSafePtr walker = var_list_walker ()[s_current_frame.function_name ()];
     BOOST_REQUIRE (walker);
     walker->remove_variables ();
@@ -218,7 +231,7 @@ test_main (int argc, char **argv)
     debugger->set_breakpoint ("func3");
 
     var_list_walker ()["main"] = create_var_list_walker (debugger);
-    expected_variables ()["main"] = " person a_argc a_argv";
+    expected_variables ()["main"] = " person";
     var_list_walker ()["func1"] = create_var_list_walker (debugger);
     expected_variables ()["func1"] = " i";
     var_list_walker ()["func2"] = create_var_list_walker (debugger);
@@ -232,6 +245,8 @@ test_main (int argc, char **argv)
     //****************************************
     s_loop->run ();
 
+    variables.clear ();
+
     BOOST_REQUIRE (actual_variables ().find ("main")  != actual_variables ().end ());
     BOOST_REQUIRE (actual_variables ().find ("func1") != actual_variables ().end ());
     BOOST_REQUIRE (actual_variables ().find ("func2") != actual_variables ().end ());
diff --git a/tests/test-vars.cc b/tests/test-vars.cc
index b3f438f..bb1a017 100644
--- a/tests/test-vars.cc
+++ b/tests/test-vars.cc
@@ -12,6 +12,13 @@
 using namespace nemiver;
 using namespace nemiver::common;
 
+typedef  std::list<IDebugger::VariableSafePtr> Variables;
+
+// This is to hold instances of IDebugger::Variable which backend-side
+// variable object has to live throughout the life time of this test.
+static Variables variables;
+static IDebugger::VariableSafePtr person_var;
+
 Glib::RefPtr<Glib::MainLoop> s_loop =
     Glib::MainLoop::create (Glib::MainContext::get_default ());
 static int nb_vars_created;
@@ -19,7 +26,7 @@ static int nb_vars_created2;
 static int nb_vars_deleted;
 static int nb_vars_deleted2;
 static int unfold_requests;
-static IDebugger::VariableSafePtr var_to_delete;
+
 
 void on_variable_deleted_signal (const IDebugger::VariableSafePtr a_var);
 void on_variable_unfolded_signal (const IDebugger::VariableSafePtr a_var,
@@ -61,11 +68,12 @@ on_variable_created_signal (IDebugger::VariableSafePtr a_var)
     a_var->to_string (var_str, true /*show var name*/);
     MESSAGE ("variable created " << var_str);
 
+    variables.push_back (a_var);
     nb_vars_created++;
     if (a_var->name () == "person") {
         // put the variable aside so that we
         // can delete it later
-        var_to_delete = a_var;
+        person_var = a_var;
     }
 }
 
@@ -77,6 +85,7 @@ on_variable_created_signal2 (IDebugger::VariableSafePtr a_var,
     UString var_str;
     a_var->to_string (var_str, true /*show var name*/);
     MESSAGE ("variable created (second report): " << var_str);
+    variables.push_back (a_var);
     nb_vars_created2++;
 
     unfold_requests++;
@@ -166,16 +175,21 @@ on_changed_variables_listed_signal
         MESSAGE ("name: "  + (*it)->internal_name ());
         MESSAGE ("value: " + (*it)->value ());
     }
-    a_debugger->delete_variable (root, &on_variable_deleted_signal);
+    a_debugger->step_over ();
+    person_var.reset ();
 }
 
 void
 on_variable_deleted_signal (const IDebugger::VariableSafePtr a_var)
 {
-    MESSAGE ("variable deleted. Name: "
-             << a_var->name ()
-             << ", Internal Name: "
-             << a_var->internal_name ());
+    if (a_var) {
+        MESSAGE ("variable deleted. Name: "
+                 << a_var->name ()
+                 << ", Internal Name: "
+                 << a_var->internal_name ());
+    } else {
+        MESSAGE ("backend-side variable object deleted");
+    }
     nb_vars_deleted++;
 }
 
@@ -184,10 +198,14 @@ on_variable_deleted_signal2 (const IDebugger::VariableSafePtr a_var,
                              const UString&,
                              IDebuggerSafePtr a_debugger)
 {
-    MESSAGE ("variable deleted. Name: "
-             << a_var->name ()
-             << ", Internal Name: "
-             << a_var->internal_name ());
+    if (a_var) {
+        MESSAGE ("variable deleted. Name: "
+                 << a_var->name ()
+                 << ", Internal Name: "
+                 << a_var->internal_name ());
+    } else {
+        MESSAGE ("backend-side variable object deleted");
+    }
     nb_vars_deleted2++;
     a_debugger->step_over ();
 }
@@ -219,13 +237,13 @@ on_stopped_signal (IDebugger::StopReason /*a_reason*/,
                  sigc::bind (&on_variable_created_in_func4_signal,
                              a_debugger));
         } else if (nb_stops_in_func4 < 5 ) {
-            a_debugger->step_over ("in-func4");
+            a_debugger->step_over ();
         } else {
             a_debugger->do_continue ();
         }
     } else if (nb_stops == 2) {
-        // Okay we stepped once, now we can now create the variable
-        // for the person variable.
+        // Okay we stepped once, we can now create the variable for
+        // the person variable.
         a_debugger->create_variable ("person",
                                      &on_variable_created_signal);
         MESSAGE ("Requested creation of variable 'person'");
@@ -235,7 +253,7 @@ on_stopped_signal (IDebugger::StopReason /*a_reason*/,
         // let's now ask the debugger to tell us which descendant variable
         // was changed exactly.
         a_debugger->list_changed_variables
-                (var_to_delete,
+                (person_var,
                  sigc::bind (&on_changed_variables_listed_signal, a_debugger));
     } else {
         a_debugger->step_over ();
@@ -288,12 +306,13 @@ test_main (int, char **)
     //****************************************
     s_loop->run ();
 
-    NEMIVER_CATCH_AND_RETURN_NOX (-1)
-
+    NEMIVER_CATCH_AND_RETURN_NOX (-1);
+    
     BOOST_REQUIRE (nb_vars_created == nb_vars_created2);
     BOOST_REQUIRE (nb_vars_created > 0);
-    BOOST_REQUIRE (nb_vars_deleted == nb_vars_deleted2);
-    BOOST_REQUIRE (nb_vars_deleted > 0);
+    BOOST_REQUIRE (nb_vars_deleted == 0);
+
+    variables.clear ();
 
     return 0;
 }



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