changeset 21754:34a582f2edd7

Allow dbstop in functions nested in subfunctions (bug #47918). * debug.cc (find_fcn_by_line): New function. Recursive code refactored out of bp_table::do_add_breakpoint * debug.cc (bp_table:do_add_breakpoint): Factor out the search for the function containing the specified line.
author Lachlan Andrew <lachlanbis@gmail.com>
date Wed, 18 May 2016 13:05:09 +1000
parents be52b94354a3
children 08e861873118
files libinterp/corefcn/debug.cc
diffstat 1 files changed, 64 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/debug.cc	Tue May 17 22:45:07 2016 +1000
+++ b/libinterp/corefcn/debug.cc	Wed May 18 13:05:09 2016 +1000
@@ -644,10 +644,71 @@
   return true;
 }
 
+// Return the sub/nested/main function of MAIN_FCN that contains
+// line number LINENO of the source file.
+// If END_LINE != 0, *END_LINE is set to last line of the returned function.
+static octave_user_code*
+find_fcn_by_line (octave_user_code *main_fcn, int lineno, int *end_line = 0)
+{
+  octave_user_code *retval = 0;
+  octave_user_code *next_fcn = 0;  // 1st function starting after lineno
+
+  // Find innermost nested (or parent) function containing lineno.
+  int earliest_end = std::numeric_limits<int>::max ();
+
+  std::map<std::string, octave_value> subfcns = main_fcn->subfunctions ();
+  for (std::map<std::string,octave_value>::const_iterator q = subfcns.begin ();
+       q != subfcns.end (); q++)
+    {
+      if (q->second.is_user_function ())
+        {
+          octave_user_function *dbg_subfcn = q->second.user_function_value ();
+
+          // Check if lineno is within dbg_subfcn.
+          // FIXME: we could break when beginning_line() > lineno,
+          // but that makes the code "fragile"
+          // if the order of walking subfcns changes,
+          // for a minor speed improvement in non-critical code.
+          if (dbg_subfcn->ending_line () < earliest_end
+              && dbg_subfcn->ending_line () >= lineno
+              && dbg_subfcn->beginning_line () <= lineno)
+            {
+              earliest_end = dbg_subfcn->ending_line ();
+              retval = find_fcn_by_line (dbg_subfcn, lineno, &earliest_end);
+            }
+
+          // Find the first fcn starting after lineno.
+          // This is used if line is not inside any function.
+          if (dbg_subfcn->beginning_line () >= lineno && ! next_fcn)
+            next_fcn = dbg_subfcn;
+        }
+    }
+
+  // The breakpoint is either in the subfunction found above,
+  // or in the main function, which we check now.
+  if (main_fcn->is_user_function ())
+    {
+      int e = dynamic_cast<octave_user_function*> (main_fcn)->ending_line ();
+      if (e >= lineno && e < earliest_end)
+        retval = main_fcn;
+
+      if (! retval)
+        retval = next_fcn;
+    }
+  else  // main_fcn is a script.
+    {
+      if (! retval)
+        retval = main_fcn;
+    }
+
+  if (end_line != 0 && earliest_end < *end_line)
+    *end_line = earliest_end;
+
+  return retval;
+}
+
 // Given file name fname, find the subfunction at line and create
 // a breakpoint there.  Put the system into debug_mode.
-// (FIXME: If line is multiple lines, what happens if they are in different
-//         functions?)
 bp_table::intmap
 bp_table::do_add_breakpoint (const std::string& fname,
                              const bp_table::intmap& line,
@@ -662,9 +723,6 @@
 
   intmap retval;
 
-  const std::list<std::string> subfcn_names   = main_fcn->subfunction_names ();
-  std::map<std::string, octave_value> subfcns = main_fcn->subfunctions ();
-
   octave_idx_type len = line.size ();
 
   for (int i = 0; i < len; i++)
@@ -675,56 +733,7 @@
         {
           int lineno = m->second;
 
-          octave_user_code *dbg_fcn = 0;
-          octave_user_code *next_fcn = 0;  // 1st function starting after line
-
-          // Find innermost nested (or parent) function containing line.
-          int earliest_end = std::numeric_limits<int>::max ();
-
-          for (std::list<std::string>::const_iterator p
-                                                      = subfcn_names.begin ();
-               p != subfcn_names.end (); p++)
-            {
-              std::map<std::string, octave_value>::const_iterator
-                q = subfcns.find (*p);
-
-              if (q != subfcns.end () && q->second.is_user_function ())
-                {
-                  octave_user_function *dbg_subfcn
-                                        = q->second.user_function_value ();
-
-                  if (dbg_subfcn->ending_line () < earliest_end
-                      && dbg_subfcn->ending_line () >= lineno
-                      && dbg_subfcn->beginning_line () <= lineno)
-                    {
-                      earliest_end = dbg_subfcn->ending_line ();
-                      dbg_fcn = dbg_subfcn;
-                    }
-
-                  // First fcn starting after line.
-                  // This is used if line is not inside any function.
-                  if (dbg_subfcn->beginning_line () >= lineno && ! next_fcn)
-                    next_fcn = dbg_subfcn;
-                }
-            }
-
-          // The breakpoint is either in the subfunction found above,
-          // or in the main function, which we check now.
-          if (main_fcn->is_user_function ())
-            {
-              int e = dynamic_cast<octave_user_function*> (main_fcn)
-                      ->ending_line ();
-              if (e >= lineno && e < earliest_end)
-                dbg_fcn = main_fcn;
-
-              if (! dbg_fcn)
-                dbg_fcn = next_fcn;
-            }
-          else
-            {
-              if (! dbg_fcn)
-                dbg_fcn = main_fcn;
-            }
+          octave_user_code *dbg_fcn = find_fcn_by_line (main_fcn, lineno);
 
           // We've found the right (sub)function.  Now insert the breakpoint.
           // We insert all breakpoints.