changeset 25719:154663508d9b v8.2.3395

patch 8.2.3395: Vim9: expression breakpoint not checked in :def function Commit: https://github.com/vim/vim/commit/26a4484da20039b61f18d3565a4b4339c4d1f7e3 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Sep 2 18:49:06 2021 +0200 patch 8.2.3395: Vim9: expression breakpoint not checked in :def function Problem: Vim9: expression breakpoint not checked in :def function. Solution: Always compile a function for debugging if there is an expression breakpoint. (closes #8803)
author Bram Moolenaar <Bram@vim.org>
date Thu, 02 Sep 2021 19:00:04 +0200
parents c3adc383b30f
children ebc29a793c7d
files src/debugger.c src/proto/debugger.pro src/proto/vim9execute.pro src/testdir/test_debugger.vim src/version.c src/vim.h src/vim9.h src/vim9execute.c
diffstat 8 files changed, 75 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/debugger.c
+++ b/src/debugger.c
@@ -518,6 +518,7 @@ static garray_T dbg_breakp = {0, 0, size
 #define BREAKP(idx)		(((struct debuggy *)dbg_breakp.ga_data)[idx])
 #define DEBUGGY(gap, idx)	(((struct debuggy *)gap->ga_data)[idx])
 static int last_breakp = 0;	// nr of last defined breakpoint
+static int has_expr_breakpoint = FALSE;
 
 #ifdef FEAT_PROFILE
 // Profiling uses file and func names similar to breakpoints.
@@ -691,6 +692,8 @@ ex_breakadd(exarg_T *eap)
 	    // DBG_EXPR
 	    DEBUGGY(gap, gap->ga_len++).dbg_nr = ++last_breakp;
 	    ++debug_tick;
+	    if (gap == &dbg_breakp)
+		has_expr_breakpoint = TRUE;
 	}
     }
 }
@@ -707,6 +710,29 @@ ex_debuggreedy(exarg_T *eap)
 	debug_greedy = FALSE;
 }
 
+    static void
+update_has_expr_breakpoint()
+{
+    int i;
+
+    has_expr_breakpoint = FALSE;
+    for (i = 0; i < dbg_breakp.ga_len; ++i)
+	if (BREAKP(i).dbg_type == DBG_EXPR)
+	{
+	    has_expr_breakpoint = TRUE;
+	    break;
+	}
+}
+
+/*
+ * Return TRUE if there is any expression breakpoint.
+ */
+    int
+debug_has_expr_breakpoint()
+{
+    return has_expr_breakpoint;
+}
+
 /*
  * ":breakdel" and ":profdel".
  */
@@ -799,6 +825,8 @@ ex_breakdel(exarg_T *eap)
 	// If all breakpoints were removed clear the array.
 	if (gap->ga_len == 0)
 	    ga_clear(gap);
+	if (gap == &dbg_breakp)
+	    update_has_expr_breakpoint();
     }
 }
 
--- a/src/proto/debugger.pro
+++ b/src/proto/debugger.pro
@@ -6,6 +6,7 @@ void dbg_check_breakpoint(exarg_T *eap);
 int dbg_check_skipped(exarg_T *eap);
 void ex_breakadd(exarg_T *eap);
 void ex_debuggreedy(exarg_T *eap);
+int debug_has_expr_breakpoint(void);
 void ex_breakdel(exarg_T *eap);
 void ex_breaklist(exarg_T *eap);
 linenr_T dbg_find_breakpoint(int file, char_u *fname, linenr_T after);
--- a/src/proto/vim9execute.pro
+++ b/src/proto/vim9execute.pro
@@ -5,6 +5,7 @@ char_u *char_from_string(char_u *str, va
 char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int exclusive);
 int fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx);
 typval_T *lookup_debug_var(char_u *name);
+int may_break_in_function(ufunc_T *ufunc);
 int exe_typval_instr(typval_T *tv, typval_T *rettv);
 char_u *exe_substitute_instr(void);
 int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, partial_T *partial, typval_T *rettv);
--- a/src/testdir/test_debugger.vim
+++ b/src/testdir/test_debugger.vim
@@ -932,6 +932,27 @@ func Test_Backtrace_DefFunction()
   call delete('Xtest2.vim')
 endfunc
 
+func Test_DefFunction_expr()
+  CheckCWD
+  let file3 =<< trim END
+      vim9script
+      g:someVar = "foo"
+      def g:ChangeVar()
+        g:someVar = "bar"
+        echo "changed"
+      enddef
+      defcompile
+  END
+  call writefile(file3, 'Xtest3.vim')
+  let buf = RunVimInTerminal('-S Xtest3.vim', {})
+
+  call RunDbgCmd(buf, ':breakadd expr g:someVar')
+  call RunDbgCmd(buf, ':call g:ChangeVar()', ['Oldval = "''foo''"', 'Newval = "''bar''"', 'function ChangeVar', 'line 2: echo "changed"'])
+
+  call StopVimInTerminal(buf)
+  call delete('Xtest3.vim')
+endfunc
+
 func Test_debug_def_and_legacy_function()
   CheckCWD
   let file =<< trim END
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3395,
+/**/
     3394,
 /**/
     3393,
--- a/src/vim.h
+++ b/src/vim.h
@@ -1808,9 +1808,16 @@ typedef enum {
 
 // Keep in sync with INSTRUCTIONS().
 #ifdef FEAT_PROFILE
-# define COMPILE_TYPE(ufunc) (debug_break_level > 0 || ufunc->uf_has_breakpoint ? CT_DEBUG : do_profiling == PROF_YES && (ufunc)->uf_profiling ? CT_PROFILE : CT_NONE)
+# define COMPILE_TYPE(ufunc) (debug_break_level > 0 \
+	|| may_break_in_function(ufunc) \
+		? CT_DEBUG \
+		: do_profiling == PROF_YES && (ufunc)->uf_profiling \
+			? CT_PROFILE : CT_NONE)
 #else
-# define COMPILE_TYPE(ufunc) debug_break_level > 0 || ufunc->uf_has_breakpoint ? CT_DEBUG : CT_NONE
+# define COMPILE_TYPE(ufunc) debug_break_level > 0 \
+	|| may_break_in_function(ufunc) \
+		? CT_DEBUG \
+		: CT_NONE
 #endif
 
 /*
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -513,14 +513,14 @@ extern garray_T def_functions;
 // Keep in sync with COMPILE_TYPE()
 #ifdef FEAT_PROFILE
 # define INSTRUCTIONS(dfunc) \
-	(debug_break_level > 0 || dfunc->df_ufunc->uf_has_breakpoint \
+	(debug_break_level > 0 || may_break_in_function(dfunc->df_ufunc) \
 	    ? (dfunc)->df_instr_debug \
 	    : ((do_profiling == PROF_YES && (dfunc->df_ufunc)->uf_profiling) \
 		? (dfunc)->df_instr_prof \
 		: (dfunc)->df_instr))
 #else
 # define INSTRUCTIONS(dfunc) \
-	(debug_break_level > 0 || dfunc->df_ufunc->uf_has_breakpoint \
+	(debug_break_level > 0 || may_break_in_function(dfunc->df_ufunc) \
 		? (dfunc)->df_instr_debug \
 		: (dfunc)->df_instr)
 #endif
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -1483,6 +1483,16 @@ lookup_debug_var(char_u *name)
     return NULL;
 }
 
+/*
+ * Return TRUE if there might be a breakpoint in "ufunc", which is when a
+ * breakpoint was set in that function or when there is any expression.
+ */
+    int
+may_break_in_function(ufunc_T *ufunc)
+{
+    return ufunc->uf_has_breakpoint || debug_has_expr_breakpoint();
+}
+
     static void
 handle_debug(isn_T *iptr, ectx_T *ectx)
 {
@@ -1498,7 +1508,7 @@ handle_debug(isn_T *iptr, ectx_T *ectx)
     {
 	linenr_T breakpoint;
 
-	if (!ufunc->uf_has_breakpoint)
+	if (!may_break_in_function(ufunc))
 	    return;
 
 	// check for the next breakpoint if needed