# HG changeset patch # User Bram Moolenaar # Date 1630602004 -7200 # Node ID 154663508d9b63498e9bb95e3109324fe9e8670a # Parent c3adc383b30f0b7dbcf7afd33155f1cba83dc670 patch 8.2.3395: Vim9: expression breakpoint not checked in :def function Commit: https://github.com/vim/vim/commit/26a4484da20039b61f18d3565a4b4339c4d1f7e3 Author: Bram Moolenaar 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) diff --git a/src/debugger.c b/src/debugger.c --- 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(); } } diff --git a/src/proto/debugger.pro b/src/proto/debugger.pro --- 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); diff --git a/src/proto/vim9execute.pro b/src/proto/vim9execute.pro --- 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); diff --git a/src/testdir/test_debugger.vim b/src/testdir/test_debugger.vim --- 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 diff --git a/src/version.c b/src/version.c --- 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, diff --git a/src/vim.h b/src/vim.h --- 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 /* diff --git a/src/vim9.h b/src/vim9.h --- 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 diff --git a/src/vim9execute.c b/src/vim9execute.c --- 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